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