1 #define PETSCDM_DLL 2 #include <petsc/private/dmswarmimpl.h> /*I "petscdmswarm.h" I*/ 3 #include <petscsf.h> 4 #include <petscdmda.h> 5 #include <petscdmplex.h> 6 #include <petscdt.h> 7 #include "../src/dm/impls/swarm/data_bucket.h" 8 9 #include <petsc/private/petscfeimpl.h> /* For CoordinatesRefToReal() */ 10 11 /* Coordinate insertition/addition API */ 12 /*@C 13 DMSwarmSetPointsUniformCoordinates - Set point coordinates in a `DMSWARM` on a regular (ijk) grid 14 15 Collective 16 17 Input Parameters: 18 + dm - the `DMSWARM` 19 . min - minimum coordinate values in the x, y, z directions (array of length dim) 20 . max - maximum coordinate values in the x, y, z directions (array of length dim) 21 . npoints - number of points in each spatial direction (array of length dim) 22 - mode - indicates whether to append points to the swarm (`ADD_VALUES`), or over-ride existing points (`INSERT_VALUES`) 23 24 Level: beginner 25 26 Notes: 27 When using mode = `INSERT_VALUES`, this method will reset the number of particles in the `DMSWARM` 28 to be `npoints[0]` x `npoints[1]` (2D) or `npoints[0]` x `npoints[1]` x `npoints[2]` (3D). When using mode = `ADD_VALUES`, 29 new points will be appended to any already existing in the `DMSWARM` 30 31 .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType` 32 @*/ 33 PETSC_EXTERN PetscErrorCode DMSwarmSetPointsUniformCoordinates(DM dm, PetscReal min[], PetscReal max[], PetscInt npoints[], InsertMode mode) 34 { 35 PetscReal lmin[] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL}; 36 PetscReal lmax[] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 37 PetscInt i, j, k, bs, b, n_estimate, n_curr, n_new_est, p, n_found; 38 const PetscScalar *_coor; 39 DM celldm; 40 PetscReal dx[3]; 41 PetscInt _npoints[] = {0, 0, 1}; 42 Vec pos; 43 PetscScalar *_pos; 44 PetscReal *swarm_coor; 45 PetscInt *swarm_cellid; 46 PetscSF sfcell = NULL; 47 const PetscSFNode *LA_sfcell; 48 49 PetscFunctionBegin; 50 DMSWARMPICVALID(dm); 51 PetscCall(DMSwarmGetCellDM(dm, &celldm)); 52 PetscCall(DMGetLocalBoundingBox(celldm, lmin, lmax)); 53 PetscCall(DMGetCoordinateDim(celldm, &bs)); 54 55 for (b = 0; b < bs; b++) { 56 if (npoints[b] > 1) { 57 dx[b] = (max[b] - min[b]) / ((PetscReal)(npoints[b] - 1)); 58 } else { 59 dx[b] = 0.0; 60 } 61 _npoints[b] = npoints[b]; 62 } 63 64 /* determine number of points living in the bounding box */ 65 n_estimate = 0; 66 for (k = 0; k < _npoints[2]; k++) { 67 for (j = 0; j < _npoints[1]; j++) { 68 for (i = 0; i < _npoints[0]; i++) { 69 PetscReal xp[] = {0.0, 0.0, 0.0}; 70 PetscInt ijk[3]; 71 PetscBool point_inside = PETSC_TRUE; 72 73 ijk[0] = i; 74 ijk[1] = j; 75 ijk[2] = k; 76 for (b = 0; b < bs; b++) xp[b] = min[b] + ijk[b] * dx[b]; 77 for (b = 0; b < bs; b++) { 78 if (xp[b] < lmin[b]) point_inside = PETSC_FALSE; 79 if (xp[b] > lmax[b]) point_inside = PETSC_FALSE; 80 } 81 if (point_inside) n_estimate++; 82 } 83 } 84 } 85 86 /* create candidate list */ 87 PetscCall(VecCreate(PETSC_COMM_SELF, &pos)); 88 PetscCall(VecSetSizes(pos, bs * n_estimate, PETSC_DECIDE)); 89 PetscCall(VecSetBlockSize(pos, bs)); 90 PetscCall(VecSetFromOptions(pos)); 91 PetscCall(VecGetArray(pos, &_pos)); 92 93 n_estimate = 0; 94 for (k = 0; k < _npoints[2]; k++) { 95 for (j = 0; j < _npoints[1]; j++) { 96 for (i = 0; i < _npoints[0]; i++) { 97 PetscReal xp[] = {0.0, 0.0, 0.0}; 98 PetscInt ijk[3]; 99 PetscBool point_inside = PETSC_TRUE; 100 101 ijk[0] = i; 102 ijk[1] = j; 103 ijk[2] = k; 104 for (b = 0; b < bs; b++) xp[b] = min[b] + ijk[b] * dx[b]; 105 for (b = 0; b < bs; b++) { 106 if (xp[b] < lmin[b]) point_inside = PETSC_FALSE; 107 if (xp[b] > lmax[b]) point_inside = PETSC_FALSE; 108 } 109 if (point_inside) { 110 for (b = 0; b < bs; b++) _pos[bs * n_estimate + b] = xp[b]; 111 n_estimate++; 112 } 113 } 114 } 115 } 116 PetscCall(VecRestoreArray(pos, &_pos)); 117 118 /* locate points */ 119 PetscCall(DMLocatePoints(celldm, pos, DM_POINTLOCATION_NONE, &sfcell)); 120 PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell)); 121 n_found = 0; 122 for (p = 0; p < n_estimate; p++) { 123 if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) n_found++; 124 } 125 126 /* adjust size */ 127 if (mode == ADD_VALUES) { 128 PetscCall(DMSwarmGetLocalSize(dm, &n_curr)); 129 n_new_est = n_curr + n_found; 130 PetscCall(DMSwarmSetLocalSizes(dm, n_new_est, -1)); 131 } 132 if (mode == INSERT_VALUES) { 133 n_curr = 0; 134 n_new_est = n_found; 135 PetscCall(DMSwarmSetLocalSizes(dm, n_new_est, -1)); 136 } 137 138 /* initialize new coords, cell owners, pid */ 139 PetscCall(VecGetArrayRead(pos, &_coor)); 140 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&swarm_coor)); 141 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid)); 142 n_found = 0; 143 for (p = 0; p < n_estimate; p++) { 144 if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) { 145 for (b = 0; b < bs; b++) swarm_coor[bs * (n_curr + n_found) + b] = PetscRealPart(_coor[bs * p + b]); 146 swarm_cellid[n_curr + n_found] = LA_sfcell[p].index; 147 n_found++; 148 } 149 } 150 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid)); 151 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&swarm_coor)); 152 PetscCall(VecRestoreArrayRead(pos, &_coor)); 153 154 PetscCall(PetscSFDestroy(&sfcell)); 155 PetscCall(VecDestroy(&pos)); 156 PetscFunctionReturn(PETSC_SUCCESS); 157 } 158 159 /*@C 160 DMSwarmSetPointCoordinates - Set point coordinates in a `DMSWARM` from a user defined list 161 162 Collective 163 164 Input Parameters: 165 + dm - the `DMSWARM` 166 . npoints - the number of points to insert 167 . coor - the coordinate values 168 . redundant - if set to `PETSC_TRUE`, it is assumed that `npoints` and `coor` are only valid on rank 0 and should be broadcast to other ranks 169 - mode - indicates whether to append points to the swarm (`ADD_VALUES`), or over-ride existing points (`INSERT_VALUES`) 170 171 Level: beginner 172 173 Notes: 174 If the user has specified `redundant` as `PETSC_FALSE`, the cell `DM` will attempt to locate the coordinates provided by `coor` within 175 its sub-domain. If they any values within `coor` are not located in the sub-domain, they will be ignored and will not get 176 added to the `DMSWARM`. 177 178 .seealso: `DMSWARM`, `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType`, `DMSwarmSetPointsUniformCoordinates()` 179 @*/ 180 PETSC_EXTERN PetscErrorCode DMSwarmSetPointCoordinates(DM dm, PetscInt npoints, PetscReal coor[], PetscBool redundant, InsertMode mode) 181 { 182 PetscReal gmin[] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL}; 183 PetscReal gmax[] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 184 PetscInt i, N, bs, b, n_estimate, n_curr, n_new_est, p, n_found; 185 Vec coorlocal; 186 const PetscScalar *_coor; 187 DM celldm; 188 Vec pos; 189 PetscScalar *_pos; 190 PetscReal *swarm_coor; 191 PetscInt *swarm_cellid; 192 PetscSF sfcell = NULL; 193 const PetscSFNode *LA_sfcell; 194 PetscReal *my_coor; 195 PetscInt my_npoints; 196 PetscMPIInt rank; 197 MPI_Comm comm; 198 199 PetscFunctionBegin; 200 DMSWARMPICVALID(dm); 201 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 202 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 203 204 PetscCall(DMSwarmGetCellDM(dm, &celldm)); 205 PetscCall(DMGetCoordinatesLocal(celldm, &coorlocal)); 206 PetscCall(VecGetSize(coorlocal, &N)); 207 PetscCall(VecGetBlockSize(coorlocal, &bs)); 208 N = N / bs; 209 PetscCall(VecGetArrayRead(coorlocal, &_coor)); 210 for (i = 0; i < N; i++) { 211 for (b = 0; b < bs; b++) { 212 gmin[b] = PetscMin(gmin[b], PetscRealPart(_coor[bs * i + b])); 213 gmax[b] = PetscMax(gmax[b], PetscRealPart(_coor[bs * i + b])); 214 } 215 } 216 PetscCall(VecRestoreArrayRead(coorlocal, &_coor)); 217 218 /* broadcast points from rank 0 if requested */ 219 if (redundant) { 220 my_npoints = npoints; 221 PetscCallMPI(MPI_Bcast(&my_npoints, 1, MPIU_INT, 0, comm)); 222 223 if (rank > 0) { /* allocate space */ 224 PetscCall(PetscMalloc1(bs * my_npoints, &my_coor)); 225 } else { 226 my_coor = coor; 227 } 228 PetscCallMPI(MPI_Bcast(my_coor, bs * my_npoints, MPIU_REAL, 0, comm)); 229 } else { 230 my_npoints = npoints; 231 my_coor = coor; 232 } 233 234 /* determine the number of points living in the bounding box */ 235 n_estimate = 0; 236 for (i = 0; i < my_npoints; i++) { 237 PetscBool point_inside = PETSC_TRUE; 238 239 for (b = 0; b < bs; b++) { 240 if (my_coor[bs * i + b] < gmin[b]) point_inside = PETSC_FALSE; 241 if (my_coor[bs * i + b] > gmax[b]) point_inside = PETSC_FALSE; 242 } 243 if (point_inside) n_estimate++; 244 } 245 246 /* create candidate list */ 247 PetscCall(VecCreate(PETSC_COMM_SELF, &pos)); 248 PetscCall(VecSetSizes(pos, bs * n_estimate, PETSC_DECIDE)); 249 PetscCall(VecSetBlockSize(pos, bs)); 250 PetscCall(VecSetFromOptions(pos)); 251 PetscCall(VecGetArray(pos, &_pos)); 252 253 n_estimate = 0; 254 for (i = 0; i < my_npoints; i++) { 255 PetscBool point_inside = PETSC_TRUE; 256 257 for (b = 0; b < bs; b++) { 258 if (my_coor[bs * i + b] < gmin[b]) point_inside = PETSC_FALSE; 259 if (my_coor[bs * i + b] > gmax[b]) point_inside = PETSC_FALSE; 260 } 261 if (point_inside) { 262 for (b = 0; b < bs; b++) _pos[bs * n_estimate + b] = my_coor[bs * i + b]; 263 n_estimate++; 264 } 265 } 266 PetscCall(VecRestoreArray(pos, &_pos)); 267 268 /* locate points */ 269 PetscCall(DMLocatePoints(celldm, pos, DM_POINTLOCATION_NONE, &sfcell)); 270 271 PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell)); 272 n_found = 0; 273 for (p = 0; p < n_estimate; p++) { 274 if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) n_found++; 275 } 276 277 /* adjust size */ 278 if (mode == ADD_VALUES) { 279 PetscCall(DMSwarmGetLocalSize(dm, &n_curr)); 280 n_new_est = n_curr + n_found; 281 PetscCall(DMSwarmSetLocalSizes(dm, n_new_est, -1)); 282 } 283 if (mode == INSERT_VALUES) { 284 n_curr = 0; 285 n_new_est = n_found; 286 PetscCall(DMSwarmSetLocalSizes(dm, n_new_est, -1)); 287 } 288 289 /* initialize new coords, cell owners, pid */ 290 PetscCall(VecGetArrayRead(pos, &_coor)); 291 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&swarm_coor)); 292 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid)); 293 n_found = 0; 294 for (p = 0; p < n_estimate; p++) { 295 if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) { 296 for (b = 0; b < bs; b++) swarm_coor[bs * (n_curr + n_found) + b] = PetscRealPart(_coor[bs * p + b]); 297 swarm_cellid[n_curr + n_found] = LA_sfcell[p].index; 298 n_found++; 299 } 300 } 301 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid)); 302 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&swarm_coor)); 303 PetscCall(VecRestoreArrayRead(pos, &_coor)); 304 305 if (redundant) { 306 if (rank > 0) PetscCall(PetscFree(my_coor)); 307 } 308 PetscCall(PetscSFDestroy(&sfcell)); 309 PetscCall(VecDestroy(&pos)); 310 PetscFunctionReturn(PETSC_SUCCESS); 311 } 312 313 extern PetscErrorCode private_DMSwarmInsertPointsUsingCellDM_DA(DM, DM, DMSwarmPICLayoutType, PetscInt); 314 extern PetscErrorCode private_DMSwarmInsertPointsUsingCellDM_PLEX(DM, DM, DMSwarmPICLayoutType, PetscInt); 315 316 /*@C 317 DMSwarmInsertPointsUsingCellDM - Insert point coordinates within each cell 318 319 Not Collective 320 321 Input Parameters: 322 + dm - the `DMSWARM` 323 . layout_type - method used to fill each cell with the cell `DM` 324 - fill_param - parameter controlling how many points per cell are added (the meaning of this parameter is dependent on the layout type) 325 326 Level: beginner 327 328 Notes: 329 The insert method will reset any previous defined points within the `DMSWARM`. 330 331 When using a `DMDA` both 2D and 3D are supported for all layout types provided you are using `DMDA_ELEMENT_Q1`. 332 333 When using a `DMPLEX` the following case are supported\: 334 .vb 335 (i) DMSWARMPIC_LAYOUT_REGULAR: 2D (triangle), 336 (ii) DMSWARMPIC_LAYOUT_GAUSS: 2D and 3D provided the cell is a tri/tet or a quad/hex, 337 (iii) DMSWARMPIC_LAYOUT_SUBDIVISION: 2D and 3D for quad/hex and 2D tri. 338 .ve 339 340 .seealso: `DMSWARM`, `DMSwarmPICLayoutType`, `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType` 341 @*/ 342 PETSC_EXTERN PetscErrorCode DMSwarmInsertPointsUsingCellDM(DM dm, DMSwarmPICLayoutType layout_type, PetscInt fill_param) 343 { 344 DM celldm; 345 PetscBool isDA, isPLEX; 346 347 PetscFunctionBegin; 348 DMSWARMPICVALID(dm); 349 PetscCall(DMSwarmGetCellDM(dm, &celldm)); 350 PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMDA, &isDA)); 351 PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMPLEX, &isPLEX)); 352 if (isDA) { 353 PetscCall(private_DMSwarmInsertPointsUsingCellDM_DA(dm, celldm, layout_type, fill_param)); 354 } else if (isPLEX) { 355 PetscCall(private_DMSwarmInsertPointsUsingCellDM_PLEX(dm, celldm, layout_type, fill_param)); 356 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only supported for cell DMs of type DMDA and DMPLEX"); 357 PetscFunctionReturn(PETSC_SUCCESS); 358 } 359 360 extern PetscErrorCode private_DMSwarmSetPointCoordinatesCellwise_PLEX(DM, DM, PetscInt, PetscReal *); 361 362 /*@C 363 DMSwarmSetPointCoordinatesCellwise - Insert point coordinates (defined over the reference cell) within each cell 364 365 Not Collective 366 367 Input Parameters: 368 + dm - the `DMSWARM` 369 . npoints - the number of points to insert in each cell 370 - xi - the coordinates (defined in the local coordinate system for each cell) to insert 371 372 Level: beginner 373 374 Notes: 375 The method will reset any previous defined points within the `DMSWARM`. 376 Only supported for `DMPLEX`. If you are using a `DMDA` it is recommended to either use 377 `DMSwarmInsertPointsUsingCellDM()`, or extract and set the coordinates yourself the following code 378 .vb 379 PetscReal *coor; 380 DMSwarmGetField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&coor); 381 // user code to define the coordinates here 382 DMSwarmRestoreField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&coor); 383 .ve 384 385 .seealso: `DMSWARM`, `DMSwarmSetCellDM()`, `DMSwarmInsertPointsUsingCellDM()` 386 @*/ 387 PETSC_EXTERN PetscErrorCode DMSwarmSetPointCoordinatesCellwise(DM dm, PetscInt npoints, PetscReal xi[]) 388 { 389 DM celldm; 390 PetscBool isDA, isPLEX; 391 392 PetscFunctionBegin; 393 DMSWARMPICVALID(dm); 394 PetscCall(DMSwarmGetCellDM(dm, &celldm)); 395 PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMDA, &isDA)); 396 PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMPLEX, &isPLEX)); 397 PetscCheck(!isDA, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only supported for cell DMs of type DMPLEX. Recommended you use DMSwarmInsertPointsUsingCellDM()"); 398 if (isPLEX) { 399 PetscCall(private_DMSwarmSetPointCoordinatesCellwise_PLEX(dm, celldm, npoints, xi)); 400 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only supported for cell DMs of type DMDA and DMPLEX"); 401 PetscFunctionReturn(PETSC_SUCCESS); 402 } 403 404 /*@C 405 DMSwarmCreatePointPerCellCount - Count the number of points within all cells in the cell DM 406 407 Not Collective 408 409 Input Parameter: 410 . dm - the `DMSWARM` 411 412 Output Parameters: 413 + ncells - the number of cells in the cell `DM` (optional argument, pass `NULL` to ignore) 414 - count - array of length ncells containing the number of points per cell 415 416 Level: beginner 417 418 Notes: 419 The array count is allocated internally and must be free'd by the user. 420 421 .seealso: `DMSWARM`, `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType` 422 @*/ 423 PETSC_EXTERN PetscErrorCode DMSwarmCreatePointPerCellCount(DM dm, PetscInt *ncells, PetscInt **count) 424 { 425 PetscBool isvalid; 426 PetscInt nel; 427 PetscInt *sum; 428 429 PetscFunctionBegin; 430 PetscCall(DMSwarmSortGetIsValid(dm, &isvalid)); 431 nel = 0; 432 if (isvalid) { 433 PetscInt e; 434 435 PetscCall(DMSwarmSortGetSizes(dm, &nel, NULL)); 436 437 PetscCall(PetscMalloc1(nel, &sum)); 438 for (e = 0; e < nel; e++) PetscCall(DMSwarmSortGetNumberOfPointsPerCell(dm, e, &sum[e])); 439 } else { 440 DM celldm; 441 PetscBool isda, isplex, isshell; 442 PetscInt p, npoints; 443 PetscInt *swarm_cellid; 444 445 /* get the number of cells */ 446 PetscCall(DMSwarmGetCellDM(dm, &celldm)); 447 PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMDA, &isda)); 448 PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMPLEX, &isplex)); 449 PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMSHELL, &isshell)); 450 if (isda) { 451 PetscInt _nel, _npe; 452 const PetscInt *_element; 453 454 PetscCall(DMDAGetElements(celldm, &_nel, &_npe, &_element)); 455 nel = _nel; 456 PetscCall(DMDARestoreElements(celldm, &_nel, &_npe, &_element)); 457 } else if (isplex) { 458 PetscInt ps, pe; 459 460 PetscCall(DMPlexGetHeightStratum(celldm, 0, &ps, &pe)); 461 nel = pe - ps; 462 } else if (isshell) { 463 PetscErrorCode (*method_DMShellGetNumberOfCells)(DM, PetscInt *); 464 465 PetscCall(PetscObjectQueryFunction((PetscObject)celldm, "DMGetNumberOfCells_C", &method_DMShellGetNumberOfCells)); 466 if (method_DMShellGetNumberOfCells) { 467 PetscCall(method_DMShellGetNumberOfCells(celldm, &nel)); 468 } else 469 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot determine the number of cells for the DMSHELL object. User must provide a method via PetscObjectComposeFunction( (PetscObject)shelldm, \"DMGetNumberOfCells_C\", your_function_to_compute_number_of_cells);"); 470 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot determine the number of cells for a DM not of type DA, PLEX or SHELL"); 471 472 PetscCall(PetscMalloc1(nel, &sum)); 473 PetscCall(PetscArrayzero(sum, nel)); 474 PetscCall(DMSwarmGetLocalSize(dm, &npoints)); 475 PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid)); 476 for (p = 0; p < npoints; p++) { 477 if (swarm_cellid[p] != DMLOCATEPOINT_POINT_NOT_FOUND) sum[swarm_cellid[p]]++; 478 } 479 PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid)); 480 } 481 if (ncells) *ncells = nel; 482 *count = sum; 483 PetscFunctionReturn(PETSC_SUCCESS); 484 } 485 486 /*@ 487 DMSwarmGetNumSpecies - Get the number of particle species 488 489 Not Collective 490 491 Input Parameter: 492 . sw - the `DMSWARM` 493 494 Output Parameters: 495 . Ns - the number of species 496 497 Level: intermediate 498 499 .seealso: `DMSWARM`, `DMSwarmSetNumSpecies()`, `DMSwarmSetType()`, `DMSwarmType` 500 @*/ 501 PetscErrorCode DMSwarmGetNumSpecies(DM sw, PetscInt *Ns) 502 { 503 DM_Swarm *swarm = (DM_Swarm *)sw->data; 504 505 PetscFunctionBegin; 506 *Ns = swarm->Ns; 507 PetscFunctionReturn(PETSC_SUCCESS); 508 } 509 510 /*@ 511 DMSwarmSetNumSpecies - Set the number of particle species 512 513 Not Collective 514 515 Input Parameters: 516 + sw - the `DMSWARM` 517 - Ns - the number of species 518 519 Level: intermediate 520 521 .seealso: `DMSWARM`, `DMSwarmGetNumSpecies()`, `DMSwarmSetType()`, `DMSwarmType` 522 @*/ 523 PetscErrorCode DMSwarmSetNumSpecies(DM sw, PetscInt Ns) 524 { 525 DM_Swarm *swarm = (DM_Swarm *)sw->data; 526 527 PetscFunctionBegin; 528 swarm->Ns = Ns; 529 PetscFunctionReturn(PETSC_SUCCESS); 530 } 531 532 /*@C 533 DMSwarmGetCoordinateFunction - Get the function setting initial particle positions, if it exists 534 535 Not Collective 536 537 Input Parameter: 538 . sw - the `DMSWARM` 539 540 Output Parameter: 541 . coordFunc - the function setting initial particle positions, or `NULL`, see `PetscSimplePointFn` for the calling sequence 542 543 Level: intermediate 544 545 .seealso: `DMSWARM`, `DMSwarmSetCoordinateFunction()`, `DMSwarmGetVelocityFunction()`, `DMSwarmInitializeCoordinates()`, `PetscSimplePointFn` 546 @*/ 547 PetscErrorCode DMSwarmGetCoordinateFunction(DM sw, PetscSimplePointFn **coordFunc) 548 { 549 DM_Swarm *swarm = (DM_Swarm *)sw->data; 550 551 PetscFunctionBegin; 552 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 553 PetscAssertPointer(coordFunc, 2); 554 *coordFunc = swarm->coordFunc; 555 PetscFunctionReturn(PETSC_SUCCESS); 556 } 557 558 /*@C 559 DMSwarmSetCoordinateFunction - Set the function setting initial particle positions 560 561 Not Collective 562 563 Input Parameters: 564 + sw - the `DMSWARM` 565 - coordFunc - the function setting initial particle positions, see `PetscSimplePointFn` for the calling sequence 566 567 Level: intermediate 568 569 .seealso: `DMSWARM`, `DMSwarmGetCoordinateFunction()`, `DMSwarmSetVelocityFunction()`, `DMSwarmInitializeCoordinates()`, `PetscSimplePointFn` 570 @*/ 571 PetscErrorCode DMSwarmSetCoordinateFunction(DM sw, PetscSimplePointFn *coordFunc) 572 { 573 DM_Swarm *swarm = (DM_Swarm *)sw->data; 574 575 PetscFunctionBegin; 576 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 577 PetscValidFunction(coordFunc, 2); 578 swarm->coordFunc = coordFunc; 579 PetscFunctionReturn(PETSC_SUCCESS); 580 } 581 582 /*@C 583 DMSwarmGetVelocityFunction - Get the function setting initial particle velocities, if it exists 584 585 Not Collective 586 587 Input Parameter: 588 . sw - the `DMSWARM` 589 590 Output Parameter: 591 . velFunc - the function setting initial particle velocities, or `NULL`, see `PetscSimplePointFn` for the calling sequence 592 593 Level: intermediate 594 595 .seealso: `DMSWARM`, `DMSwarmSetVelocityFunction()`, `DMSwarmGetCoordinateFunction()`, `DMSwarmInitializeVelocities()`, `PetscSimplePointFn` 596 @*/ 597 PetscErrorCode DMSwarmGetVelocityFunction(DM sw, PetscSimplePointFn **velFunc) 598 { 599 DM_Swarm *swarm = (DM_Swarm *)sw->data; 600 601 PetscFunctionBegin; 602 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 603 PetscAssertPointer(velFunc, 2); 604 *velFunc = swarm->velFunc; 605 PetscFunctionReturn(PETSC_SUCCESS); 606 } 607 608 /*@C 609 DMSwarmSetVelocityFunction - Set the function setting initial particle velocities 610 611 Not Collective 612 613 Input Parameters: 614 + sw - the `DMSWARM` 615 - velFunc - the function setting initial particle velocities, see `PetscSimplePointFn` for the calling sequence 616 617 Level: intermediate 618 619 .seealso: `DMSWARM`, `DMSwarmGetVelocityFunction()`, `DMSwarmSetCoordinateFunction()`, `DMSwarmInitializeVelocities()`, `PetscSimplePointFn` 620 @*/ 621 PetscErrorCode DMSwarmSetVelocityFunction(DM sw, PetscSimplePointFn *velFunc) 622 { 623 DM_Swarm *swarm = (DM_Swarm *)sw->data; 624 625 PetscFunctionBegin; 626 PetscValidHeaderSpecific(sw, DM_CLASSID, 1); 627 PetscValidFunction(velFunc, 2); 628 swarm->velFunc = velFunc; 629 PetscFunctionReturn(PETSC_SUCCESS); 630 } 631 632 /*@C 633 DMSwarmComputeLocalSize - Compute the local number and distribution of particles based upon a density function 634 635 Not Collective 636 637 Input Parameters: 638 + sw - The `DMSWARM` 639 . N - The target number of particles 640 - density - The density field for the particle layout, normalized to unity 641 642 Level: advanced 643 644 Note: 645 One particle will be created for each species. 646 647 .seealso: `DMSWARM`, `DMSwarmComputeLocalSizeFromOptions()` 648 @*/ 649 PetscErrorCode DMSwarmComputeLocalSize(DM sw, PetscInt N, PetscProbFunc density) 650 { 651 DM dm; 652 PetscQuadrature quad; 653 const PetscReal *xq, *wq; 654 PetscReal *n_int; 655 PetscInt *npc_s, *cellid, Ni; 656 PetscReal gmin[3], gmax[3], xi0[3]; 657 PetscInt Ns, cStart, cEnd, c, dim, d, Nq, q, Np = 0, p, s; 658 PetscBool simplex; 659 660 PetscFunctionBegin; 661 PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 662 PetscCall(DMSwarmGetCellDM(sw, &dm)); 663 PetscCall(DMGetDimension(dm, &dim)); 664 PetscCall(DMGetBoundingBox(dm, gmin, gmax)); 665 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 666 PetscCall(DMPlexIsSimplex(dm, &simplex)); 667 PetscCall(DMGetCoordinatesLocalSetUp(dm)); 668 if (simplex) PetscCall(PetscDTStroudConicalQuadrature(dim, 1, 5, -1.0, 1.0, &quad)); 669 else PetscCall(PetscDTGaussTensorQuadrature(dim, 1, 5, -1.0, 1.0, &quad)); 670 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, &xq, &wq)); 671 PetscCall(PetscCalloc2(Ns, &n_int, (cEnd - cStart) * Ns, &npc_s)); 672 /* Integrate the density function to get the number of particles in each cell */ 673 for (d = 0; d < dim; ++d) xi0[d] = -1.0; 674 for (c = 0; c < cEnd - cStart; ++c) { 675 const PetscInt cell = c + cStart; 676 PetscReal v0[3], J[9], invJ[9], detJ, detJp = 2. / (gmax[0] - gmin[0]), xr[3], den; 677 678 /* Have to transform quadrature points/weights to cell domain */ 679 PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, invJ, &detJ)); 680 PetscCall(PetscArrayzero(n_int, Ns)); 681 for (q = 0; q < Nq; ++q) { 682 CoordinatesRefToReal(dim, dim, xi0, v0, J, &xq[q * dim], xr); 683 /* Have to transform mesh to domain of definition of PDF, [-1, 1], and weight PDF by |J|/2 */ 684 xr[0] = detJp * (xr[0] - gmin[0]) - 1.; 685 686 for (s = 0; s < Ns; ++s) { 687 PetscCall(density(xr, NULL, &den)); 688 n_int[s] += (detJp * den) * (detJ * wq[q]) / (PetscReal)Ns; 689 } 690 } 691 for (s = 0; s < Ns; ++s) { 692 Ni = N; 693 npc_s[c * Ns + s] += (PetscInt)(Ni * n_int[s]); 694 Np += npc_s[c * Ns + s]; 695 } 696 } 697 PetscCall(PetscQuadratureDestroy(&quad)); 698 PetscCall(DMSwarmSetLocalSizes(sw, Np, 0)); 699 PetscCall(DMSwarmGetField(sw, DMSwarmPICField_cellid, NULL, NULL, (void **)&cellid)); 700 for (c = 0, p = 0; c < cEnd - cStart; ++c) { 701 for (s = 0; s < Ns; ++s) { 702 for (q = 0; q < npc_s[c * Ns + s]; ++q, ++p) cellid[p] = c; 703 } 704 } 705 PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_cellid, NULL, NULL, (void **)&cellid)); 706 PetscCall(PetscFree2(n_int, npc_s)); 707 PetscFunctionReturn(PETSC_SUCCESS); 708 } 709 710 /*@ 711 DMSwarmComputeLocalSizeFromOptions - Compute the local number and distribution of particles based upon a density function determined by options 712 713 Not Collective 714 715 Input Parameter: 716 . sw - The `DMSWARM` 717 718 Level: advanced 719 720 .seealso: `DMSWARM`, `DMSwarmComputeLocalSize()` 721 @*/ 722 PetscErrorCode DMSwarmComputeLocalSizeFromOptions(DM sw) 723 { 724 PetscProbFunc pdf; 725 const char *prefix; 726 char funcname[PETSC_MAX_PATH_LEN]; 727 PetscInt *N, Ns, dim, n; 728 PetscBool flg; 729 PetscMPIInt size, rank; 730 731 PetscFunctionBegin; 732 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)sw), &size)); 733 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sw), &rank)); 734 PetscCall(PetscCalloc1(size, &N)); 735 PetscOptionsBegin(PetscObjectComm((PetscObject)sw), "", "DMSwarm Options", "DMSWARM"); 736 n = size; 737 PetscCall(PetscOptionsIntArray("-dm_swarm_num_particles", "The target number of particles", "", N, &n, NULL)); 738 PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 739 PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg)); 740 if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns)); 741 PetscCall(PetscOptionsString("-dm_swarm_coordinate_function", "Function to determine particle coordinates", "DMSwarmSetCoordinateFunction", funcname, funcname, sizeof(funcname), &flg)); 742 PetscOptionsEnd(); 743 if (flg) { 744 PetscSimplePointFn *coordFunc; 745 746 PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 747 PetscCall(PetscDLSym(NULL, funcname, (void **)&coordFunc)); 748 PetscCheck(coordFunc, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONG, "Could not locate function %s", funcname); 749 PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 750 PetscCall(DMSwarmSetLocalSizes(sw, N[rank] * Ns, 0)); 751 PetscCall(DMSwarmSetCoordinateFunction(sw, coordFunc)); 752 } else { 753 PetscCall(DMGetDimension(sw, &dim)); 754 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)sw, &prefix)); 755 PetscCall(PetscProbCreateFromOptions(dim, prefix, "-dm_swarm_coordinate_density", &pdf, NULL, NULL)); 756 PetscCall(DMSwarmComputeLocalSize(sw, N[rank], pdf)); 757 } 758 PetscCall(PetscFree(N)); 759 PetscFunctionReturn(PETSC_SUCCESS); 760 } 761 762 /*@ 763 DMSwarmInitializeCoordinates - Determine the initial coordinates of particles for a PIC method 764 765 Not Collective 766 767 Input Parameter: 768 . sw - The `DMSWARM` 769 770 Level: advanced 771 772 Note: 773 Currently, we randomly place particles in their assigned cell 774 775 .seealso: `DMSWARM`, `DMSwarmComputeLocalSize()`, `DMSwarmInitializeVelocities()` 776 @*/ 777 PetscErrorCode DMSwarmInitializeCoordinates(DM sw) 778 { 779 PetscSimplePointFn *coordFunc; 780 PetscScalar *weight; 781 PetscReal *x; 782 PetscInt *species; 783 void *ctx; 784 PetscBool removePoints = PETSC_TRUE; 785 PetscDataType dtype; 786 PetscInt Np, p, Ns, dim, d, bs; 787 788 PetscFunctionBeginUser; 789 PetscCall(DMGetDimension(sw, &dim)); 790 PetscCall(DMSwarmGetLocalSize(sw, &Np)); 791 PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 792 PetscCall(DMSwarmGetCoordinateFunction(sw, &coordFunc)); 793 794 PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, &bs, &dtype, (void **)&x)); 795 PetscCall(DMSwarmGetField(sw, "w_q", &bs, &dtype, (void **)&weight)); 796 PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 797 if (coordFunc) { 798 PetscCall(DMGetApplicationContext(sw, &ctx)); 799 for (p = 0; p < Np; ++p) { 800 PetscScalar X[3]; 801 802 PetscCall((*coordFunc)(dim, 0., NULL, p, X, ctx)); 803 for (d = 0; d < dim; ++d) x[p * dim + d] = PetscRealPart(X[d]); 804 weight[p] = 1.0; 805 species[p] = p % Ns; 806 } 807 } else { 808 DM dm; 809 PetscRandom rnd; 810 PetscReal xi0[3]; 811 PetscInt cStart, cEnd, c; 812 813 PetscCall(DMSwarmGetCellDM(sw, &dm)); 814 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 815 PetscCall(DMGetApplicationContext(sw, &ctx)); 816 817 /* Set particle position randomly in cell, set weights to 1 */ 818 PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm), &rnd)); 819 PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0)); 820 PetscCall(PetscRandomSetFromOptions(rnd)); 821 PetscCall(DMSwarmSortGetAccess(sw)); 822 for (d = 0; d < dim; ++d) xi0[d] = -1.0; 823 for (c = cStart; c < cEnd; ++c) { 824 PetscReal v0[3], J[9], invJ[9], detJ; 825 PetscInt *pidx, Npc, q; 826 827 PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 828 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ)); 829 for (q = 0; q < Npc; ++q) { 830 const PetscInt p = pidx[q]; 831 PetscReal xref[3]; 832 833 for (d = 0; d < dim; ++d) PetscCall(PetscRandomGetValueReal(rnd, &xref[d])); 834 CoordinatesRefToReal(dim, dim, xi0, v0, J, xref, &x[p * dim]); 835 836 weight[p] = 1.0 / Np; 837 species[p] = p % Ns; 838 } 839 PetscCall(PetscFree(pidx)); 840 } 841 PetscCall(PetscRandomDestroy(&rnd)); 842 PetscCall(DMSwarmSortRestoreAccess(sw)); 843 } 844 PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 845 PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 846 PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 847 848 PetscCall(DMSwarmMigrate(sw, removePoints)); 849 PetscCall(DMLocalizeCoordinates(sw)); 850 PetscFunctionReturn(PETSC_SUCCESS); 851 } 852 853 /*@C 854 DMSwarmInitializeVelocities - Set the initial velocities of particles using a distribution. 855 856 Collective 857 858 Input Parameters: 859 + sw - The `DMSWARM` object 860 . sampler - A function which uniformly samples the velocity PDF 861 - v0 - The velocity scale for nondimensionalization for each species 862 863 Level: advanced 864 865 Note: 866 If `v0` is zero for the first species, all velocities are set to zero. If it is zero for any other species, the effect will be to give that species zero velocity. 867 868 .seealso: `DMSWARM`, `DMSwarmComputeLocalSize()`, `DMSwarmInitializeCoordinates()`, `DMSwarmInitializeVelocitiesFromOptions()` 869 @*/ 870 PetscErrorCode DMSwarmInitializeVelocities(DM sw, PetscProbFunc sampler, const PetscReal v0[]) 871 { 872 PetscSimplePointFn *velFunc; 873 PetscReal *v; 874 PetscInt *species; 875 void *ctx; 876 PetscInt dim, Np, p; 877 878 PetscFunctionBegin; 879 PetscCall(DMSwarmGetVelocityFunction(sw, &velFunc)); 880 881 PetscCall(DMGetDimension(sw, &dim)); 882 PetscCall(DMSwarmGetLocalSize(sw, &Np)); 883 PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v)); 884 PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 885 if (v0[0] == 0.) { 886 PetscCall(PetscArrayzero(v, Np * dim)); 887 } else if (velFunc) { 888 PetscCall(DMGetApplicationContext(sw, &ctx)); 889 for (p = 0; p < Np; ++p) { 890 PetscInt s = species[p], d; 891 PetscScalar vel[3]; 892 893 PetscCall((*velFunc)(dim, 0., NULL, p, vel, ctx)); 894 for (d = 0; d < dim; ++d) v[p * dim + d] = (v0[s] / v0[0]) * PetscRealPart(vel[d]); 895 } 896 } else { 897 PetscRandom rnd; 898 899 PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)sw), &rnd)); 900 PetscCall(PetscRandomSetInterval(rnd, 0, 1.)); 901 PetscCall(PetscRandomSetFromOptions(rnd)); 902 903 for (p = 0; p < Np; ++p) { 904 PetscInt s = species[p], d; 905 PetscReal a[3], vel[3]; 906 907 for (d = 0; d < dim; ++d) PetscCall(PetscRandomGetValueReal(rnd, &a[d])); 908 PetscCall(sampler(a, NULL, vel)); 909 for (d = 0; d < dim; ++d) v[p * dim + d] = (v0[s] / v0[0]) * vel[d]; 910 } 911 PetscCall(PetscRandomDestroy(&rnd)); 912 } 913 PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v)); 914 PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 915 PetscFunctionReturn(PETSC_SUCCESS); 916 } 917 918 /*@ 919 DMSwarmInitializeVelocitiesFromOptions - Set the initial velocities of particles using a distribution determined from options. 920 921 Collective 922 923 Input Parameters: 924 + sw - The `DMSWARM` object 925 - v0 - The velocity scale for nondimensionalization for each species 926 927 Level: advanced 928 929 .seealso: `DMSWARM`, `DMSwarmComputeLocalSize()`, `DMSwarmInitializeCoordinates()`, `DMSwarmInitializeVelocities()` 930 @*/ 931 PetscErrorCode DMSwarmInitializeVelocitiesFromOptions(DM sw, const PetscReal v0[]) 932 { 933 PetscProbFunc sampler; 934 PetscInt dim; 935 const char *prefix; 936 char funcname[PETSC_MAX_PATH_LEN]; 937 PetscBool flg; 938 939 PetscFunctionBegin; 940 PetscOptionsBegin(PetscObjectComm((PetscObject)sw), "", "DMSwarm Options", "DMSWARM"); 941 PetscCall(PetscOptionsString("-dm_swarm_velocity_function", "Function to determine particle velocities", "DMSwarmSetVelocityFunction", funcname, funcname, sizeof(funcname), &flg)); 942 PetscOptionsEnd(); 943 if (flg) { 944 PetscSimplePointFn *velFunc; 945 946 PetscCall(PetscDLSym(NULL, funcname, (void **)&velFunc)); 947 PetscCheck(velFunc, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONG, "Could not locate function %s", funcname); 948 PetscCall(DMSwarmSetVelocityFunction(sw, velFunc)); 949 } 950 PetscCall(DMGetDimension(sw, &dim)); 951 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)sw, &prefix)); 952 PetscCall(PetscProbCreateFromOptions(dim, prefix, "-dm_swarm_velocity_density", NULL, NULL, &sampler)); 953 PetscCall(DMSwarmInitializeVelocities(sw, sampler, v0)); 954 PetscFunctionReturn(PETSC_SUCCESS); 955 } 956