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