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 PetscBool opt; 261 PetscErrorCode ierr; 262 263 PetscFunctionBegin; 264 PetscValidPointer(aoout,5); 265 *aoout = 0; 266 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES) 267 ierr = AOInitializePackage(NULL);CHKERRQ(ierr); 268 #endif 269 270 ierr = PetscHeaderCreate(ao, _p_AO, struct _AOOps, AO_CLASSID, "AO", "Application Ordering", "AO", comm, AODestroy, AOView);CHKERRQ(ierr); 271 ierr = PetscNewLog(ao, AO_Mapping, &aomap);CHKERRQ(ierr); 272 ierr = PetscMemcpy(ao->ops, &AOps, sizeof(AOps));CHKERRQ(ierr); 273 ao->data = (void*) aomap; 274 275 /* transmit all lengths to all processors */ 276 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 277 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 278 ierr = PetscMalloc2(size,PetscMPIInt, &lens,size,PetscMPIInt,&disp);CHKERRQ(ierr); 279 nnapp = napp; 280 ierr = MPI_Allgather(&nnapp, 1, MPI_INT, lens, 1, MPI_INT, comm);CHKERRQ(ierr); 281 N = 0; 282 for (i = 0; i < size; i++) { 283 disp[i] = N; 284 N += lens[i]; 285 } 286 aomap->N = N; 287 ao->N = N; 288 ao->n = N; 289 290 /* If mypetsc is 0 then use "natural" numbering */ 291 if (!mypetsc) { 292 start = disp[rank]; 293 ierr = PetscMalloc((napp+1) * sizeof(PetscInt), &petsc);CHKERRQ(ierr); 294 for (i = 0; i < napp; i++) petsc[i] = start + i; 295 } else { 296 petsc = (PetscInt*)mypetsc; 297 } 298 299 /* get all indices on all processors */ 300 ierr = PetscMalloc4(N,PetscInt, &allapp,N,PetscInt,&appPerm,N,PetscInt,&allpetsc,N,PetscInt,&petscPerm);CHKERRQ(ierr); 301 ierr = MPI_Allgatherv((void*)myapp, napp, MPIU_INT, allapp, lens, disp, MPIU_INT, comm);CHKERRQ(ierr); 302 ierr = MPI_Allgatherv((void*)petsc, napp, MPIU_INT, allpetsc, lens, disp, MPIU_INT, comm);CHKERRQ(ierr); 303 ierr = PetscFree2(lens,disp);CHKERRQ(ierr); 304 305 /* generate a list of application and PETSc node numbers */ 306 ierr = PetscMalloc4(N,PetscInt, &aomap->app,N,PetscInt,&aomap->appPerm,N,PetscInt,&aomap->petsc,N,PetscInt,&aomap->petscPerm);CHKERRQ(ierr); 307 ierr = PetscLogObjectMemory(ao, 4*N * sizeof(PetscInt));CHKERRQ(ierr); 308 for (i = 0; i < N; i++) { 309 appPerm[i] = i; 310 petscPerm[i] = i; 311 } 312 ierr = PetscSortIntWithPermutation(N, allpetsc, petscPerm);CHKERRQ(ierr); 313 ierr = PetscSortIntWithPermutation(N, allapp, appPerm);CHKERRQ(ierr); 314 /* Form sorted arrays of indices */ 315 for (i = 0; i < N; i++) { 316 aomap->app[i] = allapp[appPerm[i]]; 317 aomap->petsc[i] = allpetsc[petscPerm[i]]; 318 } 319 /* Invert petscPerm[] into aomap->petscPerm[] */ 320 for (i = 0; i < N; i++) aomap->petscPerm[petscPerm[i]] = i; 321 322 /* Form map between aomap->app[] and aomap->petsc[] */ 323 for (i = 0; i < N; i++) aomap->appPerm[i] = aomap->petscPerm[appPerm[i]]; 324 325 /* Invert appPerm[] into allapp[] */ 326 for (i = 0; i < N; i++) allapp[appPerm[i]] = i; 327 328 /* Form map between aomap->petsc[] and aomap->app[] */ 329 for (i = 0; i < N; i++) aomap->petscPerm[i] = allapp[petscPerm[i]]; 330 331 #if defined(PETSC_USE_DEBUG) 332 /* Check that the permutations are complementary */ 333 for (i = 0; i < N; i++) { 334 if (i != aomap->appPerm[aomap->petscPerm[i]]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB, "Invalid ordering"); 335 } 336 #endif 337 /* Cleanup */ 338 if (!mypetsc) { 339 ierr = PetscFree(petsc);CHKERRQ(ierr); 340 } 341 ierr = PetscFree4(allapp,appPerm,allpetsc,petscPerm);CHKERRQ(ierr); 342 343 opt = PETSC_FALSE; 344 ierr = PetscOptionsGetBool(NULL, "-ao_view", &opt,NULL);CHKERRQ(ierr); 345 if (opt) { 346 ierr = AOView(ao, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr); 347 } 348 349 *aoout = ao; 350 PetscFunctionReturn(0); 351 } 352 353 #undef __FUNCT__ 354 #define __FUNCT__ "AOCreateMappingIS" 355 /*@C 356 AOCreateMappingIS - Creates a basic application ordering using two index sets. 357 358 Input Parameters: 359 + comm - MPI communicator that is to share AO 360 . isapp - index set that defines an ordering 361 - ispetsc - index set that defines another ordering, maybe NULL for identity IS 362 363 Output Parameter: 364 . aoout - the new application ordering 365 366 Options Database Key: 367 $ -ao_view : call AOView() at the conclusion of AOCreateMappingIS() 368 369 Level: beginner 370 371 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. 372 Use AOCreateBasic() or AOCreateBasicIS() if they do not have holes for better performance. 373 374 .keywords: AO, create 375 .seealso: AOCreateBasic(), AOCreateMapping(), AODestroy() 376 @*/ 377 PetscErrorCode AOCreateMappingIS(IS isapp, IS ispetsc, AO *aoout) 378 { 379 MPI_Comm comm; 380 const PetscInt *mypetsc, *myapp; 381 PetscInt napp, npetsc; 382 PetscErrorCode ierr; 383 384 PetscFunctionBegin; 385 ierr = PetscObjectGetComm((PetscObject) isapp, &comm);CHKERRQ(ierr); 386 ierr = ISGetLocalSize(isapp, &napp);CHKERRQ(ierr); 387 if (ispetsc) { 388 ierr = ISGetLocalSize(ispetsc, &npetsc);CHKERRQ(ierr); 389 if (napp != npetsc) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ, "Local IS lengths must match"); 390 ierr = ISGetIndices(ispetsc, &mypetsc);CHKERRQ(ierr); 391 } else { 392 mypetsc = NULL; 393 } 394 ierr = ISGetIndices(isapp, &myapp);CHKERRQ(ierr); 395 396 ierr = AOCreateMapping(comm, napp, myapp, mypetsc, aoout);CHKERRQ(ierr); 397 398 ierr = ISRestoreIndices(isapp, &myapp);CHKERRQ(ierr); 399 if (ispetsc) { 400 ierr = ISRestoreIndices(ispetsc, &mypetsc);CHKERRQ(ierr); 401 } 402 PetscFunctionReturn(0); 403 } 404