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