xref: /petsc/src/vec/is/ao/impls/mapping/aomapping.c (revision 9df9fd5143ba1c31a6ffdf5ee874e33aec476f24)
1 
2 /*
3   These AO application ordering routines do not require that the input
4   be a permutation, but merely a 1-1 mapping. This implementation still
5   keeps the entire ordering on each processor.
6 */
7 
8 #include <../src/vec/is/ao/aoimpl.h>          /*I  "petscao.h" I*/
9 
10 typedef struct {
11   PetscInt N;
12   PetscInt *app;       /* app[i] is the partner for petsc[appPerm[i]] */
13   PetscInt *appPerm;
14   PetscInt *petsc;     /* petsc[j] is the partner for app[petscPerm[j]] */
15   PetscInt *petscPerm;
16 } AO_Mapping;
17 
18 #undef __FUNCT__
19 #define __FUNCT__ "AODestroy_Mapping"
20 PetscErrorCode AODestroy_Mapping(AO ao)
21 {
22   AO_Mapping     *aomap = (AO_Mapping*) ao->data;
23   PetscErrorCode ierr;
24 
25   PetscFunctionBegin;
26   ierr = PetscFree4(aomap->app,aomap->appPerm,aomap->petsc,aomap->petscPerm);CHKERRQ(ierr);
27   ierr = PetscFree(aomap);CHKERRQ(ierr);
28   PetscFunctionReturn(0);
29 }
30 
31 #undef __FUNCT__
32 #define __FUNCT__ "AOView_Mapping"
33 PetscErrorCode AOView_Mapping(AO ao, PetscViewer viewer)
34 {
35   AO_Mapping     *aomap = (AO_Mapping*) ao->data;
36   PetscMPIInt    rank;
37   PetscInt       i;
38   PetscBool      iascii;
39   PetscErrorCode ierr;
40 
41   PetscFunctionBegin;
42   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)ao), &rank);CHKERRQ(ierr);
43   if (rank) PetscFunctionReturn(0);
44 
45   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
46 
47   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
48   if (iascii) {
49     PetscViewerASCIIPrintf(viewer, "Number of elements in ordering %D\n", aomap->N);
50     PetscViewerASCIIPrintf(viewer, "   App.   PETSc\n");
51     for (i = 0; i < aomap->N; i++) {
52       PetscViewerASCIIPrintf(viewer, "%D   %D    %D\n", i, aomap->app[i], aomap->petsc[aomap->appPerm[i]]);
53     }
54   }
55   PetscFunctionReturn(0);
56 }
57 
58 #undef __FUNCT__
59 #define __FUNCT__ "AOPetscToApplication_Mapping"
60 PetscErrorCode AOPetscToApplication_Mapping(AO ao, PetscInt n, PetscInt *ia)
61 {
62   AO_Mapping *aomap = (AO_Mapping*) ao->data;
63   PetscInt   *app   = aomap->app;
64   PetscInt   *petsc = aomap->petsc;
65   PetscInt   *perm  = aomap->petscPerm;
66   PetscInt   N      = aomap->N;
67   PetscInt   low, high, mid=0;
68   PetscInt   idex;
69   PetscInt   i;
70 
71   /* It would be possible to use a single bisection search, which
72      recursively divided the indices to be converted, and searched
73      partitions which contained an index. This would result in
74      better running times if indices are clustered.
75   */
76   PetscFunctionBegin;
77   for (i = 0; i < n; i++) {
78     idex = ia[i];
79     if (idex < 0) continue;
80     /* Use bisection since the array is sorted */
81     low  = 0;
82     high = N - 1;
83     while (low <= high) {
84       mid = (low + high)/2;
85       if (idex == petsc[mid]) break;
86       else if (idex < petsc[mid]) high = mid - 1;
87       else low = mid + 1;
88     }
89     if (low > high) ia[i] = -1;
90     else            ia[i] = app[perm[mid]];
91   }
92   PetscFunctionReturn(0);
93 }
94 
95 #undef __FUNCT__
96 #define __FUNCT__ "AOApplicationToPetsc_Mapping"
97 PetscErrorCode AOApplicationToPetsc_Mapping(AO ao, PetscInt n, PetscInt *ia)
98 {
99   AO_Mapping *aomap = (AO_Mapping*) ao->data;
100   PetscInt   *app   = aomap->app;
101   PetscInt   *petsc = aomap->petsc;
102   PetscInt   *perm  = aomap->appPerm;
103   PetscInt   N      = aomap->N;
104   PetscInt   low, high, mid=0;
105   PetscInt   idex;
106   PetscInt   i;
107 
108   /* It would be possible to use a single bisection search, which
109      recursively divided the indices to be converted, and searched
110      partitions which contained an index. This would result in
111      better running times if indices are clustered.
112   */
113   PetscFunctionBegin;
114   for (i = 0; i < n; i++) {
115     idex = ia[i];
116     if (idex < 0) continue;
117     /* Use bisection since the array is sorted */
118     low  = 0;
119     high = N - 1;
120     while (low <= high) {
121       mid = (low + high)/2;
122       if (idex == app[mid]) break;
123       else if (idex < app[mid]) high = mid - 1;
124       else low = mid + 1;
125     }
126     if (low > high) ia[i] = -1;
127     else            ia[i] = petsc[perm[mid]];
128   }
129   PetscFunctionReturn(0);
130 }
131 
132 static struct _AOOps AOps = {AOView_Mapping,
133                              AODestroy_Mapping,
134                              AOPetscToApplication_Mapping,
135                              AOApplicationToPetsc_Mapping,
136                              NULL,
137                              NULL,
138                              NULL,
139                              NULL};
140 
141 #undef __FUNCT__
142 #define __FUNCT__ "AOMappingHasApplicationIndex"
143 /*@C
144   AOMappingHasApplicationIndex - Searches for the supplied application index.
145 
146   Input Parameters:
147 + ao       - The AOMapping
148 - index    - The application index
149 
150   Output Parameter:
151 . hasIndex - Flag is PETSC_TRUE if the index exists
152 
153   Level: intermediate
154 
155 .keywords: AO, index
156 .seealso: AOMappingHasPetscIndex(), AOCreateMapping()
157 @*/
158 PetscErrorCode  AOMappingHasApplicationIndex(AO ao, PetscInt idex, PetscBool  *hasIndex)
159 {
160   AO_Mapping *aomap;
161   PetscInt   *app;
162   PetscInt   low, high, mid;
163 
164   PetscFunctionBegin;
165   PetscValidHeaderSpecific(ao, AO_CLASSID,1);
166   PetscValidPointer(hasIndex,3);
167   aomap = (AO_Mapping*) ao->data;
168   app   = aomap->app;
169   /* Use bisection since the array is sorted */
170   low  = 0;
171   high = aomap->N - 1;
172   while (low <= high) {
173     mid = (low + high)/2;
174     if (idex == app[mid]) break;
175     else if (idex < app[mid]) high = mid - 1;
176     else low = mid + 1;
177   }
178   if (low > high) *hasIndex = PETSC_FALSE;
179   else *hasIndex = PETSC_TRUE;
180   PetscFunctionReturn(0);
181 }
182 
183 #undef __FUNCT__
184 #define __FUNCT__ "AOMappingHasPetscIndex"
185 /*@
186   AOMappingHasPetscIndex - Searches for the supplied petsc index.
187 
188   Input Parameters:
189 + ao       - The AOMapping
190 - index    - The petsc index
191 
192   Output Parameter:
193 . hasIndex - Flag is PETSC_TRUE if the index exists
194 
195   Level: intermediate
196 
197 .keywords: AO, index
198 .seealso: AOMappingHasApplicationIndex(), AOCreateMapping()
199 @*/
200 PetscErrorCode  AOMappingHasPetscIndex(AO ao, PetscInt idex, PetscBool  *hasIndex)
201 {
202   AO_Mapping *aomap;
203   PetscInt   *petsc;
204   PetscInt   low, high, mid;
205 
206   PetscFunctionBegin;
207   PetscValidHeaderSpecific(ao, AO_CLASSID,1);
208   PetscValidPointer(hasIndex,3);
209   aomap = (AO_Mapping*) ao->data;
210   petsc = aomap->petsc;
211   /* Use bisection since the array is sorted */
212   low  = 0;
213   high = aomap->N - 1;
214   while (low <= high) {
215     mid = (low + high)/2;
216     if (idex == petsc[mid]) break;
217     else if (idex < petsc[mid]) high = mid - 1;
218     else low = mid + 1;
219   }
220   if (low > high) *hasIndex = PETSC_FALSE;
221   else *hasIndex = PETSC_TRUE;
222   PetscFunctionReturn(0);
223 }
224 
225 #undef __FUNCT__
226 #define __FUNCT__ "AOCreateMapping"
227 /*@C
228   AOCreateMapping - Creates a basic application mapping using two integer arrays.
229 
230   Input Parameters:
231 + comm    - MPI communicator that is to share AO
232 . napp    - size of integer arrays
233 . myapp   - integer array that defines an ordering
234 - mypetsc - integer array that defines another ordering (may be NULL to indicate the identity ordering)
235 
236   Output Parameter:
237 . aoout   - the new application mapping
238 
239   Options Database Key:
240 $ -ao_view : call AOView() at the conclusion of AOCreateMapping()
241 
242   Level: beginner
243 
244     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.
245        Use AOCreateBasic() or AOCreateBasicIS() if they do not have holes for better performance.
246 
247 .keywords: AO, create
248 .seealso: AOCreateBasic(), AOCreateBasic(), AOCreateMappingIS(), AODestroy()
249 @*/
250 PetscErrorCode  AOCreateMapping(MPI_Comm comm,PetscInt napp,const PetscInt myapp[],const PetscInt mypetsc[],AO *aoout)
251 {
252   AO             ao;
253   AO_Mapping     *aomap;
254   PetscInt       *allpetsc,  *allapp;
255   PetscInt       *petscPerm, *appPerm;
256   PetscInt       *petsc;
257   PetscMPIInt    size, rank,*lens, *disp,nnapp;
258   PetscInt       N, start;
259   PetscInt       i;
260   PetscErrorCode ierr;
261 
262   PetscFunctionBegin;
263   PetscValidPointer(aoout,5);
264   *aoout = 0;
265 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
266   ierr = AOInitializePackage();CHKERRQ(ierr);
267 #endif
268 
269   ierr     = PetscHeaderCreate(ao, _p_AO, struct _AOOps, AO_CLASSID, "AO", "Application Ordering", "AO", comm, AODestroy, AOView);CHKERRQ(ierr);
270   ierr     = PetscNewLog(ao, AO_Mapping, &aomap);CHKERRQ(ierr);
271   ierr     = PetscMemcpy(ao->ops, &AOps, sizeof(AOps));CHKERRQ(ierr);
272   ao->data = (void*) aomap;
273 
274   /* transmit all lengths to all processors */
275   ierr  = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
276   ierr  = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
277   ierr  = PetscMalloc2(size,PetscMPIInt, &lens,size,PetscMPIInt,&disp);CHKERRQ(ierr);
278   nnapp = napp;
279   ierr  = MPI_Allgather(&nnapp, 1, MPI_INT, lens, 1, MPI_INT, comm);CHKERRQ(ierr);
280   N     = 0;
281   for (i = 0; i < size; i++) {
282     disp[i] = N;
283     N      += lens[i];
284   }
285   aomap->N = N;
286   ao->N    = N;
287   ao->n    = N;
288 
289   /* If mypetsc is 0 then use "natural" numbering */
290   if (!mypetsc) {
291     start = disp[rank];
292     ierr  = PetscMalloc((napp+1) * sizeof(PetscInt), &petsc);CHKERRQ(ierr);
293     for (i = 0; i < napp; i++) petsc[i] = start + i;
294   } else {
295     petsc = (PetscInt*)mypetsc;
296   }
297 
298   /* get all indices on all processors */
299   ierr = PetscMalloc4(N,PetscInt, &allapp,N,PetscInt,&appPerm,N,PetscInt,&allpetsc,N,PetscInt,&petscPerm);CHKERRQ(ierr);
300   ierr = MPI_Allgatherv((void*)myapp, napp, MPIU_INT, allapp,   lens, disp, MPIU_INT, comm);CHKERRQ(ierr);
301   ierr = MPI_Allgatherv((void*)petsc, napp, MPIU_INT, allpetsc, lens, disp, MPIU_INT, comm);CHKERRQ(ierr);
302   ierr = PetscFree2(lens,disp);CHKERRQ(ierr);
303 
304   /* generate a list of application and PETSc node numbers */
305   ierr = PetscMalloc4(N,PetscInt, &aomap->app,N,PetscInt,&aomap->appPerm,N,PetscInt,&aomap->petsc,N,PetscInt,&aomap->petscPerm);CHKERRQ(ierr);
306   ierr = PetscLogObjectMemory(ao, 4*N * sizeof(PetscInt));CHKERRQ(ierr);
307   for (i = 0; i < N; i++) {
308     appPerm[i]   = i;
309     petscPerm[i] = i;
310   }
311   ierr = PetscSortIntWithPermutation(N, allpetsc, petscPerm);CHKERRQ(ierr);
312   ierr = PetscSortIntWithPermutation(N, allapp,   appPerm);CHKERRQ(ierr);
313   /* Form sorted arrays of indices */
314   for (i = 0; i < N; i++) {
315     aomap->app[i]   = allapp[appPerm[i]];
316     aomap->petsc[i] = allpetsc[petscPerm[i]];
317   }
318   /* Invert petscPerm[] into aomap->petscPerm[] */
319   for (i = 0; i < N; i++) aomap->petscPerm[petscPerm[i]] = i;
320 
321   /* Form map between aomap->app[] and aomap->petsc[] */
322   for (i = 0; i < N; i++) aomap->appPerm[i] = aomap->petscPerm[appPerm[i]];
323 
324   /* Invert appPerm[] into allapp[] */
325   for (i = 0; i < N; i++) allapp[appPerm[i]] = i;
326 
327   /* Form map between aomap->petsc[] and aomap->app[] */
328   for (i = 0; i < N; i++) aomap->petscPerm[i] = allapp[petscPerm[i]];
329 
330 #if defined(PETSC_USE_DEBUG)
331   /* Check that the permutations are complementary */
332   for (i = 0; i < N; i++) {
333     if (i != aomap->appPerm[aomap->petscPerm[i]]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB, "Invalid ordering");
334   }
335 #endif
336   /* Cleanup */
337   if (!mypetsc) {
338     ierr = PetscFree(petsc);CHKERRQ(ierr);
339   }
340   ierr = PetscFree4(allapp,appPerm,allpetsc,petscPerm);CHKERRQ(ierr);
341 
342   ierr = AOViewFromOptions(ao,NULL,"-ao_view");CHKERRQ(ierr);
343 
344   *aoout = ao;
345   PetscFunctionReturn(0);
346 }
347 
348 #undef __FUNCT__
349 #define __FUNCT__ "AOCreateMappingIS"
350 /*@C
351   AOCreateMappingIS - Creates a basic application ordering using two index sets.
352 
353   Input Parameters:
354 + comm    - MPI communicator that is to share AO
355 . isapp   - index set that defines an ordering
356 - ispetsc - index set that defines another ordering, maybe NULL for identity IS
357 
358   Output Parameter:
359 . aoout   - the new application ordering
360 
361   Options Database Key:
362 $ -ao_view : call AOView() at the conclusion of AOCreateMappingIS()
363 
364   Level: beginner
365 
366     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.
367        Use AOCreateBasic() or AOCreateBasicIS() if they do not have holes for better performance.
368 
369 .keywords: AO, create
370 .seealso: AOCreateBasic(), AOCreateMapping(), AODestroy()
371 @*/
372 PetscErrorCode  AOCreateMappingIS(IS isapp, IS ispetsc, AO *aoout)
373 {
374   MPI_Comm       comm;
375   const PetscInt *mypetsc, *myapp;
376   PetscInt       napp, npetsc;
377   PetscErrorCode ierr;
378 
379   PetscFunctionBegin;
380   ierr = PetscObjectGetComm((PetscObject) isapp, &comm);CHKERRQ(ierr);
381   ierr = ISGetLocalSize(isapp, &napp);CHKERRQ(ierr);
382   if (ispetsc) {
383     ierr = ISGetLocalSize(ispetsc, &npetsc);CHKERRQ(ierr);
384     if (napp != npetsc) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ, "Local IS lengths must match");
385     ierr = ISGetIndices(ispetsc, &mypetsc);CHKERRQ(ierr);
386   } else {
387     mypetsc = NULL;
388   }
389   ierr = ISGetIndices(isapp, &myapp);CHKERRQ(ierr);
390 
391   ierr = AOCreateMapping(comm, napp, myapp, mypetsc, aoout);CHKERRQ(ierr);
392 
393   ierr = ISRestoreIndices(isapp, &myapp);CHKERRQ(ierr);
394   if (ispetsc) {
395     ierr = ISRestoreIndices(ispetsc, &mypetsc);CHKERRQ(ierr);
396   }
397   PetscFunctionReturn(0);
398 }
399