xref: /petsc/src/dm/impls/swarm/swarmpic.c (revision 94f7d2dc2cd9280e3d3b4516abfcb703cfdf61a5)
1 
2 #define PETSCDM_DLL
3 #include <petsc/private/dmswarmimpl.h>    /*I   "petscdmswarm.h"   I*/
4 #include <petscsf.h>
5 #include <petscdmda.h>
6 #include <petscdmplex.h>
7 #include "data_bucket.h"
8 
9 /*
10  Error chceking macto to ensure the swarm type is correct and that a cell DM has been set
11 */
12 #define DMSWARMPICVALID(dm) \
13 { \
14   DM_Swarm *_swarm = (DM_Swarm*)(dm)->data; \
15   if (_swarm->swarm_type != DMSWARM_PIC) SETERRQ(PetscObjectComm((PetscObject)(dm)),PETSC_ERR_SUP,"Only valid for DMSwarm-PIC. You must call DMSwarmSetType(dm,DMSWARM_PIC)"); \
16   else \
17     if (!_swarm->dmcell) SETERRQ(PetscObjectComm((PetscObject)(dm)),PETSC_ERR_SUP,"Only valid for DMSwarmPIC if the cell DM is set. You must call DMSwarmSetCellDM(dm,celldm)"); \
18 }
19 
20 /* Coordinate insertition/addition API */
21 /*@C
22    DMSwarmSetPointsUniformCoordinates - Set point coordinates in a DMSwarm on a regular (ijk) grid
23 
24    Collective on DM
25 
26    Input parameters:
27 +  dm - the DMSwarm
28 .  min - minimum coordinate values in the x, y, z directions (array of length dim)
29 .  max - maximum coordinate values in the x, y, z directions (array of length dim)
30 .  npoints - number of points in each spatial direction (array of length dim)
31 -  mode - indicates whether to append points to the swarm (ADD_VALUES), or over-ride existing points (INSERT_VALUES)
32 
33    Level: beginner
34 
35    Notes:
36    When using mode = INSERT_VALUES, this method will reset the number of particles in the DMSwarm
37    to be npoints[0]*npoints[1] (2D) or npoints[0]*npoints[1]*npoints[2] (3D). When using mode = ADD_VALUES,
38    new points will be appended to any already existing in the DMSwarm
39 
40 .seealso: DMSwarmSetType(), DMSwarmSetCellDM(), DMSwarmType
41 @*/
42 PETSC_EXTERN PetscErrorCode DMSwarmSetPointsUniformCoordinates(DM dm,PetscReal min[],PetscReal max[],PetscInt npoints[],InsertMode mode)
43 {
44   PetscErrorCode ierr;
45   PetscReal gmin[] = {PETSC_MAX_REAL ,PETSC_MAX_REAL, PETSC_MAX_REAL};
46   PetscReal gmax[] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
47   PetscInt i,j,k,N,bs,b,n_estimate,n_curr,n_new_est,p,n_found;
48   Vec coorlocal;
49   const PetscScalar *_coor;
50   DM celldm;
51   PetscReal dx[3];
52   Vec pos;
53   PetscScalar *_pos;
54   PetscReal *swarm_coor;
55   PetscInt *swarm_cellid;
56   PetscSF sfcell = NULL;
57   const PetscSFNode *LA_sfcell;
58 
59   PetscFunctionBegin;
60   DMSWARMPICVALID(dm);
61   ierr = DMSwarmGetCellDM(dm,&celldm);CHKERRQ(ierr);
62   ierr = DMGetCoordinatesLocal(celldm,&coorlocal);CHKERRQ(ierr);
63   ierr = VecGetSize(coorlocal,&N);CHKERRQ(ierr);
64   ierr = VecGetBlockSize(coorlocal,&bs);CHKERRQ(ierr);
65   N = N / bs;
66   ierr = VecGetArrayRead(coorlocal,&_coor);CHKERRQ(ierr);
67   for (i=0; i<N; i++) {
68     for (b=0; b<bs; b++) {
69       gmin[b] = PetscMin(gmin[b],_coor[bs*i+b]);
70       gmax[b] = PetscMax(gmax[b],_coor[bs*i+b]);
71     }
72   }
73   ierr = VecRestoreArrayRead(coorlocal,&_coor);CHKERRQ(ierr);
74 
75   for (b=0; b<bs; b++) {
76     if (npoints[b] > 1) {
77       dx[b] = (max[b] - min[b])/((PetscReal)(npoints[b]-1));
78     } else {
79       dx[b] = 0.0;
80     }
81   }
82 
83   /* determine number of points living in the bounding box */
84   n_estimate = 0;
85   if (bs == 2) { npoints[2] = 1; }
86   for (k=0; k<npoints[2]; k++) {
87     for (j=0; j<npoints[1]; j++) {
88       for (i=0; i<npoints[0]; i++) {
89         PetscReal xp[] = {0.0,0.0,0.0};
90         PetscInt ijk[3];
91         PetscBool point_inside = PETSC_TRUE;
92 
93         ijk[0] = i;
94         ijk[1] = j;
95         ijk[2] = k;
96         for (b=0; b<bs; b++) {
97           xp[b] = min[b] + ijk[b] * dx[b];
98         }
99         for (b=0; b<bs; b++) {
100           if (xp[b] < gmin[b]) { point_inside = PETSC_FALSE; }
101           if (xp[b] > gmax[b]) { point_inside = PETSC_FALSE; }
102         }
103         if (point_inside) { n_estimate++; }
104       }
105     }
106   }
107 
108   /* create candidate list */
109   ierr = VecCreate(PetscObjectComm((PetscObject)dm),&pos);CHKERRQ(ierr);
110   ierr = VecSetSizes(pos,bs*n_estimate,PETSC_DECIDE);CHKERRQ(ierr);
111   ierr = VecSetBlockSize(pos,bs);CHKERRQ(ierr);
112   ierr = VecSetFromOptions(pos);CHKERRQ(ierr);
113   ierr = VecGetArray(pos,&_pos);CHKERRQ(ierr);
114 
115   n_estimate = 0;
116   for (k=0; k<npoints[2]; k++) {
117     for (j=0; j<npoints[1]; j++) {
118       for (i=0; i<npoints[0]; i++) {
119         PetscReal xp[] = {0.0,0.0,0.0};
120         PetscInt ijk[3];
121         PetscBool point_inside = PETSC_TRUE;
122 
123         ijk[0] = i;
124         ijk[1] = j;
125         ijk[2] = k;
126         for (b=0; b<bs; b++) {
127           xp[b] = min[b] + ijk[b] * dx[b];
128         }
129         for (b=0; b<bs; b++) {
130           if (xp[b] < gmin[b]) { point_inside = PETSC_FALSE; }
131           if (xp[b] > gmax[b]) { point_inside = PETSC_FALSE; }
132         }
133         if (point_inside) {
134           for (b=0; b<bs; b++) {
135             _pos[bs*n_estimate+b] = xp[b];
136           }
137           n_estimate++;
138         }
139       }
140     }
141   }
142   ierr = VecRestoreArray(pos,&_pos);CHKERRQ(ierr);
143 
144   /* locate points */
145   ierr = DMLocatePoints(celldm,pos,DM_POINTLOCATION_NONE,&sfcell);CHKERRQ(ierr);
146 
147   ierr = PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell);CHKERRQ(ierr);
148   n_found = 0;
149   for (p=0; p<n_estimate; p++) {
150     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
151       n_found++;
152     }
153   }
154 
155   /* adjust size */
156   if (mode == ADD_VALUES) {
157     ierr = DMSwarmGetLocalSize(dm,&n_curr);CHKERRQ(ierr);
158     n_new_est = n_curr + n_found;
159     ierr = DMSwarmSetLocalSizes(dm,n_new_est,-1);CHKERRQ(ierr);
160   }
161   if (mode == INSERT_VALUES) {
162     n_curr = 0;
163     n_new_est = n_found;
164     ierr = DMSwarmSetLocalSizes(dm,n_new_est,-1);CHKERRQ(ierr);
165   }
166 
167   /* initialize new coords, cell owners, pid */
168   ierr = VecGetArrayRead(pos,&_coor);CHKERRQ(ierr);
169   ierr = DMSwarmGetField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&swarm_coor);CHKERRQ(ierr);
170   ierr = DMSwarmGetField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid);CHKERRQ(ierr);
171   n_found = 0;
172   for (p=0; p<n_estimate; p++) {
173     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
174       for (b=0; b<bs; b++) {
175         swarm_coor[bs*(n_curr + n_found) + b] = _coor[bs*p+b];
176       }
177       swarm_cellid[n_curr + n_found] = LA_sfcell[p].index;
178       n_found++;
179     }
180   }
181   ierr = DMSwarmRestoreField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid);CHKERRQ(ierr);
182   ierr = DMSwarmRestoreField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&swarm_coor);CHKERRQ(ierr);
183   ierr = VecRestoreArrayRead(pos,&_coor);CHKERRQ(ierr);
184 
185   ierr = PetscSFDestroy(&sfcell);CHKERRQ(ierr);
186   ierr = VecDestroy(&pos);CHKERRQ(ierr);
187 
188   PetscFunctionReturn(0);
189 }
190 
191 /*@C
192    DMSwarmSetPointCoordinates - Set point coordinates in a DMSwarm from a user defined list
193 
194    Collective on DM
195 
196    Input parameters:
197 +  dm - the DMSwarm
198 .  npoints - the number of points to insert
199 .  coor - the coordinate values
200 .  redundant - if set to PETSC_TRUE, it is assumed that npoints and coor[] are only valid on rank 0 and should be broadcast to other ranks
201 -  mode - indicates whether to append points to the swarm (ADD_VALUES), or over-ride existing points (INSERT_VALUES)
202 
203    Level: beginner
204 
205    Notes:
206    If the user has specified redundant = PETSC_FALSE, the cell DM will attempt to locate the coordinates provided by coor[] within
207    its sub-domain. If they any values within coor[] are not located in the sub-domain, they will be ignored and will not get
208    added to the DMSwarm.
209 
210 .seealso: DMSwarmSetType(), DMSwarmSetCellDM(), DMSwarmType, DMSwarmSetPointsUniformCoordinates()
211 @*/
212 PETSC_EXTERN PetscErrorCode DMSwarmSetPointCoordinates(DM dm,PetscInt npoints,PetscReal coor[],PetscBool redundant,InsertMode mode)
213 {
214   PetscErrorCode ierr;
215   PetscReal gmin[] = {PETSC_MAX_REAL ,PETSC_MAX_REAL, PETSC_MAX_REAL};
216   PetscReal gmax[] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
217   PetscInt i,N,bs,b,n_estimate,n_curr,n_new_est,p,n_found;
218   Vec coorlocal;
219   const PetscScalar *_coor;
220   DM celldm;
221   Vec pos;
222   PetscScalar *_pos;
223   PetscReal *swarm_coor;
224   PetscInt *swarm_cellid;
225   PetscSF sfcell = NULL;
226   const PetscSFNode *LA_sfcell;
227   PetscReal *my_coor;
228   PetscInt my_npoints;
229   PetscMPIInt rank;
230   MPI_Comm comm;
231 
232   PetscFunctionBegin;
233   DMSWARMPICVALID(dm);
234   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
235   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
236 
237   ierr = DMSwarmGetCellDM(dm,&celldm);CHKERRQ(ierr);
238   ierr = DMGetCoordinatesLocal(celldm,&coorlocal);CHKERRQ(ierr);
239   ierr = VecGetSize(coorlocal,&N);CHKERRQ(ierr);
240   ierr = VecGetBlockSize(coorlocal,&bs);CHKERRQ(ierr);
241   N = N / bs;
242   ierr = VecGetArrayRead(coorlocal,&_coor);CHKERRQ(ierr);
243   for (i=0; i<N; i++) {
244     for (b=0; b<bs; b++) {
245       gmin[b] = PetscMin(gmin[b],_coor[bs*i+b]);
246       gmax[b] = PetscMax(gmax[b],_coor[bs*i+b]);
247     }
248   }
249   ierr = VecRestoreArrayRead(coorlocal,&_coor);CHKERRQ(ierr);
250 
251   /* broadcast points from rank 0 if requested */
252   if (redundant) {
253     my_npoints = npoints;
254     ierr = MPI_Bcast(&my_npoints,1,MPIU_INT,0,comm);CHKERRQ(ierr);
255 
256     if (rank > 0) { /* allocate space */
257       ierr = PetscMalloc1(bs*my_npoints,&my_coor);CHKERRQ(ierr);
258     } else {
259       my_coor = coor;
260     }
261     ierr = MPI_Bcast(my_coor,bs*my_npoints,MPIU_REAL,0,comm);CHKERRQ(ierr);
262   } else {
263     my_npoints = npoints;
264     my_coor = coor;
265   }
266 
267   /* determine the number of points living in the bounding box */
268   n_estimate = 0;
269   for (i=0; i<my_npoints; i++) {
270     PetscBool point_inside = PETSC_TRUE;
271 
272     for (b=0; b<bs; b++) {
273       if (my_coor[bs*i+b] < gmin[b]) { point_inside = PETSC_FALSE; }
274       if (my_coor[bs*i+b] > gmax[b]) { point_inside = PETSC_FALSE; }
275     }
276     if (point_inside) { n_estimate++; }
277   }
278 
279   /* create candidate list */
280   ierr = VecCreate(PetscObjectComm((PetscObject)dm),&pos);CHKERRQ(ierr);
281   ierr = VecSetSizes(pos,bs*n_estimate,PETSC_DECIDE);CHKERRQ(ierr);
282   ierr = VecSetBlockSize(pos,bs);CHKERRQ(ierr);
283   ierr = VecSetFromOptions(pos);CHKERRQ(ierr);
284   ierr = VecGetArray(pos,&_pos);CHKERRQ(ierr);
285 
286   n_estimate = 0;
287   for (i=0; i<my_npoints; i++) {
288     PetscBool point_inside = PETSC_TRUE;
289 
290     for (b=0; b<bs; b++) {
291       if (my_coor[bs*i+b] < gmin[b]) { point_inside = PETSC_FALSE; }
292       if (my_coor[bs*i+b] > gmax[b]) { point_inside = PETSC_FALSE; }
293     }
294     if (point_inside) {
295       for (b=0; b<bs; b++) {
296         _pos[bs*n_estimate+b] = my_coor[bs*i+b];
297       }
298       n_estimate++;
299     }
300   }
301   ierr = VecRestoreArray(pos,&_pos);CHKERRQ(ierr);
302 
303   /* locate points */
304   ierr = DMLocatePoints(celldm,pos,DM_POINTLOCATION_NONE,&sfcell);CHKERRQ(ierr);
305 
306   ierr = PetscSFGetGraph(sfcell, NULL, NULL, NULL, &LA_sfcell);CHKERRQ(ierr);
307   n_found = 0;
308   for (p=0; p<n_estimate; p++) {
309     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
310       n_found++;
311     }
312   }
313 
314   /* adjust size */
315   if (mode == ADD_VALUES) {
316     ierr = DMSwarmGetLocalSize(dm,&n_curr);CHKERRQ(ierr);
317     n_new_est = n_curr + n_found;
318     ierr = DMSwarmSetLocalSizes(dm,n_new_est,-1);CHKERRQ(ierr);
319   }
320   if (mode == INSERT_VALUES) {
321     n_curr = 0;
322     n_new_est = n_found;
323     ierr = DMSwarmSetLocalSizes(dm,n_new_est,-1);CHKERRQ(ierr);
324   }
325 
326   /* initialize new coords, cell owners, pid */
327   ierr = VecGetArrayRead(pos,&_coor);CHKERRQ(ierr);
328   ierr = DMSwarmGetField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&swarm_coor);CHKERRQ(ierr);
329   ierr = DMSwarmGetField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid);CHKERRQ(ierr);
330   n_found = 0;
331   for (p=0; p<n_estimate; p++) {
332     if (LA_sfcell[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
333       for (b=0; b<bs; b++) {
334         swarm_coor[bs*(n_curr + n_found) + b] = _coor[bs*p+b];
335       }
336       swarm_cellid[n_curr + n_found] = LA_sfcell[p].index;
337       n_found++;
338     }
339   }
340   ierr = DMSwarmRestoreField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid);CHKERRQ(ierr);
341   ierr = DMSwarmRestoreField(dm,DMSwarmPICField_coor,NULL,NULL,(void**)&swarm_coor);CHKERRQ(ierr);
342   ierr = VecRestoreArrayRead(pos,&_coor);CHKERRQ(ierr);
343 
344   if (redundant) {
345     if (rank > 0) {
346       ierr = PetscFree(my_coor);CHKERRQ(ierr);
347     }
348   }
349   ierr = PetscSFDestroy(&sfcell);CHKERRQ(ierr);
350   ierr = VecDestroy(&pos);CHKERRQ(ierr);
351 
352   PetscFunctionReturn(0);
353 }
354 
355 extern PetscErrorCode private_DMSwarmInsertPointsUsingCellDM_DA(DM,DM,DMSwarmPICLayoutType,PetscInt);
356 extern PetscErrorCode private_DMSwarmInsertPointsUsingCellDM_PLEX(DM,DM,DMSwarmPICLayoutType,PetscInt);
357 
358 /*@C
359    DMSwarmInsertPointsUsingCellDM - Insert point coordinates within each cell
360 
361    Not collective
362 
363    Input parameters:
364 +  dm - the DMSwarm
365 .  layout_type - method used to fill each cell with the cell DM
366 -  fill_param - parameter controlling how many points per cell are added (the meaning of this parameter is dependent on the layout type)
367 
368  Level: beginner
369 
370  Notes:
371  The insert method will reset any previous defined points within the DMSwarm
372 
373 .seealso: DMSwarmPICLayoutType, DMSwarmSetType(), DMSwarmSetCellDM(), DMSwarmType
374 @*/
375 PETSC_EXTERN PetscErrorCode DMSwarmInsertPointsUsingCellDM(DM dm,DMSwarmPICLayoutType layout_type,PetscInt fill_param)
376 {
377   PetscErrorCode ierr;
378   DM celldm;
379   PetscBool isDA,isPLEX;
380 
381   PetscFunctionBegin;
382   DMSWARMPICVALID(dm);
383   ierr = DMSwarmGetCellDM(dm,&celldm);CHKERRQ(ierr);
384   ierr = PetscObjectTypeCompare((PetscObject)celldm,DMDA,&isDA);CHKERRQ(ierr);
385   ierr = PetscObjectTypeCompare((PetscObject)celldm,DMPLEX,&isPLEX);CHKERRQ(ierr);
386   if (isDA) {
387     ierr = private_DMSwarmInsertPointsUsingCellDM_DA(dm,celldm,layout_type,fill_param);CHKERRQ(ierr);
388   } else if (isPLEX) {
389     ierr = private_DMSwarmInsertPointsUsingCellDM_PLEX(dm,celldm,layout_type,fill_param);CHKERRQ(ierr);
390   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Only supported for cell DMs of type DMDA and DMPLEX");
391 
392   PetscFunctionReturn(0);
393 }
394 
395 /*
396 PETSC_EXTERN PetscErrorCode DMSwarmAddPointCoordinatesCellWise(DM dm,PetscInt cell,PetscInt npoints,PetscReal xi[],PetscBool proximity_initialization)
397 {
398   PetscFunctionBegin;
399   PetscFunctionReturn(0);
400 }
401 */
402 
403 /* Field projection API */
404 extern PetscErrorCode private_DMSwarmProjectFields_DA(DM swarm,DM celldm,PetscInt project_type,PetscInt nfields,DataField dfield[],Vec vecs[]);
405 extern PetscErrorCode private_DMSwarmProjectFields_PLEX(DM swarm,DM celldm,PetscInt project_type,PetscInt nfields,DataField dfield[],Vec vecs[]);
406 
407 /*@C
408    DMSwarmProjectFields - Project a set of swarm fields onto the cell DM
409 
410    Collective on Vec
411 
412    Input parameters:
413 +  dm - the DMSwarm
414 .  nfields - the number of swarm fields to project
415 .  fieldnames - the textual names of the swarm fields to project
416 .  fields - an array of Vec's of length nfields
417 -  reuse - flag indicating whether the array and contents of fields should be re-used or internally allocated
418 
419    Currently, the only available projection method consists of
420      phi_i = \sum_{p=0}^{np} N_i(x_p) phi_p dJ / \sum_{p=0}^{np} N_i(x_p) dJ
421    where phi_p is the swarm field at point p,
422      N_i() is the cell DM basis function at vertex i,
423      dJ is the determinant of the cell Jacobian and
424      phi_i is the projected vertex value of the field phi.
425 
426    Level: beginner
427 
428    Notes:
429    - If reuse = PETSC_FALSE, this function will allocate the array of Vec's, and each individual Vec.
430      The user is responsible for destroying both the array and the individual Vec objects.
431    - Only swarm fields registered with data type = PETSC_REAL can be projected onto the cell DM.
432    - Only swarm fields of block size = 1 can currently be projected.
433    - The only projection methods currently only support the DA (2D) and PLEX (triangles 2D).
434 
435 .seealso: DMSwarmSetType(), DMSwarmSetCellDM(), DMSwarmType
436 @*/
437 PETSC_EXTERN PetscErrorCode DMSwarmProjectFields(DM dm,PetscInt nfields,const char *fieldnames[],Vec **fields,PetscBool reuse)
438 {
439   DM_Swarm *swarm = (DM_Swarm*)dm->data;
440   DataField *gfield;
441   DM celldm;
442   PetscBool isDA,isPLEX;
443   Vec *vecs;
444   PetscInt f,nvecs;
445   PetscInt project_type = 0;
446   PetscErrorCode ierr;
447 
448   PetscFunctionBegin;
449   DMSWARMPICVALID(dm);
450   ierr = DMSwarmGetCellDM(dm,&celldm);CHKERRQ(ierr);
451   ierr = PetscMalloc1(nfields,&gfield);CHKERRQ(ierr);
452   nvecs = 0;
453   for (f=0; f<nfields; f++) {
454     ierr = DataBucketGetDataFieldByName(swarm->db,fieldnames[f],&gfield[f]);CHKERRQ(ierr);
455     if (gfield[f]->petsc_type != PETSC_REAL) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Projection only valid for fields using a data type = PETSC_REAL");
456     if (gfield[f]->bs != 1) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Projection only valid for fields with block size = 1");
457     nvecs += gfield[f]->bs;
458   }
459   if (!reuse) {
460     ierr = PetscMalloc1(nvecs,&vecs);CHKERRQ(ierr);
461     for (f=0; f<nvecs; f++) {
462       ierr = DMCreateGlobalVector(celldm,&vecs[f]);CHKERRQ(ierr);
463       ierr = PetscObjectSetName((PetscObject)vecs[f],gfield[f]->name);CHKERRQ(ierr);
464     }
465   } else {
466     vecs = *fields;
467   }
468 
469   ierr = PetscObjectTypeCompare((PetscObject)celldm,DMDA,&isDA);CHKERRQ(ierr);
470   ierr = PetscObjectTypeCompare((PetscObject)celldm,DMPLEX,&isPLEX);CHKERRQ(ierr);
471   if (isDA) {
472     ierr = private_DMSwarmProjectFields_DA(dm,celldm,project_type,nfields,gfield,vecs);CHKERRQ(ierr);
473   } else if (isPLEX) {
474     ierr = private_DMSwarmProjectFields_PLEX(dm,celldm,project_type,nfields,gfield,vecs);CHKERRQ(ierr);
475   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Only supported for cell DMs of type DMDA and DMPLEX");
476 
477   ierr = PetscFree(gfield);CHKERRQ(ierr);
478   if (!reuse) {
479     *fields = vecs;
480   }
481 
482   PetscFunctionReturn(0);
483 }
484 
485 /*@C
486    DMSwarmCreatePointPerCellCount - Count the number of points within all cells in the cell DM
487 
488    Not collective
489 
490    Input parameter:
491 .  dm - the DMSwarm
492 
493    Output parameters:
494 +  ncells - the number of cells in the cell DM (optional argument, pass NULL to ignore)
495 -  count - array of length ncells containing the number of points per cell
496 
497    Level: beginner
498 
499    Notes:
500    The array count is allocated internally and must be free'd by the user.
501 
502 .seealso: DMSwarmSetType(), DMSwarmSetCellDM(), DMSwarmType
503 @*/
504 PETSC_EXTERN PetscErrorCode DMSwarmCreatePointPerCellCount(DM dm,PetscInt *ncells,PetscInt **count)
505 {
506   PetscErrorCode ierr;
507   PetscBool      isvalid;
508   PetscInt       nel;
509   PetscInt       *sum;
510 
511   PetscFunctionBegin;
512   ierr = DMSwarmSortGetIsValid(dm,&isvalid);CHKERRQ(ierr);
513   nel = 0;
514   if (isvalid) {
515     PetscInt e;
516 
517     ierr = DMSwarmSortGetSizes(dm,&nel,NULL);CHKERRQ(ierr);
518 
519     ierr = PetscMalloc1(nel,&sum);CHKERRQ(ierr);
520     for (e=0; e<nel; e++) {
521       ierr = DMSwarmSortGetNumberOfPointsPerCell(dm,e,&sum[e]);CHKERRQ(ierr);
522     }
523   } else {
524     DM        celldm;
525     PetscBool isda,isplex,isshell;
526     PetscInt  p,npoints;
527     PetscInt *swarm_cellid;
528 
529     /* get the number of cells */
530     ierr = DMSwarmGetCellDM(dm,&celldm);CHKERRQ(ierr);
531     ierr = PetscObjectTypeCompare((PetscObject)celldm,DMDA,&isda);CHKERRQ(ierr);
532     ierr = PetscObjectTypeCompare((PetscObject)celldm,DMPLEX,&isplex);CHKERRQ(ierr);
533     ierr = PetscObjectTypeCompare((PetscObject)celldm,DMSHELL,&isshell);CHKERRQ(ierr);
534     if (isda) {
535       PetscInt _nel,_npe;
536       const PetscInt *_element;
537 
538       ierr = DMDAGetElements(celldm,&_nel,&_npe,&_element);CHKERRQ(ierr);
539       nel = _nel;
540       ierr = DMDARestoreElements(celldm,&_nel,&_npe,&_element);CHKERRQ(ierr);
541     } else if (isplex) {
542       PetscInt ps,pe;
543 
544       ierr = DMPlexGetHeightStratum(celldm,0,&ps,&pe);CHKERRQ(ierr);
545       nel = pe - ps;
546     } else if (isshell) {
547       PetscErrorCode (*method_DMShellGetNumberOfCells)(DM,PetscInt*);
548 
549       ierr = PetscObjectQueryFunction((PetscObject)celldm,"DMGetNumberOfCells_C",&method_DMShellGetNumberOfCells);CHKERRQ(ierr);
550       if (method_DMShellGetNumberOfCells) {
551         ierr = method_DMShellGetNumberOfCells(celldm,&nel);CHKERRQ(ierr);
552       } 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 );");
553     } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Cannot determine the number of cells for a DM not of type DA, PLEX or SHELL");
554 
555     ierr = PetscMalloc1(nel,&sum);CHKERRQ(ierr);
556     ierr = PetscMemzero(sum,sizeof(PetscInt)*nel);CHKERRQ(ierr);
557     ierr = DMSwarmGetLocalSize(dm,&npoints);CHKERRQ(ierr);
558     ierr = DMSwarmGetField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid);CHKERRQ(ierr);
559     for (p=0; p<npoints; p++) {
560       if (swarm_cellid[p] != DMLOCATEPOINT_POINT_NOT_FOUND) {
561         sum[ swarm_cellid[p] ]++;
562       }
563     }
564     ierr = DMSwarmRestoreField(dm,DMSwarmPICField_cellid,NULL,NULL,(void**)&swarm_cellid);CHKERRQ(ierr);
565   }
566   if (ncells) { *ncells = nel; }
567   *count  = sum;
568   PetscFunctionReturn(0);
569 }
570