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