xref: /petsc/src/dm/impls/swarm/swarmpic.c (revision f7d195e4ad6e26c05f14257c8116f4b5b3c9cdd8)
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 /*
125627991aSBarry Smith  Error checking to ensure the swarm type is correct and that a cell DM has been set
130e2ec84fSDave May */
140e2ec84fSDave May #define DMSWARMPICVALID(dm) \
15*f7d195e4SLawrence Mitchell   do { \
160e2ec84fSDave May     DM_Swarm *_swarm = (DM_Swarm*)(dm)->data; \
175f80ce2aSJacob Faibussowitsch     PetscCheck(_swarm->swarm_type == DMSWARM_PIC,PetscObjectComm((PetscObject)(dm)),PETSC_ERR_SUP,"Valid only for DMSwarm-PIC. You must call DMSwarmSetType(dm,DMSWARM_PIC)"); \
1828b400f6SJacob Faibussowitsch     PetscCheck(_swarm->dmcell,PetscObjectComm((PetscObject)(dm)),PETSC_ERR_SUP,"Valid only for DMSwarmPIC if the cell DM is set. You must call DMSwarmSetCellDM(dm,celldm)"); \
19*f7d195e4SLawrence Mitchell   } while (0)
200e2ec84fSDave May 
210e2ec84fSDave May /* Coordinate insertition/addition API */
220e2ec84fSDave May /*@C
230e2ec84fSDave May    DMSwarmSetPointsUniformCoordinates - Set point coordinates in a DMSwarm on a regular (ijk) grid
240e2ec84fSDave May 
25d083f849SBarry Smith    Collective on dm
260e2ec84fSDave May 
270e2ec84fSDave May    Input parameters:
280e2ec84fSDave May +  dm - the DMSwarm
290e2ec84fSDave May .  min - minimum coordinate values in the x, y, z directions (array of length dim)
300e2ec84fSDave May .  max - maximum coordinate values in the x, y, z directions (array of length dim)
310e2ec84fSDave May .  npoints - number of points in each spatial direction (array of length dim)
320e2ec84fSDave May -  mode - indicates whether to append points to the swarm (ADD_VALUES), or over-ride existing points (INSERT_VALUES)
330e2ec84fSDave May 
340e2ec84fSDave May    Level: beginner
350e2ec84fSDave May 
360e2ec84fSDave May    Notes:
370e2ec84fSDave May    When using mode = INSERT_VALUES, this method will reset the number of particles in the DMSwarm
380e2ec84fSDave May    to be npoints[0]*npoints[1] (2D) or npoints[0]*npoints[1]*npoints[2] (3D). When using mode = ADD_VALUES,
390e2ec84fSDave May    new points will be appended to any already existing in the DMSwarm
400e2ec84fSDave May 
41db781477SPatrick Sanan .seealso: `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType`
420e2ec84fSDave May @*/
430e2ec84fSDave May PETSC_EXTERN PetscErrorCode DMSwarmSetPointsUniformCoordinates(DM dm,PetscReal min[],PetscReal max[],PetscInt npoints[],InsertMode mode)
440e2ec84fSDave May {
450e2ec84fSDave May   PetscReal         gmin[] = {PETSC_MAX_REAL ,PETSC_MAX_REAL, PETSC_MAX_REAL};
460e2ec84fSDave May   PetscReal         gmax[] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
470e2ec84fSDave May   PetscInt          i,j,k,N,bs,b,n_estimate,n_curr,n_new_est,p,n_found;
480e2ec84fSDave May   Vec               coorlocal;
490e2ec84fSDave May   const PetscScalar *_coor;
500e2ec84fSDave May   DM                celldm;
510e2ec84fSDave May   PetscReal         dx[3];
522e3d3761SDave May   PetscInt          _npoints[] = { 0, 0, 1 };
530e2ec84fSDave May   Vec               pos;
540e2ec84fSDave May   PetscScalar       *_pos;
550e2ec84fSDave May   PetscReal         *swarm_coor;
560e2ec84fSDave May   PetscInt          *swarm_cellid;
570e2ec84fSDave May   PetscSF           sfcell = NULL;
580e2ec84fSDave May   const PetscSFNode *LA_sfcell;
590e2ec84fSDave May 
600e2ec84fSDave May   PetscFunctionBegin;
610e2ec84fSDave May   DMSWARMPICVALID(dm);
629566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm,&celldm));
639566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(celldm,&coorlocal));
649566063dSJacob Faibussowitsch   PetscCall(VecGetSize(coorlocal,&N));
659566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(coorlocal,&bs));
660e2ec84fSDave May   N = N / bs;
679566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coorlocal,&_coor));
680e2ec84fSDave May   for (i=0; i<N; i++) {
690e2ec84fSDave May     for (b=0; b<bs; b++) {
70a5f152d1SDave May       gmin[b] = PetscMin(gmin[b],PetscRealPart(_coor[bs*i+b]));
71a5f152d1SDave May       gmax[b] = PetscMax(gmax[b],PetscRealPart(_coor[bs*i+b]));
720e2ec84fSDave May     }
730e2ec84fSDave May   }
749566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coorlocal,&_coor));
750e2ec84fSDave May 
760e2ec84fSDave May   for (b=0; b<bs; b++) {
7771844bb8SDave May     if (npoints[b] > 1) {
780e2ec84fSDave May       dx[b] = (max[b] - min[b])/((PetscReal)(npoints[b]-1));
7971844bb8SDave May     } else {
8071844bb8SDave May       dx[b] = 0.0;
8171844bb8SDave May     }
822e3d3761SDave May     _npoints[b] = npoints[b];
830e2ec84fSDave May   }
840e2ec84fSDave May 
850e2ec84fSDave May   /* determine number of points living in the bounding box */
860e2ec84fSDave May   n_estimate = 0;
872e3d3761SDave May   for (k=0; k<_npoints[2]; k++) {
882e3d3761SDave May     for (j=0; j<_npoints[1]; j++) {
892e3d3761SDave May       for (i=0; i<_npoints[0]; i++) {
900e2ec84fSDave May         PetscReal xp[] = {0.0,0.0,0.0};
910e2ec84fSDave May         PetscInt ijk[3];
920e2ec84fSDave May         PetscBool point_inside = PETSC_TRUE;
930e2ec84fSDave May 
940e2ec84fSDave May         ijk[0] = i;
950e2ec84fSDave May         ijk[1] = j;
960e2ec84fSDave May         ijk[2] = k;
970e2ec84fSDave May         for (b=0; b<bs; b++) {
980e2ec84fSDave May           xp[b] = min[b] + ijk[b] * dx[b];
990e2ec84fSDave May         }
1000e2ec84fSDave May         for (b=0; b<bs; b++) {
1010e2ec84fSDave May           if (xp[b] < gmin[b]) { point_inside = PETSC_FALSE; }
1020e2ec84fSDave May           if (xp[b] > gmax[b]) { point_inside = PETSC_FALSE; }
1030e2ec84fSDave May         }
1040e2ec84fSDave May         if (point_inside) { n_estimate++; }
1050e2ec84fSDave May       }
1060e2ec84fSDave May     }
1070e2ec84fSDave May   }
1080e2ec84fSDave May 
1090e2ec84fSDave May   /* create candidate list */
1109566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF,&pos));
1119566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(pos,bs*n_estimate,PETSC_DECIDE));
1129566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(pos,bs));
1139566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(pos));
1149566063dSJacob Faibussowitsch   PetscCall(VecGetArray(pos,&_pos));
1150e2ec84fSDave May 
1160e2ec84fSDave May   n_estimate = 0;
1172e3d3761SDave May   for (k=0; k<_npoints[2]; k++) {
1182e3d3761SDave May     for (j=0; j<_npoints[1]; j++) {
1192e3d3761SDave May       for (i=0; i<_npoints[0]; i++) {
1200e2ec84fSDave May         PetscReal xp[] = {0.0,0.0,0.0};
1210e2ec84fSDave May         PetscInt  ijk[3];
1220e2ec84fSDave May         PetscBool point_inside = PETSC_TRUE;
1230e2ec84fSDave May 
1240e2ec84fSDave May         ijk[0] = i;
1250e2ec84fSDave May         ijk[1] = j;
1260e2ec84fSDave May         ijk[2] = k;
1270e2ec84fSDave May         for (b=0; b<bs; b++) {
1280e2ec84fSDave May           xp[b] = min[b] + ijk[b] * dx[b];
1290e2ec84fSDave May         }
1300e2ec84fSDave May         for (b=0; b<bs; b++) {
1310e2ec84fSDave May           if (xp[b] < gmin[b]) { point_inside = PETSC_FALSE; }
1320e2ec84fSDave May           if (xp[b] > gmax[b]) { point_inside = PETSC_FALSE; }
1330e2ec84fSDave May         }
1340e2ec84fSDave May         if (point_inside) {
1350e2ec84fSDave May           for (b=0; b<bs; b++) {
1360e2ec84fSDave May             _pos[bs*n_estimate+b] = xp[b];
1370e2ec84fSDave May           }
1380e2ec84fSDave May           n_estimate++;
1390e2ec84fSDave May         }
1400e2ec84fSDave May       }
1410e2ec84fSDave May     }
1420e2ec84fSDave May   }
1439566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(pos,&_pos));
1440e2ec84fSDave May 
1450e2ec84fSDave May   /* locate points */
1469566063dSJacob Faibussowitsch   PetscCall(DMLocatePoints(celldm,pos,DM_POINTLOCATION_NONE,&sfcell));
1479566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell));
1480e2ec84fSDave May   n_found = 0;
1490e2ec84fSDave May   for (p=0; p<n_estimate; p++) {
1500e2ec84fSDave May     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
1510e2ec84fSDave May       n_found++;
1520e2ec84fSDave May     }
1530e2ec84fSDave May   }
1540e2ec84fSDave May 
1550e2ec84fSDave May   /* adjust size */
1560e2ec84fSDave May   if (mode == ADD_VALUES) {
1579566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetLocalSize(dm,&n_curr));
1580e2ec84fSDave May     n_new_est = n_curr + n_found;
1599566063dSJacob Faibussowitsch     PetscCall(DMSwarmSetLocalSizes(dm,n_new_est,-1));
1600e2ec84fSDave May   }
1610e2ec84fSDave May   if (mode == INSERT_VALUES) {
1620e2ec84fSDave May     n_curr = 0;
1630e2ec84fSDave May     n_new_est = n_found;
1649566063dSJacob Faibussowitsch     PetscCall(DMSwarmSetLocalSizes(dm,n_new_est,-1));
1650e2ec84fSDave May   }
1660e2ec84fSDave May 
1670e2ec84fSDave May   /* initialize new coords, cell owners, pid */
1689566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(pos,&_coor));
1699566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&swarm_coor));
1709566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid));
1710e2ec84fSDave May   n_found = 0;
1720e2ec84fSDave May   for (p=0; p<n_estimate; p++) {
1730e2ec84fSDave May     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
1740e2ec84fSDave May       for (b=0; b<bs; b++) {
1750ca99263SDave May         swarm_coor[bs*(n_curr + n_found) + b] = PetscRealPart(_coor[bs*p+b]);
1760e2ec84fSDave May       }
1770e2ec84fSDave May       swarm_cellid[n_curr + n_found] = LA_sfcell[p].index;
1780e2ec84fSDave May       n_found++;
1790e2ec84fSDave May     }
1800e2ec84fSDave May   }
1819566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid));
1829566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&swarm_coor));
1839566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(pos,&_coor));
1840e2ec84fSDave May 
1859566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfcell));
1869566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pos));
1870e2ec84fSDave May   PetscFunctionReturn(0);
1880e2ec84fSDave May }
1890e2ec84fSDave May 
1900e2ec84fSDave May /*@C
1910e2ec84fSDave May    DMSwarmSetPointCoordinates - Set point coordinates in a DMSwarm from a user defined list
1920e2ec84fSDave May 
193d083f849SBarry Smith    Collective on dm
1940e2ec84fSDave May 
1950e2ec84fSDave May    Input parameters:
1960e2ec84fSDave May +  dm - the DMSwarm
1970e2ec84fSDave May .  npoints - the number of points to insert
1980e2ec84fSDave May .  coor - the coordinate values
1990e2ec84fSDave May .  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
2000e2ec84fSDave May -  mode - indicates whether to append points to the swarm (ADD_VALUES), or over-ride existing points (INSERT_VALUES)
2010e2ec84fSDave May 
2020e2ec84fSDave May    Level: beginner
2030e2ec84fSDave May 
2040e2ec84fSDave May    Notes:
2050e2ec84fSDave May    If the user has specified redundant = PETSC_FALSE, the cell DM will attempt to locate the coordinates provided by coor[] within
2060e2ec84fSDave May    its sub-domain. If they any values within coor[] are not located in the sub-domain, they will be ignored and will not get
2070e2ec84fSDave May    added to the DMSwarm.
2080e2ec84fSDave May 
209db781477SPatrick Sanan .seealso: `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType`, `DMSwarmSetPointsUniformCoordinates()`
2100e2ec84fSDave May @*/
2110e2ec84fSDave May PETSC_EXTERN PetscErrorCode DMSwarmSetPointCoordinates(DM dm,PetscInt npoints,PetscReal coor[],PetscBool redundant,InsertMode mode)
2120e2ec84fSDave May {
2130e2ec84fSDave May   PetscReal         gmin[] = {PETSC_MAX_REAL ,PETSC_MAX_REAL, PETSC_MAX_REAL};
2140e2ec84fSDave May   PetscReal         gmax[] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
2150e2ec84fSDave May   PetscInt          i,N,bs,b,n_estimate,n_curr,n_new_est,p,n_found;
2160e2ec84fSDave May   Vec               coorlocal;
2170e2ec84fSDave May   const PetscScalar *_coor;
2180e2ec84fSDave May   DM                celldm;
2190e2ec84fSDave May   Vec               pos;
2200e2ec84fSDave May   PetscScalar       *_pos;
2210e2ec84fSDave May   PetscReal         *swarm_coor;
2220e2ec84fSDave May   PetscInt          *swarm_cellid;
2230e2ec84fSDave May   PetscSF           sfcell = NULL;
2240e2ec84fSDave May   const PetscSFNode *LA_sfcell;
2250e2ec84fSDave May   PetscReal         *my_coor;
2260e2ec84fSDave May   PetscInt          my_npoints;
2270e2ec84fSDave May   PetscMPIInt       rank;
2280e2ec84fSDave May   MPI_Comm          comm;
2290e2ec84fSDave May 
2300e2ec84fSDave May   PetscFunctionBegin;
2310e2ec84fSDave May   DMSWARMPICVALID(dm);
2329566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
2339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm,&rank));
2340e2ec84fSDave May 
2359566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm,&celldm));
2369566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(celldm,&coorlocal));
2379566063dSJacob Faibussowitsch   PetscCall(VecGetSize(coorlocal,&N));
2389566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(coorlocal,&bs));
2390e2ec84fSDave May   N = N / bs;
2409566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coorlocal,&_coor));
2410e2ec84fSDave May   for (i=0; i<N; i++) {
2420e2ec84fSDave May     for (b=0; b<bs; b++) {
243a5f152d1SDave May       gmin[b] = PetscMin(gmin[b],PetscRealPart(_coor[bs*i+b]));
244a5f152d1SDave May       gmax[b] = PetscMax(gmax[b],PetscRealPart(_coor[bs*i+b]));
2450e2ec84fSDave May     }
2460e2ec84fSDave May   }
2479566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coorlocal,&_coor));
2480e2ec84fSDave May 
2490e2ec84fSDave May   /* broadcast points from rank 0 if requested */
2500e2ec84fSDave May   if (redundant) {
2510e2ec84fSDave May     my_npoints = npoints;
2529566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(&my_npoints,1,MPIU_INT,0,comm));
2530e2ec84fSDave May 
2540e2ec84fSDave May     if (rank > 0) { /* allocate space */
2559566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bs*my_npoints,&my_coor));
2560e2ec84fSDave May     } else {
2570e2ec84fSDave May       my_coor = coor;
2580e2ec84fSDave May     }
2599566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(my_coor,bs*my_npoints,MPIU_REAL,0,comm));
2600e2ec84fSDave May   } else {
2610e2ec84fSDave May     my_npoints = npoints;
2620e2ec84fSDave May     my_coor = coor;
2630e2ec84fSDave May   }
2640e2ec84fSDave May 
2650e2ec84fSDave May   /* determine the number of points living in the bounding box */
2660e2ec84fSDave May   n_estimate = 0;
2670e2ec84fSDave May   for (i=0; i<my_npoints; i++) {
2680e2ec84fSDave May     PetscBool point_inside = PETSC_TRUE;
2690e2ec84fSDave May 
2700e2ec84fSDave May     for (b=0; b<bs; b++) {
2710e2ec84fSDave May       if (my_coor[bs*i+b] < gmin[b]) { point_inside = PETSC_FALSE; }
2720e2ec84fSDave May       if (my_coor[bs*i+b] > gmax[b]) { point_inside = PETSC_FALSE; }
2730e2ec84fSDave May     }
2740e2ec84fSDave May     if (point_inside) { n_estimate++; }
2750e2ec84fSDave May   }
2760e2ec84fSDave May 
2770e2ec84fSDave May   /* create candidate list */
2789566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF,&pos));
2799566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(pos,bs*n_estimate,PETSC_DECIDE));
2809566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(pos,bs));
2819566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(pos));
2829566063dSJacob Faibussowitsch   PetscCall(VecGetArray(pos,&_pos));
2830e2ec84fSDave May 
2840e2ec84fSDave May   n_estimate = 0;
2850e2ec84fSDave May   for (i=0; i<my_npoints; i++) {
2860e2ec84fSDave May     PetscBool point_inside = PETSC_TRUE;
2870e2ec84fSDave May 
2880e2ec84fSDave May     for (b=0; b<bs; b++) {
2890e2ec84fSDave May       if (my_coor[bs*i+b] < gmin[b]) { point_inside = PETSC_FALSE; }
2900e2ec84fSDave May       if (my_coor[bs*i+b] > gmax[b]) { point_inside = PETSC_FALSE; }
2910e2ec84fSDave May     }
2920e2ec84fSDave May     if (point_inside) {
2930e2ec84fSDave May       for (b=0; b<bs; b++) {
2940e2ec84fSDave May         _pos[bs*n_estimate+b] = my_coor[bs*i+b];
2950e2ec84fSDave May       }
2960e2ec84fSDave May       n_estimate++;
2970e2ec84fSDave May     }
2980e2ec84fSDave May   }
2999566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(pos,&_pos));
3000e2ec84fSDave May 
3010e2ec84fSDave May   /* locate points */
3029566063dSJacob Faibussowitsch   PetscCall(DMLocatePoints(celldm,pos,DM_POINTLOCATION_NONE,&sfcell));
3030e2ec84fSDave May 
3049566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell));
3050e2ec84fSDave May   n_found = 0;
3060e2ec84fSDave May   for (p=0; p<n_estimate; p++) {
3070e2ec84fSDave May     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
3080e2ec84fSDave May       n_found++;
3090e2ec84fSDave May     }
3100e2ec84fSDave May   }
3110e2ec84fSDave May 
3120e2ec84fSDave May   /* adjust size */
3130e2ec84fSDave May   if (mode == ADD_VALUES) {
3149566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetLocalSize(dm,&n_curr));
3150e2ec84fSDave May     n_new_est = n_curr + n_found;
3169566063dSJacob Faibussowitsch     PetscCall(DMSwarmSetLocalSizes(dm,n_new_est,-1));
3170e2ec84fSDave May   }
3180e2ec84fSDave May   if (mode == INSERT_VALUES) {
3190e2ec84fSDave May     n_curr = 0;
3200e2ec84fSDave May     n_new_est = n_found;
3219566063dSJacob Faibussowitsch     PetscCall(DMSwarmSetLocalSizes(dm,n_new_est,-1));
3220e2ec84fSDave May   }
3230e2ec84fSDave May 
3240e2ec84fSDave May   /* initialize new coords, cell owners, pid */
3259566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(pos,&_coor));
3269566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&swarm_coor));
3279566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid));
3280e2ec84fSDave May   n_found = 0;
3290e2ec84fSDave May   for (p=0; p<n_estimate; p++) {
3300e2ec84fSDave May     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
3310e2ec84fSDave May       for (b=0; b<bs; b++) {
3320ca99263SDave May         swarm_coor[bs*(n_curr + n_found) + b] = PetscRealPart(_coor[bs*p+b]);
3330e2ec84fSDave May       }
3340e2ec84fSDave May       swarm_cellid[n_curr + n_found] = LA_sfcell[p].index;
3350e2ec84fSDave May       n_found++;
3360e2ec84fSDave May     }
3370e2ec84fSDave May   }
3389566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid));
3399566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&swarm_coor));
3409566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(pos,&_coor));
3410e2ec84fSDave May 
3420e2ec84fSDave May   if (redundant) {
3430e2ec84fSDave May     if (rank > 0) {
3449566063dSJacob Faibussowitsch       PetscCall(PetscFree(my_coor));
3450e2ec84fSDave May     }
3460e2ec84fSDave May   }
3479566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfcell));
3489566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pos));
3490e2ec84fSDave May   PetscFunctionReturn(0);
3500e2ec84fSDave May }
3510e2ec84fSDave May 
3520e2ec84fSDave May extern PetscErrorCode private_DMSwarmInsertPointsUsingCellDM_DA(DM,DM,DMSwarmPICLayoutType,PetscInt);
3530e2ec84fSDave May extern PetscErrorCode private_DMSwarmInsertPointsUsingCellDM_PLEX(DM,DM,DMSwarmPICLayoutType,PetscInt);
3540e2ec84fSDave May 
3550e2ec84fSDave May /*@C
3560e2ec84fSDave May    DMSwarmInsertPointsUsingCellDM - Insert point coordinates within each cell
3570e2ec84fSDave May 
3580e2ec84fSDave May    Not collective
3590e2ec84fSDave May 
3600e2ec84fSDave May    Input parameters:
3610e2ec84fSDave May +  dm - the DMSwarm
3620e2ec84fSDave May .  layout_type - method used to fill each cell with the cell DM
3630e2ec84fSDave May -  fill_param - parameter controlling how many points per cell are added (the meaning of this parameter is dependent on the layout type)
3640e2ec84fSDave May 
3650e2ec84fSDave May    Level: beginner
3660e2ec84fSDave May 
3670e2ec84fSDave May    Notes:
368e7af74c8SDave May 
369e7af74c8SDave May    The insert method will reset any previous defined points within the DMSwarm.
370e7af74c8SDave May 
371e7af74c8SDave May    When using a DMDA both 2D and 3D are supported for all layout types provided you are using DMDA_ELEMENT_Q1.
372e7af74c8SDave May 
373e7af74c8SDave May    When using a DMPLEX the following case are supported:
374ea3d7275SDave May    (i) DMSWARMPIC_LAYOUT_REGULAR: 2D (triangle),
375ea3d7275SDave May    (ii) DMSWARMPIC_LAYOUT_GAUSS: 2D and 3D provided the cell is a tri/tet or a quad/hex,
376ea3d7275SDave May    (iii) DMSWARMPIC_LAYOUT_SUBDIVISION: 2D and 3D for quad/hex and 2D tri.
3770e2ec84fSDave May 
378db781477SPatrick Sanan .seealso: `DMSwarmPICLayoutType`, `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType`
3790e2ec84fSDave May @*/
3800e2ec84fSDave May PETSC_EXTERN PetscErrorCode DMSwarmInsertPointsUsingCellDM(DM dm,DMSwarmPICLayoutType layout_type,PetscInt fill_param)
3810e2ec84fSDave May {
3820e2ec84fSDave May   DM             celldm;
3830e2ec84fSDave May   PetscBool      isDA,isPLEX;
3840e2ec84fSDave May 
3850e2ec84fSDave May   PetscFunctionBegin;
3860e2ec84fSDave May   DMSWARMPICVALID(dm);
3879566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm,&celldm));
3889566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)celldm,DMDA,&isDA));
3899566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)celldm,DMPLEX,&isPLEX));
3900e2ec84fSDave May   if (isDA) {
3919566063dSJacob Faibussowitsch     PetscCall(private_DMSwarmInsertPointsUsingCellDM_DA(dm,celldm,layout_type,fill_param));
3920e2ec84fSDave May   } else if (isPLEX) {
3939566063dSJacob Faibussowitsch     PetscCall(private_DMSwarmInsertPointsUsingCellDM_PLEX(dm,celldm,layout_type,fill_param));
3940e2ec84fSDave May   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Only supported for cell DMs of type DMDA and DMPLEX");
3950e2ec84fSDave May   PetscFunctionReturn(0);
3960e2ec84fSDave May }
3970e2ec84fSDave May 
398431382f2SDave May extern PetscErrorCode private_DMSwarmSetPointCoordinatesCellwise_PLEX(DM,DM,PetscInt,PetscReal*);
399431382f2SDave May 
400431382f2SDave May /*@C
401431382f2SDave May    DMSwarmSetPointCoordinatesCellwise - Insert point coordinates (defined over the reference cell) within each cell
402431382f2SDave May 
403431382f2SDave May    Not collective
404431382f2SDave May 
405431382f2SDave May    Input parameters:
406431382f2SDave May +  dm - the DMSwarm
407431382f2SDave May .  celldm - the cell DM
408431382f2SDave May .  npoints - the number of points to insert in each cell
409431382f2SDave May -  xi - the coordinates (defined in the local coordinate system for each cell) to insert
410431382f2SDave May 
411431382f2SDave May  Level: beginner
412431382f2SDave May 
413431382f2SDave May  Notes:
414431382f2SDave May  The method will reset any previous defined points within the DMSwarm.
415ea3d7275SDave May  Only supported for DMPLEX. If you are using a DMDA it is recommended to either use
416e7af74c8SDave May  DMSwarmInsertPointsUsingCellDM(), or extract and set the coordinates yourself the following code
417e7af74c8SDave May 
418e7af74c8SDave May $    PetscReal *coor;
419e7af74c8SDave May $    DMSwarmGetField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&coor);
420e7af74c8SDave May $    // user code to define the coordinates here
421e7af74c8SDave May $    DMSwarmRestoreField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&coor);
422431382f2SDave May 
423db781477SPatrick Sanan .seealso: `DMSwarmSetCellDM()`, `DMSwarmInsertPointsUsingCellDM()`
424431382f2SDave May @*/
425431382f2SDave May PETSC_EXTERN PetscErrorCode DMSwarmSetPointCoordinatesCellwise(DM dm,PetscInt npoints,PetscReal xi[])
4260e2ec84fSDave May {
427431382f2SDave May   DM             celldm;
428431382f2SDave May   PetscBool      isDA,isPLEX;
429431382f2SDave May 
4300e2ec84fSDave May   PetscFunctionBegin;
431431382f2SDave May   DMSWARMPICVALID(dm);
4329566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm,&celldm));
4339566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)celldm,DMDA,&isDA));
4349566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)celldm,DMPLEX,&isPLEX));
43528b400f6SJacob Faibussowitsch   PetscCheck(!isDA,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Only supported for cell DMs of type DMPLEX. Recommended you use DMSwarmInsertPointsUsingCellDM()");
436*f7d195e4SLawrence Mitchell   if (isPLEX) {
4379566063dSJacob Faibussowitsch     PetscCall(private_DMSwarmSetPointCoordinatesCellwise_PLEX(dm,celldm,npoints,xi));
438431382f2SDave May   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Only supported for cell DMs of type DMDA and DMPLEX");
4390e2ec84fSDave May   PetscFunctionReturn(0);
4400e2ec84fSDave May }
441431382f2SDave May 
4420e2ec84fSDave May /* Field projection API */
44377048351SPatrick Sanan extern PetscErrorCode private_DMSwarmProjectFields_DA(DM swarm,DM celldm,PetscInt project_type,PetscInt nfields,DMSwarmDataField dfield[],Vec vecs[]);
44477048351SPatrick Sanan extern PetscErrorCode private_DMSwarmProjectFields_PLEX(DM swarm,DM celldm,PetscInt project_type,PetscInt nfields,DMSwarmDataField dfield[],Vec vecs[]);
44594f7d2dcSDave May 
44694f7d2dcSDave May /*@C
44794f7d2dcSDave May    DMSwarmProjectFields - Project a set of swarm fields onto the cell DM
44894f7d2dcSDave May 
449d083f849SBarry Smith    Collective on dm
45094f7d2dcSDave May 
45194f7d2dcSDave May    Input parameters:
45294f7d2dcSDave May +  dm - the DMSwarm
45394f7d2dcSDave May .  nfields - the number of swarm fields to project
45494f7d2dcSDave May .  fieldnames - the textual names of the swarm fields to project
45594f7d2dcSDave May .  fields - an array of Vec's of length nfields
45694f7d2dcSDave May -  reuse - flag indicating whether the array and contents of fields should be re-used or internally allocated
45794f7d2dcSDave May 
45894f7d2dcSDave May    Currently, the only available projection method consists of
45994f7d2dcSDave May      phi_i = \sum_{p=0}^{np} N_i(x_p) phi_p dJ / \sum_{p=0}^{np} N_i(x_p) dJ
46094f7d2dcSDave May    where phi_p is the swarm field at point p,
46194f7d2dcSDave May      N_i() is the cell DM basis function at vertex i,
46294f7d2dcSDave May      dJ is the determinant of the cell Jacobian and
46394f7d2dcSDave May      phi_i is the projected vertex value of the field phi.
46494f7d2dcSDave May 
46594f7d2dcSDave May    Level: beginner
46694f7d2dcSDave May 
46794f7d2dcSDave May    Notes:
468e7af74c8SDave May 
469e7af74c8SDave May    If reuse = PETSC_FALSE, this function will allocate the array of Vec's, and each individual Vec.
47094f7d2dcSDave May      The user is responsible for destroying both the array and the individual Vec objects.
471e7af74c8SDave May 
472e7af74c8SDave May    Only swarm fields registered with data type = PETSC_REAL can be projected onto the cell DM.
473e7af74c8SDave May 
474e7af74c8SDave May    Only swarm fields of block size = 1 can currently be projected.
475e7af74c8SDave May 
476e7af74c8SDave May    The only projection methods currently only support the DA (2D) and PLEX (triangles 2D).
47794f7d2dcSDave May 
478db781477SPatrick Sanan .seealso: `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType`
47994f7d2dcSDave May @*/
48094f7d2dcSDave May PETSC_EXTERN PetscErrorCode DMSwarmProjectFields(DM dm,PetscInt nfields,const char *fieldnames[],Vec **fields,PetscBool reuse)
4810e2ec84fSDave May {
48294f7d2dcSDave May   DM_Swarm         *swarm = (DM_Swarm*)dm->data;
48377048351SPatrick Sanan   DMSwarmDataField *gfield;
48494f7d2dcSDave May   DM               celldm;
48594f7d2dcSDave May   PetscBool        isDA,isPLEX;
48694f7d2dcSDave May   Vec              *vecs;
48794f7d2dcSDave May   PetscInt         f,nvecs;
48894f7d2dcSDave May   PetscInt         project_type = 0;
48994f7d2dcSDave May 
4900e2ec84fSDave May   PetscFunctionBegin;
49194f7d2dcSDave May   DMSWARMPICVALID(dm);
4929566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm,&celldm));
4939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nfields,&gfield));
49494f7d2dcSDave May   nvecs = 0;
49594f7d2dcSDave May   for (f=0; f<nfields; f++) {
4969566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db,fieldnames[f],&gfield[f]));
4975f80ce2aSJacob Faibussowitsch     PetscCheck(gfield[f]->petsc_type == PETSC_REAL,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Projection only valid for fields using a data type = PETSC_REAL");
4985f80ce2aSJacob Faibussowitsch     PetscCheck(gfield[f]->bs == 1,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Projection only valid for fields with block size = 1");
49994f7d2dcSDave May     nvecs += gfield[f]->bs;
50094f7d2dcSDave May   }
50194f7d2dcSDave May   if (!reuse) {
5029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nvecs,&vecs));
50394f7d2dcSDave May     for (f=0; f<nvecs; f++) {
5049566063dSJacob Faibussowitsch       PetscCall(DMCreateGlobalVector(celldm,&vecs[f]));
5059566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)vecs[f],gfield[f]->name));
50694f7d2dcSDave May     }
50794f7d2dcSDave May   } else {
50894f7d2dcSDave May     vecs = *fields;
50994f7d2dcSDave May   }
51094f7d2dcSDave May 
5119566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)celldm,DMDA,&isDA));
5129566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)celldm,DMPLEX,&isPLEX));
51394f7d2dcSDave May   if (isDA) {
5149566063dSJacob Faibussowitsch     PetscCall(private_DMSwarmProjectFields_DA(dm,celldm,project_type,nfields,gfield,vecs));
51594f7d2dcSDave May   } else if (isPLEX) {
5169566063dSJacob Faibussowitsch     PetscCall(private_DMSwarmProjectFields_PLEX(dm,celldm,project_type,nfields,gfield,vecs));
51794f7d2dcSDave May   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Only supported for cell DMs of type DMDA and DMPLEX");
51894f7d2dcSDave May 
5199566063dSJacob Faibussowitsch   PetscCall(PetscFree(gfield));
5205f80ce2aSJacob Faibussowitsch   if (!reuse) *fields = vecs;
5210e2ec84fSDave May   PetscFunctionReturn(0);
5220e2ec84fSDave May }
5230e2ec84fSDave May 
5240e2ec84fSDave May /*@C
525b799feefSDave May    DMSwarmCreatePointPerCellCount - Count the number of points within all cells in the cell DM
5260e2ec84fSDave May 
5270e2ec84fSDave May    Not collective
5280e2ec84fSDave May 
5290e2ec84fSDave May    Input parameter:
5300e2ec84fSDave May .  dm - the DMSwarm
5310e2ec84fSDave May 
5320e2ec84fSDave May    Output parameters:
5330e2ec84fSDave May +  ncells - the number of cells in the cell DM (optional argument, pass NULL to ignore)
534b799feefSDave May -  count - array of length ncells containing the number of points per cell
5350e2ec84fSDave May 
5360e2ec84fSDave May    Level: beginner
5370e2ec84fSDave May 
5380e2ec84fSDave May    Notes:
5390e2ec84fSDave May    The array count is allocated internally and must be free'd by the user.
5400e2ec84fSDave May 
541db781477SPatrick Sanan .seealso: `DMSwarmSetType()`, `DMSwarmSetCellDM()`, `DMSwarmType`
5420e2ec84fSDave May @*/
5430e2ec84fSDave May PETSC_EXTERN PetscErrorCode DMSwarmCreatePointPerCellCount(DM dm,PetscInt *ncells,PetscInt **count)
5440e2ec84fSDave May {
545b799feefSDave May   PetscBool      isvalid;
546b799feefSDave May   PetscInt       nel;
547b799feefSDave May   PetscInt       *sum;
548b799feefSDave May 
5490e2ec84fSDave May   PetscFunctionBegin;
5509566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetIsValid(dm,&isvalid));
551b799feefSDave May   nel = 0;
552b799feefSDave May   if (isvalid) {
553b799feefSDave May     PetscInt e;
554b799feefSDave May 
5559566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortGetSizes(dm,&nel,NULL));
556b799feefSDave May 
5579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nel,&sum));
558b799feefSDave May     for (e=0; e<nel; e++) {
5599566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetNumberOfPointsPerCell(dm,e,&sum[e]));
560b799feefSDave May     }
561b799feefSDave May   } else {
562b799feefSDave May     DM        celldm;
563b799feefSDave May     PetscBool isda,isplex,isshell;
564b799feefSDave May     PetscInt  p,npoints;
565b799feefSDave May     PetscInt *swarm_cellid;
566b799feefSDave May 
567b799feefSDave May     /* get the number of cells */
5689566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetCellDM(dm,&celldm));
5699566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)celldm,DMDA,&isda));
5709566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)celldm,DMPLEX,&isplex));
5719566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)celldm,DMSHELL,&isshell));
572b799feefSDave May     if (isda) {
573b799feefSDave May       PetscInt       _nel,_npe;
574b799feefSDave May       const PetscInt *_element;
575b799feefSDave May 
5769566063dSJacob Faibussowitsch       PetscCall(DMDAGetElements(celldm,&_nel,&_npe,&_element));
577b799feefSDave May       nel = _nel;
5789566063dSJacob Faibussowitsch       PetscCall(DMDARestoreElements(celldm,&_nel,&_npe,&_element));
579b799feefSDave May     } else if (isplex) {
580b799feefSDave May       PetscInt ps,pe;
581b799feefSDave May 
5829566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(celldm,0,&ps,&pe));
583b799feefSDave May       nel = pe - ps;
584b799feefSDave May     } else if (isshell) {
585b799feefSDave May       PetscErrorCode (*method_DMShellGetNumberOfCells)(DM,PetscInt*);
586b799feefSDave May 
5879566063dSJacob Faibussowitsch       PetscCall(PetscObjectQueryFunction((PetscObject)celldm,"DMGetNumberOfCells_C",&method_DMShellGetNumberOfCells));
588b799feefSDave May       if (method_DMShellGetNumberOfCells) {
5899566063dSJacob Faibussowitsch         PetscCall(method_DMShellGetNumberOfCells(celldm,&nel));
590b799feefSDave May       } 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);");
591b799feefSDave 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");
592b799feefSDave May 
5939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nel,&sum));
5949566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(sum,nel));
5959566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetLocalSize(dm,&npoints));
5969566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid));
597b799feefSDave May     for (p=0; p<npoints; p++) {
598b799feefSDave May       if (swarm_cellid[p] != DMLOCATEPOINT_POINT_NOT_FOUND) {
599b799feefSDave May         sum[ swarm_cellid[p] ]++;
600b799feefSDave May       }
601b799feefSDave May     }
6029566063dSJacob Faibussowitsch     PetscCall(DMSwarmRestoreField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid));
603b799feefSDave May   }
604b799feefSDave May   if (ncells) { *ncells = nel; }
605b799feefSDave May   *count  = sum;
6060e2ec84fSDave May   PetscFunctionReturn(0);
6070e2ec84fSDave May }
60835b38c60SMatthew G. Knepley 
60935b38c60SMatthew G. Knepley /*@
61035b38c60SMatthew G. Knepley   DMSwarmGetNumSpecies - Get the number of particle species
61135b38c60SMatthew G. Knepley 
61235b38c60SMatthew G. Knepley   Not collective
61335b38c60SMatthew G. Knepley 
61435b38c60SMatthew G. Knepley   Input parameter:
61535b38c60SMatthew G. Knepley . dm - the DMSwarm
61635b38c60SMatthew G. Knepley 
61735b38c60SMatthew G. Knepley   Output parameters:
61835b38c60SMatthew G. Knepley . Ns - the number of species
61935b38c60SMatthew G. Knepley 
62035b38c60SMatthew G. Knepley   Level: intermediate
62135b38c60SMatthew G. Knepley 
622db781477SPatrick Sanan .seealso: `DMSwarmSetNumSpecies()`, `DMSwarmSetType()`, `DMSwarmType`
62335b38c60SMatthew G. Knepley @*/
62435b38c60SMatthew G. Knepley PetscErrorCode DMSwarmGetNumSpecies(DM sw, PetscInt *Ns)
62535b38c60SMatthew G. Knepley {
62635b38c60SMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *) sw->data;
62735b38c60SMatthew G. Knepley 
62835b38c60SMatthew G. Knepley   PetscFunctionBegin;
62935b38c60SMatthew G. Knepley   *Ns = swarm->Ns;
63035b38c60SMatthew G. Knepley   PetscFunctionReturn(0);
63135b38c60SMatthew G. Knepley }
63235b38c60SMatthew G. Knepley 
63335b38c60SMatthew G. Knepley /*@
63435b38c60SMatthew G. Knepley   DMSwarmSetNumSpecies - Set the number of particle species
63535b38c60SMatthew G. Knepley 
63635b38c60SMatthew G. Knepley   Not collective
63735b38c60SMatthew G. Knepley 
63835b38c60SMatthew G. Knepley   Input parameter:
63935b38c60SMatthew G. Knepley + dm - the DMSwarm
64035b38c60SMatthew G. Knepley - Ns - the number of species
64135b38c60SMatthew G. Knepley 
64235b38c60SMatthew G. Knepley   Level: intermediate
64335b38c60SMatthew G. Knepley 
644db781477SPatrick Sanan .seealso: `DMSwarmGetNumSpecies()`, `DMSwarmSetType()`, `DMSwarmType`
64535b38c60SMatthew G. Knepley @*/
64635b38c60SMatthew G. Knepley PetscErrorCode DMSwarmSetNumSpecies(DM sw, PetscInt Ns)
64735b38c60SMatthew G. Knepley {
64835b38c60SMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *) sw->data;
64935b38c60SMatthew G. Knepley 
65035b38c60SMatthew G. Knepley   PetscFunctionBegin;
65135b38c60SMatthew G. Knepley   swarm->Ns =  Ns;
65235b38c60SMatthew G. Knepley   PetscFunctionReturn(0);
65335b38c60SMatthew G. Knepley }
65435b38c60SMatthew G. Knepley 
65535b38c60SMatthew G. Knepley /*@C
6566c5a79ebSMatthew G. Knepley   DMSwarmGetCoordinateFunction - Get the function setting initial particle positions, if it exists
6576c5a79ebSMatthew G. Knepley 
6586c5a79ebSMatthew G. Knepley   Not collective
6596c5a79ebSMatthew G. Knepley 
6606c5a79ebSMatthew G. Knepley   Input parameter:
6616c5a79ebSMatthew G. Knepley . dm - the DMSwarm
6626c5a79ebSMatthew G. Knepley 
6636c5a79ebSMatthew G. Knepley   Output Parameter:
6646c5a79ebSMatthew G. Knepley . coordFunc - the function setting initial particle positions, or NULL
6656c5a79ebSMatthew G. Knepley 
6666c5a79ebSMatthew G. Knepley   Level: intermediate
6676c5a79ebSMatthew G. Knepley 
668db781477SPatrick Sanan .seealso: `DMSwarmSetCoordinateFunction()`, `DMSwarmGetVelocityFunction()`, `DMSwarmInitializeCoordinates()`
6696c5a79ebSMatthew G. Knepley @*/
6706c5a79ebSMatthew G. Knepley PetscErrorCode DMSwarmGetCoordinateFunction(DM sw, PetscSimplePointFunc *coordFunc)
6716c5a79ebSMatthew G. Knepley {
6726c5a79ebSMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *) sw->data;
6736c5a79ebSMatthew G. Knepley 
6746c5a79ebSMatthew G. Knepley   PetscFunctionBegin;
6756c5a79ebSMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
6766c5a79ebSMatthew G. Knepley   PetscValidPointer(coordFunc, 2);
6776c5a79ebSMatthew G. Knepley   *coordFunc = swarm->coordFunc;
6786c5a79ebSMatthew G. Knepley   PetscFunctionReturn(0);
6796c5a79ebSMatthew G. Knepley }
6806c5a79ebSMatthew G. Knepley 
6816c5a79ebSMatthew G. Knepley /*@C
6826c5a79ebSMatthew G. Knepley   DMSwarmSetCoordinateFunction - Set the function setting initial particle positions
6836c5a79ebSMatthew G. Knepley 
6846c5a79ebSMatthew G. Knepley   Not collective
6856c5a79ebSMatthew G. Knepley 
6866c5a79ebSMatthew G. Knepley   Input parameters:
6876c5a79ebSMatthew G. Knepley + dm - the DMSwarm
6886c5a79ebSMatthew G. Knepley - coordFunc - the function setting initial particle positions
6896c5a79ebSMatthew G. Knepley 
6906c5a79ebSMatthew G. Knepley   Level: intermediate
6916c5a79ebSMatthew G. Knepley 
692db781477SPatrick Sanan .seealso: `DMSwarmGetCoordinateFunction()`, `DMSwarmSetVelocityFunction()`, `DMSwarmInitializeCoordinates()`
6936c5a79ebSMatthew G. Knepley @*/
6946c5a79ebSMatthew G. Knepley PetscErrorCode DMSwarmSetCoordinateFunction(DM sw, PetscSimplePointFunc coordFunc)
6956c5a79ebSMatthew G. Knepley {
6966c5a79ebSMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *) sw->data;
6976c5a79ebSMatthew G. Knepley 
6986c5a79ebSMatthew G. Knepley   PetscFunctionBegin;
6996c5a79ebSMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
7006c5a79ebSMatthew G. Knepley   PetscValidFunction(coordFunc, 2);
7016c5a79ebSMatthew G. Knepley   swarm->coordFunc = coordFunc;
7026c5a79ebSMatthew G. Knepley   PetscFunctionReturn(0);
7036c5a79ebSMatthew G. Knepley }
7046c5a79ebSMatthew G. Knepley 
7056c5a79ebSMatthew G. Knepley /*@C
7066c5a79ebSMatthew G. Knepley   DMSwarmGetCoordinateFunction - Get the function setting initial particle velocities, if it exists
7076c5a79ebSMatthew G. Knepley 
7086c5a79ebSMatthew G. Knepley   Not collective
7096c5a79ebSMatthew G. Knepley 
7106c5a79ebSMatthew G. Knepley   Input parameter:
7116c5a79ebSMatthew G. Knepley . dm - the DMSwarm
7126c5a79ebSMatthew G. Knepley 
7136c5a79ebSMatthew G. Knepley   Output Parameter:
7146c5a79ebSMatthew G. Knepley . velFunc - the function setting initial particle velocities, or NULL
7156c5a79ebSMatthew G. Knepley 
7166c5a79ebSMatthew G. Knepley   Level: intermediate
7176c5a79ebSMatthew G. Knepley 
718db781477SPatrick Sanan .seealso: `DMSwarmSetVelocityFunction()`, `DMSwarmGetCoordinateFunction()`, `DMSwarmInitializeVelocities()`
7196c5a79ebSMatthew G. Knepley @*/
7206c5a79ebSMatthew G. Knepley PetscErrorCode DMSwarmGetVelocityFunction(DM sw, PetscSimplePointFunc *velFunc)
7216c5a79ebSMatthew G. Knepley {
7226c5a79ebSMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *) sw->data;
7236c5a79ebSMatthew G. Knepley 
7246c5a79ebSMatthew G. Knepley   PetscFunctionBegin;
7256c5a79ebSMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
7266c5a79ebSMatthew G. Knepley   PetscValidPointer(velFunc, 2);
7276c5a79ebSMatthew G. Knepley   *velFunc = swarm->velFunc;
7286c5a79ebSMatthew G. Knepley   PetscFunctionReturn(0);
7296c5a79ebSMatthew G. Knepley }
7306c5a79ebSMatthew G. Knepley 
7316c5a79ebSMatthew G. Knepley /*@C
7326c5a79ebSMatthew G. Knepley   DMSwarmSetVelocityFunction - Set the function setting initial particle velocities
7336c5a79ebSMatthew G. Knepley 
7346c5a79ebSMatthew G. Knepley   Not collective
7356c5a79ebSMatthew G. Knepley 
7366c5a79ebSMatthew G. Knepley   Input parameters:
7376c5a79ebSMatthew G. Knepley + dm - the DMSwarm
7386c5a79ebSMatthew G. Knepley - coordFunc - the function setting initial particle velocities
7396c5a79ebSMatthew G. Knepley 
7406c5a79ebSMatthew G. Knepley   Level: intermediate
7416c5a79ebSMatthew G. Knepley 
742db781477SPatrick Sanan .seealso: `DMSwarmGetVelocityFunction()`, `DMSwarmSetCoordinateFunction()`, `DMSwarmInitializeVelocities()`
7436c5a79ebSMatthew G. Knepley @*/
7446c5a79ebSMatthew G. Knepley PetscErrorCode DMSwarmSetVelocityFunction(DM sw, PetscSimplePointFunc velFunc)
7456c5a79ebSMatthew G. Knepley {
7466c5a79ebSMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *) sw->data;
7476c5a79ebSMatthew G. Knepley 
7486c5a79ebSMatthew G. Knepley   PetscFunctionBegin;
7496c5a79ebSMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
7506c5a79ebSMatthew G. Knepley   PetscValidFunction(velFunc, 2);
7516c5a79ebSMatthew G. Knepley   swarm->velFunc = velFunc;
7526c5a79ebSMatthew G. Knepley   PetscFunctionReturn(0);
7536c5a79ebSMatthew G. Knepley }
7546c5a79ebSMatthew G. Knepley 
7556c5a79ebSMatthew G. Knepley /*@C
75635b38c60SMatthew G. Knepley   DMSwarmComputeLocalSize - Compute the local number and distribution of particles based upon a density function
75735b38c60SMatthew G. Knepley 
75835b38c60SMatthew G. Knepley   Not collective
75935b38c60SMatthew G. Knepley 
76035b38c60SMatthew G. Knepley   Input Parameters:
76135b38c60SMatthew G. Knepley + sw      - The DMSwarm
76235b38c60SMatthew G. Knepley . N       - The target number of particles
76335b38c60SMatthew G. Knepley - density - The density field for the particle layout, normalized to unity
76435b38c60SMatthew G. Knepley 
76535b38c60SMatthew G. Knepley   Note: One particle will be created for each species.
76635b38c60SMatthew G. Knepley 
76735b38c60SMatthew G. Knepley   Level: advanced
76835b38c60SMatthew G. Knepley 
769db781477SPatrick Sanan .seealso: `DMSwarmComputeLocalSizeFromOptions()`
77035b38c60SMatthew G. Knepley @*/
77135b38c60SMatthew G. Knepley PetscErrorCode DMSwarmComputeLocalSize(DM sw, PetscInt N, PetscProbFunc density)
77235b38c60SMatthew G. Knepley {
77335b38c60SMatthew G. Knepley   DM               dm;
77435b38c60SMatthew G. Knepley   PetscQuadrature  quad;
77535b38c60SMatthew G. Knepley   const PetscReal *xq, *wq;
77635b38c60SMatthew G. Knepley   PetscInt        *npc, *cellid;
7776c5a79ebSMatthew G. Knepley   PetscReal        xi0[3];
77835b38c60SMatthew G. Knepley   PetscInt         Ns, cStart, cEnd, c, dim, d, Nq, q, Np = 0, p;
77935b38c60SMatthew G. Knepley   PetscBool        simplex;
78035b38c60SMatthew G. Knepley 
78135b38c60SMatthew G. Knepley   PetscFunctionBegin;
7829566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
7839566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(sw, &dm));
7849566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
7859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
7869566063dSJacob Faibussowitsch   PetscCall(DMPlexIsSimplex(dm, &simplex));
7879566063dSJacob Faibussowitsch   if (simplex) PetscCall(PetscDTStroudConicalQuadrature(dim, 1, 5, -1.0, 1.0, &quad));
7889566063dSJacob Faibussowitsch   else         PetscCall(PetscDTGaussTensorQuadrature(dim, 1, 5, -1.0, 1.0, &quad));
7899566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, &xq, &wq));
7909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cEnd-cStart, &npc));
79135b38c60SMatthew G. Knepley   /* Integrate the density function to get the number of particles in each cell */
79235b38c60SMatthew G. Knepley   for (d = 0; d < dim; ++d) xi0[d] = -1.0;
79335b38c60SMatthew G. Knepley   for (c = 0; c < cEnd-cStart; ++c) {
79435b38c60SMatthew G. Knepley     const PetscInt cell = c + cStart;
79535b38c60SMatthew G. Knepley     PetscReal v0[3], J[9], invJ[9], detJ;
79635b38c60SMatthew G. Knepley     PetscReal n_int = 0.;
79735b38c60SMatthew G. Knepley 
7989566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, invJ, &detJ));
79935b38c60SMatthew G. Knepley     for (q = 0; q < Nq; ++q) {
80035b38c60SMatthew G. Knepley       PetscReal xr[3], den[3];
80135b38c60SMatthew G. Knepley 
80235b38c60SMatthew G. Knepley       CoordinatesRefToReal(dim, dim, xi0, v0, J, &xq[q*dim], xr);
8036c5a79ebSMatthew G. Knepley       PetscCall(density(xr, NULL, den));
8046c5a79ebSMatthew G. Knepley       n_int += den[0]*wq[q];
80535b38c60SMatthew G. Knepley     }
8066c5a79ebSMatthew G. Knepley     npc[c]  = (PetscInt) (N*n_int);
80735b38c60SMatthew G. Knepley     npc[c] *= Ns;
80835b38c60SMatthew G. Knepley     Np     += npc[c];
80935b38c60SMatthew G. Knepley   }
8109566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&quad));
8119566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetLocalSizes(sw, Np, 0));
81235b38c60SMatthew G. Knepley 
8139566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_cellid, NULL, NULL, (void **) &cellid));
81435b38c60SMatthew G. Knepley   for (c = 0, p = 0; c < cEnd-cStart; ++c) {
81535b38c60SMatthew G. Knepley     for (q = 0; q < npc[c]; ++q, ++p) cellid[p] = c;
81635b38c60SMatthew G. Knepley   }
8179566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_cellid, NULL, NULL, (void **) &cellid));
8189566063dSJacob Faibussowitsch   PetscCall(PetscFree(npc));
81935b38c60SMatthew G. Knepley   PetscFunctionReturn(0);
82035b38c60SMatthew G. Knepley }
82135b38c60SMatthew G. Knepley 
82235b38c60SMatthew G. Knepley /*@
82335b38c60SMatthew G. Knepley   DMSwarmComputeLocalSizeFromOptions - Compute the local number and distribution of particles based upon a density function determined by options
82435b38c60SMatthew G. Knepley 
82535b38c60SMatthew G. Knepley   Not collective
82635b38c60SMatthew G. Knepley 
82735b38c60SMatthew G. Knepley   Input Parameters:
82835b38c60SMatthew G. Knepley , sw - The DMSwarm
82935b38c60SMatthew G. Knepley 
83035b38c60SMatthew G. Knepley   Level: advanced
83135b38c60SMatthew G. Knepley 
832db781477SPatrick Sanan .seealso: `DMSwarmComputeLocalSize()`
83335b38c60SMatthew G. Knepley @*/
83435b38c60SMatthew G. Knepley PetscErrorCode DMSwarmComputeLocalSizeFromOptions(DM sw)
83535b38c60SMatthew G. Knepley {
83635b38c60SMatthew G. Knepley   PetscProbFunc  pdf;
83735b38c60SMatthew G. Knepley   const char    *prefix;
8386c5a79ebSMatthew G. Knepley   char           funcname[PETSC_MAX_PATH_LEN];
8396c5a79ebSMatthew G. Knepley   PetscInt      *N, Ns, dim, n;
8406c5a79ebSMatthew G. Knepley   PetscBool      flg;
8416c5a79ebSMatthew G. Knepley   PetscMPIInt    size, rank;
84235b38c60SMatthew G. Knepley 
84335b38c60SMatthew G. Knepley   PetscFunctionBegin;
8446c5a79ebSMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject) sw), &size));
8456c5a79ebSMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) sw), &rank));
8466c5a79ebSMatthew G. Knepley   PetscCall(PetscCalloc1(size, &N));
847d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject) sw), "", "DMSwarm Options", "DMSWARM");
8486c5a79ebSMatthew G. Knepley   n = size;
8496c5a79ebSMatthew G. Knepley   PetscCall(PetscOptionsIntArray("-dm_swarm_num_particles", "The target number of particles", "", N, &n, NULL));
8506c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
8519566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg));
8529566063dSJacob Faibussowitsch   if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns));
8536c5a79ebSMatthew G. Knepley   PetscCall(PetscOptionsString("-dm_swarm_coordinate_function", "Function to determine particle coordinates", "DMSwarmSetCoordinateFunction", funcname, funcname, sizeof(funcname), &flg));
854d0609cedSBarry Smith   PetscOptionsEnd();
8556c5a79ebSMatthew G. Knepley   if (flg) {
8566c5a79ebSMatthew G. Knepley     PetscSimplePointFunc coordFunc;
85735b38c60SMatthew G. Knepley 
8586c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
8596c5a79ebSMatthew G. Knepley     PetscCall(PetscDLSym(NULL, funcname, (void **) &coordFunc));
8606c5a79ebSMatthew G. Knepley     PetscCheck(coordFunc, PetscObjectComm((PetscObject) sw), PETSC_ERR_ARG_WRONG, "Could not locate function %s", funcname);
8616c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
8626c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmSetLocalSizes(sw, N[rank]*Ns, 0));
8636c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmSetCoordinateFunction(sw, coordFunc));
8646c5a79ebSMatthew G. Knepley   } else {
8659566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(sw, &dim));
8669566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetOptionsPrefix((PetscObject) sw, &prefix));
8679566063dSJacob Faibussowitsch     PetscCall(PetscProbCreateFromOptions(dim, prefix, "-dm_swarm_coordinate_density", &pdf, NULL, NULL));
8686c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmComputeLocalSize(sw, N[rank], pdf));
8696c5a79ebSMatthew G. Knepley   }
8706c5a79ebSMatthew G. Knepley   PetscCall(PetscFree(N));
87135b38c60SMatthew G. Knepley   PetscFunctionReturn(0);
87235b38c60SMatthew G. Knepley }
87335b38c60SMatthew G. Knepley 
87435b38c60SMatthew G. Knepley /*@
87535b38c60SMatthew G. Knepley   DMSwarmInitializeCoordinates - Determine the initial coordinates of particles for a PIC method
87635b38c60SMatthew G. Knepley 
87735b38c60SMatthew G. Knepley   Not collective
87835b38c60SMatthew G. Knepley 
87935b38c60SMatthew G. Knepley   Input Parameters:
88035b38c60SMatthew G. Knepley , sw - The DMSwarm
88135b38c60SMatthew G. Knepley 
88235b38c60SMatthew G. Knepley   Note: Currently, we randomly place particles in their assigned cell
88335b38c60SMatthew G. Knepley 
88435b38c60SMatthew G. Knepley   Level: advanced
88535b38c60SMatthew G. Knepley 
886db781477SPatrick Sanan .seealso: `DMSwarmComputeLocalSize()`, `DMSwarmInitializeVelocities()`
88735b38c60SMatthew G. Knepley @*/
88835b38c60SMatthew G. Knepley PetscErrorCode DMSwarmInitializeCoordinates(DM sw)
88935b38c60SMatthew G. Knepley {
8906c5a79ebSMatthew G. Knepley   PetscSimplePointFunc coordFunc;
89135b38c60SMatthew G. Knepley   PetscScalar         *weight;
8926c5a79ebSMatthew G. Knepley   PetscReal           *x;
89335b38c60SMatthew G. Knepley   PetscInt            *species;
8946c5a79ebSMatthew G. Knepley   void                *ctx;
89535b38c60SMatthew G. Knepley   PetscBool            removePoints = PETSC_TRUE;
89635b38c60SMatthew G. Knepley   PetscDataType        dtype;
8976c5a79ebSMatthew G. Knepley   PetscInt             Np, p, Ns, dim, d, bs;
89835b38c60SMatthew G. Knepley 
89935b38c60SMatthew G. Knepley   PetscFunctionBeginUser;
9006c5a79ebSMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
9016c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
9029566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
9036c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetCoordinateFunction(sw, &coordFunc));
9046c5a79ebSMatthew G. Knepley 
9056c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, &bs, &dtype, (void **) &x));
9066c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", &bs, &dtype, (void **) &weight));
9076c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **) &species));
9086c5a79ebSMatthew G. Knepley   if (coordFunc) {
9096c5a79ebSMatthew G. Knepley     PetscCall(DMGetApplicationContext(sw, &ctx));
9106c5a79ebSMatthew G. Knepley     for (p = 0; p < Np; ++p) {
9116c5a79ebSMatthew G. Knepley       PetscScalar X[3];
9126c5a79ebSMatthew G. Knepley 
9136c5a79ebSMatthew G. Knepley       PetscCall((*coordFunc)(dim, 0., NULL, p, X, ctx));
9146c5a79ebSMatthew G. Knepley       for (d = 0; d < dim; ++d) x[p*dim+d] = PetscRealPart(X[d]);
9156c5a79ebSMatthew G. Knepley       weight[p]  = 1.0;
9166c5a79ebSMatthew G. Knepley       species[p] = p % Ns;
9176c5a79ebSMatthew G. Knepley     }
9186c5a79ebSMatthew G. Knepley   } else {
9196c5a79ebSMatthew G. Knepley     DM          dm;
9206c5a79ebSMatthew G. Knepley     PetscRandom rnd;
9216c5a79ebSMatthew G. Knepley     PetscReal   xi0[3];
9226c5a79ebSMatthew G. Knepley     PetscInt    cStart, cEnd, c;
9236c5a79ebSMatthew G. Knepley 
9249566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetCellDM(sw, &dm));
9259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
92635b38c60SMatthew G. Knepley 
92735b38c60SMatthew G. Knepley     /* Set particle position randomly in cell, set weights to 1 */
9289566063dSJacob Faibussowitsch     PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject) dm), &rnd));
9299566063dSJacob Faibussowitsch     PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0));
9309566063dSJacob Faibussowitsch     PetscCall(PetscRandomSetFromOptions(rnd));
9319566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortGetAccess(sw));
93235b38c60SMatthew G. Knepley     for (d = 0; d < dim; ++d) xi0[d] = -1.0;
93335b38c60SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
93435b38c60SMatthew G. Knepley       PetscReal v0[3], J[9], invJ[9], detJ;
93535b38c60SMatthew G. Knepley       PetscInt *pidx, Npc, q;
93635b38c60SMatthew G. Knepley 
9379566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
9389566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
93935b38c60SMatthew G. Knepley       for (q = 0; q < Npc; ++q) {
94035b38c60SMatthew G. Knepley         const PetscInt p = pidx[q];
94135b38c60SMatthew G. Knepley         PetscReal      xref[3];
94235b38c60SMatthew G. Knepley 
9439566063dSJacob Faibussowitsch         for (d = 0; d < dim; ++d) PetscCall(PetscRandomGetValueReal(rnd, &xref[d]));
94435b38c60SMatthew G. Knepley         CoordinatesRefToReal(dim, dim, xi0, v0, J, xref, &x[p*dim]);
94535b38c60SMatthew G. Knepley 
94635b38c60SMatthew G. Knepley         weight[p]  = 1.0;
9476c5a79ebSMatthew G. Knepley         species[p] = p % Ns;
94835b38c60SMatthew G. Knepley       }
9499566063dSJacob Faibussowitsch       PetscCall(PetscFree(pidx));
95035b38c60SMatthew G. Knepley     }
9519566063dSJacob Faibussowitsch     PetscCall(PetscRandomDestroy(&rnd));
9529566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortRestoreAccess(sw));
9536c5a79ebSMatthew G. Knepley   }
9549566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **) &x));
9556c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **) &weight));
9569566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **) &species));
9576c5a79ebSMatthew G. Knepley 
9589566063dSJacob Faibussowitsch   PetscCall(DMSwarmMigrate(sw, removePoints));
9599566063dSJacob Faibussowitsch   PetscCall(DMLocalizeCoordinates(sw));
96035b38c60SMatthew G. Knepley   PetscFunctionReturn(0);
96135b38c60SMatthew G. Knepley }
96235b38c60SMatthew G. Knepley 
96335b38c60SMatthew G. Knepley /*@C
96435b38c60SMatthew G. Knepley   DMSwarmInitializeVelocities - Set the initial velocities of particles using a distribution.
96535b38c60SMatthew G. Knepley 
96635b38c60SMatthew G. Knepley   Collective on dm
96735b38c60SMatthew G. Knepley 
96835b38c60SMatthew G. Knepley   Input Parameters:
96935b38c60SMatthew G. Knepley + sw      - The DMSwarm object
97035b38c60SMatthew G. Knepley . sampler - A function which uniformly samples the velocity PDF
97135b38c60SMatthew G. Knepley - v0      - The velocity scale for nondimensionalization for each species
97235b38c60SMatthew G. Knepley 
9736c5a79ebSMatthew G. Knepley   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.
9746c5a79ebSMatthew G. Knepley 
97535b38c60SMatthew G. Knepley   Level: advanced
97635b38c60SMatthew G. Knepley 
977db781477SPatrick Sanan .seealso: `DMSwarmComputeLocalSize()`, `DMSwarmInitializeCoordinates()`, `DMSwarmInitializeVelocitiesFromOptions()`
97835b38c60SMatthew G. Knepley @*/
97935b38c60SMatthew G. Knepley PetscErrorCode DMSwarmInitializeVelocities(DM sw, PetscProbFunc sampler, const PetscReal v0[])
98035b38c60SMatthew G. Knepley {
9816c5a79ebSMatthew G. Knepley   PetscSimplePointFunc velFunc;
98235b38c60SMatthew G. Knepley   PetscReal           *v;
98335b38c60SMatthew G. Knepley   PetscInt            *species;
9846c5a79ebSMatthew G. Knepley   void                *ctx;
98535b38c60SMatthew G. Knepley   PetscInt             dim, Np, p;
98635b38c60SMatthew G. Knepley 
98735b38c60SMatthew G. Knepley   PetscFunctionBegin;
9886c5a79ebSMatthew G. Knepley   PetscCall(DMSwarmGetVelocityFunction(sw, &velFunc));
98935b38c60SMatthew G. Knepley 
9909566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(sw, &dim));
9919566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(sw, &Np));
9929566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **) &v));
9939566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **) &species));
9946c5a79ebSMatthew G. Knepley   if (v0[0] == 0.) {
9956c5a79ebSMatthew G. Knepley     PetscCall(PetscArrayzero(v, Np*dim));
9966c5a79ebSMatthew G. Knepley   } else if (velFunc) {
9976c5a79ebSMatthew G. Knepley     PetscCall(DMGetApplicationContext(sw, &ctx));
9986c5a79ebSMatthew G. Knepley     for (p = 0; p < Np; ++p) {
9996c5a79ebSMatthew G. Knepley       PetscInt    s = species[p], d;
10006c5a79ebSMatthew G. Knepley       PetscScalar vel[3];
10016c5a79ebSMatthew G. Knepley 
10026c5a79ebSMatthew G. Knepley       PetscCall((*velFunc)(dim, 0., NULL, p, vel, ctx));
10036c5a79ebSMatthew G. Knepley       for (d = 0; d < dim; ++d) v[p*dim+d] = (v0[s] / v0[0]) * PetscRealPart(vel[d]);
10046c5a79ebSMatthew G. Knepley     }
10056c5a79ebSMatthew G. Knepley   } else {
10066c5a79ebSMatthew G. Knepley     PetscRandom  rnd;
10076c5a79ebSMatthew G. Knepley 
10086c5a79ebSMatthew G. Knepley     PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject) sw), &rnd));
10096c5a79ebSMatthew G. Knepley     PetscCall(PetscRandomSetInterval(rnd, 0, 1.));
10106c5a79ebSMatthew G. Knepley     PetscCall(PetscRandomSetFromOptions(rnd));
10116c5a79ebSMatthew G. Knepley 
101235b38c60SMatthew G. Knepley     for (p = 0; p < Np; ++p) {
101335b38c60SMatthew G. Knepley       PetscInt  s = species[p], d;
101435b38c60SMatthew G. Knepley       PetscReal a[3], vel[3];
101535b38c60SMatthew G. Knepley 
10169566063dSJacob Faibussowitsch       for (d = 0; d < dim; ++d) PetscCall(PetscRandomGetValueReal(rnd, &a[d]));
10179566063dSJacob Faibussowitsch       PetscCall(sampler(a, NULL, vel));
101835b38c60SMatthew G. Knepley       for (d = 0; d < dim; ++d) {v[p*dim+d] = (v0[s] / v0[0]) * vel[d];}
101935b38c60SMatthew G. Knepley     }
10206c5a79ebSMatthew G. Knepley     PetscCall(PetscRandomDestroy(&rnd));
10216c5a79ebSMatthew G. Knepley   }
10229566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **) &v));
10239566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **) &species));
102435b38c60SMatthew G. Knepley   PetscFunctionReturn(0);
102535b38c60SMatthew G. Knepley }
102635b38c60SMatthew G. Knepley 
102735b38c60SMatthew G. Knepley /*@
102835b38c60SMatthew G. Knepley   DMSwarmInitializeVelocitiesFromOptions - Set the initial velocities of particles using a distribution determined from options.
102935b38c60SMatthew G. Knepley 
103035b38c60SMatthew G. Knepley   Collective on dm
103135b38c60SMatthew G. Knepley 
103235b38c60SMatthew G. Knepley   Input Parameters:
103335b38c60SMatthew G. Knepley + sw      - The DMSwarm object
103435b38c60SMatthew G. Knepley - v0      - The velocity scale for nondimensionalization for each species
103535b38c60SMatthew G. Knepley 
103635b38c60SMatthew G. Knepley   Level: advanced
103735b38c60SMatthew G. Knepley 
1038db781477SPatrick Sanan .seealso: `DMSwarmComputeLocalSize()`, `DMSwarmInitializeCoordinates()`, `DMSwarmInitializeVelocities()`
103935b38c60SMatthew G. Knepley @*/
104035b38c60SMatthew G. Knepley PetscErrorCode DMSwarmInitializeVelocitiesFromOptions(DM sw, const PetscReal v0[])
104135b38c60SMatthew G. Knepley {
104235b38c60SMatthew G. Knepley   PetscProbFunc  sampler;
104335b38c60SMatthew G. Knepley   PetscInt       dim;
104435b38c60SMatthew G. Knepley   const char    *prefix;
10456c5a79ebSMatthew G. Knepley   char           funcname[PETSC_MAX_PATH_LEN];
10466c5a79ebSMatthew G. Knepley   PetscBool      flg;
104735b38c60SMatthew G. Knepley 
104835b38c60SMatthew G. Knepley   PetscFunctionBegin;
1049d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject) sw), "", "DMSwarm Options", "DMSWARM");
10506c5a79ebSMatthew G. Knepley   PetscCall(PetscOptionsString("-dm_swarm_velocity_function", "Function to determine particle velocities", "DMSwarmSetVelocityFunction", funcname, funcname, sizeof(funcname), &flg));
1051d0609cedSBarry Smith   PetscOptionsEnd();
10526c5a79ebSMatthew G. Knepley   if (flg) {
10536c5a79ebSMatthew G. Knepley     PetscSimplePointFunc velFunc;
10546c5a79ebSMatthew G. Knepley 
10556c5a79ebSMatthew G. Knepley     PetscCall(PetscDLSym(NULL, funcname, (void **) &velFunc));
10566c5a79ebSMatthew G. Knepley     PetscCheck(velFunc, PetscObjectComm((PetscObject) sw), PETSC_ERR_ARG_WRONG, "Could not locate function %s", funcname);
10576c5a79ebSMatthew G. Knepley     PetscCall(DMSwarmSetVelocityFunction(sw, velFunc));
10586c5a79ebSMatthew G. Knepley   }
10599566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(sw, &dim));
10609566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetOptionsPrefix((PetscObject) sw, &prefix));
10619566063dSJacob Faibussowitsch   PetscCall(PetscProbCreateFromOptions(dim, prefix, "-dm_swarm_velocity_density", NULL, NULL, &sampler));
10629566063dSJacob Faibussowitsch   PetscCall(DMSwarmInitializeVelocities(sw, sampler, v0));
106335b38c60SMatthew G. Knepley   PetscFunctionReturn(0);
106435b38c60SMatthew G. Knepley }
1065