xref: /petsc/src/dm/impls/swarm/swarm.c (revision 65f8aed5f7eaa1e2ef2ddeffe666264e0669c876)
1 #define PETSCDM_DLL
2 #include <petsc/private/dmswarmimpl.h>    /*I   "petscdmswarm.h"   I*/
3 #include <petsc/private/hashsetij.h>
4 #include <petscviewer.h>
5 #include <petscdraw.h>
6 #include <petscdmplex.h>
7 #include "../src/dm/impls/swarm/data_bucket.h"
8 
9 PetscLogEvent DMSWARM_Migrate, DMSWARM_SetSizes, DMSWARM_AddPoints, DMSWARM_RemovePoints, DMSWARM_Sort;
10 PetscLogEvent DMSWARM_DataExchangerTopologySetup, DMSWARM_DataExchangerBegin, DMSWARM_DataExchangerEnd;
11 PetscLogEvent DMSWARM_DataExchangerSendCount, DMSWARM_DataExchangerPack;
12 
13 const char* DMSwarmTypeNames[] = { "basic", "pic", 0 };
14 const char* DMSwarmMigrateTypeNames[] = { "basic", "dmcellnscatter", "dmcellexact", "user", 0 };
15 const char* DMSwarmCollectTypeNames[] = { "basic", "boundingbox", "general", "user", 0 };
16 const char* DMSwarmPICLayoutTypeNames[] = { "regular", "gauss", "subdivision", 0 };
17 
18 const char DMSwarmField_pid[] = "DMSwarm_pid";
19 const char DMSwarmField_rank[] = "DMSwarm_rank";
20 const char DMSwarmPICField_coor[] = "DMSwarmPIC_coor";
21 const char DMSwarmPICField_cellid[] = "DMSwarm_cellid";
22 
23 /*@C
24    DMSwarmVectorDefineField - Sets the field from which to define a Vec object
25                              when DMCreateLocalVector(), or DMCreateGlobalVector() is called
26 
27    Collective on DM
28 
29    Input parameters:
30 +  dm - a DMSwarm
31 -  fieldname - the textual name given to a registered field
32 
33    Level: beginner
34 
35    Notes:
36 
37    The field with name fieldname must be defined as having a data type of PetscScalar.
38 
39    This function must be called prior to calling DMCreateLocalVector(), DMCreateGlobalVector().
40    Mutiple calls to DMSwarmVectorDefineField() are permitted.
41 
42 .seealso: DMSwarmRegisterPetscDatatypeField(), DMCreateGlobalVector(), DMCreateLocalVector()
43 @*/
44 PETSC_EXTERN PetscErrorCode DMSwarmVectorDefineField(DM dm,const char fieldname[])
45 {
46   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
47   PetscErrorCode ierr;
48   PetscInt       bs,n;
49   PetscScalar    *array;
50   PetscDataType  type;
51 
52   PetscFunctionBegin;
53   if (!swarm->issetup) { ierr = DMSetUp(dm);CHKERRQ(ierr); }
54   ierr = DMSwarmDataBucketGetSizes(swarm->db,&n,NULL,NULL);CHKERRQ(ierr);
55   ierr = DMSwarmGetField(dm,fieldname,&bs,&type,(void**)&array);CHKERRQ(ierr);
56 
57   /* Check all fields are of type PETSC_REAL or PETSC_SCALAR */
58   if (type != PETSC_REAL) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Only valid for PETSC_REAL");
59   ierr = PetscSNPrintf(swarm->vec_field_name,PETSC_MAX_PATH_LEN-1,"%s",fieldname);CHKERRQ(ierr);
60   swarm->vec_field_set = PETSC_TRUE;
61   swarm->vec_field_bs = bs;
62   swarm->vec_field_nlocal = n;
63   ierr = DMSwarmRestoreField(dm,fieldname,&bs,&type,(void**)&array);CHKERRQ(ierr);
64   PetscFunctionReturn(0);
65 }
66 
67 /* requires DMSwarmDefineFieldVector has been called */
68 PetscErrorCode DMCreateGlobalVector_Swarm(DM dm,Vec *vec)
69 {
70   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
71   PetscErrorCode ierr;
72   Vec            x;
73   char           name[PETSC_MAX_PATH_LEN];
74 
75   PetscFunctionBegin;
76   if (!swarm->issetup) { ierr = DMSetUp(dm);CHKERRQ(ierr); }
77   if (!swarm->vec_field_set) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMSwarmVectorDefineField first");
78   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 */
79 
80   ierr = PetscSNPrintf(name,PETSC_MAX_PATH_LEN-1,"DMSwarmField_%s",swarm->vec_field_name);CHKERRQ(ierr);
81   ierr = VecCreate(PetscObjectComm((PetscObject)dm),&x);CHKERRQ(ierr);
82   ierr = PetscObjectSetName((PetscObject)x,name);CHKERRQ(ierr);
83   ierr = VecSetSizes(x,swarm->db->L*swarm->vec_field_bs,PETSC_DETERMINE);CHKERRQ(ierr);
84   ierr = VecSetBlockSize(x,swarm->vec_field_bs);CHKERRQ(ierr);
85   ierr = VecSetFromOptions(x);CHKERRQ(ierr);
86   *vec = x;
87   PetscFunctionReturn(0);
88 }
89 
90 /* requires DMSwarmDefineFieldVector has been called */
91 PetscErrorCode DMCreateLocalVector_Swarm(DM dm,Vec *vec)
92 {
93   DM_Swarm *swarm = (DM_Swarm*)dm->data;
94   PetscErrorCode ierr;
95   Vec x;
96   char name[PETSC_MAX_PATH_LEN];
97 
98   PetscFunctionBegin;
99   if (!swarm->issetup) { ierr = DMSetUp(dm);CHKERRQ(ierr); }
100   if (!swarm->vec_field_set) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMSwarmVectorDefineField first");
101   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 */
102 
103   ierr = PetscSNPrintf(name,PETSC_MAX_PATH_LEN-1,"DMSwarmField_%s",swarm->vec_field_name);CHKERRQ(ierr);
104   ierr = VecCreate(PETSC_COMM_SELF,&x);CHKERRQ(ierr);
105   ierr = PetscObjectSetName((PetscObject)x,name);CHKERRQ(ierr);
106   ierr = VecSetSizes(x,swarm->db->L*swarm->vec_field_bs,PETSC_DETERMINE);CHKERRQ(ierr);
107   ierr = VecSetBlockSize(x,swarm->vec_field_bs);CHKERRQ(ierr);
108   ierr = VecSetFromOptions(x);CHKERRQ(ierr);
109   *vec = x;
110   PetscFunctionReturn(0);
111 }
112 
113 static PetscErrorCode DMSwarmDestroyVectorFromField_Private(DM dm, const char fieldname[], Vec *vec)
114 {
115   DM_Swarm      *swarm = (DM_Swarm *) dm->data;
116   DMSwarmDataField      gfield;
117   void         (*fptr)(void);
118   PetscInt       bs, nlocal;
119   char           name[PETSC_MAX_PATH_LEN];
120   PetscErrorCode ierr;
121 
122   PetscFunctionBegin;
123   ierr = VecGetLocalSize(*vec, &nlocal);CHKERRQ(ierr);
124   ierr = VecGetBlockSize(*vec, &bs);CHKERRQ(ierr);
125   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 */
126   ierr = DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield);CHKERRQ(ierr);
127   /* check vector is an inplace array */
128   ierr = PetscSNPrintf(name, PETSC_MAX_PATH_LEN-1, "DMSwarm_VecFieldInPlace_%s", fieldname);CHKERRQ(ierr);
129   ierr = PetscObjectQueryFunction((PetscObject) *vec, name, &fptr);CHKERRQ(ierr);
130   if (!fptr) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_USER, "Vector being destroyed was not created from DMSwarm field(%s)", fieldname);
131   ierr = DMSwarmDataFieldRestoreAccess(gfield);CHKERRQ(ierr);
132   ierr = VecDestroy(vec);CHKERRQ(ierr);
133   PetscFunctionReturn(0);
134 }
135 
136 static PetscErrorCode DMSwarmCreateVectorFromField_Private(DM dm, const char fieldname[], MPI_Comm comm, Vec *vec)
137 {
138   DM_Swarm      *swarm = (DM_Swarm *) dm->data;
139   PetscDataType  type;
140   PetscScalar   *array;
141   PetscInt       bs, n;
142   char           name[PETSC_MAX_PATH_LEN];
143   PetscMPIInt    size;
144   PetscErrorCode ierr;
145 
146   PetscFunctionBegin;
147   if (!swarm->issetup) {ierr = DMSetUp(dm);CHKERRQ(ierr);}
148   ierr = DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL);CHKERRQ(ierr);
149   ierr = DMSwarmGetField(dm, fieldname, &bs, &type, (void **) &array);CHKERRQ(ierr);
150   if (type != PETSC_REAL) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
151 
152   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
153   if (size == 1) {
154     ierr = VecCreateSeqWithArray(comm, bs, n*bs, array, vec);CHKERRQ(ierr);
155   } else {
156     ierr = VecCreateMPIWithArray(comm, bs, n*bs, PETSC_DETERMINE, array, vec);CHKERRQ(ierr);
157   }
158   ierr = PetscSNPrintf(name, PETSC_MAX_PATH_LEN-1, "DMSwarmSharedField_%s", fieldname);CHKERRQ(ierr);
159   ierr = PetscObjectSetName((PetscObject) *vec, name);CHKERRQ(ierr);
160 
161   /* Set guard */
162   ierr = PetscSNPrintf(name, PETSC_MAX_PATH_LEN-1, "DMSwarm_VecFieldInPlace_%s", fieldname);CHKERRQ(ierr);
163   ierr = PetscObjectComposeFunction((PetscObject) *vec, name, DMSwarmDestroyVectorFromField_Private);CHKERRQ(ierr);
164   PetscFunctionReturn(0);
165 }
166 
167 static PetscErrorCode DMSwarmComputeMassMatrix_Private(DM dmc, DM dmf, Mat mass, void *ctx)
168 {
169   const char    *name = "Mass Matrix";
170   PetscDS        prob;
171   PetscSection   fsection, globalFSection;
172   PetscHSetIJ    ht;
173   PetscLayout    rLayout;
174   PetscInt      *dnz, *onz;
175   PetscInt       locRows, rStart, rEnd;
176   PetscReal     *x, *v0, *J, *invJ, detJ;
177   PetscScalar   *elemMat;
178   PetscInt       dim, Nf, field, totDim, cStart, cEnd, cell, maxC = 0;
179   PetscMPIInt    size;
180   PetscErrorCode ierr;
181 
182   PetscFunctionBegin;
183   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dmf), &size);CHKERRQ(ierr);
184   ierr = DMGetCoordinateDim(dmf, &dim);CHKERRQ(ierr);
185   ierr = DMGetDS(dmf, &prob);CHKERRQ(ierr);
186   ierr = PetscDSGetRefCoordArrays(prob, &x, NULL);CHKERRQ(ierr);
187   ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr);
188   ierr = PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr);
189   ierr = DMGetSection(dmf, &fsection);CHKERRQ(ierr);
190   ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);
191   ierr = DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);CHKERRQ(ierr);
192   ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr);
193   ierr = DMSwarmSortGetAccess(dmc);CHKERRQ(ierr);
194 
195   ierr = MatGetLocalSize(mass, &locRows, NULL);CHKERRQ(ierr);
196   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) mass), &rLayout);CHKERRQ(ierr);
197   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
198   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
199   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
200   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
201   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
202   ierr = PetscCalloc2(locRows,&dnz,locRows,&onz);CHKERRQ(ierr);
203   ierr = PetscHSetIJCreate(&ht);CHKERRQ(ierr);
204   for (field = 0; field < Nf; ++field) {
205     PetscObject      obj;
206     PetscQuadrature  quad;
207     const PetscReal *qpoints;
208     PetscInt         Nq, Nc, i;
209 
210     ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr);
211     ierr = PetscFEGetQuadrature((PetscFE) obj, &quad);CHKERRQ(ierr);
212     ierr = PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL);CHKERRQ(ierr);
213     /* For each fine grid cell */
214     for (cell = cStart; cell < cEnd; ++cell) {
215       PetscInt  Np, c;
216       PetscInt *findices,   *cindices;
217       PetscInt  numFIndices, numCIndices;
218 
219       ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr);
220       ierr = DMSwarmSortGetNumberOfPointsPerCell(dmc, cell, &Np);CHKERRQ(ierr);
221       if (Np != Nq) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located %D != %D", Np, Nq);
222       ierr = DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices);CHKERRQ(ierr);
223       maxC = PetscMax(maxC, numCIndices);
224       /* Update preallocation info */
225       {
226         PetscHashIJKey key;
227         PetscBool      missing;
228 
229         for (i = 0; i < numFIndices; ++i) {
230           key.i = findices[i];
231           if (key.i >= 0) {
232             /* Get indices for coarse elements */
233             for (c = 0; c < numCIndices; ++c) {
234               key.j = cindices[c];
235               if (key.j < 0) continue;
236               ierr = PetscHSetIJQueryAdd(ht, key, &missing);CHKERRQ(ierr);
237               if (missing) {
238                 if ((size == 1) || ((key.j >= rStart) && (key.j < rEnd))) ++dnz[key.i-rStart];
239                 else                                                      ++onz[key.i-rStart];
240               }
241             }
242           }
243         }
244         ierr = PetscFree(cindices);CHKERRQ(ierr);
245       }
246       ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr);
247     }
248   }
249   ierr = PetscHSetIJDestroy(&ht);CHKERRQ(ierr);
250   ierr = MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL);CHKERRQ(ierr);
251   ierr = MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
252   ierr = PetscFree2(dnz,onz);CHKERRQ(ierr);
253   ierr = PetscMalloc1(maxC, &elemMat);CHKERRQ(ierr);
254   for (field = 0; field < Nf; ++field) {
255     PetscObject      obj;
256     PetscQuadrature  quad;
257     PetscReal       *Bfine;
258     const PetscReal *qweights;
259     PetscInt         Nq, Nc, i;
260 
261     ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr);
262     ierr = PetscFEGetDefaultTabulation((PetscFE) obj, &Bfine, NULL, NULL);CHKERRQ(ierr);
263     ierr = PetscFEGetQuadrature((PetscFE) obj, &quad);CHKERRQ(ierr);
264     ierr = PetscQuadratureGetData(quad, NULL, &Nc, &Nq, NULL, &qweights);CHKERRQ(ierr);
265     /* For each fine grid cell */
266     for (cell = cStart; cell < cEnd; ++cell) {
267       PetscInt           Np, c, j;
268       PetscInt          *findices,   *cindices;
269       PetscInt           numFIndices, numCIndices;
270 
271       ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
272       ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr);
273       ierr = DMSwarmSortGetNumberOfPointsPerCell(dmc, cell, &Np);CHKERRQ(ierr);
274       if (Np != Nq) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located %D != %D", Np, Nq);
275       ierr = DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices);CHKERRQ(ierr);
276       /* Get elemMat entries by multiplying by weight */
277       for (i = 0; i < numFIndices; ++i) {
278         ierr = PetscMemzero(elemMat, numCIndices * sizeof(PetscScalar));CHKERRQ(ierr);
279         for (j = 0; j < numCIndices; ++j) {
280           for (c = 0; c < Nc; ++c) elemMat[j] += Bfine[(j*numFIndices + i)*Nc + c]*qweights[j*Nc + c]*detJ;
281         }
282         /* Update interpolator */
283         if (0) {ierr = DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);CHKERRQ(ierr);}
284         ierr = MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);CHKERRQ(ierr);
285       }
286       ierr = PetscFree(cindices);CHKERRQ(ierr);
287       ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr);
288     }
289   }
290   ierr = DMSwarmSortRestoreAccess(dmc);CHKERRQ(ierr);
291   ierr = PetscFree3(v0,J,invJ);CHKERRQ(ierr);
292   ierr = PetscFree(elemMat);CHKERRQ(ierr);
293   ierr = MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
294   ierr = MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
295   PetscFunctionReturn(0);
296 }
297 
298 static PetscErrorCode DMCreateMassMatrix_Swarm(DM dmCoarse, DM dmFine, Mat *mass)
299 {
300   PetscSection   gsf;
301   PetscInt       m, n;
302   void          *ctx;
303   PetscErrorCode ierr;
304 
305   PetscFunctionBegin;
306   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
307   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
308   ierr = DMSwarmGetLocalSize(dmCoarse, &n);CHKERRQ(ierr);
309 
310   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr);
311   ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
312   ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr);
313   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
314 
315   ierr = DMSwarmComputeMassMatrix_Private(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);
316   ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
317   PetscFunctionReturn(0);
318 }
319 
320 /*@C
321    DMSwarmCreateGlobalVectorFromField - Creates a Vec object sharing the array associated with a given field
322 
323    Collective on DM
324 
325    Input parameters:
326 +  dm - a DMSwarm
327 -  fieldname - the textual name given to a registered field
328 
329    Output parameter:
330 .  vec - the vector
331 
332    Level: beginner
333 
334    Notes:
335    The vector must be returned using a matching call to DMSwarmDestroyGlobalVectorFromField().
336 
337 .seealso: DMSwarmRegisterPetscDatatypeField(), DMSwarmDestroyGlobalVectorFromField()
338 @*/
339 PETSC_EXTERN PetscErrorCode DMSwarmCreateGlobalVectorFromField(DM dm,const char fieldname[],Vec *vec)
340 {
341   MPI_Comm       comm = PetscObjectComm((PetscObject) dm);
342   PetscErrorCode ierr;
343 
344   PetscFunctionBegin;
345   ierr = DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec);CHKERRQ(ierr);
346   PetscFunctionReturn(0);
347 }
348 
349 /*@C
350    DMSwarmDestroyGlobalVectorFromField - Destroys the Vec object which share the array associated with a given field
351 
352    Collective on DM
353 
354    Input parameters:
355 +  dm - a DMSwarm
356 -  fieldname - the textual name given to a registered field
357 
358    Output parameter:
359 .  vec - the vector
360 
361    Level: beginner
362 
363 .seealso: DMSwarmRegisterPetscDatatypeField(), DMSwarmCreateGlobalVectorFromField()
364 @*/
365 PETSC_EXTERN PetscErrorCode DMSwarmDestroyGlobalVectorFromField(DM dm,const char fieldname[],Vec *vec)
366 {
367   PetscErrorCode ierr;
368 
369   PetscFunctionBegin;
370   ierr = DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec);CHKERRQ(ierr);
371   PetscFunctionReturn(0);
372 }
373 
374 /*@C
375    DMSwarmCreateLocalVectorFromField - Creates a Vec object sharing the array associated with a given field
376 
377    Collective on DM
378 
379    Input parameters:
380 +  dm - a DMSwarm
381 -  fieldname - the textual name given to a registered field
382 
383    Output parameter:
384 .  vec - the vector
385 
386    Level: beginner
387 
388    Notes:
389    The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField().
390 
391 .seealso: DMSwarmRegisterPetscDatatypeField(), DMSwarmDestroyLocalVectorFromField()
392 @*/
393 PETSC_EXTERN PetscErrorCode DMSwarmCreateLocalVectorFromField(DM dm,const char fieldname[],Vec *vec)
394 {
395   MPI_Comm       comm = PETSC_COMM_SELF;
396   PetscErrorCode ierr;
397 
398   PetscFunctionBegin;
399   ierr = DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec);CHKERRQ(ierr);
400   PetscFunctionReturn(0);
401 }
402 
403 /*@C
404    DMSwarmDestroyLocalVectorFromField - Destroys the Vec object which share the array associated with a given field
405 
406    Collective on DM
407 
408    Input parameters:
409 +  dm - a DMSwarm
410 -  fieldname - the textual name given to a registered field
411 
412    Output parameter:
413 .  vec - the vector
414 
415    Level: beginner
416 
417 .seealso: DMSwarmRegisterPetscDatatypeField(), DMSwarmCreateLocalVectorFromField()
418 @*/
419 PETSC_EXTERN PetscErrorCode DMSwarmDestroyLocalVectorFromField(DM dm,const char fieldname[],Vec *vec)
420 {
421   PetscErrorCode ierr;
422 
423   PetscFunctionBegin;
424   ierr = DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec);CHKERRQ(ierr);
425   PetscFunctionReturn(0);
426 }
427 
428 /*
429 PETSC_EXTERN PetscErrorCode DMSwarmCreateGlobalVectorFromFields(DM dm,const PetscInt nf,const char *fieldnames[],Vec *vec)
430 {
431   PetscFunctionReturn(0);
432 }
433 
434 PETSC_EXTERN PetscErrorCode DMSwarmRestoreGlobalVectorFromFields(DM dm,Vec *vec)
435 {
436   PetscFunctionReturn(0);
437 }
438 */
439 
440 /*@C
441    DMSwarmInitializeFieldRegister - Initiates the registration of fields to a DMSwarm
442 
443    Collective on DM
444 
445    Input parameter:
446 .  dm - a DMSwarm
447 
448    Level: beginner
449 
450    Notes:
451    After all fields have been registered, you must call DMSwarmFinalizeFieldRegister().
452 
453 .seealso: DMSwarmFinalizeFieldRegister(), DMSwarmRegisterPetscDatatypeField(),
454  DMSwarmRegisterUserStructField(), DMSwarmRegisterUserDatatypeField()
455 @*/
456 PETSC_EXTERN PetscErrorCode DMSwarmInitializeFieldRegister(DM dm)
457 {
458   DM_Swarm      *swarm = (DM_Swarm *) dm->data;
459   PetscErrorCode ierr;
460 
461   PetscFunctionBegin;
462   if (!swarm->field_registration_initialized) {
463     swarm->field_registration_initialized = PETSC_TRUE;
464     ierr = DMSwarmRegisterPetscDatatypeField(dm,DMSwarmField_pid,1,PETSC_LONG);CHKERRQ(ierr); /* unique identifer */
465     ierr = DMSwarmRegisterPetscDatatypeField(dm,DMSwarmField_rank,1,PETSC_INT);CHKERRQ(ierr); /* used for communication */
466   }
467   PetscFunctionReturn(0);
468 }
469 
470 /*@C
471    DMSwarmFinalizeFieldRegister - Finalizes the registration of fields to a DMSwarm
472 
473    Collective on DM
474 
475    Input parameter:
476 .  dm - a DMSwarm
477 
478    Level: beginner
479 
480    Notes:
481    After DMSwarmFinalizeFieldRegister() has been called, no new fields can be defined on the DMSwarm.
482 
483 .seealso: DMSwarmInitializeFieldRegister(), DMSwarmRegisterPetscDatatypeField(),
484  DMSwarmRegisterUserStructField(), DMSwarmRegisterUserDatatypeField()
485 @*/
486 PETSC_EXTERN PetscErrorCode DMSwarmFinalizeFieldRegister(DM dm)
487 {
488   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
489   PetscErrorCode ierr;
490 
491   PetscFunctionBegin;
492   if (!swarm->field_registration_finalized) {
493     ierr = DMSwarmDataBucketFinalize(swarm->db);CHKERRQ(ierr);
494   }
495   swarm->field_registration_finalized = PETSC_TRUE;
496   PetscFunctionReturn(0);
497 }
498 
499 /*@C
500    DMSwarmSetLocalSizes - Sets the length of all registered fields on the DMSwarm
501 
502    Not collective
503 
504    Input parameters:
505 +  dm - a DMSwarm
506 .  nlocal - the length of each registered field
507 -  buffer - the length of the buffer used to efficient dynamic re-sizing
508 
509    Level: beginner
510 
511 .seealso: DMSwarmGetLocalSize()
512 @*/
513 PETSC_EXTERN PetscErrorCode DMSwarmSetLocalSizes(DM dm,PetscInt nlocal,PetscInt buffer)
514 {
515   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
516   PetscErrorCode ierr;
517 
518   PetscFunctionBegin;
519   ierr = PetscLogEventBegin(DMSWARM_SetSizes,0,0,0,0);CHKERRQ(ierr);
520   ierr = DMSwarmDataBucketSetSizes(swarm->db,nlocal,buffer);CHKERRQ(ierr);
521   ierr = PetscLogEventEnd(DMSWARM_SetSizes,0,0,0,0);CHKERRQ(ierr);
522   PetscFunctionReturn(0);
523 }
524 
525 /*@C
526    DMSwarmSetCellDM - Attachs a DM to a DMSwarm
527 
528    Collective on DM
529 
530    Input parameters:
531 +  dm - a DMSwarm
532 -  dmcell - the DM to attach to the DMSwarm
533 
534    Level: beginner
535 
536    Notes:
537    The attached DM (dmcell) will be queried for point location and
538    neighbor MPI-rank information if DMSwarmMigrate() is called.
539 
540 .seealso: DMSwarmSetType(), DMSwarmGetCellDM(), DMSwarmMigrate()
541 @*/
542 PETSC_EXTERN PetscErrorCode DMSwarmSetCellDM(DM dm,DM dmcell)
543 {
544   DM_Swarm *swarm = (DM_Swarm*)dm->data;
545 
546   PetscFunctionBegin;
547   swarm->dmcell = dmcell;
548   PetscFunctionReturn(0);
549 }
550 
551 /*@C
552    DMSwarmGetCellDM - Fetches the attached cell DM
553 
554    Collective on DM
555 
556    Input parameter:
557 .  dm - a DMSwarm
558 
559    Output parameter:
560 .  dmcell - the DM which was attached to the DMSwarm
561 
562    Level: beginner
563 
564 .seealso: DMSwarmSetCellDM()
565 @*/
566 PETSC_EXTERN PetscErrorCode DMSwarmGetCellDM(DM dm,DM *dmcell)
567 {
568   DM_Swarm *swarm = (DM_Swarm*)dm->data;
569 
570   PetscFunctionBegin;
571   *dmcell = swarm->dmcell;
572   PetscFunctionReturn(0);
573 }
574 
575 /*@C
576    DMSwarmGetLocalSize - Retrives the local length of fields registered
577 
578    Not collective
579 
580    Input parameter:
581 .  dm - a DMSwarm
582 
583    Output parameter:
584 .  nlocal - the length of each registered field
585 
586    Level: beginner
587 
588 .seealso: DMSwarmGetSize(), DMSwarmSetLocalSizes()
589 @*/
590 PETSC_EXTERN PetscErrorCode DMSwarmGetLocalSize(DM dm,PetscInt *nlocal)
591 {
592   DM_Swarm *swarm = (DM_Swarm*)dm->data;
593   PetscErrorCode ierr;
594 
595   PetscFunctionBegin;
596   if (nlocal) {ierr = DMSwarmDataBucketGetSizes(swarm->db,nlocal,NULL,NULL);CHKERRQ(ierr);}
597   PetscFunctionReturn(0);
598 }
599 
600 /*@C
601    DMSwarmGetSize - Retrives the total length of fields registered
602 
603    Collective on DM
604 
605    Input parameter:
606 .  dm - a DMSwarm
607 
608    Output parameter:
609 .  n - the total length of each registered field
610 
611    Level: beginner
612 
613    Note:
614    This calls MPI_Allreduce upon each call (inefficient but safe)
615 
616 .seealso: DMSwarmGetLocalSize(), DMSwarmSetLocalSizes()
617 @*/
618 PETSC_EXTERN PetscErrorCode DMSwarmGetSize(DM dm,PetscInt *n)
619 {
620   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
621   PetscErrorCode ierr;
622   PetscInt       nlocal,ng;
623 
624   PetscFunctionBegin;
625   ierr = DMSwarmDataBucketGetSizes(swarm->db,&nlocal,NULL,NULL);CHKERRQ(ierr);
626   ierr = MPI_Allreduce(&nlocal,&ng,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
627   if (n) { *n = ng; }
628   PetscFunctionReturn(0);
629 }
630 
631 /*@C
632    DMSwarmRegisterPetscDatatypeField - Register a field to a DMSwarm with a native PETSc data type
633 
634    Collective on DM
635 
636    Input parameters:
637 +  dm - a DMSwarm
638 .  fieldname - the textual name to identify this field
639 .  blocksize - the number of each data type
640 -  type - a valid PETSc data type (PETSC_CHAR, PETSC_SHORT, PETSC_INT, PETSC_FLOAT, PETSC_REAL, PETSC_LONG)
641 
642    Level: beginner
643 
644    Notes:
645    The textual name for each registered field must be unique.
646 
647 .seealso: DMSwarmRegisterUserStructField(), DMSwarmRegisterUserDatatypeField()
648 @*/
649 PETSC_EXTERN PetscErrorCode DMSwarmRegisterPetscDatatypeField(DM dm,const char fieldname[],PetscInt blocksize,PetscDataType type)
650 {
651   PetscErrorCode ierr;
652   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
653   size_t         size;
654 
655   PetscFunctionBegin;
656   if (!swarm->field_registration_initialized) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMSwarmInitializeFieldRegister() first");
657   if (swarm->field_registration_finalized) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot register additional fields after calling DMSwarmFinalizeFieldRegister() first");
658 
659   if (type == PETSC_OBJECT) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Valid for {char,short,int,long,float,double}");
660   if (type == PETSC_FUNCTION) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Valid for {char,short,int,long,float,double}");
661   if (type == PETSC_STRING) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Valid for {char,short,int,long,float,double}");
662   if (type == PETSC_STRUCT) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Valid for {char,short,int,long,float,double}");
663   if (type == PETSC_DATATYPE_UNKNOWN) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Valid for {char,short,int,long,float,double}");
664 
665   ierr = PetscDataTypeGetSize(type, &size);CHKERRQ(ierr);
666   /* Load a specific data type into data bucket, specifying textual name and its size in bytes */
667   ierr = DMSwarmDataBucketRegisterField(swarm->db,"DMSwarmRegisterPetscDatatypeField",fieldname,blocksize*size,NULL);CHKERRQ(ierr);
668   {
669     DMSwarmDataField gfield;
670 
671     ierr = DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db,fieldname,&gfield);CHKERRQ(ierr);
672     ierr = DMSwarmDataFieldSetBlockSize(gfield,blocksize);CHKERRQ(ierr);
673   }
674   swarm->db->field[swarm->db->nfields-1]->petsc_type = type;
675   PetscFunctionReturn(0);
676 }
677 
678 /*@C
679    DMSwarmRegisterUserStructField - Register a user defined struct to a DMSwarm
680 
681    Collective on DM
682 
683    Input parameters:
684 +  dm - a DMSwarm
685 .  fieldname - the textual name to identify this field
686 -  size - the size in bytes of the user struct of each data type
687 
688    Level: beginner
689 
690    Notes:
691    The textual name for each registered field must be unique.
692 
693 .seealso: DMSwarmRegisterPetscDatatypeField(), DMSwarmRegisterUserDatatypeField()
694 @*/
695 PETSC_EXTERN PetscErrorCode DMSwarmRegisterUserStructField(DM dm,const char fieldname[],size_t size)
696 {
697   PetscErrorCode ierr;
698   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
699 
700   PetscFunctionBegin;
701   ierr = DMSwarmDataBucketRegisterField(swarm->db,"DMSwarmRegisterUserStructField",fieldname,size,NULL);CHKERRQ(ierr);
702   swarm->db->field[swarm->db->nfields-1]->petsc_type = PETSC_STRUCT ;
703   PetscFunctionReturn(0);
704 }
705 
706 /*@C
707    DMSwarmRegisterUserDatatypeField - Register a user defined data type to a DMSwarm
708 
709    Collective on DM
710 
711    Input parameters:
712 +  dm - a DMSwarm
713 .  fieldname - the textual name to identify this field
714 .  size - the size in bytes of the user data type
715 -  blocksize - the number of each data type
716 
717    Level: beginner
718 
719    Notes:
720    The textual name for each registered field must be unique.
721 
722 .seealso: DMSwarmRegisterPetscDatatypeField(), DMSwarmRegisterUserStructField(), DMSwarmRegisterUserDatatypeField()
723 @*/
724 PETSC_EXTERN PetscErrorCode DMSwarmRegisterUserDatatypeField(DM dm,const char fieldname[],size_t size,PetscInt blocksize)
725 {
726   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
727   PetscErrorCode ierr;
728 
729   PetscFunctionBegin;
730   ierr = DMSwarmDataBucketRegisterField(swarm->db,"DMSwarmRegisterUserDatatypeField",fieldname,blocksize*size,NULL);CHKERRQ(ierr);
731   {
732     DMSwarmDataField gfield;
733 
734     ierr = DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db,fieldname,&gfield);CHKERRQ(ierr);
735     ierr = DMSwarmDataFieldSetBlockSize(gfield,blocksize);CHKERRQ(ierr);
736   }
737   swarm->db->field[swarm->db->nfields-1]->petsc_type = PETSC_DATATYPE_UNKNOWN;
738   PetscFunctionReturn(0);
739 }
740 
741 /*@C
742    DMSwarmGetField - Get access to the underlying array storing all entries associated with a registered field
743 
744    Not collective
745 
746    Input parameters:
747 +  dm - a DMSwarm
748 -  fieldname - the textual name to identify this field
749 
750    Output parameters:
751 +  blocksize - the number of each data type
752 .  type - the data type
753 -  data - pointer to raw array
754 
755    Level: beginner
756 
757    Notes:
758    The array must be returned using a matching call to DMSwarmRestoreField().
759 
760 .seealso: DMSwarmRestoreField()
761 @*/
762 PETSC_EXTERN PetscErrorCode DMSwarmGetField(DM dm,const char fieldname[],PetscInt *blocksize,PetscDataType *type,void **data)
763 {
764   DM_Swarm         *swarm = (DM_Swarm*)dm->data;
765   DMSwarmDataField gfield;
766   PetscErrorCode ierr;
767 
768   PetscFunctionBegin;
769   if (!swarm->issetup) { ierr = DMSetUp(dm);CHKERRQ(ierr); }
770   ierr = DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db,fieldname,&gfield);CHKERRQ(ierr);
771   ierr = DMSwarmDataFieldGetAccess(gfield);CHKERRQ(ierr);
772   ierr = DMSwarmDataFieldGetEntries(gfield,data);CHKERRQ(ierr);
773   if (blocksize) {*blocksize = gfield->bs; }
774   if (type) { *type = gfield->petsc_type; }
775   PetscFunctionReturn(0);
776 }
777 
778 /*@C
779    DMSwarmRestoreField - Restore access to the underlying array storing all entries associated with a registered field
780 
781    Not collective
782 
783    Input parameters:
784 +  dm - a DMSwarm
785 -  fieldname - the textual name to identify this field
786 
787    Output parameters:
788 +  blocksize - the number of each data type
789 .  type - the data type
790 -  data - pointer to raw array
791 
792    Level: beginner
793 
794    Notes:
795    The user must call DMSwarmGetField() prior to calling DMSwarmRestoreField().
796 
797 .seealso: DMSwarmGetField()
798 @*/
799 PETSC_EXTERN PetscErrorCode DMSwarmRestoreField(DM dm,const char fieldname[],PetscInt *blocksize,PetscDataType *type,void **data)
800 {
801   DM_Swarm         *swarm = (DM_Swarm*)dm->data;
802   DMSwarmDataField gfield;
803   PetscErrorCode ierr;
804 
805   PetscFunctionBegin;
806   ierr = DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db,fieldname,&gfield);CHKERRQ(ierr);
807   ierr = DMSwarmDataFieldRestoreAccess(gfield);CHKERRQ(ierr);
808   if (data) *data = NULL;
809   PetscFunctionReturn(0);
810 }
811 
812 /*@C
813    DMSwarmAddPoint - Add space for one new point in the DMSwarm
814 
815    Not collective
816 
817    Input parameter:
818 .  dm - a DMSwarm
819 
820    Level: beginner
821 
822    Notes:
823    The new point will have all fields initialized to zero.
824 
825 .seealso: DMSwarmAddNPoints()
826 @*/
827 PETSC_EXTERN PetscErrorCode DMSwarmAddPoint(DM dm)
828 {
829   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
830   PetscErrorCode ierr;
831 
832   PetscFunctionBegin;
833   if (!swarm->issetup) {ierr = DMSetUp(dm);CHKERRQ(ierr);}
834   ierr = PetscLogEventBegin(DMSWARM_AddPoints,0,0,0,0);CHKERRQ(ierr);
835   ierr = DMSwarmDataBucketAddPoint(swarm->db);CHKERRQ(ierr);
836   ierr = PetscLogEventEnd(DMSWARM_AddPoints,0,0,0,0);CHKERRQ(ierr);
837   PetscFunctionReturn(0);
838 }
839 
840 /*@C
841    DMSwarmAddNPoints - Add space for a number of new points in the DMSwarm
842 
843    Not collective
844 
845    Input parameters:
846 +  dm - a DMSwarm
847 -  npoints - the number of new points to add
848 
849    Level: beginner
850 
851    Notes:
852    The new point will have all fields initialized to zero.
853 
854 .seealso: DMSwarmAddPoint()
855 @*/
856 PETSC_EXTERN PetscErrorCode DMSwarmAddNPoints(DM dm,PetscInt npoints)
857 {
858   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
859   PetscErrorCode ierr;
860   PetscInt       nlocal;
861 
862   PetscFunctionBegin;
863   ierr = PetscLogEventBegin(DMSWARM_AddPoints,0,0,0,0);CHKERRQ(ierr);
864   ierr = DMSwarmDataBucketGetSizes(swarm->db,&nlocal,NULL,NULL);CHKERRQ(ierr);
865   nlocal = nlocal + npoints;
866   ierr = DMSwarmDataBucketSetSizes(swarm->db,nlocal,DMSWARM_DATA_BUCKET_BUFFER_DEFAULT);CHKERRQ(ierr);
867   ierr = PetscLogEventEnd(DMSWARM_AddPoints,0,0,0,0);CHKERRQ(ierr);
868   PetscFunctionReturn(0);
869 }
870 
871 /*@C
872    DMSwarmRemovePoint - Remove the last point from the DMSwarm
873 
874    Not collective
875 
876    Input parameter:
877 .  dm - a DMSwarm
878 
879    Level: beginner
880 
881 .seealso: DMSwarmRemovePointAtIndex()
882 @*/
883 PETSC_EXTERN PetscErrorCode DMSwarmRemovePoint(DM dm)
884 {
885   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
886   PetscErrorCode ierr;
887 
888   PetscFunctionBegin;
889   ierr = PetscLogEventBegin(DMSWARM_RemovePoints,0,0,0,0);CHKERRQ(ierr);
890   ierr = DMSwarmDataBucketRemovePoint(swarm->db);CHKERRQ(ierr);
891   ierr = PetscLogEventEnd(DMSWARM_RemovePoints,0,0,0,0);CHKERRQ(ierr);
892   PetscFunctionReturn(0);
893 }
894 
895 /*@C
896    DMSwarmRemovePointAtIndex - Removes a specific point from the DMSwarm
897 
898    Not collective
899 
900    Input parameters:
901 +  dm - a DMSwarm
902 -  idx - index of point to remove
903 
904    Level: beginner
905 
906 .seealso: DMSwarmRemovePoint()
907 @*/
908 PETSC_EXTERN PetscErrorCode DMSwarmRemovePointAtIndex(DM dm,PetscInt idx)
909 {
910   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
911   PetscErrorCode ierr;
912 
913   PetscFunctionBegin;
914   ierr = PetscLogEventBegin(DMSWARM_RemovePoints,0,0,0,0);CHKERRQ(ierr);
915   ierr = DMSwarmDataBucketRemovePointAtIndex(swarm->db,idx);CHKERRQ(ierr);
916   ierr = PetscLogEventEnd(DMSWARM_RemovePoints,0,0,0,0);CHKERRQ(ierr);
917   PetscFunctionReturn(0);
918 }
919 
920 /*@C
921    DMSwarmCopyPoint - Copy point pj to point pi in the DMSwarm
922 
923    Not collective
924 
925    Input parameters:
926 +  dm - a DMSwarm
927 .  pi - the index of the point to copy
928 -  pj - the point index where the copy should be located
929 
930  Level: beginner
931 
932 .seealso: DMSwarmRemovePoint()
933 @*/
934 PETSC_EXTERN PetscErrorCode DMSwarmCopyPoint(DM dm,PetscInt pi,PetscInt pj)
935 {
936   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
937   PetscErrorCode ierr;
938 
939   PetscFunctionBegin;
940   if (!swarm->issetup) {ierr = DMSetUp(dm);CHKERRQ(ierr);}
941   ierr = DMSwarmDataBucketCopyPoint(swarm->db,pi,swarm->db,pj);CHKERRQ(ierr);
942   PetscFunctionReturn(0);
943 }
944 
945 PetscErrorCode DMSwarmMigrate_Basic(DM dm,PetscBool remove_sent_points)
946 {
947   PetscErrorCode ierr;
948 
949   PetscFunctionBegin;
950   ierr = DMSwarmMigrate_Push_Basic(dm,remove_sent_points);CHKERRQ(ierr);
951   PetscFunctionReturn(0);
952 }
953 
954 /*@C
955    DMSwarmMigrate - Relocates points defined in the DMSwarm to other MPI-ranks
956 
957    Collective on DM
958 
959    Input parameters:
960 +  dm - the DMSwarm
961 -  remove_sent_points - flag indicating if sent points should be removed from the current MPI-rank
962 
963    Notes:
964    The DM will be modified to accomodate received points.
965    If remove_sent_points = PETSC_TRUE, any points that were sent will be removed from the DM.
966    Different styles of migration are supported. See DMSwarmSetMigrateType().
967 
968    Level: advanced
969 
970 .seealso: DMSwarmSetMigrateType()
971 @*/
972 PETSC_EXTERN PetscErrorCode DMSwarmMigrate(DM dm,PetscBool remove_sent_points)
973 {
974   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
975   PetscErrorCode ierr;
976 
977   PetscFunctionBegin;
978   ierr = PetscLogEventBegin(DMSWARM_Migrate,0,0,0,0);CHKERRQ(ierr);
979   switch (swarm->migrate_type) {
980     case DMSWARM_MIGRATE_BASIC:
981       ierr = DMSwarmMigrate_Basic(dm,remove_sent_points);CHKERRQ(ierr);
982       break;
983     case DMSWARM_MIGRATE_DMCELLNSCATTER:
984       ierr = DMSwarmMigrate_CellDMScatter(dm,remove_sent_points);CHKERRQ(ierr);
985       break;
986     case DMSWARM_MIGRATE_DMCELLEXACT:
987       SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"DMSWARM_MIGRATE_DMCELLEXACT not implemented");
988       /*ierr = DMSwarmMigrate_CellDMExact(dm,remove_sent_points);CHKERRQ(ierr);*/
989       break;
990     case DMSWARM_MIGRATE_USER:
991       SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"DMSWARM_MIGRATE_USER not implemented");
992       /*ierr = swarm->migrate(dm,remove_sent_points);CHKERRQ(ierr);*/
993       break;
994     default:
995       SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"DMSWARM_MIGRATE type unknown");
996       break;
997   }
998   ierr = PetscLogEventEnd(DMSWARM_Migrate,0,0,0,0);CHKERRQ(ierr);
999   PetscFunctionReturn(0);
1000 }
1001 
1002 PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm,PetscInt *globalsize);
1003 
1004 /*
1005  DMSwarmCollectViewCreate
1006 
1007  * Applies a collection method and gathers point neighbour points into dm
1008 
1009  Notes:
1010  Users should call DMSwarmCollectViewDestroy() after
1011  they have finished computations associated with the collected points
1012 */
1013 
1014 /*@C
1015    DMSwarmCollectViewCreate - Applies a collection method and gathers points
1016    in neighbour MPI-ranks into the DMSwarm
1017 
1018    Collective on DM
1019 
1020    Input parameter:
1021 .  dm - the DMSwarm
1022 
1023    Notes:
1024    Users should call DMSwarmCollectViewDestroy() after
1025    they have finished computations associated with the collected points
1026    Different collect methods are supported. See DMSwarmSetCollectType().
1027 
1028    Level: advanced
1029 
1030 .seealso: DMSwarmCollectViewDestroy(), DMSwarmSetCollectType()
1031 @*/
1032 PETSC_EXTERN PetscErrorCode DMSwarmCollectViewCreate(DM dm)
1033 {
1034   PetscErrorCode ierr;
1035   DM_Swarm *swarm = (DM_Swarm*)dm->data;
1036   PetscInt ng;
1037 
1038   PetscFunctionBegin;
1039   if (swarm->collect_view_active) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"CollectView currently active");
1040   ierr = DMSwarmGetLocalSize(dm,&ng);CHKERRQ(ierr);
1041   switch (swarm->collect_type) {
1042 
1043     case DMSWARM_COLLECT_BASIC:
1044       ierr = DMSwarmMigrate_GlobalToLocal_Basic(dm,&ng);CHKERRQ(ierr);
1045       break;
1046     case DMSWARM_COLLECT_DMDABOUNDINGBOX:
1047       SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"DMSWARM_COLLECT_DMDABOUNDINGBOX not implemented");
1048       /*ierr = DMSwarmCollect_DMDABoundingBox(dm,&ng);CHKERRQ(ierr);*/
1049       break;
1050     case DMSWARM_COLLECT_GENERAL:
1051       SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"DMSWARM_COLLECT_GENERAL not implemented");
1052       /*ierr = DMSwarmCollect_General(dm,..,,..,&ng);CHKERRQ(ierr);*/
1053       break;
1054     default:
1055       SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"DMSWARM_COLLECT type unknown");
1056       break;
1057   }
1058   swarm->collect_view_active = PETSC_TRUE;
1059   swarm->collect_view_reset_nlocal = ng;
1060   PetscFunctionReturn(0);
1061 }
1062 
1063 /*@C
1064    DMSwarmCollectViewDestroy - Resets the DMSwarm to the size prior to calling DMSwarmCollectViewCreate()
1065 
1066    Collective on DM
1067 
1068    Input parameters:
1069 .  dm - the DMSwarm
1070 
1071    Notes:
1072    Users should call DMSwarmCollectViewCreate() before this function is called.
1073 
1074    Level: advanced
1075 
1076 .seealso: DMSwarmCollectViewCreate(), DMSwarmSetCollectType()
1077 @*/
1078 PETSC_EXTERN PetscErrorCode DMSwarmCollectViewDestroy(DM dm)
1079 {
1080   PetscErrorCode ierr;
1081   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
1082 
1083   PetscFunctionBegin;
1084   if (!swarm->collect_view_active) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"CollectView is currently not active");
1085   ierr = DMSwarmSetLocalSizes(dm,swarm->collect_view_reset_nlocal,-1);CHKERRQ(ierr);
1086   swarm->collect_view_active = PETSC_FALSE;
1087   PetscFunctionReturn(0);
1088 }
1089 
1090 PetscErrorCode DMSwarmSetUpPIC(DM dm)
1091 {
1092   PetscInt       dim;
1093   PetscErrorCode ierr;
1094 
1095   PetscFunctionBegin;
1096   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
1097   if (dim < 1) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Dimension must be 1,2,3 - found %D",dim);
1098   if (dim > 3) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Dimension must be 1,2,3 - found %D",dim);
1099   ierr = DMSwarmRegisterPetscDatatypeField(dm,DMSwarmPICField_coor,dim,PETSC_DOUBLE);CHKERRQ(ierr);
1100   ierr = DMSwarmRegisterPetscDatatypeField(dm,DMSwarmPICField_cellid,1,PETSC_INT);CHKERRQ(ierr);
1101   PetscFunctionReturn(0);
1102 }
1103 
1104 /*@C
1105    DMSwarmSetType - Set particular flavor of DMSwarm
1106 
1107    Collective on DM
1108 
1109    Input parameters:
1110 +  dm - the DMSwarm
1111 -  stype - the DMSwarm type (e.g. DMSWARM_PIC)
1112 
1113    Level: advanced
1114 
1115 .seealso: DMSwarmSetMigrateType(), DMSwarmSetCollectType()
1116 @*/
1117 PETSC_EXTERN PetscErrorCode DMSwarmSetType(DM dm,DMSwarmType stype)
1118 {
1119   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
1120   PetscErrorCode ierr;
1121 
1122   PetscFunctionBegin;
1123   swarm->swarm_type = stype;
1124   if (swarm->swarm_type == DMSWARM_PIC) {
1125     ierr = DMSwarmSetUpPIC(dm);CHKERRQ(ierr);
1126   }
1127   PetscFunctionReturn(0);
1128 }
1129 
1130 PetscErrorCode DMSetup_Swarm(DM dm)
1131 {
1132   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
1133   PetscErrorCode ierr;
1134   PetscMPIInt    rank;
1135   PetscInt       p,npoints,*rankval;
1136 
1137   PetscFunctionBegin;
1138   if (swarm->issetup) PetscFunctionReturn(0);
1139 
1140   swarm->issetup = PETSC_TRUE;
1141 
1142   if (swarm->swarm_type == DMSWARM_PIC) {
1143     /* check dmcell exists */
1144     if (!swarm->dmcell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"DMSWARM_PIC requires you call DMSwarmSetCellDM");
1145 
1146     if (swarm->dmcell->ops->locatepointssubdomain) {
1147       /* check methods exists for exact ownership identificiation */
1148       ierr = PetscPrintf(PetscObjectComm((PetscObject)dm),"  DMSWARM_PIC: Using method CellDM->ops->LocatePointsSubdomain\n");CHKERRQ(ierr);
1149       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLEXACT;
1150     } else {
1151       /* check methods exist for point location AND rank neighbor identification */
1152       if (swarm->dmcell->ops->locatepoints) {
1153         ierr = PetscPrintf(PetscObjectComm((PetscObject)dm),"  DMSWARM_PIC: Using method CellDM->LocatePoints\n");CHKERRQ(ierr);
1154       } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"DMSWARM_PIC requires the method CellDM->ops->locatepoints be defined");
1155 
1156       if (swarm->dmcell->ops->getneighbors) {
1157         ierr = PetscPrintf(PetscObjectComm((PetscObject)dm),"  DMSWARM_PIC: Using method CellDM->GetNeigbors\n");CHKERRQ(ierr);
1158       } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"DMSWARM_PIC requires the method CellDM->ops->getneighbors be defined");
1159 
1160       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLNSCATTER;
1161     }
1162   }
1163 
1164   ierr = DMSwarmFinalizeFieldRegister(dm);CHKERRQ(ierr);
1165 
1166   /* check some fields were registered */
1167   if (swarm->db->nfields <= 2) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"At least one field user must be registered via DMSwarmRegisterXXX()");
1168 
1169   /* check local sizes were set */
1170   if (swarm->db->L == -1) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Local sizes must be set via DMSwarmSetLocalSizes()");
1171 
1172   /* initialize values in pid and rank placeholders */
1173   /* TODO: [pid - use MPI_Scan] */
1174   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRQ(ierr);
1175   ierr = DMSwarmDataBucketGetSizes(swarm->db,&npoints,NULL,NULL);CHKERRQ(ierr);
1176   ierr = DMSwarmGetField(dm,DMSwarmField_rank,NULL,NULL,(void**)&rankval);CHKERRQ(ierr);
1177   for (p=0; p<npoints; p++) {
1178     rankval[p] = (PetscInt)rank;
1179   }
1180   ierr = DMSwarmRestoreField(dm,DMSwarmField_rank,NULL,NULL,(void**)&rankval);CHKERRQ(ierr);
1181   PetscFunctionReturn(0);
1182 }
1183 
1184 extern PetscErrorCode DMSwarmSortDestroy(DMSwarmSort *_ctx);
1185 
1186 PetscErrorCode DMDestroy_Swarm(DM dm)
1187 {
1188   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
1189   PetscErrorCode ierr;
1190 
1191   PetscFunctionBegin;
1192   ierr = DMSwarmDataBucketDestroy(&swarm->db);CHKERRQ(ierr);
1193   if (swarm->sort_context) {
1194     ierr = DMSwarmSortDestroy(&swarm->sort_context);CHKERRQ(ierr);
1195   }
1196   ierr = PetscFree(swarm);CHKERRQ(ierr);
1197   PetscFunctionReturn(0);
1198 }
1199 
1200 PetscErrorCode DMSwarmView_Draw(DM dm, PetscViewer viewer)
1201 {
1202   DM             cdm;
1203   PetscDraw      draw;
1204   PetscReal     *coords, oldPause;
1205   PetscInt       Np, p, bs;
1206   PetscErrorCode ierr;
1207 
1208   PetscFunctionBegin;
1209   ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr);
1210   ierr = DMSwarmGetCellDM(dm, &cdm);CHKERRQ(ierr);
1211   ierr = PetscDrawGetPause(draw, &oldPause);CHKERRQ(ierr);
1212   ierr = PetscDrawSetPause(draw, 0.0);CHKERRQ(ierr);
1213   ierr = DMView(cdm, viewer);CHKERRQ(ierr);
1214   ierr = PetscDrawSetPause(draw, oldPause);CHKERRQ(ierr);
1215 
1216   ierr = DMSwarmGetLocalSize(dm, &Np);CHKERRQ(ierr);
1217   ierr = DMSwarmGetField(dm, DMSwarmPICField_coor, &bs, NULL, (void **) &coords);CHKERRQ(ierr);
1218   for (p = 0; p < Np; ++p) {
1219     const PetscInt i = p*bs;
1220 
1221     ierr = PetscDrawEllipse(draw, coords[i], coords[i+1], 0.01, 0.01, PETSC_DRAW_BLUE);CHKERRQ(ierr);
1222   }
1223   ierr = DMSwarmRestoreField(dm, DMSwarmPICField_coor, &bs, NULL, (void **) &coords);CHKERRQ(ierr);
1224   ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
1225   ierr = PetscDrawPause(draw);CHKERRQ(ierr);
1226   ierr = PetscDrawSave(draw);CHKERRQ(ierr);
1227   PetscFunctionReturn(0);
1228 }
1229 
1230 PetscErrorCode DMView_Swarm(DM dm, PetscViewer viewer)
1231 {
1232   DM_Swarm       *swarm = (DM_Swarm*)dm->data;
1233   PetscBool      iascii,ibinary,ishdf5,isvtk,isdraw;
1234   PetscErrorCode ierr;
1235 
1236   PetscFunctionBegin;
1237   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1238   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
1239   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1240   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY,&ibinary);CHKERRQ(ierr);
1241   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK,   &isvtk);CHKERRQ(ierr);
1242   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5,  &ishdf5);CHKERRQ(ierr);
1243   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW,  &isdraw);CHKERRQ(ierr);
1244   if (iascii) {
1245     ierr = DMSwarmDataBucketView(PetscObjectComm((PetscObject)dm),swarm->db,NULL,DATABUCKET_VIEW_STDOUT);CHKERRQ(ierr);
1246   } else if (ibinary) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"NO Binary support");
1247 #if defined(PETSC_HAVE_HDF5)
1248   else if (ishdf5) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"NO HDF5 support");
1249 #else
1250   else if (ishdf5) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"HDF5 not supported. Please reconfigure using --download-hdf5");
1251 #endif
1252   else if (isvtk) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"NO VTK support");
1253   else if (isdraw) {
1254     ierr = DMSwarmView_Draw(dm, viewer);CHKERRQ(ierr);
1255   }
1256   PetscFunctionReturn(0);
1257 }
1258 
1259 /*MC
1260 
1261  DMSWARM = "swarm" - A DM object used to represent arrays of data (fields) of arbitrary data type.
1262  This implementation was designed for particle methods in which the underlying
1263  data required to be represented is both (i) dynamic in length, (ii) and of arbitrary data type.
1264 
1265  User data can be represented by DMSwarm through a registering "fields".
1266  To register a field, the user must provide;
1267  (a) a unique name;
1268  (b) the data type (or size in bytes);
1269  (c) the block size of the data.
1270 
1271  For example, suppose the application requires a unique id, energy, momentum and density to be stored
1272  on a set of of particles. Then the following code could be used
1273 
1274 $    DMSwarmInitializeFieldRegister(dm)
1275 $    DMSwarmRegisterPetscDatatypeField(dm,"uid",1,PETSC_LONG);
1276 $    DMSwarmRegisterPetscDatatypeField(dm,"energy",1,PETSC_REAL);
1277 $    DMSwarmRegisterPetscDatatypeField(dm,"momentum",3,PETSC_REAL);
1278 $    DMSwarmRegisterPetscDatatypeField(dm,"density",1,PETSC_FLOAT);
1279 $    DMSwarmFinalizeFieldRegister(dm)
1280 
1281  The fields represented by DMSwarm are dynamic and can be re-sized at any time.
1282  The only restriction imposed by DMSwarm is that all fields contain the same number of points.
1283 
1284  To support particle methods, "migration" techniques are provided. These methods migrate data
1285  between MPI-ranks.
1286 
1287  DMSwarm supports the methods DMCreateGlobalVector() and DMCreateLocalVector().
1288  As a DMSwarm may internally define and store values of different data types,
1289  before calling DMCreateGlobalVector() or DMCreateLocalVector(), the user must inform DMSwarm which
1290  fields should be used to define a Vec object via
1291    DMSwarmVectorDefineField()
1292  The specified field can can changed be changed at any time - thereby permitting vectors
1293  compatable with different fields to be created.
1294 
1295  A dual representation of fields in the DMSwarm and a Vec object is permitted via
1296    DMSwarmCreateGlobalVectorFromField()
1297  Here the data defining the field in the DMSwarm is shared with a Vec.
1298  This is inherently unsafe if you alter the size of the field at any time between
1299  calls to DMSwarmCreateGlobalVectorFromField() and DMSwarmDestroyGlobalVectorFromField().
1300  If the local size of the DMSwarm does not match the local size of the global vector
1301  when DMSwarmDestroyGlobalVectorFromField() is called, an error is thrown.
1302 
1303  Additional high-level support is provided for Particle-In-Cell methods.
1304  Please refer to the man page for DMSwarmSetType().
1305 
1306  Level: beginner
1307 
1308 .seealso: DMType, DMCreate(), DMSetType()
1309 M*/
1310 PETSC_EXTERN PetscErrorCode DMCreate_Swarm(DM dm)
1311 {
1312   DM_Swarm      *swarm;
1313   PetscErrorCode ierr;
1314 
1315   PetscFunctionBegin;
1316   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1317   ierr     = PetscNewLog(dm,&swarm);CHKERRQ(ierr);
1318   dm->data = swarm;
1319 
1320   ierr = DMSwarmDataBucketCreate(&swarm->db);CHKERRQ(ierr);
1321   ierr = DMSwarmInitializeFieldRegister(dm);CHKERRQ(ierr);
1322 
1323   swarm->vec_field_set = PETSC_FALSE;
1324   swarm->issetup = PETSC_FALSE;
1325   swarm->swarm_type = DMSWARM_BASIC;
1326   swarm->migrate_type = DMSWARM_MIGRATE_BASIC;
1327   swarm->collect_type = DMSWARM_COLLECT_BASIC;
1328   swarm->migrate_error_on_missing_point = PETSC_FALSE;
1329 
1330   swarm->dmcell = NULL;
1331   swarm->collect_view_active = PETSC_FALSE;
1332   swarm->collect_view_reset_nlocal = -1;
1333 
1334   dm->dim  = 0;
1335   dm->ops->view                            = DMView_Swarm;
1336   dm->ops->load                            = NULL;
1337   dm->ops->setfromoptions                  = NULL;
1338   dm->ops->clone                           = NULL;
1339   dm->ops->setup                           = DMSetup_Swarm;
1340   dm->ops->createdefaultsection            = NULL;
1341   dm->ops->createdefaultconstraints        = NULL;
1342   dm->ops->createglobalvector              = DMCreateGlobalVector_Swarm;
1343   dm->ops->createlocalvector               = DMCreateLocalVector_Swarm;
1344   dm->ops->getlocaltoglobalmapping         = NULL;
1345   dm->ops->createfieldis                   = NULL;
1346   dm->ops->createcoordinatedm              = NULL;
1347   dm->ops->getcoloring                     = NULL;
1348   dm->ops->creatematrix                    = NULL;
1349   dm->ops->createinterpolation             = NULL;
1350   dm->ops->getaggregates                   = NULL;
1351   dm->ops->getinjection                    = NULL;
1352   dm->ops->createmassmatrix                = DMCreateMassMatrix_Swarm;
1353   dm->ops->refine                          = NULL;
1354   dm->ops->coarsen                         = NULL;
1355   dm->ops->refinehierarchy                 = NULL;
1356   dm->ops->coarsenhierarchy                = NULL;
1357   dm->ops->globaltolocalbegin              = NULL;
1358   dm->ops->globaltolocalend                = NULL;
1359   dm->ops->localtoglobalbegin              = NULL;
1360   dm->ops->localtoglobalend                = NULL;
1361   dm->ops->destroy                         = DMDestroy_Swarm;
1362   dm->ops->createsubdm                     = NULL;
1363   dm->ops->getdimpoints                    = NULL;
1364   dm->ops->locatepoints                    = NULL;
1365   PetscFunctionReturn(0);
1366 }
1367