1 #include <petscsf.h> 2 #include <petscdmswarm.h> 3 #include <petscdmda.h> 4 #include <petsc/private/dmswarmimpl.h> /*I "petscdmswarm.h" I*/ 5 #include "../src/dm/impls/swarm/data_bucket.h" 6 #include "../src/dm/impls/swarm/data_ex.h" 7 8 /* 9 User loads desired location (MPI rank) into field DMSwarm_rank 10 */ 11 PetscErrorCode DMSwarmMigrate_Push_Basic(DM dm, PetscBool remove_sent_points) 12 { 13 DM_Swarm *swarm = (DM_Swarm *)dm->data; 14 DMSwarmDataEx de; 15 PetscInt p, npoints, *rankval, n_points_recv; 16 PetscMPIInt rank, nrank; 17 void *point_buffer, *recv_points; 18 size_t sizeof_dmswarm_point; 19 PetscBool debug = PETSC_FALSE; 20 21 PetscFunctionBegin; 22 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 23 24 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 25 PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 26 PetscCall(DMSwarmDataExCreate(PetscObjectComm((PetscObject)dm), 0, &de)); 27 PetscCall(DMSwarmDataExTopologyInitialize(de)); 28 for (p = 0; p < npoints; ++p) { 29 nrank = rankval[p]; 30 if (nrank != rank) PetscCall(DMSwarmDataExTopologyAddNeighbour(de, nrank)); 31 } 32 PetscCall(DMSwarmDataExTopologyFinalize(de)); 33 PetscCall(DMSwarmDataExInitializeSendCount(de)); 34 for (p = 0; p < npoints; p++) { 35 nrank = rankval[p]; 36 if (nrank != rank) PetscCall(DMSwarmDataExAddToSendCount(de, nrank, 1)); 37 } 38 PetscCall(DMSwarmDataExFinalizeSendCount(de)); 39 PetscCall(DMSwarmDataBucketCreatePackedArray(swarm->db, &sizeof_dmswarm_point, &point_buffer)); 40 PetscCall(DMSwarmDataExPackInitialize(de, sizeof_dmswarm_point)); 41 for (p = 0; p < npoints; p++) { 42 nrank = rankval[p]; 43 if (nrank != rank) { 44 /* copy point into buffer */ 45 PetscCall(DMSwarmDataBucketFillPackedArray(swarm->db, p, point_buffer)); 46 /* insert point buffer into DMSwarmDataExchanger */ 47 PetscCall(DMSwarmDataExPackData(de, nrank, 1, point_buffer)); 48 } 49 } 50 PetscCall(DMSwarmDataExPackFinalize(de)); 51 PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 52 53 if (remove_sent_points) { 54 DMSwarmDataField gfield; 55 56 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, DMSwarmField_rank, &gfield)); 57 PetscCall(DMSwarmDataFieldGetAccess(gfield)); 58 PetscCall(DMSwarmDataFieldGetEntries(gfield, (void **)&rankval)); 59 60 /* remove points which left processor */ 61 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 62 for (p = 0; p < npoints; p++) { 63 nrank = rankval[p]; 64 if (nrank != rank) { 65 /* kill point */ 66 PetscCall(DMSwarmDataFieldRestoreAccess(gfield)); 67 68 PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, p)); 69 70 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); /* you need to update npoints as the list size decreases! */ 71 PetscCall(DMSwarmDataFieldGetAccess(gfield)); 72 PetscCall(DMSwarmDataFieldGetEntries(gfield, (void **)&rankval)); 73 p--; /* check replacement point */ 74 } 75 } 76 PetscCall(DMSwarmDataFieldRestoreEntries(gfield, (void **)&rankval)); 77 PetscCall(DMSwarmDataFieldRestoreAccess(gfield)); 78 } 79 PetscCall(DMSwarmDataExBegin(de)); 80 PetscCall(DMSwarmDataExEnd(de)); 81 PetscCall(DMSwarmDataExGetRecvData(de, &n_points_recv, (void **)&recv_points)); 82 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 83 PetscCall(DMSwarmDataBucketSetSizes(swarm->db, npoints + n_points_recv, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT)); 84 for (p = 0; p < n_points_recv; p++) { 85 void *data_p = (void *)((char *)recv_points + p * sizeof_dmswarm_point); 86 87 PetscCall(DMSwarmDataBucketInsertPackedArray(swarm->db, npoints + p, data_p)); 88 } 89 if (debug) PetscCall(DMSwarmDataExView(de)); 90 PetscCall(DMSwarmDataBucketDestroyPackedArray(swarm->db, &point_buffer)); 91 PetscCall(DMSwarmDataExDestroy(de)); 92 PetscFunctionReturn(PETSC_SUCCESS); 93 } 94 95 static PetscErrorCode DMSwarmMigrate_DMNeighborScatter(DM dm, DM dmcell, PetscBool remove_sent_points, PetscInt *npoints_prior_migration) 96 { 97 DM_Swarm *swarm = (DM_Swarm *)dm->data; 98 DMSwarmDataEx de; 99 PetscInt r, p, npoints, *p_cellid, n_points_recv; 100 PetscMPIInt rank, _rank; 101 const PetscMPIInt *neighbourranks; 102 void *point_buffer, *recv_points; 103 size_t sizeof_dmswarm_point; 104 PetscInt nneighbors; 105 PetscMPIInt mynneigh, *myneigh; 106 107 PetscFunctionBegin; 108 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 109 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 110 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid)); 111 PetscCall(DMSwarmDataExCreate(PetscObjectComm((PetscObject)dm), 0, &de)); 112 PetscCall(DMGetNeighbors(dmcell, &nneighbors, &neighbourranks)); 113 PetscCall(DMSwarmDataExTopologyInitialize(de)); 114 for (r = 0; r < nneighbors; r++) { 115 _rank = neighbourranks[r]; 116 if ((_rank != rank) && (_rank > 0)) PetscCall(DMSwarmDataExTopologyAddNeighbour(de, _rank)); 117 } 118 PetscCall(DMSwarmDataExTopologyFinalize(de)); 119 PetscCall(DMSwarmDataExTopologyGetNeighbours(de, &mynneigh, &myneigh)); 120 PetscCall(DMSwarmDataExInitializeSendCount(de)); 121 for (p = 0; p < npoints; p++) { 122 if (p_cellid[p] == DMLOCATEPOINT_POINT_NOT_FOUND) { 123 for (r = 0; r < mynneigh; r++) { 124 _rank = myneigh[r]; 125 PetscCall(DMSwarmDataExAddToSendCount(de, _rank, 1)); 126 } 127 } 128 } 129 PetscCall(DMSwarmDataExFinalizeSendCount(de)); 130 PetscCall(DMSwarmDataBucketCreatePackedArray(swarm->db, &sizeof_dmswarm_point, &point_buffer)); 131 PetscCall(DMSwarmDataExPackInitialize(de, sizeof_dmswarm_point)); 132 for (p = 0; p < npoints; p++) { 133 if (p_cellid[p] == DMLOCATEPOINT_POINT_NOT_FOUND) { 134 for (r = 0; r < mynneigh; r++) { 135 _rank = myneigh[r]; 136 /* copy point into buffer */ 137 PetscCall(DMSwarmDataBucketFillPackedArray(swarm->db, p, point_buffer)); 138 /* insert point buffer into DMSwarmDataExchanger */ 139 PetscCall(DMSwarmDataExPackData(de, _rank, 1, point_buffer)); 140 } 141 } 142 } 143 PetscCall(DMSwarmDataExPackFinalize(de)); 144 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid)); 145 if (remove_sent_points) { 146 DMSwarmDataField PField; 147 148 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, DMSwarmPICField_cellid, &PField)); 149 PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid)); 150 /* remove points which left processor */ 151 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 152 for (p = 0; p < npoints; p++) { 153 if (p_cellid[p] == DMLOCATEPOINT_POINT_NOT_FOUND) { 154 /* kill point */ 155 PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, p)); 156 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); /* you need to update npoints as the list size decreases! */ 157 PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid)); /* update date point increase realloc performed */ 158 p--; /* check replacement point */ 159 } 160 } 161 } 162 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, npoints_prior_migration, NULL, NULL)); 163 PetscCall(DMSwarmDataExBegin(de)); 164 PetscCall(DMSwarmDataExEnd(de)); 165 PetscCall(DMSwarmDataExGetRecvData(de, &n_points_recv, (void **)&recv_points)); 166 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 167 PetscCall(DMSwarmDataBucketSetSizes(swarm->db, npoints + n_points_recv, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT)); 168 for (p = 0; p < n_points_recv; p++) { 169 void *data_p = (void *)((char *)recv_points + p * sizeof_dmswarm_point); 170 171 PetscCall(DMSwarmDataBucketInsertPackedArray(swarm->db, npoints + p, data_p)); 172 } 173 PetscCall(DMSwarmDataBucketDestroyPackedArray(swarm->db, &point_buffer)); 174 PetscCall(DMSwarmDataExDestroy(de)); 175 PetscFunctionReturn(PETSC_SUCCESS); 176 } 177 178 PetscErrorCode DMSwarmMigrate_CellDMScatter(DM dm, PetscBool remove_sent_points) 179 { 180 DM_Swarm *swarm = (DM_Swarm *)dm->data; 181 PetscInt p, npoints, npointsg = 0, npoints2, npoints2g, *rankval, *p_cellid, npoints_prior_migration; 182 PetscSF sfcell = NULL; 183 const PetscSFNode *LA_sfcell; 184 DM dmcell; 185 Vec pos; 186 PetscBool error_check = swarm->migrate_error_on_missing_point; 187 PetscMPIInt size, rank; 188 189 PetscFunctionBegin; 190 PetscCall(DMSwarmGetCellDM(dm, &dmcell)); 191 PetscCheck(dmcell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid if cell DM provided"); 192 193 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 194 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 195 196 #if 1 197 { 198 PetscInt npoints_curr, range = 0; 199 PetscSFNode *sf_cells; 200 201 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints_curr, NULL, NULL)); 202 PetscCall(PetscMalloc1(npoints_curr, &sf_cells)); 203 204 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid)); 205 for (p = 0; p < npoints_curr; p++) { 206 sf_cells[p].rank = 0; 207 sf_cells[p].index = p_cellid[p]; 208 if (p_cellid[p] > range) range = p_cellid[p]; 209 } 210 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid)); 211 212 /* PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&sfcell)); */ 213 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sfcell)); 214 PetscCall(PetscSFSetGraph(sfcell, range, npoints_curr, NULL, PETSC_OWN_POINTER, sf_cells, PETSC_OWN_POINTER)); 215 } 216 #endif 217 218 PetscCall(DMSwarmCreateLocalVectorFromField(dm, DMSwarmPICField_coor, &pos)); 219 PetscCall(DMLocatePoints(dmcell, pos, DM_POINTLOCATION_NONE, &sfcell)); 220 PetscCall(DMSwarmDestroyLocalVectorFromField(dm, DMSwarmPICField_coor, &pos)); 221 222 if (error_check) PetscCall(DMSwarmGetSize(dm, &npointsg)); 223 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 224 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid)); 225 PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 226 PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell)); 227 228 for (p = 0; p < npoints; p++) { 229 p_cellid[p] = LA_sfcell[p].index; 230 rankval[p] = rank; 231 } 232 PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 233 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid)); 234 PetscCall(PetscSFDestroy(&sfcell)); 235 236 if (size > 1) { 237 PetscCall(DMSwarmMigrate_DMNeighborScatter(dm, dmcell, remove_sent_points, &npoints_prior_migration)); 238 } else { 239 DMSwarmDataField PField; 240 PetscInt npoints_curr; 241 242 /* remove points which the domain */ 243 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, DMSwarmPICField_cellid, &PField)); 244 PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid)); 245 246 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints_curr, NULL, NULL)); 247 for (p = 0; p < npoints_curr; p++) { 248 if (p_cellid[p] == DMLOCATEPOINT_POINT_NOT_FOUND) { 249 /* kill point */ 250 PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, p)); 251 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints_curr, NULL, NULL)); /* you need to update npoints as the list size decreases! */ 252 PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid)); /* update date point in case realloc performed */ 253 p--; /* check replacement point */ 254 } 255 } 256 PetscCall(DMSwarmGetLocalSize(dm, &npoints_prior_migration)); 257 } 258 259 /* locate points newly received */ 260 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints2, NULL, NULL)); 261 262 #if 0 263 { /* safe alternative - however this performs two point locations on: (i) the initial points set and; (ii) the (initial + received) point set */ 264 PetscScalar *LA_coor; 265 PetscInt bs; 266 DMSwarmDataField PField; 267 268 PetscCall(DMSwarmGetField(dm,DMSwarmPICField_coor,&bs,NULL,(void**)&LA_coor)); 269 PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF,bs,bs*npoints2,(const PetscScalar*)LA_coor,&pos)); 270 PetscCall(DMLocatePoints(dmcell,pos,DM_POINTLOCATION_NONE,&sfcell)); 271 272 PetscCall(VecDestroy(&pos)); 273 PetscCall(DMSwarmRestoreField(dm,DMSwarmPICField_coor,&bs,NULL,(void**)&LA_coor)); 274 275 PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell)); 276 PetscCall(DMSwarmGetField(dm,DMSwarmField_rank,NULL,NULL,(void**)&rankval)); 277 for (p=0; p<npoints2; p++) { 278 rankval[p] = LA_sfcell[p].index; 279 } 280 PetscCall(PetscSFDestroy(&sfcell)); 281 PetscCall(DMSwarmRestoreField(dm,DMSwarmField_rank,NULL,NULL,(void**)&rankval)); 282 283 /* remove points which left processor */ 284 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db,DMSwarmField_rank,&PField)); 285 PetscCall(DMSwarmDataFieldGetEntries(PField,(void**)&rankval)); 286 287 PetscCall(DMSwarmDataBucketGetSizes(swarm->db,&npoints2,NULL,NULL)); 288 for (p=0; p<npoints2; p++) { 289 if (rankval[p] == DMLOCATEPOINT_POINT_NOT_FOUND) { 290 /* kill point */ 291 PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db,p)); 292 PetscCall(DMSwarmDataBucketGetSizes(swarm->db,&npoints2,NULL,NULL)); /* you need to update npoints as the list size decreases! */ 293 PetscCall(DMSwarmDataFieldGetEntries(PField,(void**)&rankval)); /* update date point increase realloc performed */ 294 p--; /* check replacement point */ 295 } 296 } 297 } 298 #endif 299 300 { /* perform two point locations: (i) on the initial points set prior to communication; and (ii) on the new (received) points */ 301 PetscScalar *LA_coor; 302 PetscInt npoints_from_neighbours, bs; 303 DMSwarmDataField PField; 304 305 npoints_from_neighbours = npoints2 - npoints_prior_migration; 306 307 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&LA_coor)); 308 PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, bs, bs * npoints_from_neighbours, (const PetscScalar *)&LA_coor[bs * npoints_prior_migration], &pos)); 309 310 PetscCall(DMLocatePoints(dmcell, pos, DM_POINTLOCATION_NONE, &sfcell)); 311 312 PetscCall(VecDestroy(&pos)); 313 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&LA_coor)); 314 315 PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell)); 316 PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 317 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid)); 318 for (p = 0; p < npoints_from_neighbours; p++) { 319 rankval[npoints_prior_migration + p] = rank; 320 p_cellid[npoints_prior_migration + p] = LA_sfcell[p].index; 321 } 322 323 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&p_cellid)); 324 PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 325 PetscCall(PetscSFDestroy(&sfcell)); 326 327 /* remove points which left processor */ 328 PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, DMSwarmPICField_cellid, &PField)); 329 PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid)); 330 331 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints2, NULL, NULL)); 332 for (p = npoints_prior_migration; p < npoints2; p++) { 333 if (p_cellid[p] == DMLOCATEPOINT_POINT_NOT_FOUND) { 334 /* kill point */ 335 PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, p)); 336 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints2, NULL, NULL)); /* you need to update npoints as the list size decreases! */ 337 PetscCall(DMSwarmDataFieldGetEntries(PField, (void **)&p_cellid)); /* update date point in case realloc performed */ 338 p--; /* check replacement point */ 339 } 340 } 341 } 342 343 /* check for error on removed points */ 344 if (error_check) { 345 PetscCall(DMSwarmGetSize(dm, &npoints2g)); 346 PetscCheck(npointsg == npoints2g, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Points from the DMSwarm must remain constant during migration (initial %" PetscInt_FMT " - final %" PetscInt_FMT ")", npointsg, npoints2g); 347 } 348 PetscFunctionReturn(PETSC_SUCCESS); 349 } 350 351 PetscErrorCode DMSwarmMigrate_CellDMExact(DM dm, PetscBool remove_sent_points) 352 { 353 PetscFunctionBegin; 354 PetscFunctionReturn(PETSC_SUCCESS); 355 } 356 357 /* 358 Redundant as this assumes points can only be sent to a single rank 359 */ 360 PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm, PetscInt *globalsize) 361 { 362 DM_Swarm *swarm = (DM_Swarm *)dm->data; 363 DMSwarmDataEx de; 364 PetscInt p, npoints, *rankval, n_points_recv; 365 PetscMPIInt rank, nrank, negrank; 366 void *point_buffer, *recv_points; 367 size_t sizeof_dmswarm_point; 368 369 PetscFunctionBegin; 370 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 371 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 372 *globalsize = npoints; 373 PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 374 PetscCall(DMSwarmDataExCreate(PetscObjectComm((PetscObject)dm), 0, &de)); 375 PetscCall(DMSwarmDataExTopologyInitialize(de)); 376 for (p = 0; p < npoints; p++) { 377 negrank = rankval[p]; 378 if (negrank < 0) { 379 nrank = -negrank - 1; 380 PetscCall(DMSwarmDataExTopologyAddNeighbour(de, nrank)); 381 } 382 } 383 PetscCall(DMSwarmDataExTopologyFinalize(de)); 384 PetscCall(DMSwarmDataExInitializeSendCount(de)); 385 for (p = 0; p < npoints; p++) { 386 negrank = rankval[p]; 387 if (negrank < 0) { 388 nrank = -negrank - 1; 389 PetscCall(DMSwarmDataExAddToSendCount(de, nrank, 1)); 390 } 391 } 392 PetscCall(DMSwarmDataExFinalizeSendCount(de)); 393 PetscCall(DMSwarmDataBucketCreatePackedArray(swarm->db, &sizeof_dmswarm_point, &point_buffer)); 394 PetscCall(DMSwarmDataExPackInitialize(de, sizeof_dmswarm_point)); 395 for (p = 0; p < npoints; p++) { 396 negrank = rankval[p]; 397 if (negrank < 0) { 398 nrank = -negrank - 1; 399 rankval[p] = nrank; 400 /* copy point into buffer */ 401 PetscCall(DMSwarmDataBucketFillPackedArray(swarm->db, p, point_buffer)); 402 /* insert point buffer into DMSwarmDataExchanger */ 403 PetscCall(DMSwarmDataExPackData(de, nrank, 1, point_buffer)); 404 rankval[p] = negrank; 405 } 406 } 407 PetscCall(DMSwarmDataExPackFinalize(de)); 408 PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 409 PetscCall(DMSwarmDataExBegin(de)); 410 PetscCall(DMSwarmDataExEnd(de)); 411 PetscCall(DMSwarmDataExGetRecvData(de, &n_points_recv, (void **)&recv_points)); 412 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 413 PetscCall(DMSwarmDataBucketSetSizes(swarm->db, npoints + n_points_recv, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT)); 414 for (p = 0; p < n_points_recv; p++) { 415 void *data_p = (void *)((char *)recv_points + p * sizeof_dmswarm_point); 416 417 PetscCall(DMSwarmDataBucketInsertPackedArray(swarm->db, npoints + p, data_p)); 418 } 419 PetscCall(DMSwarmDataExView(de)); 420 PetscCall(DMSwarmDataBucketDestroyPackedArray(swarm->db, &point_buffer)); 421 PetscCall(DMSwarmDataExDestroy(de)); 422 PetscFunctionReturn(PETSC_SUCCESS); 423 } 424 425 typedef struct { 426 PetscMPIInt owner_rank; 427 PetscReal min[3], max[3]; 428 } CollectBBox; 429 430 PETSC_EXTERN PetscErrorCode DMSwarmCollect_DMDABoundingBox(DM dm, PetscInt *globalsize) 431 { 432 DM_Swarm *swarm = (DM_Swarm *)dm->data; 433 DMSwarmDataEx de; 434 PetscInt p, pk, npoints, *rankval, n_points_recv, n_bbox_recv, dim, neighbour_cells; 435 PetscMPIInt rank, nrank; 436 void *point_buffer, *recv_points; 437 size_t sizeof_dmswarm_point, sizeof_bbox_ctx; 438 PetscBool isdmda; 439 CollectBBox *bbox, *recv_bbox; 440 const PetscMPIInt *dmneighborranks; 441 DM dmcell; 442 443 PetscFunctionBegin; 444 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 445 446 PetscCall(DMSwarmGetCellDM(dm, &dmcell)); 447 PetscCheck(dmcell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid if cell DM provided"); 448 isdmda = PETSC_FALSE; 449 PetscCall(PetscObjectTypeCompare((PetscObject)dmcell, DMDA, &isdmda)); 450 PetscCheck(isdmda, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only DMDA support for CollectBoundingBox"); 451 452 PetscCall(DMGetDimension(dm, &dim)); 453 sizeof_bbox_ctx = sizeof(CollectBBox); 454 PetscCall(PetscMalloc1(1, &bbox)); 455 bbox->owner_rank = rank; 456 457 /* compute the bounding box based on the overlapping / stenctil size */ 458 { 459 Vec lcoor; 460 461 PetscCall(DMGetCoordinatesLocal(dmcell, &lcoor)); 462 if (dim >= 1) { 463 PetscCall(VecStrideMin(lcoor, 0, NULL, &bbox->min[0])); 464 PetscCall(VecStrideMax(lcoor, 0, NULL, &bbox->max[0])); 465 } 466 if (dim >= 2) { 467 PetscCall(VecStrideMin(lcoor, 1, NULL, &bbox->min[1])); 468 PetscCall(VecStrideMax(lcoor, 1, NULL, &bbox->max[1])); 469 } 470 if (dim == 3) { 471 PetscCall(VecStrideMin(lcoor, 2, NULL, &bbox->min[2])); 472 PetscCall(VecStrideMax(lcoor, 2, NULL, &bbox->max[2])); 473 } 474 } 475 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 476 *globalsize = npoints; 477 PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 478 PetscCall(DMSwarmDataExCreate(PetscObjectComm((PetscObject)dm), 0, &de)); 479 /* use DMDA neighbours */ 480 PetscCall(DMDAGetNeighbors(dmcell, &dmneighborranks)); 481 if (dim == 1) { 482 neighbour_cells = 3; 483 } else if (dim == 2) { 484 neighbour_cells = 9; 485 } else { 486 neighbour_cells = 27; 487 } 488 PetscCall(DMSwarmDataExTopologyInitialize(de)); 489 for (p = 0; p < neighbour_cells; p++) { 490 if ((dmneighborranks[p] >= 0) && (dmneighborranks[p] != rank)) PetscCall(DMSwarmDataExTopologyAddNeighbour(de, dmneighborranks[p])); 491 } 492 PetscCall(DMSwarmDataExTopologyFinalize(de)); 493 PetscCall(DMSwarmDataExInitializeSendCount(de)); 494 for (p = 0; p < neighbour_cells; p++) { 495 if ((dmneighborranks[p] >= 0) && (dmneighborranks[p] != rank)) PetscCall(DMSwarmDataExAddToSendCount(de, dmneighborranks[p], 1)); 496 } 497 PetscCall(DMSwarmDataExFinalizeSendCount(de)); 498 /* send bounding boxes */ 499 PetscCall(DMSwarmDataExPackInitialize(de, sizeof_bbox_ctx)); 500 for (p = 0; p < neighbour_cells; p++) { 501 nrank = dmneighborranks[p]; 502 if ((nrank >= 0) && (nrank != rank)) { 503 /* insert bbox buffer into DMSwarmDataExchanger */ 504 PetscCall(DMSwarmDataExPackData(de, nrank, 1, bbox)); 505 } 506 } 507 PetscCall(DMSwarmDataExPackFinalize(de)); 508 /* recv bounding boxes */ 509 PetscCall(DMSwarmDataExBegin(de)); 510 PetscCall(DMSwarmDataExEnd(de)); 511 PetscCall(DMSwarmDataExGetRecvData(de, &n_bbox_recv, (void **)&recv_bbox)); 512 /* Wrong, should not be using PETSC_COMM_WORLD */ 513 for (p = 0; p < n_bbox_recv; p++) { 514 PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[rank %d]: box from %d : range[%+1.4e,%+1.4e]x[%+1.4e,%+1.4e]\n", rank, recv_bbox[p].owner_rank, (double)recv_bbox[p].min[0], (double)recv_bbox[p].max[0], (double)recv_bbox[p].min[1], 515 (double)recv_bbox[p].max[1])); 516 } 517 PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, stdout)); 518 /* of course this is stupid as this "generic" function should have a better way to know what the coordinates are called */ 519 PetscCall(DMSwarmDataExInitializeSendCount(de)); 520 for (pk = 0; pk < n_bbox_recv; pk++) { 521 PetscReal *array_x, *array_y; 522 523 PetscCall(DMSwarmGetField(dm, "coorx", NULL, NULL, (void **)&array_x)); 524 PetscCall(DMSwarmGetField(dm, "coory", NULL, NULL, (void **)&array_y)); 525 for (p = 0; p < npoints; p++) { 526 if ((array_x[p] >= recv_bbox[pk].min[0]) && (array_x[p] <= recv_bbox[pk].max[0])) { 527 if ((array_y[p] >= recv_bbox[pk].min[1]) && (array_y[p] <= recv_bbox[pk].max[1])) PetscCall(DMSwarmDataExAddToSendCount(de, recv_bbox[pk].owner_rank, 1)); 528 } 529 } 530 PetscCall(DMSwarmRestoreField(dm, "coory", NULL, NULL, (void **)&array_y)); 531 PetscCall(DMSwarmRestoreField(dm, "coorx", NULL, NULL, (void **)&array_x)); 532 } 533 PetscCall(DMSwarmDataExFinalizeSendCount(de)); 534 PetscCall(DMSwarmDataBucketCreatePackedArray(swarm->db, &sizeof_dmswarm_point, &point_buffer)); 535 PetscCall(DMSwarmDataExPackInitialize(de, sizeof_dmswarm_point)); 536 for (pk = 0; pk < n_bbox_recv; pk++) { 537 PetscReal *array_x, *array_y; 538 539 PetscCall(DMSwarmGetField(dm, "coorx", NULL, NULL, (void **)&array_x)); 540 PetscCall(DMSwarmGetField(dm, "coory", NULL, NULL, (void **)&array_y)); 541 for (p = 0; p < npoints; p++) { 542 if ((array_x[p] >= recv_bbox[pk].min[0]) && (array_x[p] <= recv_bbox[pk].max[0])) { 543 if ((array_y[p] >= recv_bbox[pk].min[1]) && (array_y[p] <= recv_bbox[pk].max[1])) { 544 /* copy point into buffer */ 545 PetscCall(DMSwarmDataBucketFillPackedArray(swarm->db, p, point_buffer)); 546 /* insert point buffer into DMSwarmDataExchanger */ 547 PetscCall(DMSwarmDataExPackData(de, recv_bbox[pk].owner_rank, 1, point_buffer)); 548 } 549 } 550 } 551 PetscCall(DMSwarmRestoreField(dm, "coory", NULL, NULL, (void **)&array_y)); 552 PetscCall(DMSwarmRestoreField(dm, "coorx", NULL, NULL, (void **)&array_x)); 553 } 554 PetscCall(DMSwarmDataExPackFinalize(de)); 555 PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval)); 556 PetscCall(DMSwarmDataExBegin(de)); 557 PetscCall(DMSwarmDataExEnd(de)); 558 PetscCall(DMSwarmDataExGetRecvData(de, &n_points_recv, (void **)&recv_points)); 559 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 560 PetscCall(DMSwarmDataBucketSetSizes(swarm->db, npoints + n_points_recv, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT)); 561 for (p = 0; p < n_points_recv; p++) { 562 void *data_p = (void *)((char *)recv_points + p * sizeof_dmswarm_point); 563 564 PetscCall(DMSwarmDataBucketInsertPackedArray(swarm->db, npoints + p, data_p)); 565 } 566 PetscCall(DMSwarmDataBucketDestroyPackedArray(swarm->db, &point_buffer)); 567 PetscCall(PetscFree(bbox)); 568 PetscCall(DMSwarmDataExView(de)); 569 PetscCall(DMSwarmDataExDestroy(de)); 570 PetscFunctionReturn(PETSC_SUCCESS); 571 } 572 573 /* General collection when no order, or neighbour information is provided */ 574 /* 575 User provides context and collect() method 576 Broadcast user context 577 578 for each context / rank { 579 collect(swarm,context,n,list) 580 } 581 */ 582 PETSC_EXTERN PetscErrorCode DMSwarmCollect_General(DM dm, PetscErrorCode (*collect)(DM, void *, PetscInt *, PetscInt **), size_t ctx_size, void *ctx, PetscInt *globalsize) 583 { 584 DM_Swarm *swarm = (DM_Swarm *)dm->data; 585 DMSwarmDataEx de; 586 PetscInt p, r, npoints, n_points_recv; 587 PetscMPIInt size, rank; 588 void *point_buffer, *recv_points; 589 void *ctxlist; 590 PetscInt *n2collect, **collectlist; 591 size_t sizeof_dmswarm_point; 592 593 PetscFunctionBegin; 594 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 595 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 596 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 597 *globalsize = npoints; 598 /* Broadcast user context */ 599 PetscCall(PetscMalloc(ctx_size * size, &ctxlist)); 600 PetscCallMPI(MPI_Allgather(ctx, ctx_size, MPI_CHAR, ctxlist, ctx_size, MPI_CHAR, PetscObjectComm((PetscObject)dm))); 601 PetscCall(PetscMalloc1(size, &n2collect)); 602 PetscCall(PetscMalloc1(size, &collectlist)); 603 for (r = 0; r < size; r++) { 604 PetscInt _n2collect; 605 PetscInt *_collectlist; 606 void *_ctx_r; 607 608 _n2collect = 0; 609 _collectlist = NULL; 610 if (r != rank) { /* don't collect data from yourself */ 611 _ctx_r = (void *)((char *)ctxlist + r * ctx_size); 612 PetscCall(collect(dm, _ctx_r, &_n2collect, &_collectlist)); 613 } 614 n2collect[r] = _n2collect; 615 collectlist[r] = _collectlist; 616 } 617 PetscCall(DMSwarmDataExCreate(PetscObjectComm((PetscObject)dm), 0, &de)); 618 /* Define topology */ 619 PetscCall(DMSwarmDataExTopologyInitialize(de)); 620 for (r = 0; r < size; r++) { 621 if (n2collect[r] > 0) PetscCall(DMSwarmDataExTopologyAddNeighbour(de, (PetscMPIInt)r)); 622 } 623 PetscCall(DMSwarmDataExTopologyFinalize(de)); 624 /* Define send counts */ 625 PetscCall(DMSwarmDataExInitializeSendCount(de)); 626 for (r = 0; r < size; r++) { 627 if (n2collect[r] > 0) PetscCall(DMSwarmDataExAddToSendCount(de, r, n2collect[r])); 628 } 629 PetscCall(DMSwarmDataExFinalizeSendCount(de)); 630 /* Pack data */ 631 PetscCall(DMSwarmDataBucketCreatePackedArray(swarm->db, &sizeof_dmswarm_point, &point_buffer)); 632 PetscCall(DMSwarmDataExPackInitialize(de, sizeof_dmswarm_point)); 633 for (r = 0; r < size; r++) { 634 for (p = 0; p < n2collect[r]; p++) { 635 PetscCall(DMSwarmDataBucketFillPackedArray(swarm->db, collectlist[r][p], point_buffer)); 636 /* insert point buffer into the data exchanger */ 637 PetscCall(DMSwarmDataExPackData(de, r, 1, point_buffer)); 638 } 639 } 640 PetscCall(DMSwarmDataExPackFinalize(de)); 641 /* Scatter */ 642 PetscCall(DMSwarmDataExBegin(de)); 643 PetscCall(DMSwarmDataExEnd(de)); 644 /* Collect data in DMSwarm container */ 645 PetscCall(DMSwarmDataExGetRecvData(de, &n_points_recv, (void **)&recv_points)); 646 PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL)); 647 PetscCall(DMSwarmDataBucketSetSizes(swarm->db, npoints + n_points_recv, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT)); 648 for (p = 0; p < n_points_recv; p++) { 649 void *data_p = (void *)((char *)recv_points + p * sizeof_dmswarm_point); 650 651 PetscCall(DMSwarmDataBucketInsertPackedArray(swarm->db, npoints + p, data_p)); 652 } 653 /* Release memory */ 654 for (r = 0; r < size; r++) { 655 if (collectlist[r]) PetscCall(PetscFree(collectlist[r])); 656 } 657 PetscCall(PetscFree(collectlist)); 658 PetscCall(PetscFree(n2collect)); 659 PetscCall(PetscFree(ctxlist)); 660 PetscCall(DMSwarmDataBucketDestroyPackedArray(swarm->db, &point_buffer)); 661 PetscCall(DMSwarmDataExView(de)); 662 PetscCall(DMSwarmDataExDestroy(de)); 663 PetscFunctionReturn(PETSC_SUCCESS); 664 } 665 666 /*@ 667 DMSwarmGetMigrateType - Get the style of point migration 668 669 Logically Collective 670 671 Input Parameter: 672 . dm - the `DMSWARM` 673 674 Output Parameter: 675 . mtype - The migration type, see `DMSwarmMigrateType` 676 677 Level: intermediate 678 679 .seealso: `DM`, `DMSWARM`, `DMSwarmMigrateType`, `DMSwarmMigrate()` 680 @*/ 681 PetscErrorCode DMSwarmGetMigrateType(DM dm, DMSwarmMigrateType *mtype) 682 { 683 PetscFunctionBegin; 684 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 685 PetscAssertPointer(mtype, 2); 686 *mtype = ((DM_Swarm *)dm->data)->migrate_type; 687 PetscFunctionReturn(PETSC_SUCCESS); 688 } 689 690 /*@ 691 DMSwarmSetMigrateType - Set the style of point migration 692 693 Logically Collective 694 695 Input Parameters: 696 + dm - the `DMSWARM` 697 - mtype - The migration type, see `DMSwarmMigrateType` 698 699 Level: intermediate 700 701 .seealso: `DM`, `DMSWARM`, `DMSwarmMigrateType`, `DMSwarmGetMigrateType()`, `DMSwarmMigrate()` 702 @*/ 703 PetscErrorCode DMSwarmSetMigrateType(DM dm, DMSwarmMigrateType mtype) 704 { 705 PetscFunctionBegin; 706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 707 PetscValidLogicalCollectiveInt(dm, mtype, 2); 708 ((DM_Swarm *)dm->data)->migrate_type = mtype; 709 PetscFunctionReturn(PETSC_SUCCESS); 710 } 711