1 2 /* 3 The most basic AO application ordering routines. These store the 4 entire orderings on each processor. 5 */ 6 7 #include <../src/vec/is/ao/aoimpl.h> /*I "petscao.h" I*/ 8 9 typedef struct { 10 PetscInt *app; /* app[i] is the partner for the ith PETSc slot */ 11 PetscInt *petsc; /* petsc[j] is the partner for the jth app slot */ 12 } AO_Basic; 13 14 /* 15 All processors have the same data so processor 1 prints it 16 */ 17 PetscErrorCode AOView_Basic(AO ao, PetscViewer viewer) { 18 PetscMPIInt rank; 19 PetscInt i; 20 AO_Basic *aobasic = (AO_Basic *)ao->data; 21 PetscBool iascii; 22 23 PetscFunctionBegin; 24 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)ao), &rank)); 25 if (rank == 0) { 26 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 27 if (iascii) { 28 PetscCall(PetscViewerASCIIPrintf(viewer, "Number of elements in ordering %" PetscInt_FMT "\n", ao->N)); 29 PetscCall(PetscViewerASCIIPrintf(viewer, "PETSc->App App->PETSc\n")); 30 for (i = 0; i < ao->N; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " %3" PetscInt_FMT " %3" PetscInt_FMT " %3" PetscInt_FMT "\n", i, aobasic->app[i], i, aobasic->petsc[i])); 31 } 32 } 33 PetscCall(PetscViewerFlush(viewer)); 34 PetscFunctionReturn(0); 35 } 36 37 PetscErrorCode AODestroy_Basic(AO ao) { 38 AO_Basic *aobasic = (AO_Basic *)ao->data; 39 40 PetscFunctionBegin; 41 PetscCall(PetscFree2(aobasic->app, aobasic->petsc)); 42 PetscCall(PetscFree(aobasic)); 43 PetscFunctionReturn(0); 44 } 45 46 PetscErrorCode AOBasicGetIndices_Private(AO ao, PetscInt **app, PetscInt **petsc) { 47 AO_Basic *basic = (AO_Basic *)ao->data; 48 49 PetscFunctionBegin; 50 if (app) *app = basic->app; 51 if (petsc) *petsc = basic->petsc; 52 PetscFunctionReturn(0); 53 } 54 55 PetscErrorCode AOPetscToApplication_Basic(AO ao, PetscInt n, PetscInt *ia) { 56 PetscInt i, N = ao->N; 57 AO_Basic *aobasic = (AO_Basic *)ao->data; 58 59 PetscFunctionBegin; 60 for (i = 0; i < n; i++) { 61 if (ia[i] >= 0 && ia[i] < N) { 62 ia[i] = aobasic->app[ia[i]]; 63 } else { 64 ia[i] = -1; 65 } 66 } 67 PetscFunctionReturn(0); 68 } 69 70 PetscErrorCode AOApplicationToPetsc_Basic(AO ao, PetscInt n, PetscInt *ia) { 71 PetscInt i, N = ao->N; 72 AO_Basic *aobasic = (AO_Basic *)ao->data; 73 74 PetscFunctionBegin; 75 for (i = 0; i < n; i++) { 76 if (ia[i] >= 0 && ia[i] < N) { 77 ia[i] = aobasic->petsc[ia[i]]; 78 } else { 79 ia[i] = -1; 80 } 81 } 82 PetscFunctionReturn(0); 83 } 84 85 PetscErrorCode AOPetscToApplicationPermuteInt_Basic(AO ao, PetscInt block, PetscInt *array) { 86 AO_Basic *aobasic = (AO_Basic *)ao->data; 87 PetscInt *temp; 88 PetscInt i, j; 89 90 PetscFunctionBegin; 91 PetscCall(PetscMalloc1(ao->N * block, &temp)); 92 for (i = 0; i < ao->N; i++) { 93 for (j = 0; j < block; j++) temp[i * block + j] = array[aobasic->petsc[i] * block + j]; 94 } 95 PetscCall(PetscArraycpy(array, temp, ao->N * block)); 96 PetscCall(PetscFree(temp)); 97 PetscFunctionReturn(0); 98 } 99 100 PetscErrorCode AOApplicationToPetscPermuteInt_Basic(AO ao, PetscInt block, PetscInt *array) { 101 AO_Basic *aobasic = (AO_Basic *)ao->data; 102 PetscInt *temp; 103 PetscInt i, j; 104 105 PetscFunctionBegin; 106 PetscCall(PetscMalloc1(ao->N * block, &temp)); 107 for (i = 0; i < ao->N; i++) { 108 for (j = 0; j < block; j++) temp[i * block + j] = array[aobasic->app[i] * block + j]; 109 } 110 PetscCall(PetscArraycpy(array, temp, ao->N * block)); 111 PetscCall(PetscFree(temp)); 112 PetscFunctionReturn(0); 113 } 114 115 PetscErrorCode AOPetscToApplicationPermuteReal_Basic(AO ao, PetscInt block, PetscReal *array) { 116 AO_Basic *aobasic = (AO_Basic *)ao->data; 117 PetscReal *temp; 118 PetscInt i, j; 119 120 PetscFunctionBegin; 121 PetscCall(PetscMalloc1(ao->N * block, &temp)); 122 for (i = 0; i < ao->N; i++) { 123 for (j = 0; j < block; j++) temp[i * block + j] = array[aobasic->petsc[i] * block + j]; 124 } 125 PetscCall(PetscArraycpy(array, temp, ao->N * block)); 126 PetscCall(PetscFree(temp)); 127 PetscFunctionReturn(0); 128 } 129 130 PetscErrorCode AOApplicationToPetscPermuteReal_Basic(AO ao, PetscInt block, PetscReal *array) { 131 AO_Basic *aobasic = (AO_Basic *)ao->data; 132 PetscReal *temp; 133 PetscInt i, j; 134 135 PetscFunctionBegin; 136 PetscCall(PetscMalloc1(ao->N * block, &temp)); 137 for (i = 0; i < ao->N; i++) { 138 for (j = 0; j < block; j++) temp[i * block + j] = array[aobasic->app[i] * block + j]; 139 } 140 PetscCall(PetscArraycpy(array, temp, ao->N * block)); 141 PetscCall(PetscFree(temp)); 142 PetscFunctionReturn(0); 143 } 144 145 static struct _AOOps AOOps_Basic = { 146 PetscDesignatedInitializer(view, AOView_Basic), 147 PetscDesignatedInitializer(destroy, AODestroy_Basic), 148 PetscDesignatedInitializer(petsctoapplication, AOPetscToApplication_Basic), 149 PetscDesignatedInitializer(applicationtopetsc, AOApplicationToPetsc_Basic), 150 PetscDesignatedInitializer(petsctoapplicationpermuteint, AOPetscToApplicationPermuteInt_Basic), 151 PetscDesignatedInitializer(applicationtopetscpermuteint, AOApplicationToPetscPermuteInt_Basic), 152 PetscDesignatedInitializer(petsctoapplicationpermutereal, AOPetscToApplicationPermuteReal_Basic), 153 PetscDesignatedInitializer(applicationtopetscpermutereal, AOApplicationToPetscPermuteReal_Basic), 154 }; 155 156 PETSC_EXTERN PetscErrorCode AOCreate_Basic(AO ao) { 157 AO_Basic *aobasic; 158 PetscMPIInt size, rank, count, *lens, *disp; 159 PetscInt napp, *allpetsc, *allapp, ip, ia, N, i, *petsc = NULL, start; 160 IS isapp = ao->isapp, ispetsc = ao->ispetsc; 161 MPI_Comm comm; 162 const PetscInt *myapp, *mypetsc = NULL; 163 164 PetscFunctionBegin; 165 /* create special struct aobasic */ 166 PetscCall(PetscNew(&aobasic)); 167 ao->data = (void *)aobasic; 168 PetscCall(PetscMemcpy(ao->ops, &AOOps_Basic, sizeof(struct _AOOps))); 169 PetscCall(PetscObjectChangeTypeName((PetscObject)ao, AOBASIC)); 170 171 PetscCall(ISGetLocalSize(isapp, &napp)); 172 PetscCall(ISGetIndices(isapp, &myapp)); 173 174 PetscCall(PetscMPIIntCast(napp, &count)); 175 176 /* transmit all lengths to all processors */ 177 PetscCall(PetscObjectGetComm((PetscObject)isapp, &comm)); 178 PetscCallMPI(MPI_Comm_size(comm, &size)); 179 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 180 PetscCall(PetscMalloc2(size, &lens, size, &disp)); 181 PetscCallMPI(MPI_Allgather(&count, 1, MPI_INT, lens, 1, MPI_INT, comm)); 182 N = 0; 183 for (i = 0; i < size; i++) { 184 PetscCall(PetscMPIIntCast(N, disp + i)); /* = sum(lens[j]), j< i */ 185 N += lens[i]; 186 } 187 ao->N = N; 188 ao->n = N; 189 190 /* If mypetsc is 0 then use "natural" numbering */ 191 if (napp) { 192 if (!ispetsc) { 193 start = disp[rank]; 194 PetscCall(PetscMalloc1(napp + 1, &petsc)); 195 for (i = 0; i < napp; i++) petsc[i] = start + i; 196 } else { 197 PetscCall(ISGetIndices(ispetsc, &mypetsc)); 198 petsc = (PetscInt *)mypetsc; 199 } 200 } 201 202 /* get all indices on all processors */ 203 PetscCall(PetscMalloc2(N, &allpetsc, N, &allapp)); 204 PetscCallMPI(MPI_Allgatherv(petsc, count, MPIU_INT, allpetsc, lens, disp, MPIU_INT, comm)); 205 PetscCallMPI(MPI_Allgatherv((void *)myapp, count, MPIU_INT, allapp, lens, disp, MPIU_INT, comm)); 206 PetscCall(PetscFree2(lens, disp)); 207 208 if (PetscDefined(USE_DEBUG)) { 209 PetscInt *sorted; 210 PetscCall(PetscMalloc1(N, &sorted)); 211 212 PetscCall(PetscArraycpy(sorted, allpetsc, N)); 213 PetscCall(PetscSortInt(N, sorted)); 214 for (i = 0; i < N; i++) PetscCheck(sorted[i] == i, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PETSc ordering requires a permutation of numbers 0 to N-1\n it is missing %" PetscInt_FMT " has %" PetscInt_FMT, i, sorted[i]); 215 216 PetscCall(PetscArraycpy(sorted, allapp, N)); 217 PetscCall(PetscSortInt(N, sorted)); 218 for (i = 0; i < N; i++) PetscCheck(sorted[i] == i, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Application ordering requires a permutation of numbers 0 to N-1\n it is missing %" PetscInt_FMT " has %" PetscInt_FMT, i, sorted[i]); 219 220 PetscCall(PetscFree(sorted)); 221 } 222 223 /* generate a list of application and PETSc node numbers */ 224 PetscCall(PetscCalloc2(N, &aobasic->app, N, &aobasic->petsc)); 225 for (i = 0; i < N; i++) { 226 ip = allpetsc[i]; 227 ia = allapp[i]; 228 /* check there are no duplicates */ 229 PetscCheck(!aobasic->app[ip], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Duplicate in PETSc ordering at position %" PetscInt_FMT ". Already mapped to %" PetscInt_FMT ", not %" PetscInt_FMT ".", i, aobasic->app[ip] - 1, ia); 230 aobasic->app[ip] = ia + 1; 231 PetscCheck(!aobasic->petsc[ia], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Duplicate in Application ordering at position %" PetscInt_FMT ". Already mapped to %" PetscInt_FMT ", not %" PetscInt_FMT ".", i, aobasic->petsc[ia] - 1, ip); 232 aobasic->petsc[ia] = ip + 1; 233 } 234 if (napp && !mypetsc) PetscCall(PetscFree(petsc)); 235 PetscCall(PetscFree2(allpetsc, allapp)); 236 /* shift indices down by one */ 237 for (i = 0; i < N; i++) { 238 aobasic->app[i]--; 239 aobasic->petsc[i]--; 240 } 241 242 PetscCall(ISRestoreIndices(isapp, &myapp)); 243 if (napp) { 244 if (ispetsc) { 245 PetscCall(ISRestoreIndices(ispetsc, &mypetsc)); 246 } else { 247 PetscCall(PetscFree(petsc)); 248 } 249 } 250 PetscFunctionReturn(0); 251 } 252 253 /*@C 254 AOCreateBasic - Creates a basic application ordering using two integer arrays. 255 256 Collective 257 258 Input Parameters: 259 + comm - MPI communicator that is to share AO 260 . napp - size of integer arrays 261 . myapp - integer array that defines an ordering 262 - mypetsc - integer array that defines another ordering (may be NULL to 263 indicate the natural ordering, that is 0,1,2,3,...) 264 265 Output Parameter: 266 . aoout - the new application ordering 267 268 Level: beginner 269 270 Notes: 271 the arrays myapp and mypetsc must contain the all the integers 0 to napp-1 with no duplicates; that is there cannot be any "holes" 272 in the indices. Use AOCreateMapping() or AOCreateMappingIS() if you wish to have "holes" in the indices. 273 274 .seealso: `AOCreateBasicIS()`, `AODestroy()`, `AOPetscToApplication()`, `AOApplicationToPetsc()` 275 @*/ 276 PetscErrorCode AOCreateBasic(MPI_Comm comm, PetscInt napp, const PetscInt myapp[], const PetscInt mypetsc[], AO *aoout) { 277 IS isapp, ispetsc; 278 const PetscInt *app = myapp, *petsc = mypetsc; 279 280 PetscFunctionBegin; 281 PetscCall(ISCreateGeneral(comm, napp, app, PETSC_USE_POINTER, &isapp)); 282 if (mypetsc) { 283 PetscCall(ISCreateGeneral(comm, napp, petsc, PETSC_USE_POINTER, &ispetsc)); 284 } else { 285 ispetsc = NULL; 286 } 287 PetscCall(AOCreateBasicIS(isapp, ispetsc, aoout)); 288 PetscCall(ISDestroy(&isapp)); 289 if (mypetsc) PetscCall(ISDestroy(&ispetsc)); 290 PetscFunctionReturn(0); 291 } 292 293 /*@C 294 AOCreateBasicIS - Creates a basic application ordering using two index sets. 295 296 Collective on IS 297 298 Input Parameters: 299 + isapp - index set that defines an ordering 300 - ispetsc - index set that defines another ordering (may be NULL to use the 301 natural ordering) 302 303 Output Parameter: 304 . aoout - the new application ordering 305 306 Level: beginner 307 308 Notes: 309 the index sets isapp and ispetsc must contain the all the integers 0 to napp-1 (where napp is the length of the index sets) with no duplicates; 310 that is there cannot be any "holes" 311 312 .seealso: `AOCreateBasic()`, `AODestroy()` 313 @*/ 314 PetscErrorCode AOCreateBasicIS(IS isapp, IS ispetsc, AO *aoout) { 315 MPI_Comm comm; 316 AO ao; 317 318 PetscFunctionBegin; 319 PetscCall(PetscObjectGetComm((PetscObject)isapp, &comm)); 320 PetscCall(AOCreate(comm, &ao)); 321 PetscCall(AOSetIS(ao, isapp, ispetsc)); 322 PetscCall(AOSetType(ao, AOBASIC)); 323 PetscCall(AOViewFromOptions(ao, NULL, "-ao_view")); 324 *aoout = ao; 325 PetscFunctionReturn(0); 326 } 327