xref: /petsc/src/dm/impls/swarm/swarmpic.c (revision 8434afd195968570cfdb5bc7b9cfc0a316d974ae)
10e2ec84fSDave May #define PETSCDM_DLL
20e2ec84fSDave May #include <petsc/private/dmswarmimpl.h> /*I   "petscdmswarm.h"   I*/
30e2ec84fSDave May #include <petscsf.h>
4b799feefSDave May #include <petscdmda.h>
5b799feefSDave May #include <petscdmplex.h>
635b38c60SMatthew G. Knepley #include <petscdt.h>
7279f676cSBarry Smith #include "../src/dm/impls/swarm/data_bucket.h"
80e2ec84fSDave May 
935b38c60SMatthew G. Knepley #include <petsc/private/petscfeimpl.h> /* For CoordinatesRefToReal() */
1035b38c60SMatthew G. Knepley 
110e2ec84fSDave May /* Coordinate insertition/addition API */
120e2ec84fSDave May /*@C
1320f4b53cSBarry Smith   DMSwarmSetPointsUniformCoordinates - Set point coordinates in a `DMSWARM` on a regular (ijk) grid
140e2ec84fSDave May 
1520f4b53cSBarry Smith   Collective
160e2ec84fSDave May 
1760225df5SJacob Faibussowitsch   Input Parameters:
1820f4b53cSBarry Smith + dm      - the `DMSWARM`
190e2ec84fSDave May . min     - minimum coordinate values in the x, y, z directions (array of length dim)
200e2ec84fSDave May . max     - maximum coordinate values in the x, y, z directions (array of length dim)
210e2ec84fSDave May . npoints - number of points in each spatial direction (array of length dim)
2220f4b53cSBarry Smith - mode    - indicates whether to append points to the swarm (`ADD_VALUES`), or over-ride existing points (`INSERT_VALUES`)
230e2ec84fSDave May 
240e2ec84fSDave May   Level: beginner
250e2ec84fSDave May 
260e2ec84fSDave May   Notes:
2720f4b53cSBarry Smith   When using mode = `INSERT_VALUES`, this method will reset the number of particles in the `DMSWARM`
2820f4b53cSBarry Smith   to be npoints[0]*npoints[1] (2D) or npoints[0]*npoints[1]*npoints[2] (3D). When using mode = `ADD_VALUES`,
2920f4b53cSBarry Smith   new points will be appended to any already existing in the `DMSWARM`
300e2ec84fSDave May 
3120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType`
320e2ec84fSDave May @*/
33d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMSwarmSetPointsUniformCoordinates(DM dm, PetscReal min[], PetscReal max[], PetscInt npoints[], InsertMode mode)
34d71ae5a4SJacob Faibussowitsch {
350e2ec84fSDave May   PetscReal          gmin[] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
360e2ec84fSDave May   PetscReal          gmax[] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
370e2ec84fSDave May   PetscInt           i, j, k, N, bs, b, n_estimate, n_curr, n_new_est, p, n_found;
380e2ec84fSDave May   Vec                coorlocal;
390e2ec84fSDave May   const PetscScalar *_coor;
400e2ec84fSDave May   DM                 celldm;
410e2ec84fSDave May   PetscReal          dx[3];
422e3d3761SDave May   PetscInt           _npoints[] = {0, 0, 1};
430e2ec84fSDave May   Vec                pos;
440e2ec84fSDave May   PetscScalar       *_pos;
450e2ec84fSDave May   PetscReal         *swarm_coor;
460e2ec84fSDave May   PetscInt          *swarm_cellid;
470e2ec84fSDave May   PetscSF            sfcell = NULL;
480e2ec84fSDave May   const PetscSFNode *LA_sfcell;
490e2ec84fSDave May 
500e2ec84fSDave May   PetscFunctionBegin;
510e2ec84fSDave May   DMSWARMPICVALID(dm);
529566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &celldm));
539566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(celldm, &coorlocal));
549566063dSJacob Faibussowitsch   PetscCall(VecGetSize(coorlocal, &N));
559566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(coorlocal, &bs));
560e2ec84fSDave May   N = N / bs;
579566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coorlocal, &_coor));
580e2ec84fSDave May   for (i = 0; i < N; i++) {
590e2ec84fSDave May     for (b = 0; b < bs; b++) {
60a5f152d1SDave May       gmin[b] = PetscMin(gmin[b], PetscRealPart(_coor[bs * i + b]));
61a5f152d1SDave May       gmax[b] = PetscMax(gmax[b], PetscRealPart(_coor[bs * i + b]));
620e2ec84fSDave May     }
630e2ec84fSDave May   }
649566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coorlocal, &_coor));
650e2ec84fSDave May 
660e2ec84fSDave May   for (b = 0; b < bs; b++) {
6771844bb8SDave May     if (npoints[b] > 1) {
680e2ec84fSDave May       dx[b] = (max[b] - min[b]) / ((PetscReal)(npoints[b] - 1));
6971844bb8SDave May     } else {
7071844bb8SDave May       dx[b] = 0.0;
7171844bb8SDave May     }
722e3d3761SDave May     _npoints[b] = npoints[b];
730e2ec84fSDave May   }
740e2ec84fSDave May 
750e2ec84fSDave May   /* determine number of points living in the bounding box */
760e2ec84fSDave May   n_estimate = 0;
772e3d3761SDave May   for (k = 0; k < _npoints[2]; k++) {
782e3d3761SDave May     for (j = 0; j < _npoints[1]; j++) {
792e3d3761SDave May       for (i = 0; i < _npoints[0]; i++) {
800e2ec84fSDave May         PetscReal xp[] = {0.0, 0.0, 0.0};
810e2ec84fSDave May         PetscInt  ijk[3];
820e2ec84fSDave May         PetscBool point_inside = PETSC_TRUE;
830e2ec84fSDave May 
840e2ec84fSDave May         ijk[0] = i;
850e2ec84fSDave May         ijk[1] = j;
860e2ec84fSDave May         ijk[2] = k;
87ad540459SPierre Jolivet         for (b = 0; b < bs; b++) xp[b] = min[b] + ijk[b] * dx[b];
880e2ec84fSDave May         for (b = 0; b < bs; b++) {
89ad540459SPierre Jolivet           if (xp[b] < gmin[b]) point_inside = PETSC_FALSE;
90ad540459SPierre Jolivet           if (xp[b] > gmax[b]) point_inside = PETSC_FALSE;
910e2ec84fSDave May         }
92ad540459SPierre Jolivet         if (point_inside) n_estimate++;
930e2ec84fSDave May       }
940e2ec84fSDave May     }
950e2ec84fSDave May   }
960e2ec84fSDave May 
970e2ec84fSDave May   /* create candidate list */
989566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &pos));
999566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(pos, bs * n_estimate, PETSC_DECIDE));
1009566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(pos, bs));
1019566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(pos));
1029566063dSJacob Faibussowitsch   PetscCall(VecGetArray(pos, &_pos));
1030e2ec84fSDave May 
1040e2ec84fSDave May   n_estimate = 0;
1052e3d3761SDave May   for (k = 0; k < _npoints[2]; k++) {
1062e3d3761SDave May     for (j = 0; j < _npoints[1]; j++) {
1072e3d3761SDave May       for (i = 0; i < _npoints[0]; i++) {
1080e2ec84fSDave May         PetscReal xp[] = {0.0, 0.0, 0.0};
1090e2ec84fSDave May         PetscInt  ijk[3];
1100e2ec84fSDave May         PetscBool point_inside = PETSC_TRUE;
1110e2ec84fSDave May 
1120e2ec84fSDave May         ijk[0] = i;
1130e2ec84fSDave May         ijk[1] = j;
1140e2ec84fSDave May         ijk[2] = k;
115ad540459SPierre Jolivet         for (b = 0; b < bs; b++) xp[b] = min[b] + ijk[b] * dx[b];
1160e2ec84fSDave May         for (b = 0; b < bs; b++) {
117ad540459SPierre Jolivet           if (xp[b] < gmin[b]) point_inside = PETSC_FALSE;
118ad540459SPierre Jolivet           if (xp[b] > gmax[b]) point_inside = PETSC_FALSE;
1190e2ec84fSDave May         }
1200e2ec84fSDave May         if (point_inside) {
121ad540459SPierre Jolivet           for (b = 0; b < bs; b++) _pos[bs * n_estimate + b] = xp[b];
1220e2ec84fSDave May           n_estimate++;
1230e2ec84fSDave May         }
1240e2ec84fSDave May       }
1250e2ec84fSDave May     }
1260e2ec84fSDave May   }
1279566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(pos, &_pos));
1280e2ec84fSDave May 
1290e2ec84fSDave May   /* locate points */
1309566063dSJacob Faibussowitsch   PetscCall(DMLocatePoints(celldm, pos, DM_POINTLOCATION_NONE, &sfcell));
1319566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell));
1320e2ec84fSDave May   n_found = 0;
1330e2ec84fSDave May   for (p = 0; p < n_estimate; p++) {
134ad540459SPierre Jolivet     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) n_found++;
1350e2ec84fSDave May   }
1360e2ec84fSDave May 
1370e2ec84fSDave May   /* adjust size */
1380e2ec84fSDave May   if (mode == ADD_VALUES) {
1399566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetLocalSize(dm, &n_curr));
1400e2ec84fSDave May     n_new_est = n_curr + n_found;
1419566063dSJacob Faibussowitsch     PetscCall(DMSwarmSetLocalSizes(dm, n_new_est, -1));
1420e2ec84fSDave May   }
1430e2ec84fSDave May   if (mode == INSERT_VALUES) {
1440e2ec84fSDave May     n_curr    = 0;
1450e2ec84fSDave May     n_new_est = n_found;
1469566063dSJacob Faibussowitsch     PetscCall(DMSwarmSetLocalSizes(dm, n_new_est, -1));
1470e2ec84fSDave May   }
1480e2ec84fSDave May 
1490e2ec84fSDave May   /* initialize new coords, cell owners, pid */
1509566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(pos, &_coor));
1519566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&swarm_coor));
1529566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid));
1530e2ec84fSDave May   n_found = 0;
1540e2ec84fSDave May   for (p = 0; p < n_estimate; p++) {
1550e2ec84fSDave May     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
156ad540459SPierre Jolivet       for (b = 0; b < bs; b++) swarm_coor[bs * (n_curr + n_found) + b] = PetscRealPart(_coor[bs * p + b]);
1570e2ec84fSDave May       swarm_cellid[n_curr + n_found] = LA_sfcell[p].index;
1580e2ec84fSDave May       n_found++;
1590e2ec84fSDave May     }
1600e2ec84fSDave May   }
1619566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid));
1629566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&swarm_coor));
1639566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(pos, &_coor));
1640e2ec84fSDave May 
1659566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfcell));
1669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pos));
1673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1680e2ec84fSDave May }
1690e2ec84fSDave May 
1700e2ec84fSDave May /*@C
17120f4b53cSBarry Smith   DMSwarmSetPointCoordinates - Set point coordinates in a `DMSWARM` from a user defined list
1720e2ec84fSDave May 
17320f4b53cSBarry Smith   Collective
1740e2ec84fSDave May 
17560225df5SJacob Faibussowitsch   Input Parameters:
17620f4b53cSBarry Smith + dm        - the `DMSWARM`
1770e2ec84fSDave May . npoints   - the number of points to insert
1780e2ec84fSDave May . coor      - the coordinate values
17920f4b53cSBarry Smith . 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
18020f4b53cSBarry Smith - mode      - indicates whether to append points to the swarm (`ADD_VALUES`), or over-ride existing points (`INSERT_VALUES`)
1810e2ec84fSDave May 
1820e2ec84fSDave May   Level: beginner
1830e2ec84fSDave May 
1840e2ec84fSDave May   Notes:
18520f4b53cSBarry Smith   If the user has specified `redundant` as `PETSC_FALSE`, the cell `DM` will attempt to locate the coordinates provided by `coor` within
18620f4b53cSBarry Smith   its sub-domain. If they any values within `coor` are not located in the sub-domain, they will be ignored and will not get
18720f4b53cSBarry Smith   added to the `DMSWARM`.
1880e2ec84fSDave May 
18920f4b53cSBarry Smith .seealso: `DMSWARM`, `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType`, `DMSwarmSetPointsUniformCoordinates()`
1900e2ec84fSDave May @*/
191d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMSwarmSetPointCoordinates(DM dm, PetscInt npoints, PetscReal coor[], PetscBool redundant, InsertMode mode)
192d71ae5a4SJacob Faibussowitsch {
1930e2ec84fSDave May   PetscReal          gmin[] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
1940e2ec84fSDave May   PetscReal          gmax[] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1950e2ec84fSDave May   PetscInt           i, N, bs, b, n_estimate, n_curr, n_new_est, p, n_found;
1960e2ec84fSDave May   Vec                coorlocal;
1970e2ec84fSDave May   const PetscScalar *_coor;
1980e2ec84fSDave May   DM                 celldm;
1990e2ec84fSDave May   Vec                pos;
2000e2ec84fSDave May   PetscScalar       *_pos;
2010e2ec84fSDave May   PetscReal         *swarm_coor;
2020e2ec84fSDave May   PetscInt          *swarm_cellid;
2030e2ec84fSDave May   PetscSF            sfcell = NULL;
2040e2ec84fSDave May   const PetscSFNode *LA_sfcell;
2050e2ec84fSDave May   PetscReal         *my_coor;
2060e2ec84fSDave May   PetscInt           my_npoints;
2070e2ec84fSDave May   PetscMPIInt        rank;
2080e2ec84fSDave May   MPI_Comm           comm;
2090e2ec84fSDave May 
2100e2ec84fSDave May   PetscFunctionBegin;
2110e2ec84fSDave May   DMSWARMPICVALID(dm);
2129566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2139566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2140e2ec84fSDave May 
2159566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &celldm));
2169566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(celldm, &coorlocal));
2179566063dSJacob Faibussowitsch   PetscCall(VecGetSize(coorlocal, &N));
2189566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(coorlocal, &bs));
2190e2ec84fSDave May   N = N / bs;
2209566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coorlocal, &_coor));
2210e2ec84fSDave May   for (i = 0; i < N; i++) {
2220e2ec84fSDave May     for (b = 0; b < bs; b++) {
223a5f152d1SDave May       gmin[b] = PetscMin(gmin[b], PetscRealPart(_coor[bs * i + b]));
224a5f152d1SDave May       gmax[b] = PetscMax(gmax[b], PetscRealPart(_coor[bs * i + b]));
2250e2ec84fSDave May     }
2260e2ec84fSDave May   }
2279566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coorlocal, &_coor));
2280e2ec84fSDave May 
2290e2ec84fSDave May   /* broadcast points from rank 0 if requested */
2300e2ec84fSDave May   if (redundant) {
2310e2ec84fSDave May     my_npoints = npoints;
2329566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(&my_npoints, 1, MPIU_INT, 0, comm));
2330e2ec84fSDave May 
2340e2ec84fSDave May     if (rank > 0) { /* allocate space */
2359566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bs * my_npoints, &my_coor));
2360e2ec84fSDave May     } else {
2370e2ec84fSDave May       my_coor = coor;
2380e2ec84fSDave May     }
2399566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(my_coor, bs * my_npoints, MPIU_REAL, 0, comm));
2400e2ec84fSDave May   } else {
2410e2ec84fSDave May     my_npoints = npoints;
2420e2ec84fSDave May     my_coor    = coor;
2430e2ec84fSDave May   }
2440e2ec84fSDave May 
2450e2ec84fSDave May   /* determine the number of points living in the bounding box */
2460e2ec84fSDave May   n_estimate = 0;
2470e2ec84fSDave May   for (i = 0; i < my_npoints; i++) {
2480e2ec84fSDave May     PetscBool point_inside = PETSC_TRUE;
2490e2ec84fSDave May 
2500e2ec84fSDave May     for (b = 0; b < bs; b++) {
251ad540459SPierre Jolivet       if (my_coor[bs * i + b] < gmin[b]) point_inside = PETSC_FALSE;
252ad540459SPierre Jolivet       if (my_coor[bs * i + b] > gmax[b]) point_inside = PETSC_FALSE;
2530e2ec84fSDave May     }
254ad540459SPierre Jolivet     if (point_inside) n_estimate++;
2550e2ec84fSDave May   }
2560e2ec84fSDave May 
2570e2ec84fSDave May   /* create candidate list */
2589566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &pos));
2599566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(pos, bs * n_estimate, PETSC_DECIDE));
2609566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(pos, bs));
2619566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(pos));
2629566063dSJacob Faibussowitsch   PetscCall(VecGetArray(pos, &_pos));
2630e2ec84fSDave May 
2640e2ec84fSDave May   n_estimate = 0;
2650e2ec84fSDave May   for (i = 0; i < my_npoints; i++) {
2660e2ec84fSDave May     PetscBool point_inside = PETSC_TRUE;
2670e2ec84fSDave May 
2680e2ec84fSDave May     for (b = 0; b < bs; b++) {
269ad540459SPierre Jolivet       if (my_coor[bs * i + b] < gmin[b]) point_inside = PETSC_FALSE;
270ad540459SPierre Jolivet       if (my_coor[bs * i + b] > gmax[b]) point_inside = PETSC_FALSE;
2710e2ec84fSDave May     }
2720e2ec84fSDave May     if (point_inside) {
273ad540459SPierre Jolivet       for (b = 0; b < bs; b++) _pos[bs * n_estimate + b] = my_coor[bs * i + b];
2740e2ec84fSDave May       n_estimate++;
2750e2ec84fSDave May     }
2760e2ec84fSDave May   }
2779566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(pos, &_pos));
2780e2ec84fSDave May 
2790e2ec84fSDave May   /* locate points */
2809566063dSJacob Faibussowitsch   PetscCall(DMLocatePoints(celldm, pos, DM_POINTLOCATION_NONE, &sfcell));
2810e2ec84fSDave May 
2829566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell));
2830e2ec84fSDave May   n_found = 0;
2840e2ec84fSDave May   for (p = 0; p < n_estimate; p++) {
285ad540459SPierre Jolivet     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) n_found++;
2860e2ec84fSDave May   }
2870e2ec84fSDave May 
2880e2ec84fSDave May   /* adjust size */
2890e2ec84fSDave May   if (mode == ADD_VALUES) {
2909566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetLocalSize(dm, &n_curr));
2910e2ec84fSDave May     n_new_est = n_curr + n_found;
2929566063dSJacob Faibussowitsch     PetscCall(DMSwarmSetLocalSizes(dm, n_new_est, -1));
2930e2ec84fSDave May   }
2940e2ec84fSDave May   if (mode == INSERT_VALUES) {
2950e2ec84fSDave May     n_curr    = 0;
2960e2ec84fSDave May     n_new_est = n_found;
2979566063dSJacob Faibussowitsch     PetscCall(DMSwarmSetLocalSizes(dm, n_new_est, -1));
2980e2ec84fSDave May   }
2990e2ec84fSDave May 
3000e2ec84fSDave May   /* initialize new coords, cell owners, pid */
3019566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(pos, &_coor));
3029566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&swarm_coor));
3039566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid));
3040e2ec84fSDave May   n_found = 0;
3050e2ec84fSDave May   for (p = 0; p < n_estimate; p++) {
3060e2ec84fSDave May     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
307ad540459SPierre Jolivet       for (b = 0; b < bs; b++) swarm_coor[bs * (n_curr + n_found) + b] = PetscRealPart(_coor[bs * p + b]);
3080e2ec84fSDave May       swarm_cellid[n_curr + n_found] = LA_sfcell[p].index;
3090e2ec84fSDave May       n_found++;
3100e2ec84fSDave May     }
3110e2ec84fSDave May   }
3129566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid));
3139566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&swarm_coor));
3149566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(pos, &_coor));
3150e2ec84fSDave May 
3160e2ec84fSDave May   if (redundant) {
31748a46eb9SPierre Jolivet     if (rank > 0) PetscCall(PetscFree(my_coor));
3180e2ec84fSDave May   }
3199566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfcell));
3209566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pos));
3213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3220e2ec84fSDave May }
3230e2ec84fSDave May 
3240e2ec84fSDave May extern PetscErrorCode private_DMSwarmInsertPointsUsingCellDM_DA(DM, DM, DMSwarmPICLayoutType, PetscInt);
3250e2ec84fSDave May extern PetscErrorCode private_DMSwarmInsertPointsUsingCellDM_PLEX(DM, DM, DMSwarmPICLayoutType, PetscInt);
3260e2ec84fSDave May 
3270e2ec84fSDave May /*@C
3280e2ec84fSDave May   DMSwarmInsertPointsUsingCellDM - Insert point coordinates within each cell
3290e2ec84fSDave May 
33020f4b53cSBarry Smith   Not Collective
3310e2ec84fSDave May 
33260225df5SJacob Faibussowitsch   Input Parameters:
33320f4b53cSBarry Smith + dm          - the `DMSWARM`
33420f4b53cSBarry Smith . layout_type - method used to fill each cell with the cell `DM`
3350e2ec84fSDave May - fill_param  - parameter controlling how many points per cell are added (the meaning of this parameter is dependent on the layout type)
3360e2ec84fSDave May 
3370e2ec84fSDave May   Level: beginner
3380e2ec84fSDave May 
3390e2ec84fSDave May   Notes:
34020f4b53cSBarry Smith   The insert method will reset any previous defined points within the `DMSWARM`.
341e7af74c8SDave May 
34220f4b53cSBarry Smith   When using a `DMDA` both 2D and 3D are supported for all layout types provided you are using `DMDA_ELEMENT_Q1`.
343e7af74c8SDave May 
344a4e35b19SJacob Faibussowitsch   When using a `DMPLEX` the following case are supported\:
34520f4b53cSBarry Smith .vb
346ea3d7275SDave May    (i) DMSWARMPIC_LAYOUT_REGULAR: 2D (triangle),
347ea3d7275SDave May    (ii) DMSWARMPIC_LAYOUT_GAUSS: 2D and 3D provided the cell is a tri/tet or a quad/hex,
348ea3d7275SDave May    (iii) DMSWARMPIC_LAYOUT_SUBDIVISION: 2D and 3D for quad/hex and 2D tri.
34920f4b53cSBarry Smith .ve
3500e2ec84fSDave May 
35120f4b53cSBarry Smith .seealso: `DMSWARM`, `DMSwarmPICLayoutType`, `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType`
3520e2ec84fSDave May @*/
353d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMSwarmInsertPointsUsingCellDM(DM dm, DMSwarmPICLayoutType layout_type, PetscInt fill_param)
354d71ae5a4SJacob Faibussowitsch {
3550e2ec84fSDave May   DM        celldm;
3560e2ec84fSDave May   PetscBool isDA, isPLEX;
3570e2ec84fSDave May 
3580e2ec84fSDave May   PetscFunctionBegin;
3590e2ec84fSDave May   DMSWARMPICVALID(dm);
3609566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &celldm));
3619566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMDA, &isDA));
3629566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMPLEX, &isPLEX));
3630e2ec84fSDave May   if (isDA) {
3649566063dSJacob Faibussowitsch     PetscCall(private_DMSwarmInsertPointsUsingCellDM_DA(dm, celldm, layout_type, fill_param));
3650e2ec84fSDave May   } else if (isPLEX) {
3669566063dSJacob Faibussowitsch     PetscCall(private_DMSwarmInsertPointsUsingCellDM_PLEX(dm, celldm, layout_type, fill_param));
3670e2ec84fSDave May   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only supported for cell DMs of type DMDA and DMPLEX");
3683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3690e2ec84fSDave May }
3700e2ec84fSDave May 
371431382f2SDave May extern PetscErrorCode private_DMSwarmSetPointCoordinatesCellwise_PLEX(DM, DM, PetscInt, PetscReal *);
372431382f2SDave May 
373431382f2SDave May /*@C
374431382f2SDave May   DMSwarmSetPointCoordinatesCellwise - Insert point coordinates (defined over the reference cell) within each cell
375431382f2SDave May 
37620f4b53cSBarry Smith   Not Collective
377431382f2SDave May 
37860225df5SJacob Faibussowitsch   Input Parameters:
37920f4b53cSBarry Smith + dm      - the `DMSWARM`
380431382f2SDave May . npoints - the number of points to insert in each cell
381431382f2SDave May - xi      - the coordinates (defined in the local coordinate system for each cell) to insert
382431382f2SDave May 
383431382f2SDave May   Level: beginner
384431382f2SDave May 
385431382f2SDave May   Notes:
38620f4b53cSBarry Smith   The method will reset any previous defined points within the `DMSWARM`.
38720f4b53cSBarry Smith   Only supported for `DMPLEX`. If you are using a `DMDA` it is recommended to either use
38820f4b53cSBarry Smith   `DMSwarmInsertPointsUsingCellDM()`, or extract and set the coordinates yourself the following code
38920f4b53cSBarry Smith .vb
39020f4b53cSBarry Smith     PetscReal *coor;
39120f4b53cSBarry Smith     DMSwarmGetField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&coor);
39220f4b53cSBarry Smith     // user code to define the coordinates here
39320f4b53cSBarry Smith     DMSwarmRestoreField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&coor);
39420f4b53cSBarry Smith .ve
395e7af74c8SDave May 
39620f4b53cSBarry Smith .seealso: `DMSWARM`, `DMSwarmSetCellDM()`, `DMSwarmInsertPointsUsingCellDM()`
397431382f2SDave May @*/
398d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMSwarmSetPointCoordinatesCellwise(DM dm, PetscInt npoints, PetscReal xi[])
399d71ae5a4SJacob Faibussowitsch {
400431382f2SDave May   DM        celldm;
401431382f2SDave May   PetscBool isDA, isPLEX;
402431382f2SDave May 
4030e2ec84fSDave May   PetscFunctionBegin;
404431382f2SDave May   DMSWARMPICVALID(dm);
4059566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &celldm));
4069566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMDA, &isDA));
4079566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMPLEX, &isPLEX));
40828b400f6SJacob Faibussowitsch   PetscCheck(!isDA, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only supported for cell DMs of type DMPLEX. Recommended you use DMSwarmInsertPointsUsingCellDM()");
409f7d195e4SLawrence Mitchell   if (isPLEX) {
4109566063dSJacob Faibussowitsch     PetscCall(private_DMSwarmSetPointCoordinatesCellwise_PLEX(dm, celldm, npoints, xi));
411431382f2SDave May   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only supported for cell DMs of type DMDA and DMPLEX");
4123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4130e2ec84fSDave May }
414431382f2SDave May 
4150e2ec84fSDave May /*@C
416b799feefSDave May   DMSwarmCreatePointPerCellCount - Count the number of points within all cells in the cell DM
4170e2ec84fSDave May 
41820f4b53cSBarry Smith   Not Collective
4190e2ec84fSDave May 
42060225df5SJacob Faibussowitsch   Input Parameter:
42120f4b53cSBarry Smith . dm - the `DMSWARM`
4220e2ec84fSDave May 
42360225df5SJacob Faibussowitsch   Output Parameters:
42420f4b53cSBarry Smith + ncells - the number of cells in the cell `DM` (optional argument, pass `NULL` to ignore)
425b799feefSDave May - count  - array of length ncells containing the number of points per cell
4260e2ec84fSDave May 
4270e2ec84fSDave May   Level: beginner
4280e2ec84fSDave May 
4290e2ec84fSDave May   Notes:
4300e2ec84fSDave May   The array count is allocated internally and must be free'd by the user.
4310e2ec84fSDave May 
43220f4b53cSBarry Smith .seealso: `DMSWARM`, `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType`
4330e2ec84fSDave May @*/
434d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMSwarmCreatePointPerCellCount(DM dm, PetscInt *ncells, PetscInt **count)
435d71ae5a4SJacob Faibussowitsch {
436b799feefSDave May   PetscBool isvalid;
437b799feefSDave May   PetscInt  nel;
438b799feefSDave May   PetscInt *sum;
439b799feefSDave May 
4400e2ec84fSDave May   PetscFunctionBegin;
4419566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetIsValid(dm, &isvalid));
442b799feefSDave May   nel = 0;
443b799feefSDave May   if (isvalid) {
444b799feefSDave May     PetscInt e;
445b799feefSDave May 
4469566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortGetSizes(dm, &nel, NULL));
447b799feefSDave May 
4489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nel, &sum));
44948a46eb9SPierre Jolivet     for (e = 0; e < nel; e++) PetscCall(DMSwarmSortGetNumberOfPointsPerCell(dm, e, &sum[e]));
450b799feefSDave May   } else {
451b799feefSDave May     DM        celldm;
452b799feefSDave May     PetscBool isda, isplex, isshell;
453b799feefSDave May     PetscInt  p, npoints;
454b799feefSDave May     PetscInt *swarm_cellid;
455b799feefSDave May 
456b799feefSDave May     /* get the number of cells */
4579566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetCellDM(dm, &celldm));
4589566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMDA, &isda));
4599566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMPLEX, &isplex));
4609566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)celldm, DMSHELL, &isshell));
461b799feefSDave May     if (isda) {
462b799feefSDave May       PetscInt        _nel, _npe;
463b799feefSDave May       const PetscInt *_element;
464b799feefSDave May 
4659566063dSJacob Faibussowitsch       PetscCall(DMDAGetElements(celldm, &_nel, &_npe, &_element));
466b799feefSDave May       nel = _nel;
4679566063dSJacob Faibussowitsch       PetscCall(DMDARestoreElements(celldm, &_nel, &_npe, &_element));
468b799feefSDave May     } else if (isplex) {
469b799feefSDave May       PetscInt ps, pe;
470b799feefSDave May 
4719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(celldm, 0, &ps, &pe));
472b799feefSDave May       nel = pe - ps;
473b799feefSDave May     } else if (isshell) {
474b799feefSDave May       PetscErrorCode (*method_DMShellGetNumberOfCells)(DM, PetscInt *);
475b799feefSDave May 
4769566063dSJacob Faibussowitsch       PetscCall(PetscObjectQueryFunction((PetscObject)celldm, "DMGetNumberOfCells_C", &method_DMShellGetNumberOfCells));
477b799feefSDave May       if (method_DMShellGetNumberOfCells) {
4789566063dSJacob Faibussowitsch         PetscCall(method_DMShellGetNumberOfCells(celldm, &nel));
4799371c9d4SSatish Balay       } else
4809371c9d4SSatish Balay         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);");
481b799feefSDave May     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot determine the number of cells for a DM not of type DA, PLEX or SHELL");
482b799feefSDave May 
4839566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nel, &sum));
4849566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(sum, nel));
4859566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetLocalSize(dm, &npoints));
4869566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid));
487b799feefSDave May     for (p = 0; p < npoints; p++) {
488ad540459SPierre Jolivet       if (swarm_cellid[p] != DMLOCATEPOINT_POINT_NOT_FOUND) sum[swarm_cellid[p]]++;
489b799feefSDave May     }
4909566063dSJacob Faibussowitsch     PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&swarm_cellid));
491b799feefSDave May   }
492ad540459SPierre Jolivet   if (ncells) *ncells = nel;
493b799feefSDave May   *count = sum;
4943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4950e2ec84fSDave May }
49635b38c60SMatthew G. Knepley 
49735b38c60SMatthew G. Knepley /*@
49835b38c60SMatthew G. Knepley   DMSwarmGetNumSpecies - Get the number of particle species
49935b38c60SMatthew G. Knepley 
50020f4b53cSBarry Smith   Not Collective
50135b38c60SMatthew G. Knepley 
50260225df5SJacob Faibussowitsch   Input Parameter:
50360225df5SJacob Faibussowitsch . sw - the `DMSWARM`
50435b38c60SMatthew G. Knepley 
50560225df5SJacob Faibussowitsch   Output Parameters:
50635b38c60SMatthew G. Knepley . Ns - the number of species
50735b38c60SMatthew G. Knepley 
50835b38c60SMatthew G. Knepley   Level: intermediate
50935b38c60SMatthew G. Knepley 
51020f4b53cSBarry Smith .seealso: `DMSWARM`, `DMSwarmSetNumSpecies()`, `DMSwarmSetType()`, `DMSwarmType`
51135b38c60SMatthew G. Knepley @*/
512d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetNumSpecies(DM sw, PetscInt *Ns)
513d71ae5a4SJacob Faibussowitsch {
51435b38c60SMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
51535b38c60SMatthew G. Knepley 
51635b38c60SMatthew G. Knepley   PetscFunctionBegin;
51735b38c60SMatthew G. Knepley   *Ns = swarm->Ns;
5183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
51935b38c60SMatthew G. Knepley }
52035b38c60SMatthew G. Knepley 
52135b38c60SMatthew G. Knepley /*@
52235b38c60SMatthew G. Knepley   DMSwarmSetNumSpecies - Set the number of particle species
52335b38c60SMatthew G. Knepley 
52420f4b53cSBarry Smith   Not Collective
52535b38c60SMatthew G. Knepley 
52660225df5SJacob Faibussowitsch   Input Parameters:
52760225df5SJacob Faibussowitsch + sw - the `DMSWARM`
52835b38c60SMatthew G. Knepley - Ns - the number of species
52935b38c60SMatthew G. Knepley 
53035b38c60SMatthew G. Knepley   Level: intermediate
53135b38c60SMatthew G. Knepley 
53220f4b53cSBarry Smith .seealso: `DMSWARM`, `DMSwarmGetNumSpecies()`, `DMSwarmSetType()`, `DMSwarmType`
53335b38c60SMatthew G. Knepley @*/
534d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetNumSpecies(DM sw, PetscInt Ns)
535d71ae5a4SJacob Faibussowitsch {
53635b38c60SMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
53735b38c60SMatthew G. Knepley 
53835b38c60SMatthew G. Knepley   PetscFunctionBegin;
53935b38c60SMatthew G. Knepley   swarm->Ns = Ns;
5403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
54135b38c60SMatthew G. Knepley }
54235b38c60SMatthew G. Knepley 
54335b38c60SMatthew G. Knepley /*@C
5446c5a79ebSMatthew G. Knepley   DMSwarmGetCoordinateFunction - Get the function setting initial particle positions, if it exists
5456c5a79ebSMatthew G. Knepley 
54620f4b53cSBarry Smith   Not Collective
5476c5a79ebSMatthew G. Knepley 
54860225df5SJacob Faibussowitsch   Input Parameter:
54960225df5SJacob Faibussowitsch . sw - the `DMSWARM`
5506c5a79ebSMatthew G. Knepley 
5516c5a79ebSMatthew G. Knepley   Output Parameter:
552*8434afd1SBarry Smith . coordFunc - the function setting initial particle positions, or `NULL`, see `PetscSimplePointFn` for the calling sequence
5536c5a79ebSMatthew G. Knepley 
5546c5a79ebSMatthew G. Knepley   Level: intermediate
5556c5a79ebSMatthew G. Knepley 
556*8434afd1SBarry Smith .seealso: `DMSWARM`, `DMSwarmSetCoordinateFunction()`, `DMSwarmGetVelocityFunction()`, `DMSwarmInitializeCoordinates()`, `PetscSimplePointFn`
5576c5a79ebSMatthew G. Knepley @*/
558*8434afd1SBarry Smith PetscErrorCode DMSwarmGetCoordinateFunction(DM sw, PetscSimplePointFn **coordFunc)
559d71ae5a4SJacob Faibussowitsch {
5606c5a79ebSMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
5616c5a79ebSMatthew G. Knepley 
5626c5a79ebSMatthew G. Knepley   PetscFunctionBegin;
5636c5a79ebSMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
5644f572ea9SToby Isaac   PetscAssertPointer(coordFunc, 2);
5656c5a79ebSMatthew G. Knepley   *coordFunc = swarm->coordFunc;
5663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5676c5a79ebSMatthew G. Knepley }
5686c5a79ebSMatthew G. Knepley 
5696c5a79ebSMatthew G. Knepley /*@C
5706c5a79ebSMatthew G. Knepley   DMSwarmSetCoordinateFunction - Set the function setting initial particle positions
5716c5a79ebSMatthew G. Knepley 
57220f4b53cSBarry Smith   Not Collective
5736c5a79ebSMatthew G. Knepley 
57460225df5SJacob Faibussowitsch   Input Parameters:
57560225df5SJacob Faibussowitsch + sw        - the `DMSWARM`
576*8434afd1SBarry Smith - coordFunc - the function setting initial particle positions, see `PetscSimplePointFn` for the calling sequence
5776c5a79ebSMatthew G. Knepley 
5786c5a79ebSMatthew G. Knepley   Level: intermediate
5796c5a79ebSMatthew G. Knepley 
580*8434afd1SBarry Smith .seealso: `DMSWARM`, `DMSwarmGetCoordinateFunction()`, `DMSwarmSetVelocityFunction()`, `DMSwarmInitializeCoordinates()`, `PetscSimplePointFn`
5816c5a79ebSMatthew G. Knepley @*/
582*8434afd1SBarry Smith PetscErrorCode DMSwarmSetCoordinateFunction(DM sw, PetscSimplePointFn *coordFunc)
583d71ae5a4SJacob Faibussowitsch {
5846c5a79ebSMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
5856c5a79ebSMatthew G. Knepley 
5866c5a79ebSMatthew G. Knepley   PetscFunctionBegin;
5876c5a79ebSMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
5886c5a79ebSMatthew G. Knepley   PetscValidFunction(coordFunc, 2);
5896c5a79ebSMatthew G. Knepley   swarm->coordFunc = coordFunc;
5903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5916c5a79ebSMatthew G. Knepley }
5926c5a79ebSMatthew G. Knepley 
5936c5a79ebSMatthew G. Knepley /*@C
59460225df5SJacob Faibussowitsch   DMSwarmGetVelocityFunction - Get the function setting initial particle velocities, if it exists
5956c5a79ebSMatthew G. Knepley 
59620f4b53cSBarry Smith   Not Collective
5976c5a79ebSMatthew G. Knepley 
59860225df5SJacob Faibussowitsch   Input Parameter:
59960225df5SJacob Faibussowitsch . sw - the `DMSWARM`
6006c5a79ebSMatthew G. Knepley 
6016c5a79ebSMatthew G. Knepley   Output Parameter:
602*8434afd1SBarry Smith . velFunc - the function setting initial particle velocities, or `NULL`, see `PetscSimplePointFn` for the calling sequence
6036c5a79ebSMatthew G. Knepley 
6046c5a79ebSMatthew G. Knepley   Level: intermediate
6056c5a79ebSMatthew G. Knepley 
606*8434afd1SBarry Smith .seealso: `DMSWARM`, `DMSwarmSetVelocityFunction()`, `DMSwarmGetCoordinateFunction()`, `DMSwarmInitializeVelocities()`, `PetscSimplePointFn`
6076c5a79ebSMatthew G. Knepley @*/
608*8434afd1SBarry Smith PetscErrorCode DMSwarmGetVelocityFunction(DM sw, PetscSimplePointFn **velFunc)
609d71ae5a4SJacob Faibussowitsch {
6106c5a79ebSMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
6116c5a79ebSMatthew G. Knepley 
6126c5a79ebSMatthew G. Knepley   PetscFunctionBegin;
6136c5a79ebSMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
6144f572ea9SToby Isaac   PetscAssertPointer(velFunc, 2);
6156c5a79ebSMatthew G. Knepley   *velFunc = swarm->velFunc;
6163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6176c5a79ebSMatthew G. Knepley }
6186c5a79ebSMatthew G. Knepley 
6196c5a79ebSMatthew G. Knepley /*@C
6206c5a79ebSMatthew G. Knepley   DMSwarmSetVelocityFunction - Set the function setting initial particle velocities
6216c5a79ebSMatthew G. Knepley 
62220f4b53cSBarry Smith   Not Collective
6236c5a79ebSMatthew G. Knepley 
62460225df5SJacob Faibussowitsch   Input Parameters:
625a4e35b19SJacob Faibussowitsch + sw      - the `DMSWARM`
626*8434afd1SBarry Smith - velFunc - the function setting initial particle velocities, see `PetscSimplePointFn` for the calling sequence
6276c5a79ebSMatthew G. Knepley 
6286c5a79ebSMatthew G. Knepley   Level: intermediate
6296c5a79ebSMatthew G. Knepley 
630*8434afd1SBarry Smith .seealso: `DMSWARM`, `DMSwarmGetVelocityFunction()`, `DMSwarmSetCoordinateFunction()`, `DMSwarmInitializeVelocities()`, `PetscSimplePointFn`
6316c5a79ebSMatthew G. Knepley @*/
632*8434afd1SBarry Smith PetscErrorCode DMSwarmSetVelocityFunction(DM sw, PetscSimplePointFn *velFunc)
633d71ae5a4SJacob Faibussowitsch {
6346c5a79ebSMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
6356c5a79ebSMatthew G. Knepley 
6366c5a79ebSMatthew G. Knepley   PetscFunctionBegin;
6376c5a79ebSMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
6386c5a79ebSMatthew G. Knepley   PetscValidFunction(velFunc, 2);
6396c5a79ebSMatthew G. Knepley   swarm->velFunc = velFunc;
6403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6416c5a79ebSMatthew G. Knepley }
6426c5a79ebSMatthew G. Knepley 
6436c5a79ebSMatthew G. Knepley /*@C
64435b38c60SMatthew G. Knepley   DMSwarmComputeLocalSize - Compute the local number and distribution of particles based upon a density function
64535b38c60SMatthew G. Knepley 
64620f4b53cSBarry Smith   Not Collective
64735b38c60SMatthew G. Knepley 
64835b38c60SMatthew G. Knepley   Input Parameters:
64920f4b53cSBarry Smith + sw      - The `DMSWARM`
65035b38c60SMatthew G. Knepley . N       - The target number of particles
65135b38c60SMatthew G. Knepley - density - The density field for the particle layout, normalized to unity
65235b38c60SMatthew G. Knepley 
65335b38c60SMatthew G. Knepley   Level: advanced
65435b38c60SMatthew G. Knepley 
65520f4b53cSBarry Smith   Note:
65620f4b53cSBarry Smith   One particle will be created for each species.
65720f4b53cSBarry Smith 
65820f4b53cSBarry Smith .seealso: `DMSWARM`, `DMSwarmComputeLocalSizeFromOptions()`
65935b38c60SMatthew G. Knepley @*/
660d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmComputeLocalSize(DM sw, PetscInt N, PetscProbFunc density)
661d71ae5a4SJacob Faibussowitsch {
66235b38c60SMatthew G. Knepley   DM               dm;
66335b38c60SMatthew G. Knepley   PetscQuadrature  quad;
66435b38c60SMatthew G. Knepley   const PetscReal *xq, *wq;
665ea7032a0SMatthew G. Knepley   PetscReal       *n_int;
666ea7032a0SMatthew G. Knepley   PetscInt        *npc_s, *cellid, Ni;
667ea7032a0SMatthew G. Knepley   PetscReal        gmin[3], gmax[3], xi0[3];
668ea7032a0SMatthew G. Knepley   PetscInt         Ns, cStart, cEnd, c, dim, d, Nq, q, Np = 0, p, s;
66935b38c60SMatthew G. Knepley   PetscBool        simplex;
67035b38c60SMatthew G. Knepley 
67135b38c60SMatthew G. Knepley   PetscFunctionBegin;
6729566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
6739566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(sw, &dm));
6749566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
675ea7032a0SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, gmin, gmax));
6769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
6779566063dSJacob Faibussowitsch   PetscCall(DMPlexIsSimplex(dm, &simplex));
6786858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
6799566063dSJacob Faibussowitsch   if (simplex) PetscCall(PetscDTStroudConicalQuadrature(dim, 1, 5, -1.0, 1.0, &quad));
6809566063dSJacob Faibussowitsch   else PetscCall(PetscDTGaussTensorQuadrature(dim, 1, 5, -1.0, 1.0, &quad));
6819566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, &xq, &wq));
682ea7032a0SMatthew G. Knepley   PetscCall(PetscCalloc2(Ns, &n_int, (cEnd - cStart) * Ns, &npc_s));
68335b38c60SMatthew G. Knepley   /* Integrate the density function to get the number of particles in each cell */
68435b38c60SMatthew G. Knepley   for (d = 0; d < dim; ++d) xi0[d] = -1.0;
68535b38c60SMatthew G. Knepley   for (c = 0; c < cEnd - cStart; ++c) {
68635b38c60SMatthew G. Knepley     const PetscInt cell = c + cStart;
687ea7032a0SMatthew G. Knepley     PetscReal      v0[3], J[9], invJ[9], detJ, detJp = 2. / (gmax[0] - gmin[0]), xr[3], den;
68835b38c60SMatthew G. Knepley 
689ea7032a0SMatthew G. Knepley     /*Have to transform quadrature points/weights to cell domain*/
6909566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, invJ, &detJ));
691ea7032a0SMatthew G. Knepley     PetscCall(PetscArrayzero(n_int, Ns));
69235b38c60SMatthew G. Knepley     for (q = 0; q < Nq; ++q) {
69335b38c60SMatthew G. Knepley       CoordinatesRefToReal(dim, dim, xi0, v0, J, &xq[q * dim], xr);
694ea7032a0SMatthew G. Knepley       /* Have to transform mesh to domain of definition of PDF, [-1, 1], and weight PDF by |J|/2 */
695ea7032a0SMatthew G. Knepley       xr[0] = detJp * (xr[0] - gmin[0]) - 1.;
696ea7032a0SMatthew G. Knepley 
697ea7032a0SMatthew G. Knepley       for (s = 0; s < Ns; ++s) {
698ea7032a0SMatthew G. Knepley         PetscCall(density(xr, NULL, &den));
699ea7032a0SMatthew G. Knepley         n_int[s] += (detJp * den) * (detJ * wq[q]) / (PetscReal)Ns;
70035b38c60SMatthew G. Knepley       }
701ea7032a0SMatthew G. Knepley     }
702ea7032a0SMatthew G. Knepley     for (s = 0; s < Ns; ++s) {
703ea7032a0SMatthew G. Knepley       Ni = N;
704ea7032a0SMatthew G. Knepley       npc_s[c * Ns + s] += (PetscInt)(Ni * n_int[s]);
705ea7032a0SMatthew G. Knepley       Np += npc_s[c * Ns + s];
706ea7032a0SMatthew G. Knepley     }
70735b38c60SMatthew G. Knepley   }
7089566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&quad));
7099566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetLocalSizes(sw, Np, 0));
7109566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_cellid, NULL, NULL, (void **)&cellid));
71135b38c60SMatthew G. Knepley   for (c = 0, p = 0; c < cEnd - cStart; ++c) {
712ea7032a0SMatthew G. Knepley     for (s = 0; s < Ns; ++s) {
713ea7032a0SMatthew G. Knepley       for (q = 0; q < npc_s[c * Ns + s]; ++q, ++p) cellid[p] = c;
714ea7032a0SMatthew G. Knepley     }
71535b38c60SMatthew G. Knepley   }
7169566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_cellid, NULL, NULL, (void **)&cellid));
717ea7032a0SMatthew G. Knepley   PetscCall(PetscFree2(n_int, npc_s));
7183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
71935b38c60SMatthew G. Knepley }
72035b38c60SMatthew G. Knepley 
72135b38c60SMatthew G. Knepley /*@
72235b38c60SMatthew G. Knepley   DMSwarmComputeLocalSizeFromOptions - Compute the local number and distribution of particles based upon a density function determined by options
72335b38c60SMatthew G. Knepley 
72420f4b53cSBarry Smith   Not Collective
72535b38c60SMatthew G. Knepley 
7262fe279fdSBarry Smith   Input Parameter:
7272fe279fdSBarry Smith . sw - The `DMSWARM`
72835b38c60SMatthew G. Knepley 
72935b38c60SMatthew G. Knepley   Level: advanced
73035b38c60SMatthew G. Knepley 
73120f4b53cSBarry Smith .seealso: `DMSWARM`, `DMSwarmComputeLocalSize()`
73235b38c60SMatthew G. Knepley @*/
733d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmComputeLocalSizeFromOptions(DM sw)
734d71ae5a4SJacob Faibussowitsch {
73535b38c60SMatthew G. Knepley   PetscProbFunc pdf;
73635b38c60SMatthew G. Knepley   const char   *prefix;
7376c5a79ebSMatthew G. Knepley   char          funcname[PETSC_MAX_PATH_LEN];
7386c5a79ebSMatthew G. Knepley   PetscInt     *N, Ns, dim, n;
7396c5a79ebSMatthew G. Knepley   PetscBool     flg;
7406c5a79ebSMatthew G. Knepley   PetscMPIInt   size, rank;
74135b38c60SMatthew G. Knepley 
74235b38c60SMatthew G. Knepley   PetscFunctionBegin;
7436c5a79ebSMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)sw), &size));
7446c5a79ebSMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sw), &rank));
7456c5a79ebSMatthew G. Knepley   PetscCall(PetscCalloc1(size, &N));
746d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)sw), "", "DMSwarm Options", "DMSWARM");
7476c5a79ebSMatthew G. Knepley   n = size;
7486c5a79ebSMatthew G. Knepley   PetscCall(PetscOptionsIntArray("-dm_swarm_num_particles", "The target number of particles", "", N, &n, NULL));
7496c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
7509566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg));
7519566063dSJacob Faibussowitsch   if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns));
7526c5a79ebSMatthew G. Knepley   PetscCall(PetscOptionsString("-dm_swarm_coordinate_function", "Function to determine particle coordinates", "DMSwarmSetCoordinateFunction", funcname, funcname, sizeof(funcname), &flg));
753d0609cedSBarry Smith   PetscOptionsEnd();
7546c5a79ebSMatthew G. Knepley   if (flg) {
755*8434afd1SBarry Smith     PetscSimplePointFn *coordFunc;
75635b38c60SMatthew G. Knepley 
7576c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
7586c5a79ebSMatthew G. Knepley     PetscCall(PetscDLSym(NULL, funcname, (void **)&coordFunc));
7596c5a79ebSMatthew G. Knepley     PetscCheck(coordFunc, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONG, "Could not locate function %s", funcname);
7606c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
7616c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmSetLocalSizes(sw, N[rank] * Ns, 0));
7626c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmSetCoordinateFunction(sw, coordFunc));
7636c5a79ebSMatthew G. Knepley   } else {
7649566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(sw, &dim));
7659566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)sw, &prefix));
7669566063dSJacob Faibussowitsch     PetscCall(PetscProbCreateFromOptions(dim, prefix, "-dm_swarm_coordinate_density", &pdf, NULL, NULL));
7676c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmComputeLocalSize(sw, N[rank], pdf));
7686c5a79ebSMatthew G. Knepley   }
7696c5a79ebSMatthew G. Knepley   PetscCall(PetscFree(N));
7703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
77135b38c60SMatthew G. Knepley }
77235b38c60SMatthew G. Knepley 
77335b38c60SMatthew G. Knepley /*@
77435b38c60SMatthew G. Knepley   DMSwarmInitializeCoordinates - Determine the initial coordinates of particles for a PIC method
77535b38c60SMatthew G. Knepley 
77620f4b53cSBarry Smith   Not Collective
77735b38c60SMatthew G. Knepley 
77820f4b53cSBarry Smith   Input Parameter:
77920f4b53cSBarry Smith . sw - The `DMSWARM`
78035b38c60SMatthew G. Knepley 
78135b38c60SMatthew G. Knepley   Level: advanced
78235b38c60SMatthew G. Knepley 
78320f4b53cSBarry Smith   Note:
78420f4b53cSBarry Smith   Currently, we randomly place particles in their assigned cell
78520f4b53cSBarry Smith 
78620f4b53cSBarry Smith .seealso: `DMSWARM`, `DMSwarmComputeLocalSize()`, `DMSwarmInitializeVelocities()`
78735b38c60SMatthew G. Knepley @*/
788d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmInitializeCoordinates(DM sw)
789d71ae5a4SJacob Faibussowitsch {
790*8434afd1SBarry Smith   PetscSimplePointFn *coordFunc;
79135b38c60SMatthew G. Knepley   PetscScalar        *weight;
7926c5a79ebSMatthew G. Knepley   PetscReal          *x;
79335b38c60SMatthew G. Knepley   PetscInt           *species;
7946c5a79ebSMatthew G. Knepley   void               *ctx;
79535b38c60SMatthew G. Knepley   PetscBool           removePoints = PETSC_TRUE;
79635b38c60SMatthew G. Knepley   PetscDataType       dtype;
7976c5a79ebSMatthew G. Knepley   PetscInt            Np, p, Ns, dim, d, bs;
79835b38c60SMatthew G. Knepley 
79935b38c60SMatthew G. Knepley   PetscFunctionBeginUser;
8006c5a79ebSMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
8016c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
8029566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
8036c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetCoordinateFunction(sw, &coordFunc));
8046c5a79ebSMatthew G. Knepley 
8056c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, &bs, &dtype, (void **)&x));
8066c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", &bs, &dtype, (void **)&weight));
8076c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
8086c5a79ebSMatthew G. Knepley   if (coordFunc) {
8096c5a79ebSMatthew G. Knepley     PetscCall(DMGetApplicationContext(sw, &ctx));
8106c5a79ebSMatthew G. Knepley     for (p = 0; p < Np; ++p) {
8116c5a79ebSMatthew G. Knepley       PetscScalar X[3];
8126c5a79ebSMatthew G. Knepley 
8136c5a79ebSMatthew G. Knepley       PetscCall((*coordFunc)(dim, 0., NULL, p, X, ctx));
8146c5a79ebSMatthew G. Knepley       for (d = 0; d < dim; ++d) x[p * dim + d] = PetscRealPart(X[d]);
8156c5a79ebSMatthew G. Knepley       weight[p]  = 1.0;
8166c5a79ebSMatthew G. Knepley       species[p] = p % Ns;
8176c5a79ebSMatthew G. Knepley     }
8186c5a79ebSMatthew G. Knepley   } else {
8196c5a79ebSMatthew G. Knepley     DM          dm;
8206c5a79ebSMatthew G. Knepley     PetscRandom rnd;
8216c5a79ebSMatthew G. Knepley     PetscReal   xi0[3];
8226c5a79ebSMatthew G. Knepley     PetscInt    cStart, cEnd, c;
8236c5a79ebSMatthew G. Knepley 
8249566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetCellDM(sw, &dm));
8259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
826ea7032a0SMatthew G. Knepley     PetscCall(DMGetApplicationContext(sw, &ctx));
82735b38c60SMatthew G. Knepley 
82835b38c60SMatthew G. Knepley     /* Set particle position randomly in cell, set weights to 1 */
8299566063dSJacob Faibussowitsch     PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm), &rnd));
8309566063dSJacob Faibussowitsch     PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0));
8319566063dSJacob Faibussowitsch     PetscCall(PetscRandomSetFromOptions(rnd));
8329566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortGetAccess(sw));
83335b38c60SMatthew G. Knepley     for (d = 0; d < dim; ++d) xi0[d] = -1.0;
83435b38c60SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
83535b38c60SMatthew G. Knepley       PetscReal v0[3], J[9], invJ[9], detJ;
83635b38c60SMatthew G. Knepley       PetscInt *pidx, Npc, q;
83735b38c60SMatthew G. Knepley 
8389566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
8399566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
84035b38c60SMatthew G. Knepley       for (q = 0; q < Npc; ++q) {
84135b38c60SMatthew G. Knepley         const PetscInt p = pidx[q];
84235b38c60SMatthew G. Knepley         PetscReal      xref[3];
84335b38c60SMatthew G. Knepley 
8449566063dSJacob Faibussowitsch         for (d = 0; d < dim; ++d) PetscCall(PetscRandomGetValueReal(rnd, &xref[d]));
84535b38c60SMatthew G. Knepley         CoordinatesRefToReal(dim, dim, xi0, v0, J, xref, &x[p * dim]);
84635b38c60SMatthew G. Knepley 
847ea7032a0SMatthew G. Knepley         weight[p]  = 1.0 / Np;
8486c5a79ebSMatthew G. Knepley         species[p] = p % Ns;
84935b38c60SMatthew G. Knepley       }
8509566063dSJacob Faibussowitsch       PetscCall(PetscFree(pidx));
85135b38c60SMatthew G. Knepley     }
8529566063dSJacob Faibussowitsch     PetscCall(PetscRandomDestroy(&rnd));
8539566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortRestoreAccess(sw));
8546c5a79ebSMatthew G. Knepley   }
8559566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
8566c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
8579566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
8586c5a79ebSMatthew G. Knepley 
8599566063dSJacob Faibussowitsch   PetscCall(DMSwarmMigrate(sw, removePoints));
8609566063dSJacob Faibussowitsch   PetscCall(DMLocalizeCoordinates(sw));
8613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
86235b38c60SMatthew G. Knepley }
86335b38c60SMatthew G. Knepley 
86435b38c60SMatthew G. Knepley /*@C
86535b38c60SMatthew G. Knepley   DMSwarmInitializeVelocities - Set the initial velocities of particles using a distribution.
86635b38c60SMatthew G. Knepley 
86720f4b53cSBarry Smith   Collective
86835b38c60SMatthew G. Knepley 
86935b38c60SMatthew G. Knepley   Input Parameters:
87020f4b53cSBarry Smith + sw      - The `DMSWARM` object
87135b38c60SMatthew G. Knepley . sampler - A function which uniformly samples the velocity PDF
87235b38c60SMatthew G. Knepley - v0      - The velocity scale for nondimensionalization for each species
87335b38c60SMatthew G. Knepley 
87435b38c60SMatthew G. Knepley   Level: advanced
87535b38c60SMatthew G. Knepley 
87620f4b53cSBarry Smith   Note:
87720f4b53cSBarry Smith   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.
87820f4b53cSBarry Smith 
87920f4b53cSBarry Smith .seealso: `DMSWARM`, `DMSwarmComputeLocalSize()`, `DMSwarmInitializeCoordinates()`, `DMSwarmInitializeVelocitiesFromOptions()`
88035b38c60SMatthew G. Knepley @*/
881d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmInitializeVelocities(DM sw, PetscProbFunc sampler, const PetscReal v0[])
882d71ae5a4SJacob Faibussowitsch {
883*8434afd1SBarry Smith   PetscSimplePointFn *velFunc;
88435b38c60SMatthew G. Knepley   PetscReal          *v;
88535b38c60SMatthew G. Knepley   PetscInt           *species;
8866c5a79ebSMatthew G. Knepley   void               *ctx;
88735b38c60SMatthew G. Knepley   PetscInt            dim, Np, p;
88835b38c60SMatthew G. Knepley 
88935b38c60SMatthew G. Knepley   PetscFunctionBegin;
8906c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetVelocityFunction(sw, &velFunc));
89135b38c60SMatthew G. Knepley 
8929566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(sw, &dim));
8939566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(sw, &Np));
8949566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
8959566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
8966c5a79ebSMatthew G. Knepley   if (v0[0] == 0.) {
8976c5a79ebSMatthew G. Knepley     PetscCall(PetscArrayzero(v, Np * dim));
8986c5a79ebSMatthew G. Knepley   } else if (velFunc) {
8996c5a79ebSMatthew G. Knepley     PetscCall(DMGetApplicationContext(sw, &ctx));
9006c5a79ebSMatthew G. Knepley     for (p = 0; p < Np; ++p) {
9016c5a79ebSMatthew G. Knepley       PetscInt    s = species[p], d;
9026c5a79ebSMatthew G. Knepley       PetscScalar vel[3];
9036c5a79ebSMatthew G. Knepley 
9046c5a79ebSMatthew G. Knepley       PetscCall((*velFunc)(dim, 0., NULL, p, vel, ctx));
9056c5a79ebSMatthew G. Knepley       for (d = 0; d < dim; ++d) v[p * dim + d] = (v0[s] / v0[0]) * PetscRealPart(vel[d]);
9066c5a79ebSMatthew G. Knepley     }
9076c5a79ebSMatthew G. Knepley   } else {
9086c5a79ebSMatthew G. Knepley     PetscRandom rnd;
9096c5a79ebSMatthew G. Knepley 
9106c5a79ebSMatthew G. Knepley     PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)sw), &rnd));
9116c5a79ebSMatthew G. Knepley     PetscCall(PetscRandomSetInterval(rnd, 0, 1.));
9126c5a79ebSMatthew G. Knepley     PetscCall(PetscRandomSetFromOptions(rnd));
9136c5a79ebSMatthew G. Knepley 
91435b38c60SMatthew G. Knepley     for (p = 0; p < Np; ++p) {
91535b38c60SMatthew G. Knepley       PetscInt  s = species[p], d;
91635b38c60SMatthew G. Knepley       PetscReal a[3], vel[3];
91735b38c60SMatthew G. Knepley 
9189566063dSJacob Faibussowitsch       for (d = 0; d < dim; ++d) PetscCall(PetscRandomGetValueReal(rnd, &a[d]));
9199566063dSJacob Faibussowitsch       PetscCall(sampler(a, NULL, vel));
920ad540459SPierre Jolivet       for (d = 0; d < dim; ++d) v[p * dim + d] = (v0[s] / v0[0]) * vel[d];
92135b38c60SMatthew G. Knepley     }
9226c5a79ebSMatthew G. Knepley     PetscCall(PetscRandomDestroy(&rnd));
9236c5a79ebSMatthew G. Knepley   }
9249566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
9259566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
9263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
92735b38c60SMatthew G. Knepley }
92835b38c60SMatthew G. Knepley 
92935b38c60SMatthew G. Knepley /*@
93035b38c60SMatthew G. Knepley   DMSwarmInitializeVelocitiesFromOptions - Set the initial velocities of particles using a distribution determined from options.
93135b38c60SMatthew G. Knepley 
93220f4b53cSBarry Smith   Collective
93335b38c60SMatthew G. Knepley 
93435b38c60SMatthew G. Knepley   Input Parameters:
93520f4b53cSBarry Smith + sw - The `DMSWARM` object
93635b38c60SMatthew G. Knepley - v0 - The velocity scale for nondimensionalization for each species
93735b38c60SMatthew G. Knepley 
93835b38c60SMatthew G. Knepley   Level: advanced
93935b38c60SMatthew G. Knepley 
94020f4b53cSBarry Smith .seealso: `DMSWARM`, `DMSwarmComputeLocalSize()`, `DMSwarmInitializeCoordinates()`, `DMSwarmInitializeVelocities()`
94135b38c60SMatthew G. Knepley @*/
942d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmInitializeVelocitiesFromOptions(DM sw, const PetscReal v0[])
943d71ae5a4SJacob Faibussowitsch {
94435b38c60SMatthew G. Knepley   PetscProbFunc sampler;
94535b38c60SMatthew G. Knepley   PetscInt      dim;
94635b38c60SMatthew G. Knepley   const char   *prefix;
9476c5a79ebSMatthew G. Knepley   char          funcname[PETSC_MAX_PATH_LEN];
9486c5a79ebSMatthew G. Knepley   PetscBool     flg;
94935b38c60SMatthew G. Knepley 
95035b38c60SMatthew G. Knepley   PetscFunctionBegin;
951d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)sw), "", "DMSwarm Options", "DMSWARM");
9526c5a79ebSMatthew G. Knepley   PetscCall(PetscOptionsString("-dm_swarm_velocity_function", "Function to determine particle velocities", "DMSwarmSetVelocityFunction", funcname, funcname, sizeof(funcname), &flg));
953d0609cedSBarry Smith   PetscOptionsEnd();
9546c5a79ebSMatthew G. Knepley   if (flg) {
955*8434afd1SBarry Smith     PetscSimplePointFn *velFunc;
9566c5a79ebSMatthew G. Knepley 
9576c5a79ebSMatthew G. Knepley     PetscCall(PetscDLSym(NULL, funcname, (void **)&velFunc));
9586c5a79ebSMatthew G. Knepley     PetscCheck(velFunc, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONG, "Could not locate function %s", funcname);
9596c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmSetVelocityFunction(sw, velFunc));
9606c5a79ebSMatthew G. Knepley   }
9619566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(sw, &dim));
9629566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)sw, &prefix));
9639566063dSJacob Faibussowitsch   PetscCall(PetscProbCreateFromOptions(dim, prefix, "-dm_swarm_velocity_density", NULL, NULL, &sampler));
9649566063dSJacob Faibussowitsch   PetscCall(DMSwarmInitializeVelocities(sw, sampler, v0));
9653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
96635b38c60SMatthew G. Knepley }
967