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