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