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