xref: /petsc/src/dm/impls/swarm/swarm.c (revision 9072cb8bb45fb6e4a71960af0064634e8a2371f4)
1 #include "petscdm.h"
2 #include "petscdmswarm.h"
3 #include "petscstring.h"
4 #include "petscsys.h"
5 #define PETSCDM_DLL
6 #include <petsc/private/dmswarmimpl.h> /*I   "petscdmswarm.h"   I*/
7 #include <petsc/private/hashsetij.h>
8 #include <petsc/private/petscfeimpl.h>
9 #include <petscviewer.h>
10 #include <petscdraw.h>
11 #include <petscdmplex.h>
12 #include <petscblaslapack.h>
13 #include "../src/dm/impls/swarm/data_bucket.h"
14 #include <petscdmlabel.h>
15 #include <petscsection.h>
16 
17 PetscLogEvent DMSWARM_Migrate, DMSWARM_SetSizes, DMSWARM_AddPoints, DMSWARM_RemovePoints, DMSWARM_Sort;
18 PetscLogEvent DMSWARM_DataExchangerTopologySetup, DMSWARM_DataExchangerBegin, DMSWARM_DataExchangerEnd;
19 PetscLogEvent DMSWARM_DataExchangerSendCount, DMSWARM_DataExchangerPack;
20 
21 const char *DMSwarmTypeNames[]          = {"basic", "pic", NULL};
22 const char *DMSwarmMigrateTypeNames[]   = {"basic", "dmcellnscatter", "dmcellexact", "user", NULL};
23 const char *DMSwarmCollectTypeNames[]   = {"basic", "boundingbox", "general", "user", NULL};
24 const char *DMSwarmPICLayoutTypeNames[] = {"regular", "gauss", "subdivision", NULL};
25 
26 const char DMSwarmField_pid[]     = "DMSwarm_pid";
27 const char DMSwarmField_rank[]    = "DMSwarm_rank";
28 const char DMSwarmPICField_coor[] = "DMSwarmPIC_coor";
29 
30 PetscInt SwarmDataFieldId = -1;
31 
32 #if defined(PETSC_HAVE_HDF5)
33   #include <petscviewerhdf5.h>
34 
35 static PetscErrorCode VecView_Swarm_HDF5_Internal(Vec v, PetscViewer viewer)
36 {
37   DM        dm;
38   PetscReal seqval;
39   PetscInt  seqnum, bs;
40   PetscBool isseq, ists;
41 
42   PetscFunctionBegin;
43   PetscCall(VecGetDM(v, &dm));
44   PetscCall(VecGetBlockSize(v, &bs));
45   PetscCall(PetscViewerHDF5PushGroup(viewer, "/particle_fields"));
46   PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
47   PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, &seqval));
48   PetscCall(PetscViewerHDF5IsTimestepping(viewer, &ists));
49   if (ists) PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum));
50   /* PetscCall(DMSequenceView_HDF5(dm, "time", seqnum, (PetscScalar) seqval, viewer)); */
51   PetscCall(VecViewNative(v, viewer));
52   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)v, "Nc", PETSC_INT, (void *)&bs));
53   PetscCall(PetscViewerHDF5PopGroup(viewer));
54   PetscFunctionReturn(PETSC_SUCCESS);
55 }
56 
57 static PetscErrorCode DMSwarmView_HDF5(DM dm, PetscViewer viewer)
58 {
59   DMSwarmCellDM celldm;
60   Vec           coordinates;
61   PetscInt      Np, Nfc;
62   PetscBool     isseq;
63   const char  **coordFields;
64 
65   PetscFunctionBegin;
66   PetscCall(DMSwarmGetCellDMActive(dm, &celldm));
67   PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields));
68   PetscCheck(Nfc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "We only support a single coordinate field right now, not %" PetscInt_FMT, Nfc);
69   PetscCall(DMSwarmGetSize(dm, &Np));
70   PetscCall(DMSwarmCreateGlobalVectorFromField(dm, coordFields[0], &coordinates));
71   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
72   PetscCall(PetscViewerHDF5PushGroup(viewer, "/particles"));
73   PetscCall(PetscObjectTypeCompare((PetscObject)coordinates, VECSEQ, &isseq));
74   PetscCall(VecViewNative(coordinates, viewer));
75   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)coordinates, "Np", PETSC_INT, (void *)&Np));
76   PetscCall(PetscViewerHDF5PopGroup(viewer));
77   PetscCall(DMSwarmDestroyGlobalVectorFromField(dm, coordFields[0], &coordinates));
78   PetscFunctionReturn(PETSC_SUCCESS);
79 }
80 #endif
81 
82 static PetscErrorCode VecView_Swarm(Vec v, PetscViewer viewer)
83 {
84   DM dm;
85 #if defined(PETSC_HAVE_HDF5)
86   PetscBool ishdf5;
87 #endif
88 
89   PetscFunctionBegin;
90   PetscCall(VecGetDM(v, &dm));
91   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
92 #if defined(PETSC_HAVE_HDF5)
93   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
94   if (ishdf5) {
95     PetscCall(VecView_Swarm_HDF5_Internal(v, viewer));
96     PetscFunctionReturn(PETSC_SUCCESS);
97   }
98 #endif
99   PetscCall(VecViewNative(v, viewer));
100   PetscFunctionReturn(PETSC_SUCCESS);
101 }
102 
103 /*@C
104   DMSwarmVectorGetField - Gets the fields from which to define a `Vec` object
105   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
106 
107   Not collective
108 
109   Input Parameter:
110 . sw - a `DMSWARM`
111 
112   Output Parameters:
113 + Nf         - the number of fields
114 - fieldnames - the textual name given to each registered field, or NULL if it has not been set
115 
116   Level: beginner
117 
118 .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
119 @*/
120 PetscErrorCode DMSwarmVectorGetField(DM sw, PetscInt *Nf, const char **fieldnames[])
121 {
122   DMSwarmCellDM celldm;
123 
124   PetscFunctionBegin;
125   PetscValidHeaderSpecificType(sw, DM_CLASSID, 1, DMSWARM);
126   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
127   PetscCall(DMSwarmCellDMGetFields(celldm, Nf, fieldnames));
128   PetscFunctionReturn(PETSC_SUCCESS);
129 }
130 
131 /*@
132   DMSwarmVectorDefineField - Sets the field from which to define a `Vec` object
133   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
134 
135   Collective
136 
137   Input Parameters:
138 + dm        - a `DMSWARM`
139 - fieldname - the textual name given to each registered field
140 
141   Level: beginner
142 
143   Notes:
144   The field with name `fieldname` must be defined as having a data type of `PetscScalar`.
145 
146   This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`.
147   Multiple calls to `DMSwarmVectorDefineField()` are permitted.
148 
149 .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineFields()`, `DMSwarmVectorGetField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
150 @*/
151 PetscErrorCode DMSwarmVectorDefineField(DM dm, const char fieldname[])
152 {
153   PetscFunctionBegin;
154   PetscCall(DMSwarmVectorDefineFields(dm, 1, &fieldname));
155   PetscFunctionReturn(PETSC_SUCCESS);
156 }
157 
158 /*@C
159   DMSwarmVectorDefineFields - Sets the fields from which to define a `Vec` object
160   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
161 
162   Collective, No Fortran support
163 
164   Input Parameters:
165 + sw         - a `DMSWARM`
166 . Nf         - the number of fields
167 - fieldnames - the textual name given to each registered field
168 
169   Level: beginner
170 
171   Notes:
172   Each field with name in `fieldnames` must be defined as having a data type of `PetscScalar`.
173 
174   This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`.
175   Multiple calls to `DMSwarmVectorDefineField()` are permitted.
176 
177 .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineField()`, `DMSwarmVectorGetField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
178 @*/
179 PetscErrorCode DMSwarmVectorDefineFields(DM sw, PetscInt Nf, const char *fieldnames[])
180 {
181   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
182   DMSwarmCellDM celldm;
183 
184   PetscFunctionBegin;
185   PetscValidHeaderSpecificType(sw, DM_CLASSID, 1, DMSWARM);
186   if (fieldnames) PetscAssertPointer(fieldnames, 3);
187   if (!swarm->issetup) PetscCall(DMSetUp(sw));
188   PetscCheck(Nf >= 0, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields must be non-negative, not %" PetscInt_FMT, Nf);
189   // Create a dummy cell DM if none has been specified (I think we should not support this mode)
190   if (!swarm->activeCellDM) {
191     DM            dm;
192     DMSwarmCellDM celldm;
193 
194     PetscCall(DMCreate(PetscObjectComm((PetscObject)sw), &dm));
195     PetscCall(DMSetType(dm, DMSHELL));
196     PetscCall(PetscObjectSetName((PetscObject)dm, "dummy"));
197     PetscCall(DMSwarmCellDMCreate(dm, 0, NULL, 0, NULL, &celldm));
198     PetscCall(DMDestroy(&dm));
199     PetscCall(DMSwarmAddCellDM(sw, celldm));
200     PetscCall(DMSwarmCellDMDestroy(&celldm));
201     PetscCall(DMSwarmSetCellDMActive(sw, "dummy"));
202   }
203   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
204   for (PetscInt f = 0; f < celldm->Nf; ++f) PetscCall(PetscFree(celldm->dmFields[f]));
205   PetscCall(PetscFree(celldm->dmFields));
206 
207   celldm->Nf = Nf;
208   PetscCall(PetscMalloc1(Nf, &celldm->dmFields));
209   for (PetscInt f = 0; f < Nf; ++f) {
210     PetscDataType type;
211 
212     // Check all fields are of type PETSC_REAL or PETSC_SCALAR
213     PetscCall(DMSwarmGetFieldInfo(sw, fieldnames[f], NULL, &type));
214     PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)sw), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
215     PetscCall(PetscStrallocpy(fieldnames[f], (char **)&celldm->dmFields[f]));
216   }
217   PetscFunctionReturn(PETSC_SUCCESS);
218 }
219 
220 /* requires DMSwarmDefineFieldVector has been called */
221 static PetscErrorCode DMCreateGlobalVector_Swarm(DM sw, Vec *vec)
222 {
223   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
224   DMSwarmCellDM celldm;
225   Vec           x;
226   char          name[PETSC_MAX_PATH_LEN];
227   PetscInt      bs = 0, n;
228 
229   PetscFunctionBegin;
230   if (!swarm->issetup) PetscCall(DMSetUp(sw));
231   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
232   PetscCheck(celldm->Nf, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "Active cell DM does not define any fields");
233   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
234 
235   PetscCall(PetscStrncpy(name, "DMSwarmField", PETSC_MAX_PATH_LEN));
236   for (PetscInt f = 0; f < celldm->Nf; ++f) {
237     PetscInt fbs;
238     PetscCall(PetscStrlcat(name, "_", PETSC_MAX_PATH_LEN));
239     PetscCall(PetscStrlcat(name, celldm->dmFields[f], PETSC_MAX_PATH_LEN));
240     PetscCall(DMSwarmGetFieldInfo(sw, celldm->dmFields[f], &fbs, NULL));
241     bs += fbs;
242   }
243   PetscCall(VecCreate(PetscObjectComm((PetscObject)sw), &x));
244   PetscCall(PetscObjectSetName((PetscObject)x, name));
245   PetscCall(VecSetSizes(x, n * bs, PETSC_DETERMINE));
246   PetscCall(VecSetBlockSize(x, bs));
247   PetscCall(VecSetDM(x, sw));
248   PetscCall(VecSetFromOptions(x));
249   PetscCall(VecSetOperation(x, VECOP_VIEW, (void (*)(void))VecView_Swarm));
250   *vec = x;
251   PetscFunctionReturn(PETSC_SUCCESS);
252 }
253 
254 /* requires DMSwarmDefineFieldVector has been called */
255 static PetscErrorCode DMCreateLocalVector_Swarm(DM sw, Vec *vec)
256 {
257   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
258   DMSwarmCellDM celldm;
259   Vec           x;
260   char          name[PETSC_MAX_PATH_LEN];
261   PetscInt      bs = 0, n;
262 
263   PetscFunctionBegin;
264   if (!swarm->issetup) PetscCall(DMSetUp(sw));
265   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
266   PetscCheck(celldm->Nf, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "Active cell DM does not define any fields");
267   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
268 
269   PetscCall(PetscStrncpy(name, "DMSwarmField", PETSC_MAX_PATH_LEN));
270   for (PetscInt f = 0; f < celldm->Nf; ++f) {
271     PetscInt fbs;
272     PetscCall(PetscStrlcat(name, "_", PETSC_MAX_PATH_LEN));
273     PetscCall(PetscStrlcat(name, celldm->dmFields[f], PETSC_MAX_PATH_LEN));
274     PetscCall(DMSwarmGetFieldInfo(sw, celldm->dmFields[f], &fbs, NULL));
275     bs += fbs;
276   }
277   PetscCall(VecCreate(PETSC_COMM_SELF, &x));
278   PetscCall(PetscObjectSetName((PetscObject)x, name));
279   PetscCall(VecSetSizes(x, n * bs, PETSC_DETERMINE));
280   PetscCall(VecSetBlockSize(x, bs));
281   PetscCall(VecSetDM(x, sw));
282   PetscCall(VecSetFromOptions(x));
283   *vec = x;
284   PetscFunctionReturn(PETSC_SUCCESS);
285 }
286 
287 static PetscErrorCode DMSwarmDestroyVectorFromField_Private(DM dm, const char fieldname[], Vec *vec)
288 {
289   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
290   DMSwarmDataField gfield;
291   PetscInt         bs, nlocal, fid = -1, cfid = -2;
292   PetscBool        flg;
293 
294   PetscFunctionBegin;
295   /* check vector is an inplace array */
296   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
297   PetscCall(PetscObjectComposedDataGetInt((PetscObject)*vec, SwarmDataFieldId, cfid, flg));
298   (void)flg; /* avoid compiler warning */
299   PetscCheck(cfid == fid, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Vector being destroyed was not created from DMSwarm field(%s)! %" PetscInt_FMT " != %" PetscInt_FMT, fieldname, cfid, fid);
300   PetscCall(VecGetLocalSize(*vec, &nlocal));
301   PetscCall(VecGetBlockSize(*vec, &bs));
302   PetscCheck(nlocal / bs == swarm->db->L, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSwarm sizes have changed since vector was created - cannot ensure pointers are valid");
303   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
304   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
305   PetscCall(VecResetArray(*vec));
306   PetscCall(VecDestroy(vec));
307   PetscFunctionReturn(PETSC_SUCCESS);
308 }
309 
310 static PetscErrorCode DMSwarmCreateVectorFromField_Private(DM dm, const char fieldname[], MPI_Comm comm, Vec *vec)
311 {
312   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
313   PetscDataType type;
314   PetscScalar  *array;
315   PetscInt      bs, n, fid;
316   char          name[PETSC_MAX_PATH_LEN];
317   PetscMPIInt   size;
318   PetscBool     iscuda, iskokkos, iship;
319 
320   PetscFunctionBegin;
321   if (!swarm->issetup) PetscCall(DMSetUp(dm));
322   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
323   PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array));
324   PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
325 
326   PetscCallMPI(MPI_Comm_size(comm, &size));
327   PetscCall(PetscStrcmp(dm->vectype, VECKOKKOS, &iskokkos));
328   PetscCall(PetscStrcmp(dm->vectype, VECCUDA, &iscuda));
329   PetscCall(PetscStrcmp(dm->vectype, VECHIP, &iship));
330   PetscCall(VecCreate(comm, vec));
331   PetscCall(VecSetSizes(*vec, n * bs, PETSC_DETERMINE));
332   PetscCall(VecSetBlockSize(*vec, bs));
333   if (iskokkos) PetscCall(VecSetType(*vec, VECKOKKOS));
334   else if (iscuda) PetscCall(VecSetType(*vec, VECCUDA));
335   else if (iship) PetscCall(VecSetType(*vec, VECHIP));
336   else PetscCall(VecSetType(*vec, VECSTANDARD));
337   PetscCall(VecPlaceArray(*vec, array));
338 
339   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmSharedField_%s", fieldname));
340   PetscCall(PetscObjectSetName((PetscObject)*vec, name));
341 
342   /* Set guard */
343   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
344   PetscCall(PetscObjectComposedDataSetInt((PetscObject)*vec, SwarmDataFieldId, fid));
345 
346   PetscCall(VecSetDM(*vec, dm));
347   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Swarm));
348   PetscFunctionReturn(PETSC_SUCCESS);
349 }
350 
351 static PetscErrorCode DMSwarmDestroyVectorFromFields_Private(DM sw, PetscInt Nf, const char *fieldnames[], Vec *vec)
352 {
353   DM_Swarm          *swarm = (DM_Swarm *)sw->data;
354   const PetscScalar *array;
355   PetscInt           bs, n, id = 0, cid = -2;
356   PetscBool          flg;
357 
358   PetscFunctionBegin;
359   for (PetscInt f = 0; f < Nf; ++f) {
360     PetscInt fid;
361 
362     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldnames[f], &fid));
363     id += fid;
364   }
365   PetscCall(PetscObjectComposedDataGetInt((PetscObject)*vec, SwarmDataFieldId, cid, flg));
366   (void)flg; /* avoid compiler warning */
367   PetscCheck(cid == id, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "Vector being destroyed was not created from DMSwarm field(%s)! %" PetscInt_FMT " != %" PetscInt_FMT, fieldnames[0], cid, id);
368   PetscCall(VecGetLocalSize(*vec, &n));
369   PetscCall(VecGetBlockSize(*vec, &bs));
370   n /= bs;
371   PetscCheck(n == swarm->db->L, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "DMSwarm sizes have changed since vector was created - cannot ensure pointers are valid");
372   PetscCall(VecGetArrayRead(*vec, &array));
373   for (PetscInt f = 0, off = 0; f < Nf; ++f) {
374     PetscScalar  *farray;
375     PetscDataType ftype;
376     PetscInt      fbs;
377 
378     PetscCall(DMSwarmGetField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray));
379     PetscCheck(off + fbs <= bs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid blocksize %" PetscInt_FMT " < %" PetscInt_FMT, bs, off + fbs);
380     for (PetscInt i = 0; i < n; ++i) {
381       for (PetscInt b = 0; b < fbs; ++b) farray[i * fbs + b] = array[i * bs + off + b];
382     }
383     off += fbs;
384     PetscCall(DMSwarmRestoreField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray));
385   }
386   PetscCall(VecRestoreArrayRead(*vec, &array));
387   PetscCall(VecDestroy(vec));
388   PetscFunctionReturn(PETSC_SUCCESS);
389 }
390 
391 static PetscErrorCode DMSwarmCreateVectorFromFields_Private(DM sw, PetscInt Nf, const char *fieldnames[], MPI_Comm comm, Vec *vec)
392 {
393   DM_Swarm    *swarm = (DM_Swarm *)sw->data;
394   PetscScalar *array;
395   PetscInt     n, bs = 0, id = 0;
396   char         name[PETSC_MAX_PATH_LEN];
397 
398   PetscFunctionBegin;
399   if (!swarm->issetup) PetscCall(DMSetUp(sw));
400   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
401   for (PetscInt f = 0; f < Nf; ++f) {
402     PetscDataType ftype;
403     PetscInt      fbs;
404 
405     PetscCall(DMSwarmGetFieldInfo(sw, fieldnames[f], &fbs, &ftype));
406     PetscCheck(ftype == PETSC_REAL, PetscObjectComm((PetscObject)sw), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
407     bs += fbs;
408   }
409 
410   PetscCall(VecCreate(comm, vec));
411   PetscCall(VecSetSizes(*vec, n * bs, PETSC_DETERMINE));
412   PetscCall(VecSetBlockSize(*vec, bs));
413   PetscCall(VecSetType(*vec, sw->vectype));
414 
415   PetscCall(VecGetArrayWrite(*vec, &array));
416   for (PetscInt f = 0, off = 0; f < Nf; ++f) {
417     PetscScalar  *farray;
418     PetscDataType ftype;
419     PetscInt      fbs;
420 
421     PetscCall(DMSwarmGetField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray));
422     for (PetscInt i = 0; i < n; ++i) {
423       for (PetscInt b = 0; b < fbs; ++b) array[i * bs + off + b] = farray[i * fbs + b];
424     }
425     off += fbs;
426     PetscCall(DMSwarmRestoreField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray));
427   }
428   PetscCall(VecRestoreArrayWrite(*vec, &array));
429 
430   PetscCall(PetscStrncpy(name, "DMSwarmField", PETSC_MAX_PATH_LEN));
431   for (PetscInt f = 0; f < Nf; ++f) {
432     PetscCall(PetscStrlcat(name, "_", PETSC_MAX_PATH_LEN));
433     PetscCall(PetscStrlcat(name, fieldnames[f], PETSC_MAX_PATH_LEN));
434   }
435   PetscCall(PetscObjectSetName((PetscObject)*vec, name));
436 
437   for (PetscInt f = 0; f < Nf; ++f) {
438     PetscInt fid;
439 
440     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldnames[f], &fid));
441     id += fid;
442   }
443   PetscCall(PetscObjectComposedDataSetInt((PetscObject)*vec, SwarmDataFieldId, id));
444 
445   PetscCall(VecSetDM(*vec, sw));
446   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Swarm));
447   PetscFunctionReturn(PETSC_SUCCESS);
448 }
449 
450 /* This creates a "mass matrix" between a finite element and particle space. If a finite element interpolant is given by
451 
452      \hat f = \sum_i f_i \phi_i
453 
454    and a particle function is given by
455 
456      f = \sum_i w_i \delta(x - x_i)
457 
458    then we want to require that
459 
460      M \hat f = M_p f
461 
462    where the particle mass matrix is given by
463 
464      (M_p)_{ij} = \int \phi_i \delta(x - x_j)
465 
466    The way Dave May does particles, they amount to quadratue weights rather than delta functions, so he has |J| is in
467    his integral. We allow this with the boolean flag.
468 */
469 static PetscErrorCode DMSwarmComputeMassMatrix_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
470 {
471   const char   *name = "Mass Matrix";
472   MPI_Comm      comm;
473   DMSwarmCellDM celldm;
474   PetscDS       prob;
475   PetscSection  fsection, globalFSection;
476   PetscHSetIJ   ht;
477   PetscLayout   rLayout, colLayout;
478   PetscInt     *dnz, *onz;
479   PetscInt      locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
480   PetscReal    *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
481   PetscScalar  *elemMat;
482   PetscInt      dim, Nf, Nfc, cStart, cEnd, totDim, maxC = 0, totNc = 0;
483   const char  **coordFields;
484   PetscReal   **coordVals;
485   PetscInt     *bs;
486 
487   PetscFunctionBegin;
488   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
489   PetscCall(DMGetCoordinateDim(dmf, &dim));
490   PetscCall(DMGetDS(dmf, &prob));
491   PetscCall(PetscDSGetNumFields(prob, &Nf));
492   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
493   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
494   PetscCall(DMGetLocalSection(dmf, &fsection));
495   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
496   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
497   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
498 
499   PetscCall(DMSwarmGetCellDMActive(dmc, &celldm));
500   PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields));
501   PetscCall(PetscMalloc2(Nfc, &coordVals, Nfc, &bs));
502 
503   PetscCall(PetscLayoutCreate(comm, &colLayout));
504   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
505   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
506   PetscCall(PetscLayoutSetUp(colLayout));
507   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
508   PetscCall(PetscLayoutDestroy(&colLayout));
509 
510   PetscCall(PetscLayoutCreate(comm, &rLayout));
511   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
512   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
513   PetscCall(PetscLayoutSetUp(rLayout));
514   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
515   PetscCall(PetscLayoutDestroy(&rLayout));
516 
517   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
518   PetscCall(PetscHSetIJCreate(&ht));
519 
520   PetscCall(PetscSynchronizedFlush(comm, NULL));
521   for (PetscInt field = 0; field < Nf; ++field) {
522     PetscObject  obj;
523     PetscClassId id;
524     PetscInt     Nc;
525 
526     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
527     PetscCall(PetscObjectGetClassId(obj, &id));
528     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
529     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
530     totNc += Nc;
531   }
532   /* count non-zeros */
533   PetscCall(DMSwarmSortGetAccess(dmc));
534   for (PetscInt field = 0; field < Nf; ++field) {
535     PetscObject  obj;
536     PetscClassId id;
537     PetscInt     Nc;
538 
539     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
540     PetscCall(PetscObjectGetClassId(obj, &id));
541     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
542     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
543 
544     for (PetscInt cell = cStart; cell < cEnd; ++cell) {
545       PetscInt *findices, *cindices; /* fine is vertices, coarse is particles */
546       PetscInt  numFIndices, numCIndices;
547 
548       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
549       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
550       maxC = PetscMax(maxC, numCIndices);
551       {
552         PetscHashIJKey key;
553         PetscBool      missing;
554         for (PetscInt i = 0; i < numFIndices; ++i) {
555           key.j = findices[i]; /* global column (from Plex) */
556           if (key.j >= 0) {
557             /* Get indices for coarse elements */
558             for (PetscInt j = 0; j < numCIndices; ++j) {
559               for (PetscInt c = 0; c < Nc; ++c) {
560                 // TODO Need field offset on particle here
561                 key.i = cindices[j] * totNc + c + rStart; /* global cols (from Swarm) */
562                 if (key.i < 0) continue;
563                 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
564                 if (missing) {
565                   if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
566                   else ++onz[key.i - rStart];
567                 } else SETERRQ(PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Set new value at %" PetscInt_FMT ",%" PetscInt_FMT, key.i, key.j);
568               }
569             }
570           }
571         }
572         PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
573       }
574       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
575     }
576   }
577   PetscCall(PetscHSetIJDestroy(&ht));
578   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
579   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
580   PetscCall(PetscFree2(dnz, onz));
581   PetscCall(PetscMalloc3(maxC * totNc * totDim, &elemMat, maxC * totNc, &rowIDXs, maxC * dim, &xi));
582   for (PetscInt field = 0; field < Nf; ++field) {
583     PetscTabulation Tcoarse;
584     PetscObject     obj;
585     PetscClassId    id;
586     PetscInt        Nc;
587 
588     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
589     PetscCall(PetscObjectGetClassId(obj, &id));
590     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
591     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
592 
593     for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmGetField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i]));
594     for (PetscInt cell = cStart; cell < cEnd; ++cell) {
595       PetscInt *findices, *cindices;
596       PetscInt  numFIndices, numCIndices;
597 
598       /* TODO: Use DMField instead of assuming affine */
599       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
600       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
601       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
602       for (PetscInt j = 0; j < numCIndices; ++j) {
603         PetscReal xr[8];
604         PetscInt  off = 0;
605 
606         for (PetscInt i = 0; i < Nfc; ++i) {
607           for (PetscInt b = 0; b < bs[i]; ++b, ++off) xr[off] = coordVals[i][cindices[j] * bs[i] + b];
608         }
609         PetscCheck(off == dim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The total block size of coordinates is %" PetscInt_FMT " != %" PetscInt_FMT " the DM coordinate dimension", off, dim);
610         CoordinatesRealToRef(dim, dim, v0ref, v0, invJ, xr, &xi[j * dim]);
611       }
612       if (id == PETSCFE_CLASSID) PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
613       else PetscCall(PetscFVCreateTabulation((PetscFV)obj, 1, numCIndices, xi, 0, &Tcoarse));
614       /* Get elemMat entries by multiplying by weight */
615       PetscCall(PetscArrayzero(elemMat, numCIndices * Nc * totDim));
616       for (PetscInt i = 0; i < numFIndices / Nc; ++i) {
617         for (PetscInt j = 0; j < numCIndices; ++j) {
618           for (PetscInt c = 0; c < Nc; ++c) {
619             // TODO Need field offset on particle and field here
620             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
621             elemMat[(j * totNc + c) * numFIndices + i * Nc + c] += Tcoarse->T[0][(j * numFIndices + i * Nc + c) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
622           }
623         }
624       }
625       for (PetscInt j = 0; j < numCIndices; ++j)
626         // TODO Need field offset on particle here
627         for (PetscInt c = 0; c < Nc; ++c) rowIDXs[j * Nc + c] = cindices[j] * totNc + c + rStart;
628       if (0) PetscCall(DMPrintCellMatrix(cell, name, numCIndices * Nc, numFIndices, elemMat));
629       PetscCall(MatSetValues(mass, numCIndices * Nc, rowIDXs, numFIndices, findices, elemMat, ADD_VALUES));
630       PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
631       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
632       PetscCall(PetscTabulationDestroy(&Tcoarse));
633     }
634     for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmRestoreField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i]));
635   }
636   PetscCall(PetscFree3(elemMat, rowIDXs, xi));
637   PetscCall(DMSwarmSortRestoreAccess(dmc));
638   PetscCall(PetscFree3(v0, J, invJ));
639   PetscCall(PetscFree2(coordVals, bs));
640   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
641   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
642   PetscFunctionReturn(PETSC_SUCCESS);
643 }
644 
645 /* Returns empty matrix for use with SNES FD */
646 static PetscErrorCode DMCreateMatrix_Swarm(DM sw, Mat *m)
647 {
648   Vec      field;
649   PetscInt size;
650 
651   PetscFunctionBegin;
652   PetscCall(DMGetGlobalVector(sw, &field));
653   PetscCall(VecGetLocalSize(field, &size));
654   PetscCall(DMRestoreGlobalVector(sw, &field));
655   PetscCall(MatCreate(PETSC_COMM_WORLD, m));
656   PetscCall(MatSetFromOptions(*m));
657   PetscCall(MatSetSizes(*m, PETSC_DECIDE, PETSC_DECIDE, size, size));
658   PetscCall(MatSeqAIJSetPreallocation(*m, 1, NULL));
659   PetscCall(MatZeroEntries(*m));
660   PetscCall(MatAssemblyBegin(*m, MAT_FINAL_ASSEMBLY));
661   PetscCall(MatAssemblyEnd(*m, MAT_FINAL_ASSEMBLY));
662   PetscCall(MatShift(*m, 1.0));
663   PetscCall(MatSetDM(*m, sw));
664   PetscFunctionReturn(PETSC_SUCCESS);
665 }
666 
667 /* FEM cols, Particle rows */
668 static PetscErrorCode DMCreateMassMatrix_Swarm(DM dmCoarse, DM dmFine, Mat *mass)
669 {
670   DMSwarmCellDM celldm;
671   PetscSection  gsf;
672   PetscInt      m, n, Np, bs;
673   void         *ctx;
674 
675   PetscFunctionBegin;
676   PetscCall(DMSwarmGetCellDMActive(dmCoarse, &celldm));
677   PetscCheck(celldm->Nf, PetscObjectComm((PetscObject)dmCoarse), PETSC_ERR_USER, "Active cell DM does not define any fields");
678   PetscCall(DMGetGlobalSection(dmFine, &gsf));
679   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
680   PetscCall(DMSwarmGetLocalSize(dmCoarse, &Np));
681   PetscCall(DMSwarmCellDMGetBlockSize(celldm, dmCoarse, &bs));
682   n = Np * bs;
683   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
684   PetscCall(MatSetSizes(*mass, n, m, PETSC_DETERMINE, PETSC_DETERMINE));
685   PetscCall(MatSetType(*mass, dmCoarse->mattype));
686   PetscCall(DMGetApplicationContext(dmFine, &ctx));
687 
688   PetscCall(DMSwarmComputeMassMatrix_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
689   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
690   PetscFunctionReturn(PETSC_SUCCESS);
691 }
692 
693 static PetscErrorCode DMSwarmComputeMassMatrixSquare_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
694 {
695   const char   *name = "Mass Matrix Square";
696   MPI_Comm      comm;
697   DMSwarmCellDM celldm;
698   PetscDS       prob;
699   PetscSection  fsection, globalFSection;
700   PetscHSetIJ   ht;
701   PetscLayout   rLayout, colLayout;
702   PetscInt     *dnz, *onz, *adj, depth, maxConeSize, maxSupportSize, maxAdjSize;
703   PetscInt      locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
704   PetscReal    *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
705   PetscScalar  *elemMat, *elemMatSq;
706   PetscInt      cdim, Nf, Nfc, cStart, cEnd, totDim, maxC = 0;
707   const char  **coordFields;
708   PetscReal   **coordVals;
709   PetscInt     *bs;
710 
711   PetscFunctionBegin;
712   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
713   PetscCall(DMGetCoordinateDim(dmf, &cdim));
714   PetscCall(DMGetDS(dmf, &prob));
715   PetscCall(PetscDSGetNumFields(prob, &Nf));
716   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
717   PetscCall(PetscMalloc3(cdim, &v0, cdim * cdim, &J, cdim * cdim, &invJ));
718   PetscCall(DMGetLocalSection(dmf, &fsection));
719   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
720   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
721   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
722 
723   PetscCall(DMSwarmGetCellDMActive(dmc, &celldm));
724   PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields));
725   PetscCall(PetscMalloc2(Nfc, &coordVals, Nfc, &bs));
726 
727   PetscCall(PetscLayoutCreate(comm, &colLayout));
728   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
729   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
730   PetscCall(PetscLayoutSetUp(colLayout));
731   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
732   PetscCall(PetscLayoutDestroy(&colLayout));
733 
734   PetscCall(PetscLayoutCreate(comm, &rLayout));
735   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
736   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
737   PetscCall(PetscLayoutSetUp(rLayout));
738   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
739   PetscCall(PetscLayoutDestroy(&rLayout));
740 
741   PetscCall(DMPlexGetDepth(dmf, &depth));
742   PetscCall(DMPlexGetMaxSizes(dmf, &maxConeSize, &maxSupportSize));
743   maxAdjSize = PetscPowInt(maxConeSize * maxSupportSize, depth);
744   PetscCall(PetscMalloc1(maxAdjSize, &adj));
745 
746   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
747   PetscCall(PetscHSetIJCreate(&ht));
748   /* Count nonzeros
749        This is just FVM++, but we cannot use the Plex P0 allocation since unknowns in a cell will not be contiguous
750   */
751   PetscCall(DMSwarmSortGetAccess(dmc));
752   for (PetscInt cell = cStart; cell < cEnd; ++cell) {
753     PetscInt *cindices;
754     PetscInt  numCIndices;
755 #if 0
756     PetscInt  adjSize = maxAdjSize, a, j;
757 #endif
758 
759     PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
760     maxC = PetscMax(maxC, numCIndices);
761     /* Diagonal block */
762     for (PetscInt i = 0; i < numCIndices; ++i) dnz[cindices[i]] += numCIndices;
763 #if 0
764     /* Off-diagonal blocks */
765     PetscCall(DMPlexGetAdjacency(dmf, cell, &adjSize, &adj));
766     for (a = 0; a < adjSize; ++a) {
767       if (adj[a] >= cStart && adj[a] < cEnd && adj[a] != cell) {
768         const PetscInt ncell = adj[a];
769         PetscInt      *ncindices;
770         PetscInt       numNCIndices;
771 
772         PetscCall(DMSwarmSortGetPointsPerCell(dmc, ncell, &numNCIndices, &ncindices));
773         {
774           PetscHashIJKey key;
775           PetscBool      missing;
776 
777           for (i = 0; i < numCIndices; ++i) {
778             key.i = cindices[i] + rStart; /* global rows (from Swarm) */
779             if (key.i < 0) continue;
780             for (j = 0; j < numNCIndices; ++j) {
781               key.j = ncindices[j] + rStart; /* global column (from Swarm) */
782               if (key.j < 0) continue;
783               PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
784               if (missing) {
785                 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
786                 else                                         ++onz[key.i - rStart];
787               }
788             }
789           }
790         }
791         PetscCall(DMSwarmSortRestorePointsPerCell(dmc, ncell, &numNCIndices, &ncindices));
792       }
793     }
794 #endif
795     PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
796   }
797   PetscCall(PetscHSetIJDestroy(&ht));
798   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
799   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
800   PetscCall(PetscFree2(dnz, onz));
801   PetscCall(PetscMalloc4(maxC * totDim, &elemMat, maxC * maxC, &elemMatSq, maxC, &rowIDXs, maxC * cdim, &xi));
802   /* Fill in values
803        Each entry is a sum of terms \phi_i(x_p) \phi_i(x_q)
804        Start just by producing block diagonal
805        Could loop over adjacent cells
806          Produce neighboring element matrix
807          TODO Determine which columns and rows correspond to shared dual vector
808          Do MatMatMult with rectangular matrices
809          Insert block
810   */
811   for (PetscInt field = 0; field < Nf; ++field) {
812     PetscTabulation Tcoarse;
813     PetscObject     obj;
814     PetscInt        Nc;
815 
816     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
817     PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
818     PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc);
819     for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmGetField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i]));
820     for (PetscInt cell = cStart; cell < cEnd; ++cell) {
821       PetscInt *findices, *cindices;
822       PetscInt  numFIndices, numCIndices;
823 
824       /* TODO: Use DMField instead of assuming affine */
825       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
826       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
827       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
828       for (PetscInt p = 0; p < numCIndices; ++p) {
829         PetscReal xr[8];
830         PetscInt  off = 0;
831 
832         for (PetscInt i = 0; i < Nfc; ++i) {
833           for (PetscInt b = 0; b < bs[i]; ++b, ++off) xr[off] = coordVals[i][cindices[p] * bs[i] + b];
834         }
835         PetscCheck(off == cdim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The total block size of coordinates is %" PetscInt_FMT " != %" PetscInt_FMT " the DM coordinate dimension", off, cdim);
836         CoordinatesRealToRef(cdim, cdim, v0ref, v0, invJ, xr, &xi[p * cdim]);
837       }
838       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
839       /* Get elemMat entries by multiplying by weight */
840       PetscCall(PetscArrayzero(elemMat, numCIndices * totDim));
841       for (PetscInt i = 0; i < numFIndices; ++i) {
842         for (PetscInt p = 0; p < numCIndices; ++p) {
843           for (PetscInt c = 0; c < Nc; ++c) {
844             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
845             elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
846           }
847         }
848       }
849       PetscCall(PetscTabulationDestroy(&Tcoarse));
850       for (PetscInt p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart;
851       if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
852       /* Block diagonal */
853       if (numCIndices) {
854         PetscBLASInt blasn, blask;
855         PetscScalar  one = 1.0, zero = 0.0;
856 
857         PetscCall(PetscBLASIntCast(numCIndices, &blasn));
858         PetscCall(PetscBLASIntCast(numFIndices, &blask));
859         PetscCallBLAS("BLASgemm", BLASgemm_("T", "N", &blasn, &blasn, &blask, &one, elemMat, &blask, elemMat, &blask, &zero, elemMatSq, &blasn));
860       }
861       PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numCIndices, rowIDXs, elemMatSq, ADD_VALUES));
862       /* TODO off-diagonal */
863       PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
864       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
865     }
866     for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmRestoreField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i]));
867   }
868   PetscCall(PetscFree4(elemMat, elemMatSq, rowIDXs, xi));
869   PetscCall(PetscFree(adj));
870   PetscCall(DMSwarmSortRestoreAccess(dmc));
871   PetscCall(PetscFree3(v0, J, invJ));
872   PetscCall(PetscFree2(coordVals, bs));
873   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
874   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
875   PetscFunctionReturn(PETSC_SUCCESS);
876 }
877 
878 /*@
879   DMSwarmCreateMassMatrixSquare - Creates the block-diagonal of the square, M^T_p M_p, of the particle mass matrix M_p
880 
881   Collective
882 
883   Input Parameters:
884 + dmCoarse - a `DMSWARM`
885 - dmFine   - a `DMPLEX`
886 
887   Output Parameter:
888 . mass - the square of the particle mass matrix
889 
890   Level: advanced
891 
892   Note:
893   We only compute the block diagonal since this provides a good preconditioner and is completely local. It would be possible in the
894   future to compute the full normal equations.
895 
896 .seealso: `DM`, `DMSWARM`, `DMCreateMassMatrix()`
897 @*/
898 PetscErrorCode DMSwarmCreateMassMatrixSquare(DM dmCoarse, DM dmFine, Mat *mass)
899 {
900   PetscInt n;
901   void    *ctx;
902 
903   PetscFunctionBegin;
904   PetscCall(DMSwarmGetLocalSize(dmCoarse, &n));
905   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
906   PetscCall(MatSetSizes(*mass, n, n, PETSC_DETERMINE, PETSC_DETERMINE));
907   PetscCall(MatSetType(*mass, dmCoarse->mattype));
908   PetscCall(DMGetApplicationContext(dmFine, &ctx));
909 
910   PetscCall(DMSwarmComputeMassMatrixSquare_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
911   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_sq_mat_view"));
912   PetscFunctionReturn(PETSC_SUCCESS);
913 }
914 
915 /*@
916   DMSwarmCreateGlobalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
917 
918   Collective
919 
920   Input Parameters:
921 + dm        - a `DMSWARM`
922 - fieldname - the textual name given to a registered field
923 
924   Output Parameter:
925 . vec - the vector
926 
927   Level: beginner
928 
929   Note:
930   The vector must be returned using a matching call to `DMSwarmDestroyGlobalVectorFromField()`.
931 
932 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromField()`
933 @*/
934 PetscErrorCode DMSwarmCreateGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
935 {
936   MPI_Comm comm = PetscObjectComm((PetscObject)dm);
937 
938   PetscFunctionBegin;
939   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
940   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
941   PetscFunctionReturn(PETSC_SUCCESS);
942 }
943 
944 /*@
945   DMSwarmDestroyGlobalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
946 
947   Collective
948 
949   Input Parameters:
950 + dm        - a `DMSWARM`
951 - fieldname - the textual name given to a registered field
952 
953   Output Parameter:
954 . vec - the vector
955 
956   Level: beginner
957 
958 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()`
959 @*/
960 PetscErrorCode DMSwarmDestroyGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
961 {
962   PetscFunctionBegin;
963   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
964   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
965   PetscFunctionReturn(PETSC_SUCCESS);
966 }
967 
968 /*@
969   DMSwarmCreateLocalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
970 
971   Collective
972 
973   Input Parameters:
974 + dm        - a `DMSWARM`
975 - fieldname - the textual name given to a registered field
976 
977   Output Parameter:
978 . vec - the vector
979 
980   Level: beginner
981 
982   Note:
983   The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField().
984 
985 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()`
986 @*/
987 PetscErrorCode DMSwarmCreateLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
988 {
989   MPI_Comm comm = PETSC_COMM_SELF;
990 
991   PetscFunctionBegin;
992   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
993   PetscFunctionReturn(PETSC_SUCCESS);
994 }
995 
996 /*@
997   DMSwarmDestroyLocalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
998 
999   Collective
1000 
1001   Input Parameters:
1002 + dm        - a `DMSWARM`
1003 - fieldname - the textual name given to a registered field
1004 
1005   Output Parameter:
1006 . vec - the vector
1007 
1008   Level: beginner
1009 
1010 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromField()`
1011 @*/
1012 PetscErrorCode DMSwarmDestroyLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
1013 {
1014   PetscFunctionBegin;
1015   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
1016   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
1017   PetscFunctionReturn(PETSC_SUCCESS);
1018 }
1019 
1020 /*@
1021   DMSwarmCreateGlobalVectorFromFields - Creates a `Vec` object sharing the array associated with a given field set
1022 
1023   Collective
1024 
1025   Input Parameters:
1026 + dm         - a `DMSWARM`
1027 . Nf         - the number of fields
1028 - fieldnames - the textual names given to the registered fields
1029 
1030   Output Parameter:
1031 . vec - the vector
1032 
1033   Level: beginner
1034 
1035   Notes:
1036   The vector must be returned using a matching call to `DMSwarmDestroyGlobalVectorFromFields()`.
1037 
1038   This vector is copyin-copyout, rather than a direct pointer like `DMSwarmCreateGlobalVectorFromField()`
1039 
1040 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromFields()`
1041 @*/
1042 PetscErrorCode DMSwarmCreateGlobalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec)
1043 {
1044   MPI_Comm comm = PetscObjectComm((PetscObject)dm);
1045 
1046   PetscFunctionBegin;
1047   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
1048   PetscCall(DMSwarmCreateVectorFromFields_Private(dm, Nf, fieldnames, comm, vec));
1049   PetscFunctionReturn(PETSC_SUCCESS);
1050 }
1051 
1052 /*@
1053   DMSwarmDestroyGlobalVectorFromFields - Destroys the `Vec` object which share the array associated with a given field set
1054 
1055   Collective
1056 
1057   Input Parameters:
1058 + dm         - a `DMSWARM`
1059 . Nf         - the number of fields
1060 - fieldnames - the textual names given to the registered fields
1061 
1062   Output Parameter:
1063 . vec - the vector
1064 
1065   Level: beginner
1066 
1067 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()`
1068 @*/
1069 PetscErrorCode DMSwarmDestroyGlobalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec)
1070 {
1071   PetscFunctionBegin;
1072   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
1073   PetscCall(DMSwarmDestroyVectorFromFields_Private(dm, Nf, fieldnames, vec));
1074   PetscFunctionReturn(PETSC_SUCCESS);
1075 }
1076 
1077 /*@
1078   DMSwarmCreateLocalVectorFromFields - Creates a `Vec` object sharing the array associated with a given field set
1079 
1080   Collective
1081 
1082   Input Parameters:
1083 + dm         - a `DMSWARM`
1084 . Nf         - the number of fields
1085 - fieldnames - the textual names given to the registered fields
1086 
1087   Output Parameter:
1088 . vec - the vector
1089 
1090   Level: beginner
1091 
1092   Notes:
1093   The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField().
1094 
1095   This vector is copyin-copyout, rather than a direct pointer like `DMSwarmCreateLocalVectorFromField()`
1096 
1097 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()`
1098 @*/
1099 PetscErrorCode DMSwarmCreateLocalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec)
1100 {
1101   MPI_Comm comm = PETSC_COMM_SELF;
1102 
1103   PetscFunctionBegin;
1104   PetscCall(DMSwarmCreateVectorFromFields_Private(dm, Nf, fieldnames, comm, vec));
1105   PetscFunctionReturn(PETSC_SUCCESS);
1106 }
1107 
1108 /*@
1109   DMSwarmDestroyLocalVectorFromFields - Destroys the `Vec` object which share the array associated with a given field set
1110 
1111   Collective
1112 
1113   Input Parameters:
1114 + dm         - a `DMSWARM`
1115 . Nf         - the number of fields
1116 - fieldnames - the textual names given to the registered fields
1117 
1118   Output Parameter:
1119 . vec - the vector
1120 
1121   Level: beginner
1122 
1123 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromFields()`
1124 @*/
1125 PetscErrorCode DMSwarmDestroyLocalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec)
1126 {
1127   PetscFunctionBegin;
1128   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
1129   PetscCall(DMSwarmDestroyVectorFromFields_Private(dm, Nf, fieldnames, vec));
1130   PetscFunctionReturn(PETSC_SUCCESS);
1131 }
1132 
1133 /*@
1134   DMSwarmInitializeFieldRegister - Initiates the registration of fields to a `DMSWARM`
1135 
1136   Collective
1137 
1138   Input Parameter:
1139 . dm - a `DMSWARM`
1140 
1141   Level: beginner
1142 
1143   Note:
1144   After all fields have been registered, you must call `DMSwarmFinalizeFieldRegister()`.
1145 
1146 .seealso: `DM`, `DMSWARM`, `DMSwarmFinalizeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
1147           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
1148 @*/
1149 PetscErrorCode DMSwarmInitializeFieldRegister(DM dm)
1150 {
1151   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1152 
1153   PetscFunctionBegin;
1154   if (!swarm->field_registration_initialized) {
1155     swarm->field_registration_initialized = PETSC_TRUE;
1156     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_pid, 1, PETSC_INT64)); /* unique identifier */
1157     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_rank, 1, PETSC_INT));  /* used for communication */
1158   }
1159   PetscFunctionReturn(PETSC_SUCCESS);
1160 }
1161 
1162 /*@
1163   DMSwarmFinalizeFieldRegister - Finalizes the registration of fields to a `DMSWARM`
1164 
1165   Collective
1166 
1167   Input Parameter:
1168 . dm - a `DMSWARM`
1169 
1170   Level: beginner
1171 
1172   Note:
1173   After `DMSwarmFinalizeFieldRegister()` has been called, no new fields can be defined on the `DMSWARM`.
1174 
1175 .seealso: `DM`, `DMSWARM`, `DMSwarmInitializeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
1176           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
1177 @*/
1178 PetscErrorCode DMSwarmFinalizeFieldRegister(DM dm)
1179 {
1180   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1181 
1182   PetscFunctionBegin;
1183   if (!swarm->field_registration_finalized) PetscCall(DMSwarmDataBucketFinalize(swarm->db));
1184   swarm->field_registration_finalized = PETSC_TRUE;
1185   PetscFunctionReturn(PETSC_SUCCESS);
1186 }
1187 
1188 /*@
1189   DMSwarmSetLocalSizes - Sets the length of all registered fields on the `DMSWARM`
1190 
1191   Not Collective
1192 
1193   Input Parameters:
1194 + dm     - a `DMSWARM`
1195 . nlocal - the length of each registered field
1196 - buffer - the length of the buffer used to efficient dynamic re-sizing
1197 
1198   Level: beginner
1199 
1200 .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`
1201 @*/
1202 PetscErrorCode DMSwarmSetLocalSizes(DM dm, PetscInt nlocal, PetscInt buffer)
1203 {
1204   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1205 
1206   PetscFunctionBegin;
1207   PetscCall(PetscLogEventBegin(DMSWARM_SetSizes, 0, 0, 0, 0));
1208   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, buffer));
1209   PetscCall(PetscLogEventEnd(DMSWARM_SetSizes, 0, 0, 0, 0));
1210   PetscFunctionReturn(PETSC_SUCCESS);
1211 }
1212 
1213 /*@
1214   DMSwarmSetCellDM - Attaches a `DM` to a `DMSWARM`
1215 
1216   Collective
1217 
1218   Input Parameters:
1219 + sw - a `DMSWARM`
1220 - dm - the `DM` to attach to the `DMSWARM`
1221 
1222   Level: beginner
1223 
1224   Note:
1225   The attached `DM` (dm) will be queried for point location and
1226   neighbor MPI-rank information if `DMSwarmMigrate()` is called.
1227 
1228 .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmGetCellDM()`, `DMSwarmMigrate()`
1229 @*/
1230 PetscErrorCode DMSwarmSetCellDM(DM sw, DM dm)
1231 {
1232   DMSwarmCellDM celldm;
1233   const char   *name;
1234   char         *coordName;
1235 
1236   PetscFunctionBegin;
1237   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
1238   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1239   PetscCall(PetscStrallocpy(DMSwarmPICField_coor, &coordName));
1240   PetscCall(DMSwarmCellDMCreate(dm, 0, NULL, 1, (const char **)&coordName, &celldm));
1241   PetscCall(PetscFree(coordName));
1242   PetscCall(PetscObjectGetName((PetscObject)celldm, &name));
1243   PetscCall(DMSwarmAddCellDM(sw, celldm));
1244   PetscCall(DMSwarmCellDMDestroy(&celldm));
1245   PetscCall(DMSwarmSetCellDMActive(sw, name));
1246   PetscFunctionReturn(PETSC_SUCCESS);
1247 }
1248 
1249 /*@
1250   DMSwarmGetCellDM - Fetches the active cell `DM`
1251 
1252   Collective
1253 
1254   Input Parameter:
1255 . sw - a `DMSWARM`
1256 
1257   Output Parameter:
1258 . dm - the active `DM` for the `DMSWARM`
1259 
1260   Level: beginner
1261 
1262 .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
1263 @*/
1264 PetscErrorCode DMSwarmGetCellDM(DM sw, DM *dm)
1265 {
1266   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
1267   DMSwarmCellDM celldm;
1268 
1269   PetscFunctionBegin;
1270   PetscCall(PetscObjectListFind(swarm->cellDMs, swarm->activeCellDM, (PetscObject *)&celldm));
1271   PetscCheck(celldm, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONG, "There is no cell DM named %s in this Swarm", swarm->activeCellDM);
1272   PetscCall(DMSwarmCellDMGetDM(celldm, dm));
1273   PetscFunctionReturn(PETSC_SUCCESS);
1274 }
1275 
1276 /*@
1277   DMSwarmSetCellDMActive - Activates a cell `DM` for a `DMSWARM`
1278 
1279   Collective
1280 
1281   Input Parameters:
1282 + sw   - a `DMSWARM`
1283 - name - name of the cell `DM` to active for the `DMSWARM`
1284 
1285   Level: beginner
1286 
1287   Note:
1288   The attached `DM` (dmcell) will be queried for point location and
1289   neighbor MPI-rank information if `DMSwarmMigrate()` is called.
1290 
1291 .seealso: `DM`, `DMSWARM`, `DMSwarmCellDM`, `DMSwarmSetType()`, `DMSwarmAddCellDM()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()`
1292 @*/
1293 PetscErrorCode DMSwarmSetCellDMActive(DM sw, const char name[])
1294 {
1295   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
1296   DMSwarmCellDM celldm;
1297 
1298   PetscFunctionBegin;
1299   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
1300   PetscCall(PetscInfo(sw, "Setting cell DM to %s\n", name));
1301   PetscCall(PetscFree(swarm->activeCellDM));
1302   PetscCall(PetscStrallocpy(name, (char **)&swarm->activeCellDM));
1303   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
1304   PetscFunctionReturn(PETSC_SUCCESS);
1305 }
1306 
1307 /*@
1308   DMSwarmGetCellDMActive - Returns the active cell `DM` for a `DMSWARM`
1309 
1310   Collective
1311 
1312   Input Parameter:
1313 . sw - a `DMSWARM`
1314 
1315   Output Parameter:
1316 . celldm - the active `DMSwarmCellDM`
1317 
1318   Level: beginner
1319 
1320 .seealso: `DM`, `DMSWARM`, `DMSwarmCellDM`, `DMSwarmSetType()`, `DMSwarmAddCellDM()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()`
1321 @*/
1322 PetscErrorCode DMSwarmGetCellDMActive(DM sw, DMSwarmCellDM *celldm)
1323 {
1324   DM_Swarm *swarm = (DM_Swarm *)sw->data;
1325 
1326   PetscFunctionBegin;
1327   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
1328   PetscCheck(swarm->activeCellDM, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONGSTATE, "Swarm has no active cell DM");
1329   PetscCall(PetscObjectListFind(swarm->cellDMs, swarm->activeCellDM, (PetscObject *)celldm));
1330   PetscCheck(*celldm, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONGSTATE, "Swarm has invalid cell DM for %s", swarm->activeCellDM);
1331   PetscFunctionReturn(PETSC_SUCCESS);
1332 }
1333 
1334 /*@
1335   DMSwarmAddCellDM - Adds a cell `DM` to the `DMSWARM`
1336 
1337   Collective
1338 
1339   Input Parameters:
1340 + sw     - a `DMSWARM`
1341 - celldm - the `DMSwarmCellDM`
1342 
1343   Level: beginner
1344 
1345   Note:
1346   Cell DMs with the same name will share the cellid field
1347 
1348 .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmPushCellDM()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()`
1349 @*/
1350 PetscErrorCode DMSwarmAddCellDM(DM sw, DMSwarmCellDM celldm)
1351 {
1352   DM_Swarm   *swarm = (DM_Swarm *)sw->data;
1353   const char *name;
1354   PetscInt    dim;
1355   PetscBool   flg;
1356   MPI_Comm    comm;
1357 
1358   PetscFunctionBegin;
1359   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
1360   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
1361   PetscValidHeaderSpecific(celldm, DMSWARMCELLDM_CLASSID, 2);
1362   PetscCall(PetscObjectGetName((PetscObject)celldm, &name));
1363   PetscCall(PetscObjectListAdd(&swarm->cellDMs, name, (PetscObject)celldm));
1364   PetscCall(DMGetDimension(sw, &dim));
1365   for (PetscInt f = 0; f < celldm->Nfc; ++f) {
1366     PetscCall(DMSwarmDataFieldStringInList(celldm->coordFields[f], swarm->db->nfields, (const DMSwarmDataField *)swarm->db->field, &flg));
1367     if (!flg) {
1368       PetscCall(DMSwarmRegisterPetscDatatypeField(sw, celldm->coordFields[f], dim, PETSC_DOUBLE));
1369     } else {
1370       PetscDataType dt;
1371       PetscInt      bs;
1372 
1373       PetscCall(DMSwarmGetFieldInfo(sw, celldm->coordFields[f], &bs, &dt));
1374       PetscCheck(bs == dim, comm, PETSC_ERR_ARG_WRONG, "Coordinate field %s has blocksize %" PetscInt_FMT " != %" PetscInt_FMT " spatial dimension", celldm->coordFields[f], bs, dim);
1375       PetscCheck(dt == PETSC_DOUBLE, comm, PETSC_ERR_ARG_WRONG, "Coordinate field %s has datatype %s != PETSC_DOUBLE", celldm->coordFields[f], PetscDataTypes[dt]);
1376     }
1377   }
1378   // Assume that DMs with the same name share the cellid field
1379   PetscCall(DMSwarmDataFieldStringInList(celldm->cellid, swarm->db->nfields, (const DMSwarmDataField *)swarm->db->field, &flg));
1380   if (!flg) {
1381     PetscBool   isShell, isDummy;
1382     const char *name;
1383 
1384     // Allow dummy DMSHELL (I don't think we should support this mode)
1385     PetscCall(PetscObjectTypeCompare((PetscObject)celldm->dm, DMSHELL, &isShell));
1386     PetscCall(PetscObjectGetName((PetscObject)celldm->dm, &name));
1387     PetscCall(PetscStrcmp(name, "dummy", &isDummy));
1388     if (!isShell || !isDummy) PetscCall(DMSwarmRegisterPetscDatatypeField(sw, celldm->cellid, 1, PETSC_INT));
1389   }
1390   PetscCall(DMSwarmSetCellDMActive(sw, name));
1391   PetscFunctionReturn(PETSC_SUCCESS);
1392 }
1393 
1394 /*@
1395   DMSwarmGetLocalSize - Retrieves the local length of fields registered
1396 
1397   Not Collective
1398 
1399   Input Parameter:
1400 . dm - a `DMSWARM`
1401 
1402   Output Parameter:
1403 . nlocal - the length of each registered field
1404 
1405   Level: beginner
1406 
1407 .seealso: `DM`, `DMSWARM`, `DMSwarmGetSize()`, `DMSwarmSetLocalSizes()`
1408 @*/
1409 PetscErrorCode DMSwarmGetLocalSize(DM dm, PetscInt *nlocal)
1410 {
1411   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1412 
1413   PetscFunctionBegin;
1414   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, nlocal, NULL, NULL));
1415   PetscFunctionReturn(PETSC_SUCCESS);
1416 }
1417 
1418 /*@
1419   DMSwarmGetSize - Retrieves the total length of fields registered
1420 
1421   Collective
1422 
1423   Input Parameter:
1424 . dm - a `DMSWARM`
1425 
1426   Output Parameter:
1427 . n - the total length of each registered field
1428 
1429   Level: beginner
1430 
1431   Note:
1432   This calls `MPI_Allreduce()` upon each call (inefficient but safe)
1433 
1434 .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`, `DMSwarmSetLocalSizes()`
1435 @*/
1436 PetscErrorCode DMSwarmGetSize(DM dm, PetscInt *n)
1437 {
1438   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1439   PetscInt  nlocal;
1440 
1441   PetscFunctionBegin;
1442   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
1443   PetscCallMPI(MPIU_Allreduce(&nlocal, n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
1444   PetscFunctionReturn(PETSC_SUCCESS);
1445 }
1446 
1447 /*@
1448   DMSwarmRegisterPetscDatatypeField - Register a field to a `DMSWARM` with a native PETSc data type
1449 
1450   Collective
1451 
1452   Input Parameters:
1453 + dm        - a `DMSWARM`
1454 . fieldname - the textual name to identify this field
1455 . blocksize - the number of each data type
1456 - type      - a valid PETSc data type (`PETSC_CHAR`, `PETSC_SHORT`, `PETSC_INT`, `PETSC_FLOAT`, `PETSC_REAL`, `PETSC_LONG`)
1457 
1458   Level: beginner
1459 
1460   Notes:
1461   The textual name for each registered field must be unique.
1462 
1463 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
1464 @*/
1465 PetscErrorCode DMSwarmRegisterPetscDatatypeField(DM dm, const char fieldname[], PetscInt blocksize, PetscDataType type)
1466 {
1467   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1468   size_t    size;
1469 
1470   PetscFunctionBegin;
1471   PetscCheck(swarm->field_registration_initialized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmInitializeFieldRegister() first");
1472   PetscCheck(!swarm->field_registration_finalized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Cannot register additional fields after calling DMSwarmFinalizeFieldRegister() first");
1473 
1474   PetscCheck(type != PETSC_OBJECT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
1475   PetscCheck(type != PETSC_FUNCTION, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
1476   PetscCheck(type != PETSC_STRING, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
1477   PetscCheck(type != PETSC_STRUCT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
1478   PetscCheck(type != PETSC_DATATYPE_UNKNOWN, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
1479 
1480   PetscCall(PetscDataTypeGetSize(type, &size));
1481   /* Load a specific data type into data bucket, specifying textual name and its size in bytes */
1482   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterPetscDatatypeField", fieldname, blocksize * size, NULL));
1483   {
1484     DMSwarmDataField gfield;
1485 
1486     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
1487     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
1488   }
1489   swarm->db->field[swarm->db->nfields - 1]->petsc_type = type;
1490   PetscFunctionReturn(PETSC_SUCCESS);
1491 }
1492 
1493 /*@C
1494   DMSwarmRegisterUserStructField - Register a user defined struct to a `DMSWARM`
1495 
1496   Collective
1497 
1498   Input Parameters:
1499 + dm        - a `DMSWARM`
1500 . fieldname - the textual name to identify this field
1501 - size      - the size in bytes of the user struct of each data type
1502 
1503   Level: beginner
1504 
1505   Note:
1506   The textual name for each registered field must be unique.
1507 
1508 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserDatatypeField()`
1509 @*/
1510 PetscErrorCode DMSwarmRegisterUserStructField(DM dm, const char fieldname[], size_t size)
1511 {
1512   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1513 
1514   PetscFunctionBegin;
1515   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserStructField", fieldname, size, NULL));
1516   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_STRUCT;
1517   PetscFunctionReturn(PETSC_SUCCESS);
1518 }
1519 
1520 /*@C
1521   DMSwarmRegisterUserDatatypeField - Register a user defined data type to a `DMSWARM`
1522 
1523   Collective
1524 
1525   Input Parameters:
1526 + dm        - a `DMSWARM`
1527 . fieldname - the textual name to identify this field
1528 . size      - the size in bytes of the user data type
1529 - blocksize - the number of each data type
1530 
1531   Level: beginner
1532 
1533   Note:
1534   The textual name for each registered field must be unique.
1535 
1536 .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserStructField()`
1537 @*/
1538 PetscErrorCode DMSwarmRegisterUserDatatypeField(DM dm, const char fieldname[], size_t size, PetscInt blocksize)
1539 {
1540   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1541 
1542   PetscFunctionBegin;
1543   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserDatatypeField", fieldname, blocksize * size, NULL));
1544   {
1545     DMSwarmDataField gfield;
1546 
1547     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
1548     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
1549   }
1550   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_DATATYPE_UNKNOWN;
1551   PetscFunctionReturn(PETSC_SUCCESS);
1552 }
1553 
1554 /*@C
1555   DMSwarmGetField - Get access to the underlying array storing all entries associated with a registered field
1556 
1557   Not Collective, No Fortran Support
1558 
1559   Input Parameters:
1560 + dm        - a `DMSWARM`
1561 - fieldname - the textual name to identify this field
1562 
1563   Output Parameters:
1564 + blocksize - the number of each data type
1565 . type      - the data type
1566 - data      - pointer to raw array
1567 
1568   Level: beginner
1569 
1570   Notes:
1571   The array must be returned using a matching call to `DMSwarmRestoreField()`.
1572 
1573 .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreField()`
1574 @*/
1575 PetscErrorCode DMSwarmGetField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1576 {
1577   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
1578   DMSwarmDataField gfield;
1579 
1580   PetscFunctionBegin;
1581   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
1582   if (!swarm->issetup) PetscCall(DMSetUp(dm));
1583   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
1584   PetscCall(DMSwarmDataFieldGetAccess(gfield));
1585   PetscCall(DMSwarmDataFieldGetEntries(gfield, data));
1586   if (blocksize) *blocksize = gfield->bs;
1587   if (type) *type = gfield->petsc_type;
1588   PetscFunctionReturn(PETSC_SUCCESS);
1589 }
1590 
1591 /*@C
1592   DMSwarmRestoreField - Restore access to the underlying array storing all entries associated with a registered field
1593 
1594   Not Collective, No Fortran Support
1595 
1596   Input Parameters:
1597 + dm        - a `DMSWARM`
1598 - fieldname - the textual name to identify this field
1599 
1600   Output Parameters:
1601 + blocksize - the number of each data type
1602 . type      - the data type
1603 - data      - pointer to raw array
1604 
1605   Level: beginner
1606 
1607   Notes:
1608   The user must call `DMSwarmGetField()` prior to calling `DMSwarmRestoreField()`.
1609 
1610 .seealso: `DM`, `DMSWARM`, `DMSwarmGetField()`
1611 @*/
1612 PetscErrorCode DMSwarmRestoreField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1613 {
1614   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
1615   DMSwarmDataField gfield;
1616 
1617   PetscFunctionBegin;
1618   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
1619   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
1620   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
1621   if (data) *data = NULL;
1622   PetscFunctionReturn(PETSC_SUCCESS);
1623 }
1624 
1625 PetscErrorCode DMSwarmGetFieldInfo(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type)
1626 {
1627   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
1628   DMSwarmDataField gfield;
1629 
1630   PetscFunctionBegin;
1631   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
1632   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
1633   if (blocksize) *blocksize = gfield->bs;
1634   if (type) *type = gfield->petsc_type;
1635   PetscFunctionReturn(PETSC_SUCCESS);
1636 }
1637 
1638 /*@
1639   DMSwarmAddPoint - Add space for one new point in the `DMSWARM`
1640 
1641   Not Collective
1642 
1643   Input Parameter:
1644 . dm - a `DMSWARM`
1645 
1646   Level: beginner
1647 
1648   Notes:
1649   The new point will have all fields initialized to zero.
1650 
1651 .seealso: `DM`, `DMSWARM`, `DMSwarmAddNPoints()`
1652 @*/
1653 PetscErrorCode DMSwarmAddPoint(DM dm)
1654 {
1655   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1656 
1657   PetscFunctionBegin;
1658   if (!swarm->issetup) PetscCall(DMSetUp(dm));
1659   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
1660   PetscCall(DMSwarmDataBucketAddPoint(swarm->db));
1661   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
1662   PetscFunctionReturn(PETSC_SUCCESS);
1663 }
1664 
1665 /*@
1666   DMSwarmAddNPoints - Add space for a number of new points in the `DMSWARM`
1667 
1668   Not Collective
1669 
1670   Input Parameters:
1671 + dm      - a `DMSWARM`
1672 - npoints - the number of new points to add
1673 
1674   Level: beginner
1675 
1676   Notes:
1677   The new point will have all fields initialized to zero.
1678 
1679 .seealso: `DM`, `DMSWARM`, `DMSwarmAddPoint()`
1680 @*/
1681 PetscErrorCode DMSwarmAddNPoints(DM dm, PetscInt npoints)
1682 {
1683   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1684   PetscInt  nlocal;
1685 
1686   PetscFunctionBegin;
1687   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
1688   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
1689   nlocal = nlocal + npoints;
1690   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
1691   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
1692   PetscFunctionReturn(PETSC_SUCCESS);
1693 }
1694 
1695 /*@
1696   DMSwarmRemovePoint - Remove the last point from the `DMSWARM`
1697 
1698   Not Collective
1699 
1700   Input Parameter:
1701 . dm - a `DMSWARM`
1702 
1703   Level: beginner
1704 
1705 .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePointAtIndex()`
1706 @*/
1707 PetscErrorCode DMSwarmRemovePoint(DM dm)
1708 {
1709   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1710 
1711   PetscFunctionBegin;
1712   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
1713   PetscCall(DMSwarmDataBucketRemovePoint(swarm->db));
1714   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
1715   PetscFunctionReturn(PETSC_SUCCESS);
1716 }
1717 
1718 /*@
1719   DMSwarmRemovePointAtIndex - Removes a specific point from the `DMSWARM`
1720 
1721   Not Collective
1722 
1723   Input Parameters:
1724 + dm  - a `DMSWARM`
1725 - idx - index of point to remove
1726 
1727   Level: beginner
1728 
1729 .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
1730 @*/
1731 PetscErrorCode DMSwarmRemovePointAtIndex(DM dm, PetscInt idx)
1732 {
1733   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1734 
1735   PetscFunctionBegin;
1736   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
1737   PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, idx));
1738   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
1739   PetscFunctionReturn(PETSC_SUCCESS);
1740 }
1741 
1742 /*@
1743   DMSwarmCopyPoint - Copy point pj to point pi in the `DMSWARM`
1744 
1745   Not Collective
1746 
1747   Input Parameters:
1748 + dm - a `DMSWARM`
1749 . pi - the index of the point to copy
1750 - pj - the point index where the copy should be located
1751 
1752   Level: beginner
1753 
1754 .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
1755 @*/
1756 PetscErrorCode DMSwarmCopyPoint(DM dm, PetscInt pi, PetscInt pj)
1757 {
1758   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1759 
1760   PetscFunctionBegin;
1761   if (!swarm->issetup) PetscCall(DMSetUp(dm));
1762   PetscCall(DMSwarmDataBucketCopyPoint(swarm->db, pi, swarm->db, pj));
1763   PetscFunctionReturn(PETSC_SUCCESS);
1764 }
1765 
1766 static PetscErrorCode DMSwarmMigrate_Basic(DM dm, PetscBool remove_sent_points)
1767 {
1768   PetscFunctionBegin;
1769   PetscCall(DMSwarmMigrate_Push_Basic(dm, remove_sent_points));
1770   PetscFunctionReturn(PETSC_SUCCESS);
1771 }
1772 
1773 /*@
1774   DMSwarmMigrate - Relocates points defined in the `DMSWARM` to other MPI-ranks
1775 
1776   Collective
1777 
1778   Input Parameters:
1779 + dm                 - the `DMSWARM`
1780 - remove_sent_points - flag indicating if sent points should be removed from the current MPI-rank
1781 
1782   Level: advanced
1783 
1784   Notes:
1785   The `DM` will be modified to accommodate received points.
1786   If `remove_sent_points` is `PETSC_TRUE`, any points that were sent will be removed from the `DM`.
1787   Different styles of migration are supported. See `DMSwarmSetMigrateType()`.
1788 
1789 .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`
1790 @*/
1791 PetscErrorCode DMSwarmMigrate(DM dm, PetscBool remove_sent_points)
1792 {
1793   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1794 
1795   PetscFunctionBegin;
1796   PetscCall(PetscLogEventBegin(DMSWARM_Migrate, 0, 0, 0, 0));
1797   switch (swarm->migrate_type) {
1798   case DMSWARM_MIGRATE_BASIC:
1799     PetscCall(DMSwarmMigrate_Basic(dm, remove_sent_points));
1800     break;
1801   case DMSWARM_MIGRATE_DMCELLNSCATTER:
1802     PetscCall(DMSwarmMigrate_CellDMScatter(dm, remove_sent_points));
1803     break;
1804   case DMSWARM_MIGRATE_DMCELLEXACT:
1805     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_DMCELLEXACT not implemented");
1806   case DMSWARM_MIGRATE_USER:
1807     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_USER not implemented");
1808   default:
1809     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE type unknown");
1810   }
1811   PetscCall(PetscLogEventEnd(DMSWARM_Migrate, 0, 0, 0, 0));
1812   PetscCall(DMClearGlobalVectors(dm));
1813   PetscFunctionReturn(PETSC_SUCCESS);
1814 }
1815 
1816 PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm, PetscInt *globalsize);
1817 
1818 /*
1819  DMSwarmCollectViewCreate
1820 
1821  * Applies a collection method and gathers point neighbour points into dm
1822 
1823  Notes:
1824  Users should call DMSwarmCollectViewDestroy() after
1825  they have finished computations associated with the collected points
1826 */
1827 
1828 /*@
1829   DMSwarmCollectViewCreate - Applies a collection method and gathers points
1830   in neighbour ranks into the `DMSWARM`
1831 
1832   Collective
1833 
1834   Input Parameter:
1835 . dm - the `DMSWARM`
1836 
1837   Level: advanced
1838 
1839   Notes:
1840   Users should call `DMSwarmCollectViewDestroy()` after
1841   they have finished computations associated with the collected points
1842 
1843   Different collect methods are supported. See `DMSwarmSetCollectType()`.
1844 
1845   Developer Note:
1846   Create and Destroy routines create new objects that can get destroyed, they do not change the state
1847   of the current object.
1848 
1849 .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewDestroy()`, `DMSwarmSetCollectType()`
1850 @*/
1851 PetscErrorCode DMSwarmCollectViewCreate(DM dm)
1852 {
1853   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1854   PetscInt  ng;
1855 
1856   PetscFunctionBegin;
1857   PetscCheck(!swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView currently active");
1858   PetscCall(DMSwarmGetLocalSize(dm, &ng));
1859   switch (swarm->collect_type) {
1860   case DMSWARM_COLLECT_BASIC:
1861     PetscCall(DMSwarmMigrate_GlobalToLocal_Basic(dm, &ng));
1862     break;
1863   case DMSWARM_COLLECT_DMDABOUNDINGBOX:
1864     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_DMDABOUNDINGBOX not implemented");
1865   case DMSWARM_COLLECT_GENERAL:
1866     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_GENERAL not implemented");
1867   default:
1868     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT type unknown");
1869   }
1870   swarm->collect_view_active       = PETSC_TRUE;
1871   swarm->collect_view_reset_nlocal = ng;
1872   PetscFunctionReturn(PETSC_SUCCESS);
1873 }
1874 
1875 /*@
1876   DMSwarmCollectViewDestroy - Resets the `DMSWARM` to the size prior to calling `DMSwarmCollectViewCreate()`
1877 
1878   Collective
1879 
1880   Input Parameters:
1881 . dm - the `DMSWARM`
1882 
1883   Notes:
1884   Users should call `DMSwarmCollectViewCreate()` before this function is called.
1885 
1886   Level: advanced
1887 
1888   Developer Note:
1889   Create and Destroy routines create new objects that can get destroyed, they do not change the state
1890   of the current object.
1891 
1892 .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewCreate()`, `DMSwarmSetCollectType()`
1893 @*/
1894 PetscErrorCode DMSwarmCollectViewDestroy(DM dm)
1895 {
1896   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1897 
1898   PetscFunctionBegin;
1899   PetscCheck(swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView is currently not active");
1900   PetscCall(DMSwarmSetLocalSizes(dm, swarm->collect_view_reset_nlocal, -1));
1901   swarm->collect_view_active = PETSC_FALSE;
1902   PetscFunctionReturn(PETSC_SUCCESS);
1903 }
1904 
1905 static PetscErrorCode DMSwarmSetUpPIC(DM dm)
1906 {
1907   PetscInt dim;
1908 
1909   PetscFunctionBegin;
1910   PetscCall(DMSwarmSetNumSpecies(dm, 1));
1911   PetscCall(DMGetDimension(dm, &dim));
1912   PetscCheck(dim >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
1913   PetscCheck(dim <= 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
1914   PetscFunctionReturn(PETSC_SUCCESS);
1915 }
1916 
1917 /*@
1918   DMSwarmSetPointCoordinatesRandom - Sets initial coordinates for particles in each cell
1919 
1920   Collective
1921 
1922   Input Parameters:
1923 + dm  - the `DMSWARM`
1924 - Npc - The number of particles per cell in the cell `DM`
1925 
1926   Level: intermediate
1927 
1928   Notes:
1929   The user must use `DMSwarmSetCellDM()` to set the cell `DM` first. The particles are placed randomly inside each cell. If only
1930   one particle is in each cell, it is placed at the centroid.
1931 
1932 .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
1933 @*/
1934 PetscErrorCode DMSwarmSetPointCoordinatesRandom(DM dm, PetscInt Npc)
1935 {
1936   DM             cdm;
1937   DMSwarmCellDM  celldm;
1938   PetscRandom    rnd;
1939   DMPolytopeType ct;
1940   PetscBool      simplex;
1941   PetscReal     *centroid, *coords, *xi0, *v0, *J, *invJ, detJ;
1942   PetscInt       dim, d, cStart, cEnd, c, p, Nfc;
1943   const char   **coordFields;
1944 
1945   PetscFunctionBeginUser;
1946   PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm), &rnd));
1947   PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0));
1948   PetscCall(PetscRandomSetType(rnd, PETSCRAND48));
1949 
1950   PetscCall(DMSwarmGetCellDMActive(dm, &celldm));
1951   PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields));
1952   PetscCheck(Nfc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "We only support a single coordinate field right now, not %" PetscInt_FMT, Nfc);
1953   PetscCall(DMSwarmGetCellDM(dm, &cdm));
1954   PetscCall(DMGetDimension(cdm, &dim));
1955   PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd));
1956   PetscCall(DMPlexGetCellType(cdm, cStart, &ct));
1957   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
1958 
1959   PetscCall(PetscMalloc5(dim, &centroid, dim, &xi0, dim, &v0, dim * dim, &J, dim * dim, &invJ));
1960   for (d = 0; d < dim; ++d) xi0[d] = -1.0;
1961   PetscCall(DMSwarmGetField(dm, coordFields[0], NULL, NULL, (void **)&coords));
1962   for (c = cStart; c < cEnd; ++c) {
1963     if (Npc == 1) {
1964       PetscCall(DMPlexComputeCellGeometryFVM(cdm, c, NULL, centroid, NULL));
1965       for (d = 0; d < dim; ++d) coords[c * dim + d] = centroid[d];
1966     } else {
1967       PetscCall(DMPlexComputeCellGeometryFEM(cdm, c, NULL, v0, J, invJ, &detJ)); /* affine */
1968       for (p = 0; p < Npc; ++p) {
1969         const PetscInt n   = c * Npc + p;
1970         PetscReal      sum = 0.0, refcoords[3];
1971 
1972         for (d = 0; d < dim; ++d) {
1973           PetscCall(PetscRandomGetValueReal(rnd, &refcoords[d]));
1974           sum += refcoords[d];
1975         }
1976         if (simplex && sum > 0.0)
1977           for (d = 0; d < dim; ++d) refcoords[d] -= PetscSqrtReal(dim) * sum;
1978         CoordinatesRefToReal(dim, dim, xi0, v0, J, refcoords, &coords[n * dim]);
1979       }
1980     }
1981   }
1982   PetscCall(DMSwarmRestoreField(dm, coordFields[0], NULL, NULL, (void **)&coords));
1983   PetscCall(PetscFree5(centroid, xi0, v0, J, invJ));
1984   PetscCall(PetscRandomDestroy(&rnd));
1985   PetscFunctionReturn(PETSC_SUCCESS);
1986 }
1987 
1988 /*@
1989   DMSwarmSetType - Set particular flavor of `DMSWARM`
1990 
1991   Collective
1992 
1993   Input Parameters:
1994 + dm    - the `DMSWARM`
1995 - stype - the `DMSWARM` type (e.g. `DMSWARM_PIC`)
1996 
1997   Level: advanced
1998 
1999 .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`, `DMSwarmSetCollectType()`, `DMSwarmType`, `DMSWARM_PIC`, `DMSWARM_BASIC`
2000 @*/
2001 PetscErrorCode DMSwarmSetType(DM dm, DMSwarmType stype)
2002 {
2003   DM_Swarm *swarm = (DM_Swarm *)dm->data;
2004 
2005   PetscFunctionBegin;
2006   swarm->swarm_type = stype;
2007   if (swarm->swarm_type == DMSWARM_PIC) PetscCall(DMSwarmSetUpPIC(dm));
2008   PetscFunctionReturn(PETSC_SUCCESS);
2009 }
2010 
2011 static PetscErrorCode DMSetup_Swarm(DM dm)
2012 {
2013   DM_Swarm   *swarm = (DM_Swarm *)dm->data;
2014   PetscMPIInt rank;
2015   PetscInt    p, npoints, *rankval;
2016 
2017   PetscFunctionBegin;
2018   if (swarm->issetup) PetscFunctionReturn(PETSC_SUCCESS);
2019   swarm->issetup = PETSC_TRUE;
2020 
2021   if (swarm->swarm_type == DMSWARM_PIC) {
2022     DMSwarmCellDM celldm;
2023 
2024     PetscCall(DMSwarmGetCellDMActive(dm, &celldm));
2025     PetscCheck(celldm, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "No active cell DM. DMSWARM_PIC requires you call DMSwarmSetCellDM() or DMSwarmAddCellDM()");
2026     if (celldm->dm->ops->locatepointssubdomain) {
2027       /* check methods exists for exact ownership identificiation */
2028       PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->ops->LocatePointsSubdomain\n"));
2029       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLEXACT;
2030     } else {
2031       /* check methods exist for point location AND rank neighbor identification */
2032       if (celldm->dm->ops->locatepoints) {
2033         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->LocatePoints\n"));
2034       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->locatepoints be defined");
2035 
2036       if (celldm->dm->ops->getneighbors) {
2037         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->GetNeigbors\n"));
2038       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->getneighbors be defined");
2039 
2040       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLNSCATTER;
2041     }
2042   }
2043 
2044   PetscCall(DMSwarmFinalizeFieldRegister(dm));
2045 
2046   /* check some fields were registered */
2047   PetscCheck(swarm->db->nfields > 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "At least one field user must be registered via DMSwarmRegisterXXX()");
2048 
2049   /* check local sizes were set */
2050   PetscCheck(swarm->db->L != -1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Local sizes must be set via DMSwarmSetLocalSizes()");
2051 
2052   /* initialize values in pid and rank placeholders */
2053   /* TODO: [pid - use MPI_Scan] */
2054   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
2055   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
2056   PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
2057   for (p = 0; p < npoints; p++) rankval[p] = rank;
2058   PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
2059   PetscFunctionReturn(PETSC_SUCCESS);
2060 }
2061 
2062 static PetscErrorCode DMDestroy_Swarm(DM dm)
2063 {
2064   DM_Swarm *swarm = (DM_Swarm *)dm->data;
2065 
2066   PetscFunctionBegin;
2067   if (--swarm->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
2068   PetscCall(PetscObjectListDestroy(&swarm->cellDMs));
2069   PetscCall(PetscFree(swarm->activeCellDM));
2070   PetscCall(DMSwarmDataBucketDestroy(&swarm->db));
2071   PetscCall(PetscFree(swarm));
2072   PetscFunctionReturn(PETSC_SUCCESS);
2073 }
2074 
2075 static PetscErrorCode DMSwarmView_Draw(DM dm, PetscViewer viewer)
2076 {
2077   DM            cdm;
2078   DMSwarmCellDM celldm;
2079   PetscDraw     draw;
2080   PetscReal    *coords, oldPause, radius = 0.01;
2081   PetscInt      Np, p, bs, Nfc;
2082   const char  **coordFields;
2083 
2084   PetscFunctionBegin;
2085   PetscCall(PetscOptionsGetReal(NULL, ((PetscObject)dm)->prefix, "-dm_view_swarm_radius", &radius, NULL));
2086   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2087   PetscCall(DMSwarmGetCellDM(dm, &cdm));
2088   PetscCall(PetscDrawGetPause(draw, &oldPause));
2089   PetscCall(PetscDrawSetPause(draw, 0.0));
2090   PetscCall(DMView(cdm, viewer));
2091   PetscCall(PetscDrawSetPause(draw, oldPause));
2092 
2093   PetscCall(DMSwarmGetCellDMActive(dm, &celldm));
2094   PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields));
2095   PetscCheck(Nfc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "We only support a single coordinate field right now, not %" PetscInt_FMT, Nfc);
2096   PetscCall(DMSwarmGetLocalSize(dm, &Np));
2097   PetscCall(DMSwarmGetField(dm, coordFields[0], &bs, NULL, (void **)&coords));
2098   for (p = 0; p < Np; ++p) {
2099     const PetscInt i = p * bs;
2100 
2101     PetscCall(PetscDrawEllipse(draw, coords[i], coords[i + 1], radius, radius, PETSC_DRAW_BLUE));
2102   }
2103   PetscCall(DMSwarmRestoreField(dm, coordFields[0], &bs, NULL, (void **)&coords));
2104   PetscCall(PetscDrawFlush(draw));
2105   PetscCall(PetscDrawPause(draw));
2106   PetscCall(PetscDrawSave(draw));
2107   PetscFunctionReturn(PETSC_SUCCESS);
2108 }
2109 
2110 static PetscErrorCode DMView_Swarm_Ascii(DM dm, PetscViewer viewer)
2111 {
2112   PetscViewerFormat format;
2113   PetscInt         *sizes;
2114   PetscInt          dim, Np, maxSize = 17;
2115   MPI_Comm          comm;
2116   PetscMPIInt       rank, size, p;
2117   const char       *name, *cellid;
2118 
2119   PetscFunctionBegin;
2120   PetscCall(PetscViewerGetFormat(viewer, &format));
2121   PetscCall(DMGetDimension(dm, &dim));
2122   PetscCall(DMSwarmGetLocalSize(dm, &Np));
2123   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2124   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2125   PetscCallMPI(MPI_Comm_size(comm, &size));
2126   PetscCall(PetscObjectGetName((PetscObject)dm, &name));
2127   if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
2128   else PetscCall(PetscViewerASCIIPrintf(viewer, "Swarm in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
2129   if (size < maxSize) PetscCall(PetscCalloc1(size, &sizes));
2130   else PetscCall(PetscCalloc1(3, &sizes));
2131   if (size < maxSize) {
2132     PetscCallMPI(MPI_Gather(&Np, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
2133     PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of particles per rank:"));
2134     for (p = 0; p < size; ++p) {
2135       if (rank == 0) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]));
2136     }
2137   } else {
2138     PetscInt locMinMax[2] = {Np, Np};
2139 
2140     PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
2141     PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of particles per rank: %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
2142   }
2143   PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
2144   PetscCall(PetscFree(sizes));
2145   if (format == PETSC_VIEWER_ASCII_INFO) {
2146     DMSwarmCellDM celldm;
2147     PetscInt     *cell;
2148 
2149     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells containing each particle:\n"));
2150     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
2151     PetscCall(DMSwarmGetCellDMActive(dm, &celldm));
2152     PetscCall(DMSwarmCellDMGetCellID(celldm, &cellid));
2153     PetscCall(DMSwarmGetField(dm, cellid, NULL, NULL, (void **)&cell));
2154     for (p = 0; p < Np; ++p) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  p%d: %" PetscInt_FMT "\n", p, cell[p]));
2155     PetscCall(PetscViewerFlush(viewer));
2156     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2157     PetscCall(DMSwarmRestoreField(dm, cellid, NULL, NULL, (void **)&cell));
2158   }
2159   PetscFunctionReturn(PETSC_SUCCESS);
2160 }
2161 
2162 static PetscErrorCode DMView_Swarm(DM dm, PetscViewer viewer)
2163 {
2164   DM_Swarm *swarm = (DM_Swarm *)dm->data;
2165   PetscBool iascii, ibinary, isvtk, isdraw, ispython;
2166 #if defined(PETSC_HAVE_HDF5)
2167   PetscBool ishdf5;
2168 #endif
2169 
2170   PetscFunctionBegin;
2171   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2172   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2173   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
2174   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary));
2175   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
2176 #if defined(PETSC_HAVE_HDF5)
2177   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2178 #endif
2179   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
2180   PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython));
2181   if (iascii) {
2182     PetscViewerFormat format;
2183 
2184     PetscCall(PetscViewerGetFormat(viewer, &format));
2185     switch (format) {
2186     case PETSC_VIEWER_ASCII_INFO_DETAIL:
2187       PetscCall(DMSwarmDataBucketView(PetscObjectComm((PetscObject)dm), swarm->db, NULL, DATABUCKET_VIEW_STDOUT));
2188       break;
2189     default:
2190       PetscCall(DMView_Swarm_Ascii(dm, viewer));
2191     }
2192   } else {
2193 #if defined(PETSC_HAVE_HDF5)
2194     if (ishdf5) PetscCall(DMSwarmView_HDF5(dm, viewer));
2195 #endif
2196     if (isdraw) PetscCall(DMSwarmView_Draw(dm, viewer));
2197     if (ispython) PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm));
2198   }
2199   PetscFunctionReturn(PETSC_SUCCESS);
2200 }
2201 
2202 /*@
2203   DMSwarmGetCellSwarm - Extracts a single cell from the `DMSWARM` object, returns it as a single cell `DMSWARM`.
2204   The cell `DM` is filtered for fields of that cell, and the filtered `DM` is used as the cell `DM` of the new swarm object.
2205 
2206   Noncollective
2207 
2208   Input Parameters:
2209 + sw        - the `DMSWARM`
2210 . cellID    - the integer id of the cell to be extracted and filtered
2211 - cellswarm - The `DMSWARM` to receive the cell
2212 
2213   Level: beginner
2214 
2215   Notes:
2216   This presently only supports `DMSWARM_PIC` type
2217 
2218   Should be restored with `DMSwarmRestoreCellSwarm()`
2219 
2220   Changes to this cell of the swarm will be lost if they are made prior to restoring this cell.
2221 
2222 .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreCellSwarm()`
2223 @*/
2224 PetscErrorCode DMSwarmGetCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
2225 {
2226   DM_Swarm   *original = (DM_Swarm *)sw->data;
2227   DMLabel     label;
2228   DM          dmc, subdmc;
2229   PetscInt   *pids, particles, dim;
2230   const char *name;
2231 
2232   PetscFunctionBegin;
2233   /* Configure new swarm */
2234   PetscCall(DMSetType(cellswarm, DMSWARM));
2235   PetscCall(DMGetDimension(sw, &dim));
2236   PetscCall(DMSetDimension(cellswarm, dim));
2237   PetscCall(DMSwarmSetType(cellswarm, DMSWARM_PIC));
2238   /* Destroy the unused, unconfigured data bucket to prevent stragglers in memory */
2239   PetscCall(DMSwarmDataBucketDestroy(&((DM_Swarm *)cellswarm->data)->db));
2240   PetscCall(DMSwarmSortGetAccess(sw));
2241   PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, cellID, &particles));
2242   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
2243   PetscCall(DMSwarmDataBucketCreateFromSubset(original->db, particles, pids, &((DM_Swarm *)cellswarm->data)->db));
2244   PetscCall(DMSwarmSortRestoreAccess(sw));
2245   PetscCall(DMSwarmSortRestorePointsPerCell(sw, cellID, &particles, &pids));
2246   PetscCall(DMSwarmGetCellDM(sw, &dmc));
2247   PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)sw), "singlecell", &label));
2248   PetscCall(DMAddLabel(dmc, label));
2249   PetscCall(DMLabelSetValue(label, cellID, 1));
2250   PetscCall(DMPlexFilter(dmc, label, 1, PETSC_FALSE, PETSC_FALSE, NULL, &subdmc));
2251   PetscCall(PetscObjectGetName((PetscObject)dmc, &name));
2252   PetscCall(PetscObjectSetName((PetscObject)subdmc, name));
2253   PetscCall(DMSwarmSetCellDM(cellswarm, subdmc));
2254   PetscCall(DMLabelDestroy(&label));
2255   PetscFunctionReturn(PETSC_SUCCESS);
2256 }
2257 
2258 /*@
2259   DMSwarmRestoreCellSwarm - Restores a `DMSWARM` object obtained with `DMSwarmGetCellSwarm()`. All fields are copied back into the parent swarm.
2260 
2261   Noncollective
2262 
2263   Input Parameters:
2264 + sw        - the parent `DMSWARM`
2265 . cellID    - the integer id of the cell to be copied back into the parent swarm
2266 - cellswarm - the cell swarm object
2267 
2268   Level: beginner
2269 
2270   Note:
2271   This only supports `DMSWARM_PIC` types of `DMSWARM`s
2272 
2273 .seealso: `DM`, `DMSWARM`, `DMSwarmGetCellSwarm()`
2274 @*/
2275 PetscErrorCode DMSwarmRestoreCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
2276 {
2277   DM        dmc;
2278   PetscInt *pids, particles, p;
2279 
2280   PetscFunctionBegin;
2281   PetscCall(DMSwarmSortGetAccess(sw));
2282   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
2283   PetscCall(DMSwarmSortRestoreAccess(sw));
2284   /* Pointwise copy of each particle based on pid. The parent swarm may not be altered during this process. */
2285   for (p = 0; p < particles; ++p) PetscCall(DMSwarmDataBucketCopyPoint(((DM_Swarm *)cellswarm->data)->db, pids[p], ((DM_Swarm *)sw->data)->db, pids[p]));
2286   /* Free memory, destroy cell dm */
2287   PetscCall(DMSwarmGetCellDM(cellswarm, &dmc));
2288   PetscCall(DMDestroy(&dmc));
2289   PetscCall(DMSwarmSortRestorePointsPerCell(sw, cellID, &particles, &pids));
2290   PetscFunctionReturn(PETSC_SUCCESS);
2291 }
2292 
2293 /*@
2294   DMSwarmComputeMoments - Compute the first three particle moments for a given field
2295 
2296   Noncollective
2297 
2298   Input Parameters:
2299 + sw         - the `DMSWARM`
2300 . coordinate - the coordinate field name
2301 - weight     - the weight field name
2302 
2303   Output Parameter:
2304 . moments - the field moments
2305 
2306   Level: intermediate
2307 
2308   Notes:
2309   The `moments` array should be of length bs + 2, where bs is the block size of the coordinate field.
2310 
2311   The weight field must be a scalar, having blocksize 1.
2312 
2313 .seealso: `DM`, `DMSWARM`, `DMPlexComputeMoments()`
2314 @*/
2315 PetscErrorCode DMSwarmComputeMoments(DM sw, const char coordinate[], const char weight[], PetscReal moments[])
2316 {
2317   const PetscReal *coords;
2318   const PetscReal *w;
2319   PetscReal       *mom;
2320   PetscDataType    dtc, dtw;
2321   PetscInt         bsc, bsw, Np;
2322   MPI_Comm         comm;
2323 
2324   PetscFunctionBegin;
2325   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
2326   PetscAssertPointer(coordinate, 2);
2327   PetscAssertPointer(weight, 3);
2328   PetscAssertPointer(moments, 4);
2329   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
2330   PetscCall(DMSwarmGetField(sw, coordinate, &bsc, &dtc, (void **)&coords));
2331   PetscCall(DMSwarmGetField(sw, weight, &bsw, &dtw, (void **)&w));
2332   PetscCheck(dtc == PETSC_REAL, comm, PETSC_ERR_ARG_WRONG, "Coordinate field %s must be real, not %s", coordinate, PetscDataTypes[dtc]);
2333   PetscCheck(dtw == PETSC_REAL, comm, PETSC_ERR_ARG_WRONG, "Weight field %s must be real, not %s", weight, PetscDataTypes[dtw]);
2334   PetscCheck(bsw == 1, comm, PETSC_ERR_ARG_WRONG, "Weight field %s must be a scalar, not blocksize %" PetscInt_FMT, weight, bsw);
2335   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2336   PetscCall(DMGetWorkArray(sw, bsc + 2, MPIU_REAL, &mom));
2337   PetscCall(PetscArrayzero(mom, bsc + 2));
2338   for (PetscInt p = 0; p < Np; ++p) {
2339     const PetscReal *c  = &coords[p * bsc];
2340     const PetscReal  wp = w[p];
2341 
2342     mom[0] += wp;
2343     for (PetscInt d = 0; d < bsc; ++d) {
2344       mom[d + 1] += wp * c[d];
2345       mom[d + bsc + 1] += wp * PetscSqr(c[d]);
2346     }
2347   }
2348   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&coords));
2349   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w));
2350   PetscCallMPI(MPIU_Allreduce(mom, moments, bsc + 2, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)sw)));
2351   PetscCall(DMRestoreWorkArray(sw, bsc + 2, MPIU_REAL, &mom));
2352   PetscFunctionReturn(PETSC_SUCCESS);
2353 }
2354 
2355 PETSC_INTERN PetscErrorCode DMClone_Swarm(DM, DM *);
2356 
2357 static PetscErrorCode DMInitialize_Swarm(DM sw)
2358 {
2359   PetscFunctionBegin;
2360   sw->ops->view                     = DMView_Swarm;
2361   sw->ops->load                     = NULL;
2362   sw->ops->setfromoptions           = NULL;
2363   sw->ops->clone                    = DMClone_Swarm;
2364   sw->ops->setup                    = DMSetup_Swarm;
2365   sw->ops->createlocalsection       = NULL;
2366   sw->ops->createsectionpermutation = NULL;
2367   sw->ops->createdefaultconstraints = NULL;
2368   sw->ops->createglobalvector       = DMCreateGlobalVector_Swarm;
2369   sw->ops->createlocalvector        = DMCreateLocalVector_Swarm;
2370   sw->ops->getlocaltoglobalmapping  = NULL;
2371   sw->ops->createfieldis            = NULL;
2372   sw->ops->createcoordinatedm       = NULL;
2373   sw->ops->getcoloring              = NULL;
2374   sw->ops->creatematrix             = DMCreateMatrix_Swarm;
2375   sw->ops->createinterpolation      = NULL;
2376   sw->ops->createinjection          = NULL;
2377   sw->ops->createmassmatrix         = DMCreateMassMatrix_Swarm;
2378   sw->ops->refine                   = NULL;
2379   sw->ops->coarsen                  = NULL;
2380   sw->ops->refinehierarchy          = NULL;
2381   sw->ops->coarsenhierarchy         = NULL;
2382   sw->ops->globaltolocalbegin       = NULL;
2383   sw->ops->globaltolocalend         = NULL;
2384   sw->ops->localtoglobalbegin       = NULL;
2385   sw->ops->localtoglobalend         = NULL;
2386   sw->ops->destroy                  = DMDestroy_Swarm;
2387   sw->ops->createsubdm              = NULL;
2388   sw->ops->getdimpoints             = NULL;
2389   sw->ops->locatepoints             = NULL;
2390   PetscFunctionReturn(PETSC_SUCCESS);
2391 }
2392 
2393 PETSC_INTERN PetscErrorCode DMClone_Swarm(DM dm, DM *newdm)
2394 {
2395   DM_Swarm *swarm = (DM_Swarm *)dm->data;
2396 
2397   PetscFunctionBegin;
2398   swarm->refct++;
2399   (*newdm)->data = swarm;
2400   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMSWARM));
2401   PetscCall(DMInitialize_Swarm(*newdm));
2402   (*newdm)->dim = dm->dim;
2403   PetscFunctionReturn(PETSC_SUCCESS);
2404 }
2405 
2406 /*MC
2407  DMSWARM = "swarm" - A `DM` object used to represent arrays of data (fields) of arbitrary data type.
2408  This implementation was designed for particle methods in which the underlying
2409  data required to be represented is both (i) dynamic in length, (ii) and of arbitrary data type.
2410 
2411  Level: intermediate
2412 
2413   Notes:
2414  User data can be represented by `DMSWARM` through a registering "fields".
2415  To register a field, the user must provide;
2416  (a) a unique name;
2417  (b) the data type (or size in bytes);
2418  (c) the block size of the data.
2419 
2420  For example, suppose the application requires a unique id, energy, momentum and density to be stored
2421  on a set of particles. Then the following code could be used
2422 .vb
2423     DMSwarmInitializeFieldRegister(dm)
2424     DMSwarmRegisterPetscDatatypeField(dm,"uid",1,PETSC_LONG);
2425     DMSwarmRegisterPetscDatatypeField(dm,"energy",1,PETSC_REAL);
2426     DMSwarmRegisterPetscDatatypeField(dm,"momentum",3,PETSC_REAL);
2427     DMSwarmRegisterPetscDatatypeField(dm,"density",1,PETSC_FLOAT);
2428     DMSwarmFinalizeFieldRegister(dm)
2429 .ve
2430 
2431  The fields represented by `DMSWARM` are dynamic and can be re-sized at any time.
2432  The only restriction imposed by `DMSWARM` is that all fields contain the same number of points.
2433 
2434  To support particle methods, "migration" techniques are provided. These methods migrate data
2435  between ranks.
2436 
2437  `DMSWARM` supports the methods `DMCreateGlobalVector()` and `DMCreateLocalVector()`.
2438  As a `DMSWARM` may internally define and store values of different data types,
2439  before calling `DMCreateGlobalVector()` or `DMCreateLocalVector()`, the user must inform `DMSWARM` which
2440  fields should be used to define a `Vec` object via
2441    `DMSwarmVectorDefineField()`
2442  The specified field can be changed at any time - thereby permitting vectors
2443  compatible with different fields to be created.
2444 
2445  A dual representation of fields in the `DMSWARM` and a Vec object is permitted via
2446    `DMSwarmCreateGlobalVectorFromField()`
2447  Here the data defining the field in the `DMSWARM` is shared with a Vec.
2448  This is inherently unsafe if you alter the size of the field at any time between
2449  calls to `DMSwarmCreateGlobalVectorFromField()` and `DMSwarmDestroyGlobalVectorFromField()`.
2450  If the local size of the `DMSWARM` does not match the local size of the global vector
2451  when `DMSwarmDestroyGlobalVectorFromField()` is called, an error is thrown.
2452 
2453  Additional high-level support is provided for Particle-In-Cell methods.
2454  Please refer to `DMSwarmSetType()`.
2455 
2456 .seealso: `DM`, `DMSWARM`, `DMType`, `DMCreate()`, `DMSetType()`
2457 M*/
2458 
2459 PETSC_EXTERN PetscErrorCode DMCreate_Swarm(DM dm)
2460 {
2461   DM_Swarm *swarm;
2462 
2463   PetscFunctionBegin;
2464   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2465   PetscCall(PetscNew(&swarm));
2466   dm->data = swarm;
2467   PetscCall(DMSwarmDataBucketCreate(&swarm->db));
2468   PetscCall(DMSwarmInitializeFieldRegister(dm));
2469   dm->dim                               = 0;
2470   swarm->refct                          = 1;
2471   swarm->issetup                        = PETSC_FALSE;
2472   swarm->swarm_type                     = DMSWARM_BASIC;
2473   swarm->migrate_type                   = DMSWARM_MIGRATE_BASIC;
2474   swarm->collect_type                   = DMSWARM_COLLECT_BASIC;
2475   swarm->migrate_error_on_missing_point = PETSC_FALSE;
2476   swarm->collect_view_active            = PETSC_FALSE;
2477   swarm->collect_view_reset_nlocal      = -1;
2478   PetscCall(DMInitialize_Swarm(dm));
2479   if (SwarmDataFieldId == -1) PetscCall(PetscObjectComposedDataRegister(&SwarmDataFieldId));
2480   PetscFunctionReturn(PETSC_SUCCESS);
2481 }
2482 
2483 /* Replace dm with the contents of ndm, and then destroy ndm
2484    - Share the DM_Swarm structure
2485 */
2486 PetscErrorCode DMSwarmReplace(DM dm, DM *ndm)
2487 {
2488   DM               dmNew = *ndm;
2489   const PetscReal *maxCell, *Lstart, *L;
2490   PetscInt         dim;
2491 
2492   PetscFunctionBegin;
2493   if (dm == dmNew) {
2494     PetscCall(DMDestroy(ndm));
2495     PetscFunctionReturn(PETSC_SUCCESS);
2496   }
2497   dm->setupcalled = dmNew->setupcalled;
2498   if (!dm->hdr.name) {
2499     const char *name;
2500 
2501     PetscCall(PetscObjectGetName((PetscObject)*ndm, &name));
2502     PetscCall(PetscObjectSetName((PetscObject)dm, name));
2503   }
2504   PetscCall(DMGetDimension(dmNew, &dim));
2505   PetscCall(DMSetDimension(dm, dim));
2506   PetscCall(DMGetPeriodicity(dmNew, &maxCell, &Lstart, &L));
2507   PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
2508   PetscCall(DMDestroy_Swarm(dm));
2509   PetscCall(DMInitialize_Swarm(dm));
2510   dm->data = dmNew->data;
2511   ((DM_Swarm *)dmNew->data)->refct++;
2512   PetscCall(DMDestroy(ndm));
2513   PetscFunctionReturn(PETSC_SUCCESS);
2514 }
2515