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