xref: /petsc/src/dm/impls/swarm/swarm.c (revision 7f92dde0fdec9098ae2583920e5a4420d2e3ff3e)
1d52c2f21SMatthew G. Knepley #include "petscsys.h"
257795646SDave May #define PETSCDM_DLL
357795646SDave May #include <petsc/private/dmswarmimpl.h> /*I   "petscdmswarm.h"   I*/
4e8f14785SLisandro Dalcin #include <petsc/private/hashsetij.h>
50643ed39SMatthew G. Knepley #include <petsc/private/petscfeimpl.h>
65917a6f0SStefano Zampini #include <petscviewer.h>
75917a6f0SStefano Zampini #include <petscdraw.h>
883c47955SMatthew G. Knepley #include <petscdmplex.h>
94cc7f7b2SMatthew G. Knepley #include <petscblaslapack.h>
10279f676cSBarry Smith #include "../src/dm/impls/swarm/data_bucket.h"
11d0c080abSJoseph Pusztay #include <petscdmlabel.h>
12d0c080abSJoseph Pusztay #include <petscsection.h>
1357795646SDave May 
14f2b2bee7SDave May PetscLogEvent DMSWARM_Migrate, DMSWARM_SetSizes, DMSWARM_AddPoints, DMSWARM_RemovePoints, DMSWARM_Sort;
15ed923d71SDave May PetscLogEvent DMSWARM_DataExchangerTopologySetup, DMSWARM_DataExchangerBegin, DMSWARM_DataExchangerEnd;
16ed923d71SDave May PetscLogEvent DMSWARM_DataExchangerSendCount, DMSWARM_DataExchangerPack;
17ed923d71SDave May 
18ea78f98cSLisandro Dalcin const char *DMSwarmTypeNames[]          = {"basic", "pic", NULL};
19ea78f98cSLisandro Dalcin const char *DMSwarmMigrateTypeNames[]   = {"basic", "dmcellnscatter", "dmcellexact", "user", NULL};
20ea78f98cSLisandro Dalcin const char *DMSwarmCollectTypeNames[]   = {"basic", "boundingbox", "general", "user", NULL};
21ea78f98cSLisandro Dalcin const char *DMSwarmPICLayoutTypeNames[] = {"regular", "gauss", "subdivision", NULL};
22f0cdbbbaSDave May 
23f0cdbbbaSDave May const char DMSwarmField_pid[]       = "DMSwarm_pid";
24f0cdbbbaSDave May const char DMSwarmField_rank[]      = "DMSwarm_rank";
25f0cdbbbaSDave May const char DMSwarmPICField_coor[]   = "DMSwarmPIC_coor";
26e2d107dbSDave May const char DMSwarmPICField_cellid[] = "DMSwarm_cellid";
27f0cdbbbaSDave May 
282e956fe4SStefano Zampini PetscInt SwarmDataFieldId = -1;
292e956fe4SStefano Zampini 
3074d0cae8SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
3174d0cae8SMatthew G. Knepley   #include <petscviewerhdf5.h>
3274d0cae8SMatthew G. Knepley 
33d52c2f21SMatthew G. Knepley static PetscErrorCode DMInitialize_Swarm(DM);
34d52c2f21SMatthew G. Knepley static PetscErrorCode DMDestroy_Swarm(DM);
35d52c2f21SMatthew G. Knepley 
36d52c2f21SMatthew G. Knepley /* Replace dm with the contents of ndm, and then destroy ndm
37d52c2f21SMatthew G. Knepley    - Share the DM_Swarm structure
38d52c2f21SMatthew G. Knepley */
39d52c2f21SMatthew G. Knepley PetscErrorCode DMSwarmReplace_Internal(DM dm, DM *ndm)
40d52c2f21SMatthew G. Knepley {
41d52c2f21SMatthew G. Knepley   DM               dmNew = *ndm;
42d52c2f21SMatthew G. Knepley   const PetscReal *maxCell, *Lstart, *L;
43d52c2f21SMatthew G. Knepley   PetscInt         dim;
44d52c2f21SMatthew G. Knepley 
45d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
46d52c2f21SMatthew G. Knepley   if (dm == dmNew) {
47d52c2f21SMatthew G. Knepley     PetscCall(DMDestroy(ndm));
48d52c2f21SMatthew G. Knepley     PetscFunctionReturn(PETSC_SUCCESS);
49d52c2f21SMatthew G. Knepley   }
50d52c2f21SMatthew G. Knepley   dm->setupcalled = dmNew->setupcalled;
51d52c2f21SMatthew G. Knepley   if (!dm->hdr.name) {
52d52c2f21SMatthew G. Knepley     const char *name;
53d52c2f21SMatthew G. Knepley 
54d52c2f21SMatthew G. Knepley     PetscCall(PetscObjectGetName((PetscObject)*ndm, &name));
55d52c2f21SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)dm, name));
56d52c2f21SMatthew G. Knepley   }
57d52c2f21SMatthew G. Knepley   PetscCall(DMGetDimension(dmNew, &dim));
58d52c2f21SMatthew G. Knepley   PetscCall(DMSetDimension(dm, dim));
59d52c2f21SMatthew G. Knepley   PetscCall(DMGetPeriodicity(dmNew, &maxCell, &Lstart, &L));
60d52c2f21SMatthew G. Knepley   PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
61d52c2f21SMatthew G. Knepley   PetscCall(DMDestroy_Swarm(dm));
62d52c2f21SMatthew G. Knepley   PetscCall(DMInitialize_Swarm(dm));
63d52c2f21SMatthew G. Knepley   dm->data = dmNew->data;
64d52c2f21SMatthew G. Knepley   ((DM_Swarm *)dmNew->data)->refct++;
65d52c2f21SMatthew G. Knepley   PetscCall(DMDestroy(ndm));
66d52c2f21SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
67d52c2f21SMatthew G. Knepley }
68d52c2f21SMatthew G. Knepley 
6966976f2fSJacob Faibussowitsch static PetscErrorCode VecView_Swarm_HDF5_Internal(Vec v, PetscViewer viewer)
70d71ae5a4SJacob Faibussowitsch {
7174d0cae8SMatthew G. Knepley   DM        dm;
7274d0cae8SMatthew G. Knepley   PetscReal seqval;
7374d0cae8SMatthew G. Knepley   PetscInt  seqnum, bs;
74eb0c6899SMatthew G. Knepley   PetscBool isseq, ists;
7574d0cae8SMatthew G. Knepley 
7674d0cae8SMatthew G. Knepley   PetscFunctionBegin;
779566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
789566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v, &bs));
799566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PushGroup(viewer, "/particle_fields"));
809566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
819566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, &seqval));
82eb0c6899SMatthew G. Knepley   PetscCall(PetscViewerHDF5IsTimestepping(viewer, &ists));
83eb0c6899SMatthew G. Knepley   if (ists) PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum));
849566063dSJacob Faibussowitsch   /* PetscCall(DMSequenceView_HDF5(dm, "time", seqnum, (PetscScalar) seqval, viewer)); */
859566063dSJacob Faibussowitsch   PetscCall(VecViewNative(v, viewer));
869566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)v, "Nc", PETSC_INT, (void *)&bs));
879566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PopGroup(viewer));
883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8974d0cae8SMatthew G. Knepley }
9074d0cae8SMatthew G. Knepley 
9166976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmView_HDF5(DM dm, PetscViewer viewer)
92d71ae5a4SJacob Faibussowitsch {
9374d0cae8SMatthew G. Knepley   Vec         coordinates;
9474d0cae8SMatthew G. Knepley   PetscInt    Np;
9574d0cae8SMatthew G. Knepley   PetscBool   isseq;
96d52c2f21SMatthew G. Knepley   const char *coordname;
9774d0cae8SMatthew G. Knepley 
9874d0cae8SMatthew G. Knepley   PetscFunctionBegin;
99d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetCoordinateField(dm, &coordname));
1009566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetSize(dm, &Np));
101d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(dm, coordname, &coordinates));
1029566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
1039566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PushGroup(viewer, "/particles"));
1049566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)coordinates, VECSEQ, &isseq));
1059566063dSJacob Faibussowitsch   PetscCall(VecViewNative(coordinates, viewer));
1069566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)coordinates, "Np", PETSC_INT, (void *)&Np));
1079566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PopGroup(viewer));
108d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(dm, coordname, &coordinates));
1093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11074d0cae8SMatthew G. Knepley }
11174d0cae8SMatthew G. Knepley #endif
11274d0cae8SMatthew G. Knepley 
11366976f2fSJacob Faibussowitsch static PetscErrorCode VecView_Swarm(Vec v, PetscViewer viewer)
114d71ae5a4SJacob Faibussowitsch {
11574d0cae8SMatthew G. Knepley   DM dm;
116f9558f5cSBarry Smith #if defined(PETSC_HAVE_HDF5)
11774d0cae8SMatthew G. Knepley   PetscBool ishdf5;
118f9558f5cSBarry Smith #endif
11974d0cae8SMatthew G. Knepley 
12074d0cae8SMatthew G. Knepley   PetscFunctionBegin;
1219566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
12228b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
123f9558f5cSBarry Smith #if defined(PETSC_HAVE_HDF5)
1249566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
12574d0cae8SMatthew G. Knepley   if (ishdf5) {
1269566063dSJacob Faibussowitsch     PetscCall(VecView_Swarm_HDF5_Internal(v, viewer));
1273ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
12874d0cae8SMatthew G. Knepley   }
129f9558f5cSBarry Smith #endif
1309566063dSJacob Faibussowitsch   PetscCall(VecViewNative(v, viewer));
1313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13274d0cae8SMatthew G. Knepley }
13374d0cae8SMatthew G. Knepley 
134d52c2f21SMatthew G. Knepley /*@C
135d52c2f21SMatthew G. Knepley   DMSwarmVectorGetField - Gets the fields from which to define a `Vec` object
1360bf7c1c5SMatthew G. Knepley   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
1370bf7c1c5SMatthew G. Knepley 
1380bf7c1c5SMatthew G. Knepley   Not collective
1390bf7c1c5SMatthew G. Knepley 
1400bf7c1c5SMatthew G. Knepley   Input Parameter:
1410bf7c1c5SMatthew G. Knepley . dm - a `DMSWARM`
1420bf7c1c5SMatthew G. Knepley 
143d52c2f21SMatthew G. Knepley   Output Parameters:
144d52c2f21SMatthew G. Knepley + Nf         - the number of fields
145d52c2f21SMatthew G. Knepley - fieldnames - the textual name given to each registered field, or NULL if it has not been set
1460bf7c1c5SMatthew G. Knepley 
1470bf7c1c5SMatthew G. Knepley   Level: beginner
1480bf7c1c5SMatthew G. Knepley 
149d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
1500bf7c1c5SMatthew G. Knepley @*/
151d52c2f21SMatthew G. Knepley PetscErrorCode DMSwarmVectorGetField(DM dm, PetscInt *Nf, const char **fieldnames[])
1520bf7c1c5SMatthew G. Knepley {
1530bf7c1c5SMatthew G. Knepley   PetscFunctionBegin;
1540bf7c1c5SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
155d52c2f21SMatthew G. Knepley   if (Nf) {
156d52c2f21SMatthew G. Knepley     PetscAssertPointer(Nf, 2);
157d52c2f21SMatthew G. Knepley     *Nf = ((DM_Swarm *)dm->data)->vec_field_num;
158d52c2f21SMatthew G. Knepley   }
159d52c2f21SMatthew G. Knepley   if (fieldnames) {
160d52c2f21SMatthew G. Knepley     PetscAssertPointer(fieldnames, 3);
161d52c2f21SMatthew G. Knepley     *fieldnames = ((DM_Swarm *)dm->data)->vec_field_names;
162d52c2f21SMatthew G. Knepley   }
1630bf7c1c5SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1640bf7c1c5SMatthew G. Knepley }
1650bf7c1c5SMatthew G. Knepley 
166cc4c1da9SBarry Smith /*@
16720f4b53cSBarry Smith   DMSwarmVectorDefineField - Sets the field from which to define a `Vec` object
16820f4b53cSBarry Smith   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
16957795646SDave May 
17020f4b53cSBarry Smith   Collective
17157795646SDave May 
17260225df5SJacob Faibussowitsch   Input Parameters:
17320f4b53cSBarry Smith + dm        - a `DMSWARM`
174d52c2f21SMatthew G. Knepley - fieldname - the textual name given to each registered field
17557795646SDave May 
176d3a51819SDave May   Level: beginner
17757795646SDave May 
178d3a51819SDave May   Notes:
17920f4b53cSBarry Smith   The field with name `fieldname` must be defined as having a data type of `PetscScalar`.
180e7af74c8SDave May 
18120f4b53cSBarry Smith   This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`.
18220f4b53cSBarry Smith   Multiple calls to `DMSwarmVectorDefineField()` are permitted.
183e7af74c8SDave May 
184d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineFields()`, `DMSwarmVectorGetField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
185d3a51819SDave May @*/
186d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmVectorDefineField(DM dm, const char fieldname[])
187d71ae5a4SJacob Faibussowitsch {
188d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
189d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmVectorDefineFields(dm, 1, &fieldname));
190d52c2f21SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
191d52c2f21SMatthew G. Knepley }
192d52c2f21SMatthew G. Knepley 
193d52c2f21SMatthew G. Knepley /*@C
194d52c2f21SMatthew G. Knepley   DMSwarmVectorDefineFields - Sets the fields from which to define a `Vec` object
195d52c2f21SMatthew G. Knepley   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
196d52c2f21SMatthew G. Knepley 
197d52c2f21SMatthew G. Knepley   Collective, No Fortran support
198d52c2f21SMatthew G. Knepley 
199d52c2f21SMatthew G. Knepley   Input Parameters:
200d52c2f21SMatthew G. Knepley + dm         - a `DMSWARM`
201d52c2f21SMatthew G. Knepley . Nf         - the number of fields
202d52c2f21SMatthew G. Knepley - fieldnames - the textual name given to each registered field
203d52c2f21SMatthew G. Knepley 
204d52c2f21SMatthew G. Knepley   Level: beginner
205d52c2f21SMatthew G. Knepley 
206d52c2f21SMatthew G. Knepley   Notes:
207d52c2f21SMatthew G. Knepley   Each field with name in `fieldnames` must be defined as having a data type of `PetscScalar`.
208d52c2f21SMatthew G. Knepley 
209d52c2f21SMatthew G. Knepley   This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`.
210d52c2f21SMatthew G. Knepley   Multiple calls to `DMSwarmVectorDefineField()` are permitted.
211d52c2f21SMatthew G. Knepley 
212d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineField()`, `DMSwarmVectorGetField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
213d52c2f21SMatthew G. Knepley @*/
214d52c2f21SMatthew G. Knepley PetscErrorCode DMSwarmVectorDefineFields(DM dm, PetscInt Nf, const char *fieldnames[])
215d52c2f21SMatthew G. Knepley {
216d52c2f21SMatthew G. Knepley   DM_Swarm *sw = (DM_Swarm *)dm->data;
217b5bcf523SDave May 
218a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
2190bf7c1c5SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
220d52c2f21SMatthew G. Knepley   if (fieldnames) PetscAssertPointer(fieldnames, 3);
221d52c2f21SMatthew G. Knepley   if (!sw->issetup) PetscCall(DMSetUp(dm));
222d52c2f21SMatthew G. Knepley   PetscCheck(Nf >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields must be non-negative, not %" PetscInt_FMT, Nf);
223d52c2f21SMatthew G. Knepley   for (PetscInt f = 0; f < sw->vec_field_num; ++f) PetscCall(PetscFree(sw->vec_field_names[f]));
224d52c2f21SMatthew G. Knepley   PetscCall(PetscFree(sw->vec_field_names));
225b5bcf523SDave May 
226d52c2f21SMatthew G. Knepley   sw->vec_field_num = Nf;
227d52c2f21SMatthew G. Knepley   sw->vec_field_bs  = 0;
228d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmDataBucketGetSizes(sw->db, &sw->vec_field_nlocal, NULL, NULL));
229d52c2f21SMatthew G. Knepley   PetscCall(PetscMalloc1(Nf, &sw->vec_field_names));
230d52c2f21SMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) {
231d52c2f21SMatthew G. Knepley     PetscInt      bs;
232d52c2f21SMatthew G. Knepley     PetscScalar  *array;
233d52c2f21SMatthew G. Knepley     PetscDataType type;
234d52c2f21SMatthew G. Knepley 
235d52c2f21SMatthew G. Knepley     PetscCall(DMSwarmGetField(dm, fieldnames[f], &bs, &type, (void **)&array));
236d52c2f21SMatthew G. Knepley     // Check all fields are of type PETSC_REAL or PETSC_SCALAR
23708401ef6SPierre Jolivet     PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
238d52c2f21SMatthew G. Knepley     sw->vec_field_bs += bs;
239d52c2f21SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dm, fieldnames[f], &bs, &type, (void **)&array));
240d52c2f21SMatthew G. Knepley     PetscCall(PetscStrallocpy(fieldnames[f], (char **)&sw->vec_field_names[f]));
241d52c2f21SMatthew G. Knepley   }
2423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
243b5bcf523SDave May }
244b5bcf523SDave May 
245cc651181SDave May /* requires DMSwarmDefineFieldVector has been called */
24666976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateGlobalVector_Swarm(DM dm, Vec *vec)
247d71ae5a4SJacob Faibussowitsch {
248b5bcf523SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
249b5bcf523SDave May   Vec       x;
250b5bcf523SDave May   char      name[PETSC_MAX_PATH_LEN];
251b5bcf523SDave May 
252a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
2539566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
254d52c2f21SMatthew G. Knepley   PetscCheck(swarm->vec_field_num, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmVectorDefineField(s) first");
255d52c2f21SMatthew G. Knepley   PetscCheck(swarm->vec_field_nlocal == swarm->db->L, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSwarm sizes have changed since last call to VectorDefineField(s) first"); /* Stale data */
256cc651181SDave May 
257d52c2f21SMatthew G. Knepley   PetscCall(PetscStrncpy(name, "DMSwarmField", PETSC_MAX_PATH_LEN));
258d52c2f21SMatthew G. Knepley   for (PetscInt f = 0; f < swarm->vec_field_num; ++f) {
259d52c2f21SMatthew G. Knepley     PetscCall(PetscStrlcat(name, "_", PETSC_MAX_PATH_LEN));
260d52c2f21SMatthew G. Knepley     PetscCall(PetscStrlcat(name, swarm->vec_field_names[f], PETSC_MAX_PATH_LEN));
261d52c2f21SMatthew G. Knepley   }
2629566063dSJacob Faibussowitsch   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &x));
2639566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)x, name));
2649566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(x, swarm->db->L * swarm->vec_field_bs, PETSC_DETERMINE));
2659566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(x, swarm->vec_field_bs));
2669566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
2679566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(x));
2689566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
2699566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(x, VECOP_VIEW, (void (*)(void))VecView_Swarm));
270b5bcf523SDave May   *vec = x;
2713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
272b5bcf523SDave May }
273b5bcf523SDave May 
274b5bcf523SDave May /* requires DMSwarmDefineFieldVector has been called */
27566976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateLocalVector_Swarm(DM dm, Vec *vec)
276d71ae5a4SJacob Faibussowitsch {
277b5bcf523SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
278b5bcf523SDave May   Vec       x;
279b5bcf523SDave May   char      name[PETSC_MAX_PATH_LEN];
280b5bcf523SDave May 
281a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
2829566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
283d52c2f21SMatthew G. Knepley   PetscCheck(swarm->vec_field_num, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmVectorDefineField(s) first");
284d52c2f21SMatthew G. Knepley   PetscCheck(swarm->vec_field_nlocal == swarm->db->L, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSwarm sizes have changed since last call to VectorDefineField(s) first");
285cc651181SDave May 
286d52c2f21SMatthew G. Knepley   PetscCall(PetscStrncpy(name, "DMSwarmField", PETSC_MAX_PATH_LEN));
287d52c2f21SMatthew G. Knepley   for (PetscInt f = 0; f < swarm->vec_field_num; ++f) {
288d52c2f21SMatthew G. Knepley     PetscCall(PetscStrlcat(name, "_", PETSC_MAX_PATH_LEN));
289d52c2f21SMatthew G. Knepley     PetscCall(PetscStrlcat(name, swarm->vec_field_names[f], PETSC_MAX_PATH_LEN));
290d52c2f21SMatthew G. Knepley   }
2919566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &x));
2929566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)x, name));
2939566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(x, swarm->db->L * swarm->vec_field_bs, PETSC_DETERMINE));
2949566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(x, swarm->vec_field_bs));
2959566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
2969566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(x));
297b5bcf523SDave May   *vec = x;
2983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
299b5bcf523SDave May }
300b5bcf523SDave May 
301d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmDestroyVectorFromField_Private(DM dm, const char fieldname[], Vec *vec)
302d71ae5a4SJacob Faibussowitsch {
303fb1bcc12SMatthew G. Knepley   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
30477048351SPatrick Sanan   DMSwarmDataField gfield;
3052e956fe4SStefano Zampini   PetscInt         bs, nlocal, fid = -1, cfid = -2;
3062e956fe4SStefano Zampini   PetscBool        flg;
307d3a51819SDave May 
308fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
3092e956fe4SStefano Zampini   /* check vector is an inplace array */
3102e956fe4SStefano Zampini   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
3112e956fe4SStefano Zampini   PetscCall(PetscObjectComposedDataGetInt((PetscObject)*vec, SwarmDataFieldId, cfid, flg));
312ea17275aSJose E. Roman   (void)flg; /* avoid compiler warning */
313e978a55eSPierre Jolivet   PetscCheck(cfid == fid, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Vector being destroyed was not created from DMSwarm field(%s)! %" PetscInt_FMT " != %" PetscInt_FMT, fieldname, cfid, fid);
3149566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(*vec, &nlocal));
3159566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(*vec, &bs));
31608401ef6SPierre Jolivet   PetscCheck(nlocal / bs == swarm->db->L, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSwarm sizes have changed since vector was created - cannot ensure pointers are valid");
3179566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
3189566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
3198df78e51SMark Adams   PetscCall(VecResetArray(*vec));
3209566063dSJacob Faibussowitsch   PetscCall(VecDestroy(vec));
3213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
322fb1bcc12SMatthew G. Knepley }
323fb1bcc12SMatthew G. Knepley 
324d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmCreateVectorFromField_Private(DM dm, const char fieldname[], MPI_Comm comm, Vec *vec)
325d71ae5a4SJacob Faibussowitsch {
326fb1bcc12SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
327fb1bcc12SMatthew G. Knepley   PetscDataType type;
328fb1bcc12SMatthew G. Knepley   PetscScalar  *array;
3292e956fe4SStefano Zampini   PetscInt      bs, n, fid;
330fb1bcc12SMatthew G. Knepley   char          name[PETSC_MAX_PATH_LEN];
331e4fbd051SBarry Smith   PetscMPIInt   size;
332*7f92dde0SRylanor   PetscBool     iscuda, iskokkos, iship;
333fb1bcc12SMatthew G. Knepley 
334fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
3359566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
3369566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
3379566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array));
33808401ef6SPierre Jolivet   PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
339fb1bcc12SMatthew G. Knepley 
3409566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
3418df78e51SMark Adams   PetscCall(PetscStrcmp(dm->vectype, VECKOKKOS, &iskokkos));
3428df78e51SMark Adams   PetscCall(PetscStrcmp(dm->vectype, VECCUDA, &iscuda));
343*7f92dde0SRylanor   PetscCall(PetscStrcmp(dm->vectype, VECHIP, &iship));
3448df78e51SMark Adams   PetscCall(VecCreate(comm, vec));
3458df78e51SMark Adams   PetscCall(VecSetSizes(*vec, n * bs, PETSC_DETERMINE));
3468df78e51SMark Adams   PetscCall(VecSetBlockSize(*vec, bs));
3478df78e51SMark Adams   if (iskokkos) PetscCall(VecSetType(*vec, VECKOKKOS));
3488df78e51SMark Adams   else if (iscuda) PetscCall(VecSetType(*vec, VECCUDA));
349*7f92dde0SRylanor   else if (iship) PetscCall(VecSetType(*vec, VECHIP));
3508df78e51SMark Adams   else PetscCall(VecSetType(*vec, VECSTANDARD));
3518df78e51SMark Adams   PetscCall(VecPlaceArray(*vec, array));
3528df78e51SMark Adams 
3539566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmSharedField_%s", fieldname));
3549566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*vec, name));
355fb1bcc12SMatthew G. Knepley 
356fb1bcc12SMatthew G. Knepley   /* Set guard */
3572e956fe4SStefano Zampini   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
3582e956fe4SStefano Zampini   PetscCall(PetscObjectComposedDataSetInt((PetscObject)*vec, SwarmDataFieldId, fid));
35974d0cae8SMatthew G. Knepley 
3609566063dSJacob Faibussowitsch   PetscCall(VecSetDM(*vec, dm));
3619566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Swarm));
3623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
363fb1bcc12SMatthew G. Knepley }
364fb1bcc12SMatthew G. Knepley 
3650643ed39SMatthew G. Knepley /* This creates a "mass matrix" between a finite element and particle space. If a finite element interpolant is given by
3660643ed39SMatthew G. Knepley 
3670643ed39SMatthew G. Knepley      \hat f = \sum_i f_i \phi_i
3680643ed39SMatthew G. Knepley 
3690643ed39SMatthew G. Knepley    and a particle function is given by
3700643ed39SMatthew G. Knepley 
3710643ed39SMatthew G. Knepley      f = \sum_i w_i \delta(x - x_i)
3720643ed39SMatthew G. Knepley 
3730643ed39SMatthew G. Knepley    then we want to require that
3740643ed39SMatthew G. Knepley 
3750643ed39SMatthew G. Knepley      M \hat f = M_p f
3760643ed39SMatthew G. Knepley 
3770643ed39SMatthew G. Knepley    where the particle mass matrix is given by
3780643ed39SMatthew G. Knepley 
3790643ed39SMatthew G. Knepley      (M_p)_{ij} = \int \phi_i \delta(x - x_j)
3800643ed39SMatthew G. Knepley 
3810643ed39SMatthew G. Knepley    The way Dave May does particles, they amount to quadratue weights rather than delta functions, so he has |J| is in
3820643ed39SMatthew G. Knepley    his integral. We allow this with the boolean flag.
3830643ed39SMatthew G. Knepley */
384d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmComputeMassMatrix_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
385d71ae5a4SJacob Faibussowitsch {
38683c47955SMatthew G. Knepley   const char  *name = "Mass Matrix";
3870643ed39SMatthew G. Knepley   MPI_Comm     comm;
38883c47955SMatthew G. Knepley   PetscDS      prob;
38983c47955SMatthew G. Knepley   PetscSection fsection, globalFSection;
390e8f14785SLisandro Dalcin   PetscHSetIJ  ht;
3910643ed39SMatthew G. Knepley   PetscLayout  rLayout, colLayout;
39283c47955SMatthew G. Knepley   PetscInt    *dnz, *onz;
393adb2528bSMark Adams   PetscInt     locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
3940643ed39SMatthew G. Knepley   PetscReal   *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
39583c47955SMatthew G. Knepley   PetscScalar *elemMat;
3960bf7c1c5SMatthew G. Knepley   PetscInt     dim, Nf, field, cStart, cEnd, cell, totDim, maxC = 0, totNc = 0;
397d52c2f21SMatthew G. Knepley   const char  *coordname;
39883c47955SMatthew G. Knepley 
39983c47955SMatthew G. Knepley   PetscFunctionBegin;
4009566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
4019566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmf, &dim));
4029566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmf, &prob));
4039566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
4049566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
4059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
4069566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
4079566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
4089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
4099566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
41083c47955SMatthew G. Knepley 
411d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetCoordinateField(dmc, &coordname));
412d52c2f21SMatthew G. Knepley 
4139566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &colLayout));
4149566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
4159566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
4169566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colLayout));
4179566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
4189566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&colLayout));
4190643ed39SMatthew G. Knepley 
4209566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &rLayout));
4219566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
4229566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
4239566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
4249566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
4259566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
4260643ed39SMatthew G. Knepley 
4279566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
4289566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
42953e60ab4SJoseph Pusztay 
4309566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(comm, NULL));
4310bf7c1c5SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
4320bf7c1c5SMatthew G. Knepley     PetscObject  obj;
4330bf7c1c5SMatthew G. Knepley     PetscClassId id;
4340bf7c1c5SMatthew G. Knepley     PetscInt     Nc;
4350bf7c1c5SMatthew G. Knepley 
4360bf7c1c5SMatthew G. Knepley     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
4370bf7c1c5SMatthew G. Knepley     PetscCall(PetscObjectGetClassId(obj, &id));
4380bf7c1c5SMatthew G. Knepley     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
4390bf7c1c5SMatthew G. Knepley     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
4400bf7c1c5SMatthew G. Knepley     totNc += Nc;
4410bf7c1c5SMatthew G. Knepley   }
4420643ed39SMatthew G. Knepley   /* count non-zeros */
4439566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(dmc));
44483c47955SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
4450bf7c1c5SMatthew G. Knepley     PetscObject  obj;
4460bf7c1c5SMatthew G. Knepley     PetscClassId id;
4470bf7c1c5SMatthew G. Knepley     PetscInt     Nc;
4480bf7c1c5SMatthew G. Knepley 
4490bf7c1c5SMatthew G. Knepley     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
4500bf7c1c5SMatthew G. Knepley     PetscCall(PetscObjectGetClassId(obj, &id));
4510bf7c1c5SMatthew G. Knepley     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
4520bf7c1c5SMatthew G. Knepley     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
4530bf7c1c5SMatthew G. Knepley 
45483c47955SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
4550643ed39SMatthew G. Knepley       PetscInt *findices, *cindices; /* fine is vertices, coarse is particles */
45683c47955SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
45783c47955SMatthew G. Knepley 
4589566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
4599566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
460fc7c92abSMatthew G. Knepley       maxC = PetscMax(maxC, numCIndices);
46183c47955SMatthew G. Knepley       {
462e8f14785SLisandro Dalcin         PetscHashIJKey key;
463e8f14785SLisandro Dalcin         PetscBool      missing;
4640bf7c1c5SMatthew G. Knepley         for (PetscInt i = 0; i < numFIndices; ++i) {
465adb2528bSMark Adams           key.j = findices[i]; /* global column (from Plex) */
466adb2528bSMark Adams           if (key.j >= 0) {
46783c47955SMatthew G. Knepley             /* Get indices for coarse elements */
4680bf7c1c5SMatthew G. Knepley             for (PetscInt j = 0; j < numCIndices; ++j) {
4690bf7c1c5SMatthew G. Knepley               for (PetscInt c = 0; c < Nc; ++c) {
4700bf7c1c5SMatthew G. Knepley                 // TODO Need field offset on particle here
4710bf7c1c5SMatthew G. Knepley                 key.i = cindices[j] * totNc + c + rStart; /* global cols (from Swarm) */
472adb2528bSMark Adams                 if (key.i < 0) continue;
4739566063dSJacob Faibussowitsch                 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
47483c47955SMatthew G. Knepley                 if (missing) {
4750643ed39SMatthew G. Knepley                   if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
476e8f14785SLisandro Dalcin                   else ++onz[key.i - rStart];
47763a3b9bcSJacob Faibussowitsch                 } else SETERRQ(PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Set new value at %" PetscInt_FMT ",%" PetscInt_FMT, key.i, key.j);
47883c47955SMatthew G. Knepley               }
479fc7c92abSMatthew G. Knepley             }
480fc7c92abSMatthew G. Knepley           }
4810bf7c1c5SMatthew G. Knepley         }
482fe11354eSMatthew G. Knepley         PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
48383c47955SMatthew G. Knepley       }
4849566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
48583c47955SMatthew G. Knepley     }
48683c47955SMatthew G. Knepley   }
4879566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
4889566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
4899566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
4909566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
4910bf7c1c5SMatthew G. Knepley   PetscCall(PetscMalloc3(maxC * totNc * totDim, &elemMat, maxC * totNc, &rowIDXs, maxC * dim, &xi));
49283c47955SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
493ef0bb6c7SMatthew G. Knepley     PetscTabulation Tcoarse;
49483c47955SMatthew G. Knepley     PetscObject     obj;
495ad9634fcSMatthew G. Knepley     PetscClassId    id;
496ea7032a0SMatthew G. Knepley     PetscReal      *fieldVals;
497d52c2f21SMatthew G. Knepley     PetscInt        Nc, bs;
49883c47955SMatthew G. Knepley 
4999566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
500ad9634fcSMatthew G. Knepley     PetscCall(PetscObjectGetClassId(obj, &id));
501ad9634fcSMatthew G. Knepley     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
502ad9634fcSMatthew G. Knepley     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
503ea7032a0SMatthew G. Knepley 
504d52c2f21SMatthew G. Knepley     PetscCall(DMSwarmGetField(dmc, coordname, &bs, NULL, (void **)&fieldVals));
50583c47955SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
50683c47955SMatthew G. Knepley       PetscInt *findices, *cindices;
50783c47955SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
50883c47955SMatthew G. Knepley 
5090643ed39SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
5109566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
5119566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
5129566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
513d52c2f21SMatthew G. Knepley       for (PetscInt j = 0; j < numCIndices; ++j) CoordinatesRealToRef(dim, dim, v0ref, v0, invJ, &fieldVals[cindices[j] * bs], &xi[j * dim]);
514ad9634fcSMatthew G. Knepley       if (id == PETSCFE_CLASSID) PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
515ad9634fcSMatthew G. Knepley       else PetscCall(PetscFVCreateTabulation((PetscFV)obj, 1, numCIndices, xi, 0, &Tcoarse));
51683c47955SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
5170bf7c1c5SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMat, numCIndices * Nc * totDim));
5180bf7c1c5SMatthew G. Knepley       for (PetscInt i = 0; i < numFIndices / Nc; ++i) {
5190bf7c1c5SMatthew G. Knepley         for (PetscInt j = 0; j < numCIndices; ++j) {
5200bf7c1c5SMatthew G. Knepley           for (PetscInt c = 0; c < Nc; ++c) {
5210bf7c1c5SMatthew G. Knepley             // TODO Need field offset on particle and field here
5220643ed39SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
5230bf7c1c5SMatthew G. Knepley             elemMat[(j * totNc + c) * numFIndices + i * Nc + c] += Tcoarse->T[0][(j * numFIndices + i * Nc + c) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
52483c47955SMatthew G. Knepley           }
5250643ed39SMatthew G. Knepley         }
5260643ed39SMatthew G. Knepley       }
5270bf7c1c5SMatthew G. Knepley       for (PetscInt j = 0; j < numCIndices; ++j)
5280bf7c1c5SMatthew G. Knepley         // TODO Need field offset on particle here
5290bf7c1c5SMatthew G. Knepley         for (PetscInt c = 0; c < Nc; ++c) rowIDXs[j * Nc + c] = cindices[j] * totNc + c + rStart;
5300bf7c1c5SMatthew G. Knepley       if (0) PetscCall(DMPrintCellMatrix(cell, name, numCIndices * Nc, numFIndices, elemMat));
5310bf7c1c5SMatthew G. Knepley       PetscCall(MatSetValues(mass, numCIndices * Nc, rowIDXs, numFIndices, findices, elemMat, ADD_VALUES));
532fe11354eSMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
5339566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
5349566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
53583c47955SMatthew G. Knepley     }
536d52c2f21SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dmc, coordname, &bs, NULL, (void **)&fieldVals));
53783c47955SMatthew G. Knepley   }
5389566063dSJacob Faibussowitsch   PetscCall(PetscFree3(elemMat, rowIDXs, xi));
5399566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
5409566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
5419566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
5429566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
5433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
54483c47955SMatthew G. Knepley }
54583c47955SMatthew G. Knepley 
546d0c080abSJoseph Pusztay /* Returns empty matrix for use with SNES FD */
547d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMatrix_Swarm(DM sw, Mat *m)
548d71ae5a4SJacob Faibussowitsch {
549d0c080abSJoseph Pusztay   Vec      field;
550d0c080abSJoseph Pusztay   PetscInt size;
551d0c080abSJoseph Pusztay 
552d0c080abSJoseph Pusztay   PetscFunctionBegin;
5539566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(sw, &field));
5549566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(field, &size));
5559566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(sw, &field));
5569566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD, m));
5579566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*m));
5589566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*m, PETSC_DECIDE, PETSC_DECIDE, size, size));
5599566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*m, 1, NULL));
5609566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(*m));
5619566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*m, MAT_FINAL_ASSEMBLY));
5629566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*m, MAT_FINAL_ASSEMBLY));
5639566063dSJacob Faibussowitsch   PetscCall(MatShift(*m, 1.0));
5649566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*m, sw));
5653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
566d0c080abSJoseph Pusztay }
567d0c080abSJoseph Pusztay 
568adb2528bSMark Adams /* FEM cols, Particle rows */
569d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMassMatrix_Swarm(DM dmCoarse, DM dmFine, Mat *mass)
570d71ae5a4SJacob Faibussowitsch {
571d52c2f21SMatthew G. Knepley   DM_Swarm    *swarm = (DM_Swarm *)dmCoarse->data;
572895a1698SMatthew G. Knepley   PetscSection gsf;
573d52c2f21SMatthew G. Knepley   PetscInt     m, n, Np;
57483c47955SMatthew G. Knepley   void        *ctx;
57583c47955SMatthew G. Knepley 
57683c47955SMatthew G. Knepley   PetscFunctionBegin;
577d52c2f21SMatthew G. Knepley   PetscCheck(swarm->vec_field_num, PetscObjectComm((PetscObject)dmCoarse), PETSC_ERR_USER, "Must call DMSwarmVectorDefineField(s) first");
5789566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
5799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
5800bf7c1c5SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(dmCoarse, &Np));
581d52c2f21SMatthew G. Knepley   n = Np * swarm->vec_field_bs;
5829566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
5839566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, m, PETSC_DETERMINE, PETSC_DETERMINE));
5849566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
5859566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
58683c47955SMatthew G. Knepley 
5879566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrix_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
5889566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
5893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
59083c47955SMatthew G. Knepley }
59183c47955SMatthew G. Knepley 
592d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmComputeMassMatrixSquare_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
593d71ae5a4SJacob Faibussowitsch {
5944cc7f7b2SMatthew G. Knepley   const char  *name = "Mass Matrix Square";
5954cc7f7b2SMatthew G. Knepley   MPI_Comm     comm;
5964cc7f7b2SMatthew G. Knepley   PetscDS      prob;
5974cc7f7b2SMatthew G. Knepley   PetscSection fsection, globalFSection;
5984cc7f7b2SMatthew G. Knepley   PetscHSetIJ  ht;
5994cc7f7b2SMatthew G. Knepley   PetscLayout  rLayout, colLayout;
6004cc7f7b2SMatthew G. Knepley   PetscInt    *dnz, *onz, *adj, depth, maxConeSize, maxSupportSize, maxAdjSize;
6014cc7f7b2SMatthew G. Knepley   PetscInt     locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
6024cc7f7b2SMatthew G. Knepley   PetscReal   *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
6034cc7f7b2SMatthew G. Knepley   PetscScalar *elemMat, *elemMatSq;
6044cc7f7b2SMatthew G. Knepley   PetscInt     cdim, Nf, field, cStart, cEnd, cell, totDim, maxC = 0;
605d52c2f21SMatthew G. Knepley   const char  *coordname;
6064cc7f7b2SMatthew G. Knepley 
6074cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
6089566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
6099566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmf, &cdim));
6109566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmf, &prob));
6119566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
6129566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
6139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(cdim, &v0, cdim * cdim, &J, cdim * cdim, &invJ));
6149566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
6159566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
6169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
6179566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
6184cc7f7b2SMatthew G. Knepley 
619d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetCoordinateField(dmc, &coordname));
620d52c2f21SMatthew G. Knepley 
6219566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &colLayout));
6229566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
6239566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
6249566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colLayout));
6259566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
6269566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&colLayout));
6274cc7f7b2SMatthew G. Knepley 
6289566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &rLayout));
6299566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
6309566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
6319566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
6329566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
6339566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
6344cc7f7b2SMatthew G. Knepley 
6359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmf, &depth));
6369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dmf, &maxConeSize, &maxSupportSize));
6374cc7f7b2SMatthew G. Knepley   maxAdjSize = PetscPowInt(maxConeSize * maxSupportSize, depth);
6389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxAdjSize, &adj));
6394cc7f7b2SMatthew G. Knepley 
6409566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
6419566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
6424cc7f7b2SMatthew G. Knepley   /* Count nonzeros
6434cc7f7b2SMatthew G. Knepley        This is just FVM++, but we cannot use the Plex P0 allocation since unknowns in a cell will not be contiguous
6444cc7f7b2SMatthew G. Knepley   */
6459566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(dmc));
6464cc7f7b2SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
6474cc7f7b2SMatthew G. Knepley     PetscInt  i;
6484cc7f7b2SMatthew G. Knepley     PetscInt *cindices;
6494cc7f7b2SMatthew G. Knepley     PetscInt  numCIndices;
6504cc7f7b2SMatthew G. Knepley #if 0
6514cc7f7b2SMatthew G. Knepley     PetscInt  adjSize = maxAdjSize, a, j;
6524cc7f7b2SMatthew G. Knepley #endif
6534cc7f7b2SMatthew G. Knepley 
6549566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
6554cc7f7b2SMatthew G. Knepley     maxC = PetscMax(maxC, numCIndices);
6564cc7f7b2SMatthew G. Knepley     /* Diagonal block */
657ad540459SPierre Jolivet     for (i = 0; i < numCIndices; ++i) dnz[cindices[i]] += numCIndices;
6584cc7f7b2SMatthew G. Knepley #if 0
6594cc7f7b2SMatthew G. Knepley     /* Off-diagonal blocks */
6609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(dmf, cell, &adjSize, &adj));
6614cc7f7b2SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
6624cc7f7b2SMatthew G. Knepley       if (adj[a] >= cStart && adj[a] < cEnd && adj[a] != cell) {
6634cc7f7b2SMatthew G. Knepley         const PetscInt ncell = adj[a];
6644cc7f7b2SMatthew G. Knepley         PetscInt      *ncindices;
6654cc7f7b2SMatthew G. Knepley         PetscInt       numNCIndices;
6664cc7f7b2SMatthew G. Knepley 
6679566063dSJacob Faibussowitsch         PetscCall(DMSwarmSortGetPointsPerCell(dmc, ncell, &numNCIndices, &ncindices));
6684cc7f7b2SMatthew G. Knepley         {
6694cc7f7b2SMatthew G. Knepley           PetscHashIJKey key;
6704cc7f7b2SMatthew G. Knepley           PetscBool      missing;
6714cc7f7b2SMatthew G. Knepley 
6724cc7f7b2SMatthew G. Knepley           for (i = 0; i < numCIndices; ++i) {
6734cc7f7b2SMatthew G. Knepley             key.i = cindices[i] + rStart; /* global rows (from Swarm) */
6744cc7f7b2SMatthew G. Knepley             if (key.i < 0) continue;
6754cc7f7b2SMatthew G. Knepley             for (j = 0; j < numNCIndices; ++j) {
6764cc7f7b2SMatthew G. Knepley               key.j = ncindices[j] + rStart; /* global column (from Swarm) */
6774cc7f7b2SMatthew G. Knepley               if (key.j < 0) continue;
6789566063dSJacob Faibussowitsch               PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
6794cc7f7b2SMatthew G. Knepley               if (missing) {
6804cc7f7b2SMatthew G. Knepley                 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
6814cc7f7b2SMatthew G. Knepley                 else                                         ++onz[key.i - rStart];
6824cc7f7b2SMatthew G. Knepley               }
6834cc7f7b2SMatthew G. Knepley             }
6844cc7f7b2SMatthew G. Knepley           }
6854cc7f7b2SMatthew G. Knepley         }
686fe11354eSMatthew G. Knepley         PetscCall(DMSwarmSortRestorePointsPerCell(dmc, ncell, &numNCIndices, &ncindices));
6874cc7f7b2SMatthew G. Knepley       }
6884cc7f7b2SMatthew G. Knepley     }
6894cc7f7b2SMatthew G. Knepley #endif
690fe11354eSMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
6914cc7f7b2SMatthew G. Knepley   }
6929566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
6939566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
6949566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
6959566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
6969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(maxC * totDim, &elemMat, maxC * maxC, &elemMatSq, maxC, &rowIDXs, maxC * cdim, &xi));
6974cc7f7b2SMatthew G. Knepley   /* Fill in values
6984cc7f7b2SMatthew G. Knepley        Each entry is a sum of terms \phi_i(x_p) \phi_i(x_q)
6994cc7f7b2SMatthew G. Knepley        Start just by producing block diagonal
7004cc7f7b2SMatthew G. Knepley        Could loop over adjacent cells
7014cc7f7b2SMatthew G. Knepley          Produce neighboring element matrix
7024cc7f7b2SMatthew G. Knepley          TODO Determine which columns and rows correspond to shared dual vector
7034cc7f7b2SMatthew G. Knepley          Do MatMatMult with rectangular matrices
7044cc7f7b2SMatthew G. Knepley          Insert block
7054cc7f7b2SMatthew G. Knepley   */
7064cc7f7b2SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
7074cc7f7b2SMatthew G. Knepley     PetscTabulation Tcoarse;
7084cc7f7b2SMatthew G. Knepley     PetscObject     obj;
7094cc7f7b2SMatthew G. Knepley     PetscReal      *coords;
7104cc7f7b2SMatthew G. Knepley     PetscInt        Nc, i;
7114cc7f7b2SMatthew G. Knepley 
7129566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
7139566063dSJacob Faibussowitsch     PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
71463a3b9bcSJacob Faibussowitsch     PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc);
715d52c2f21SMatthew G. Knepley     PetscCall(DMSwarmGetField(dmc, coordname, NULL, NULL, (void **)&coords));
7164cc7f7b2SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
7174cc7f7b2SMatthew G. Knepley       PetscInt *findices, *cindices;
7184cc7f7b2SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
7194cc7f7b2SMatthew G. Knepley       PetscInt  p, c;
7204cc7f7b2SMatthew G. Knepley 
7214cc7f7b2SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
7229566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
7239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
7249566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
725ad540459SPierre Jolivet       for (p = 0; p < numCIndices; ++p) CoordinatesRealToRef(cdim, cdim, v0ref, v0, invJ, &coords[cindices[p] * cdim], &xi[p * cdim]);
7269566063dSJacob Faibussowitsch       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
7274cc7f7b2SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
7289566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemMat, numCIndices * totDim));
7294cc7f7b2SMatthew G. Knepley       for (i = 0; i < numFIndices; ++i) {
7304cc7f7b2SMatthew G. Knepley         for (p = 0; p < numCIndices; ++p) {
7314cc7f7b2SMatthew G. Knepley           for (c = 0; c < Nc; ++c) {
7324cc7f7b2SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
7334cc7f7b2SMatthew G. Knepley             elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
7344cc7f7b2SMatthew G. Knepley           }
7354cc7f7b2SMatthew G. Knepley         }
7364cc7f7b2SMatthew G. Knepley       }
7379566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
7384cc7f7b2SMatthew G. Knepley       for (p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart;
7399566063dSJacob Faibussowitsch       if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
7404cc7f7b2SMatthew G. Knepley       /* Block diagonal */
74178884ca7SMatthew G. Knepley       if (numCIndices) {
7424cc7f7b2SMatthew G. Knepley         PetscBLASInt blasn, blask;
7434cc7f7b2SMatthew G. Knepley         PetscScalar  one = 1.0, zero = 0.0;
7444cc7f7b2SMatthew G. Knepley 
7459566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numCIndices, &blasn));
7469566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numFIndices, &blask));
747792fecdfSBarry Smith         PetscCallBLAS("BLASgemm", BLASgemm_("T", "N", &blasn, &blasn, &blask, &one, elemMat, &blask, elemMat, &blask, &zero, elemMatSq, &blasn));
7484cc7f7b2SMatthew G. Knepley       }
7499566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numCIndices, rowIDXs, elemMatSq, ADD_VALUES));
7504cf0e950SBarry Smith       /* TODO off-diagonal */
751fe11354eSMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
7529566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
7534cc7f7b2SMatthew G. Knepley     }
754d52c2f21SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dmc, coordname, NULL, NULL, (void **)&coords));
7554cc7f7b2SMatthew G. Knepley   }
7569566063dSJacob Faibussowitsch   PetscCall(PetscFree4(elemMat, elemMatSq, rowIDXs, xi));
7579566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
7589566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
7599566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
7609566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
7619566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
7623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7634cc7f7b2SMatthew G. Knepley }
7644cc7f7b2SMatthew G. Knepley 
765cc4c1da9SBarry Smith /*@
7664cc7f7b2SMatthew G. Knepley   DMSwarmCreateMassMatrixSquare - Creates the block-diagonal of the square, M^T_p M_p, of the particle mass matrix M_p
7674cc7f7b2SMatthew G. Knepley 
76820f4b53cSBarry Smith   Collective
7694cc7f7b2SMatthew G. Knepley 
77060225df5SJacob Faibussowitsch   Input Parameters:
77120f4b53cSBarry Smith + dmCoarse - a `DMSWARM`
77220f4b53cSBarry Smith - dmFine   - a `DMPLEX`
7734cc7f7b2SMatthew G. Knepley 
77460225df5SJacob Faibussowitsch   Output Parameter:
7754cc7f7b2SMatthew G. Knepley . mass - the square of the particle mass matrix
7764cc7f7b2SMatthew G. Knepley 
7774cc7f7b2SMatthew G. Knepley   Level: advanced
7784cc7f7b2SMatthew G. Knepley 
77920f4b53cSBarry Smith   Note:
7804cc7f7b2SMatthew G. Knepley   We only compute the block diagonal since this provides a good preconditioner and is completely local. It would be possible in the
7814cc7f7b2SMatthew G. Knepley   future to compute the full normal equations.
7824cc7f7b2SMatthew G. Knepley 
78320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMCreateMassMatrix()`
7844cc7f7b2SMatthew G. Knepley @*/
785d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateMassMatrixSquare(DM dmCoarse, DM dmFine, Mat *mass)
786d71ae5a4SJacob Faibussowitsch {
7874cc7f7b2SMatthew G. Knepley   PetscInt n;
7884cc7f7b2SMatthew G. Knepley   void    *ctx;
7894cc7f7b2SMatthew G. Knepley 
7904cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
7919566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dmCoarse, &n));
7929566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
7939566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, n, PETSC_DETERMINE, PETSC_DETERMINE));
7949566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
7959566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
7964cc7f7b2SMatthew G. Knepley 
7979566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrixSquare_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
7989566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_sq_mat_view"));
7993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8004cc7f7b2SMatthew G. Knepley }
8014cc7f7b2SMatthew G. Knepley 
802cc4c1da9SBarry Smith /*@
80320f4b53cSBarry Smith   DMSwarmCreateGlobalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
804d3a51819SDave May 
80520f4b53cSBarry Smith   Collective
806d3a51819SDave May 
80760225df5SJacob Faibussowitsch   Input Parameters:
80820f4b53cSBarry Smith + dm        - a `DMSWARM`
80962741f57SDave May - fieldname - the textual name given to a registered field
810d3a51819SDave May 
81160225df5SJacob Faibussowitsch   Output Parameter:
812d3a51819SDave May . vec - the vector
813d3a51819SDave May 
814d3a51819SDave May   Level: beginner
815d3a51819SDave May 
816cc4c1da9SBarry Smith   Note:
81720f4b53cSBarry Smith   The vector must be returned using a matching call to `DMSwarmDestroyGlobalVectorFromField()`.
8188b8a3813SDave May 
81920f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromField()`
820d3a51819SDave May @*/
821d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
822d71ae5a4SJacob Faibussowitsch {
823fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PetscObjectComm((PetscObject)dm);
824b5bcf523SDave May 
825fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
826ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
8279566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
8283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
829b5bcf523SDave May }
830b5bcf523SDave May 
831cc4c1da9SBarry Smith /*@
83220f4b53cSBarry Smith   DMSwarmDestroyGlobalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
833d3a51819SDave May 
83420f4b53cSBarry Smith   Collective
835d3a51819SDave May 
83660225df5SJacob Faibussowitsch   Input Parameters:
83720f4b53cSBarry Smith + dm        - a `DMSWARM`
83862741f57SDave May - fieldname - the textual name given to a registered field
839d3a51819SDave May 
84060225df5SJacob Faibussowitsch   Output Parameter:
841d3a51819SDave May . vec - the vector
842d3a51819SDave May 
843d3a51819SDave May   Level: beginner
844d3a51819SDave May 
84520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()`
846d3a51819SDave May @*/
847d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
848d71ae5a4SJacob Faibussowitsch {
849fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
850ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
8519566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
8523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
853b5bcf523SDave May }
854b5bcf523SDave May 
855cc4c1da9SBarry Smith /*@
85620f4b53cSBarry Smith   DMSwarmCreateLocalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
857fb1bcc12SMatthew G. Knepley 
85820f4b53cSBarry Smith   Collective
859fb1bcc12SMatthew G. Knepley 
86060225df5SJacob Faibussowitsch   Input Parameters:
86120f4b53cSBarry Smith + dm        - a `DMSWARM`
86262741f57SDave May - fieldname - the textual name given to a registered field
863fb1bcc12SMatthew G. Knepley 
86460225df5SJacob Faibussowitsch   Output Parameter:
865fb1bcc12SMatthew G. Knepley . vec - the vector
866fb1bcc12SMatthew G. Knepley 
867fb1bcc12SMatthew G. Knepley   Level: beginner
868fb1bcc12SMatthew G. Knepley 
86920f4b53cSBarry Smith   Note:
8708b8a3813SDave May   The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField().
8718b8a3813SDave May 
87220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()`
873fb1bcc12SMatthew G. Knepley @*/
874d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
875d71ae5a4SJacob Faibussowitsch {
876fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PETSC_COMM_SELF;
877bbe8250bSMatthew G. Knepley 
878fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
8799566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
8803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
881bbe8250bSMatthew G. Knepley }
882fb1bcc12SMatthew G. Knepley 
883cc4c1da9SBarry Smith /*@
88420f4b53cSBarry Smith   DMSwarmDestroyLocalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
885fb1bcc12SMatthew G. Knepley 
88620f4b53cSBarry Smith   Collective
887fb1bcc12SMatthew G. Knepley 
88860225df5SJacob Faibussowitsch   Input Parameters:
88920f4b53cSBarry Smith + dm        - a `DMSWARM`
89062741f57SDave May - fieldname - the textual name given to a registered field
891fb1bcc12SMatthew G. Knepley 
89260225df5SJacob Faibussowitsch   Output Parameter:
893fb1bcc12SMatthew G. Knepley . vec - the vector
894fb1bcc12SMatthew G. Knepley 
895fb1bcc12SMatthew G. Knepley   Level: beginner
896fb1bcc12SMatthew G. Knepley 
89720f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromField()`
898fb1bcc12SMatthew G. Knepley @*/
899d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
900d71ae5a4SJacob Faibussowitsch {
901fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
902ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
9039566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
9043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
905bbe8250bSMatthew G. Knepley }
906bbe8250bSMatthew G. Knepley 
907cc4c1da9SBarry Smith /*@
90820f4b53cSBarry Smith   DMSwarmInitializeFieldRegister - Initiates the registration of fields to a `DMSWARM`
909d3a51819SDave May 
91020f4b53cSBarry Smith   Collective
911d3a51819SDave May 
91260225df5SJacob Faibussowitsch   Input Parameter:
91320f4b53cSBarry Smith . dm - a `DMSWARM`
914d3a51819SDave May 
915d3a51819SDave May   Level: beginner
916d3a51819SDave May 
91720f4b53cSBarry Smith   Note:
91820f4b53cSBarry Smith   After all fields have been registered, you must call `DMSwarmFinalizeFieldRegister()`.
919d3a51819SDave May 
92020f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmFinalizeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
921db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
922d3a51819SDave May @*/
923d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmInitializeFieldRegister(DM dm)
924d71ae5a4SJacob Faibussowitsch {
9255f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
9263454631fSDave May 
927521f74f9SMatthew G. Knepley   PetscFunctionBegin;
928cc651181SDave May   if (!swarm->field_registration_initialized) {
9295f50eb2eSDave May     swarm->field_registration_initialized = PETSC_TRUE;
930da81f932SPierre Jolivet     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_pid, 1, PETSC_INT64)); /* unique identifier */
9319566063dSJacob Faibussowitsch     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_rank, 1, PETSC_INT));  /* used for communication */
932cc651181SDave May   }
9333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9345f50eb2eSDave May }
9355f50eb2eSDave May 
93674d0cae8SMatthew G. Knepley /*@
93720f4b53cSBarry Smith   DMSwarmFinalizeFieldRegister - Finalizes the registration of fields to a `DMSWARM`
938d3a51819SDave May 
93920f4b53cSBarry Smith   Collective
940d3a51819SDave May 
94160225df5SJacob Faibussowitsch   Input Parameter:
94220f4b53cSBarry Smith . dm - a `DMSWARM`
943d3a51819SDave May 
944d3a51819SDave May   Level: beginner
945d3a51819SDave May 
94620f4b53cSBarry Smith   Note:
94720f4b53cSBarry Smith   After `DMSwarmFinalizeFieldRegister()` has been called, no new fields can be defined on the `DMSWARM`.
948d3a51819SDave May 
94920f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmInitializeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
950db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
951d3a51819SDave May @*/
952d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmFinalizeFieldRegister(DM dm)
953d71ae5a4SJacob Faibussowitsch {
9545f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
9556845f8f5SDave May 
956521f74f9SMatthew G. Knepley   PetscFunctionBegin;
95748a46eb9SPierre Jolivet   if (!swarm->field_registration_finalized) PetscCall(DMSwarmDataBucketFinalize(swarm->db));
958f0cdbbbaSDave May   swarm->field_registration_finalized = PETSC_TRUE;
9593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9605f50eb2eSDave May }
9615f50eb2eSDave May 
96274d0cae8SMatthew G. Knepley /*@
96320f4b53cSBarry Smith   DMSwarmSetLocalSizes - Sets the length of all registered fields on the `DMSWARM`
964d3a51819SDave May 
96520f4b53cSBarry Smith   Not Collective
966d3a51819SDave May 
96760225df5SJacob Faibussowitsch   Input Parameters:
96820f4b53cSBarry Smith + dm     - a `DMSWARM`
969d3a51819SDave May . nlocal - the length of each registered field
97062741f57SDave May - buffer - the length of the buffer used to efficient dynamic re-sizing
971d3a51819SDave May 
972d3a51819SDave May   Level: beginner
973d3a51819SDave May 
97420f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`
975d3a51819SDave May @*/
976d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetLocalSizes(DM dm, PetscInt nlocal, PetscInt buffer)
977d71ae5a4SJacob Faibussowitsch {
9785f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
9795f50eb2eSDave May 
980521f74f9SMatthew G. Knepley   PetscFunctionBegin;
9819566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_SetSizes, 0, 0, 0, 0));
9829566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, buffer));
9839566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_SetSizes, 0, 0, 0, 0));
9843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9855f50eb2eSDave May }
9865f50eb2eSDave May 
98774d0cae8SMatthew G. Knepley /*@
98820f4b53cSBarry Smith   DMSwarmSetCellDM - Attaches a `DM` to a `DMSWARM`
989d3a51819SDave May 
99020f4b53cSBarry Smith   Collective
991d3a51819SDave May 
99260225df5SJacob Faibussowitsch   Input Parameters:
99320f4b53cSBarry Smith + dm     - a `DMSWARM`
99420f4b53cSBarry Smith - dmcell - the `DM` to attach to the `DMSWARM`
995d3a51819SDave May 
996d3a51819SDave May   Level: beginner
997d3a51819SDave May 
99820f4b53cSBarry Smith   Note:
99920f4b53cSBarry Smith   The attached `DM` (dmcell) will be queried for point location and
100020f4b53cSBarry Smith   neighbor MPI-rank information if `DMSwarmMigrate()` is called.
1001d3a51819SDave May 
100220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmGetCellDM()`, `DMSwarmMigrate()`
1003d3a51819SDave May @*/
1004d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetCellDM(DM dm, DM dmcell)
1005d71ae5a4SJacob Faibussowitsch {
1006521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1007d52c2f21SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1008d52c2f21SMatthew G. Knepley   PetscValidHeaderSpecific(dmcell, DM_CLASSID, 2);
1009d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmPushCellDM(dm, dmcell, 0, NULL, DMSwarmPICField_coor));
10103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1011b16650c8SDave May }
1012b16650c8SDave May 
101374d0cae8SMatthew G. Knepley /*@
101420f4b53cSBarry Smith   DMSwarmGetCellDM - Fetches the attached cell `DM`
1015d3a51819SDave May 
101620f4b53cSBarry Smith   Collective
1017d3a51819SDave May 
101860225df5SJacob Faibussowitsch   Input Parameter:
101920f4b53cSBarry Smith . dm - a `DMSWARM`
1020d3a51819SDave May 
102160225df5SJacob Faibussowitsch   Output Parameter:
102220f4b53cSBarry Smith . dmcell - the `DM` which was attached to the `DMSWARM`
1023d3a51819SDave May 
1024d3a51819SDave May   Level: beginner
1025d3a51819SDave May 
102620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
1027d3a51819SDave May @*/
1028d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetCellDM(DM dm, DM *dmcell)
1029d71ae5a4SJacob Faibussowitsch {
1030fe39f135SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1031521f74f9SMatthew G. Knepley 
1032521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1033d52c2f21SMatthew G. Knepley   *dmcell = swarm->cellinfo ? swarm->cellinfo[0].dm : NULL;
1034d52c2f21SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1035d52c2f21SMatthew G. Knepley }
1036d52c2f21SMatthew G. Knepley 
1037d52c2f21SMatthew G. Knepley static PetscErrorCode CellDMInfoDestroy(CellDMInfo *info)
1038d52c2f21SMatthew G. Knepley {
1039d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
1040d52c2f21SMatthew G. Knepley   for (PetscInt f = 0; f < (*info)->Nf; ++f) PetscCall(PetscFree((*info)->dmFields[f]));
1041d52c2f21SMatthew G. Knepley   PetscCall(PetscFree((*info)->dmFields));
1042d52c2f21SMatthew G. Knepley   PetscCall(PetscFree((*info)->coordField));
1043d52c2f21SMatthew G. Knepley   PetscCall(DMDestroy(&(*info)->dm));
1044d52c2f21SMatthew G. Knepley   PetscCall(PetscFree(*info));
1045d52c2f21SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1046d52c2f21SMatthew G. Knepley }
1047d52c2f21SMatthew G. Knepley 
1048d52c2f21SMatthew G. Knepley /*@
1049d52c2f21SMatthew G. Knepley   DMSwarmPushCellDM - Attaches a `DM` to a `DMSWARM`
1050d52c2f21SMatthew G. Knepley 
1051d52c2f21SMatthew G. Knepley   Collective
1052d52c2f21SMatthew G. Knepley 
1053d52c2f21SMatthew G. Knepley   Input Parameters:
1054d52c2f21SMatthew G. Knepley + sw         - a `DMSWARM`
1055d52c2f21SMatthew G. Knepley . dmcell     - the `DM` to attach to the `DMSWARM`
1056d52c2f21SMatthew G. Knepley . Nf         - the number of swarm fields defining the `DM`
1057d52c2f21SMatthew G. Knepley . dmFields   - an array of field names for the fields defining the `DM`
1058d52c2f21SMatthew G. Knepley - coordField - the name for the swarm field to use for particle coordinates on the cell `DM`
1059d52c2f21SMatthew G. Knepley 
1060d52c2f21SMatthew G. Knepley   Level: beginner
1061d52c2f21SMatthew G. Knepley 
1062d52c2f21SMatthew G. Knepley   Note:
1063d52c2f21SMatthew G. Knepley   The attached `DM` (dmcell) will be queried for point location and
1064d52c2f21SMatthew G. Knepley   neighbor MPI-rank information if `DMSwarmMigrate()` is called.
1065d52c2f21SMatthew G. Knepley 
1066d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmPopCellDM()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()`
1067d52c2f21SMatthew G. Knepley @*/
1068d52c2f21SMatthew G. Knepley PetscErrorCode DMSwarmPushCellDM(DM sw, DM dmcell, PetscInt Nf, const char *dmFields[], const char coordField[])
1069d52c2f21SMatthew G. Knepley {
1070d52c2f21SMatthew G. Knepley   DM_Swarm  *swarm = (DM_Swarm *)sw->data;
1071d52c2f21SMatthew G. Knepley   CellDMInfo info;
1072d52c2f21SMatthew G. Knepley   PetscBool  rebin = swarm->cellinfo ? PETSC_TRUE : PETSC_FALSE;
1073d52c2f21SMatthew G. Knepley 
1074d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
1075d52c2f21SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
1076d52c2f21SMatthew G. Knepley   PetscValidHeaderSpecific(dmcell, DM_CLASSID, 2);
1077d52c2f21SMatthew G. Knepley   if (Nf) PetscAssertPointer(dmFields, 4);
1078d52c2f21SMatthew G. Knepley   PetscAssertPointer(coordField, 5);
1079d52c2f21SMatthew G. Knepley   PetscCall(PetscNew(&info));
1080d52c2f21SMatthew G. Knepley   PetscCall(PetscObjectReference((PetscObject)dmcell));
1081d52c2f21SMatthew G. Knepley   info->dm        = dmcell;
1082d52c2f21SMatthew G. Knepley   info->Nf        = Nf;
1083d52c2f21SMatthew G. Knepley   info->next      = swarm->cellinfo;
1084d52c2f21SMatthew G. Knepley   swarm->cellinfo = info;
1085d52c2f21SMatthew G. Knepley   // Define the DM fields
1086d52c2f21SMatthew G. Knepley   PetscCall(PetscMalloc1(info->Nf, &info->dmFields));
1087d52c2f21SMatthew G. Knepley   for (PetscInt f = 0; f < info->Nf; ++f) PetscCall(PetscStrallocpy(dmFields[f], &info->dmFields[f]));
1088d52c2f21SMatthew G. Knepley   if (info->Nf) PetscCall(DMSwarmVectorDefineFields(sw, info->Nf, (const char **)info->dmFields));
1089d52c2f21SMatthew G. Knepley   // Set the coordinate field
1090d52c2f21SMatthew G. Knepley   PetscCall(PetscStrallocpy(coordField, &info->coordField));
1091d52c2f21SMatthew G. Knepley   if (info->coordField) PetscCall(DMSwarmSetCoordinateField(sw, info->coordField));
1092d52c2f21SMatthew G. Knepley   // Rebin the cells and set cell_id field
1093d52c2f21SMatthew G. Knepley   if (rebin) PetscCall(DMSwarmMigrate(sw, PETSC_FALSE));
1094d52c2f21SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1095d52c2f21SMatthew G. Knepley }
1096d52c2f21SMatthew G. Knepley 
1097d52c2f21SMatthew G. Knepley /*@
1098d52c2f21SMatthew G. Knepley   DMSwarmPopCellDM - Discard the current cell `DM` and restore the previous one, if it exists
1099d52c2f21SMatthew G. Knepley 
1100d52c2f21SMatthew G. Knepley   Collective
1101d52c2f21SMatthew G. Knepley 
1102d52c2f21SMatthew G. Knepley   Input Parameter:
1103d52c2f21SMatthew G. Knepley . sw - a `DMSWARM`
1104d52c2f21SMatthew G. Knepley 
1105d52c2f21SMatthew G. Knepley   Level: beginner
1106d52c2f21SMatthew G. Knepley 
1107d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmPushCellDM()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()`
1108d52c2f21SMatthew G. Knepley @*/
1109d52c2f21SMatthew G. Knepley PetscErrorCode DMSwarmPopCellDM(DM sw)
1110d52c2f21SMatthew G. Knepley {
1111d52c2f21SMatthew G. Knepley   DM_Swarm  *swarm = (DM_Swarm *)sw->data;
1112d52c2f21SMatthew G. Knepley   CellDMInfo info  = swarm->cellinfo;
1113d52c2f21SMatthew G. Knepley 
1114d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
1115d52c2f21SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
1116d52c2f21SMatthew G. Knepley   if (!swarm->cellinfo) PetscFunctionReturn(PETSC_SUCCESS);
1117d52c2f21SMatthew G. Knepley   if (info->next) {
1118d52c2f21SMatthew G. Knepley     CellDMInfo newinfo = info->next;
1119d52c2f21SMatthew G. Knepley 
1120d52c2f21SMatthew G. Knepley     swarm->cellinfo = info->next;
1121d52c2f21SMatthew G. Knepley     // Define the DM fields
1122d52c2f21SMatthew G. Knepley     PetscCall(DMSwarmVectorDefineFields(sw, newinfo->Nf, (const char **)newinfo->dmFields));
1123d52c2f21SMatthew G. Knepley     // Set the coordinate field
1124d52c2f21SMatthew G. Knepley     PetscCall(DMSwarmSetCoordinateField(sw, newinfo->coordField));
1125d52c2f21SMatthew G. Knepley     // Rebin the cells and set cell_id field
1126d52c2f21SMatthew G. Knepley     PetscCall(DMSwarmMigrate(sw, PETSC_FALSE));
1127d52c2f21SMatthew G. Knepley   }
1128d52c2f21SMatthew G. Knepley   PetscCall(CellDMInfoDestroy(&info));
11293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1130fe39f135SDave May }
1131fe39f135SDave May 
113274d0cae8SMatthew G. Knepley /*@
1133d5b43468SJose E. Roman   DMSwarmGetLocalSize - Retrieves the local length of fields registered
1134d3a51819SDave May 
113520f4b53cSBarry Smith   Not Collective
1136d3a51819SDave May 
113760225df5SJacob Faibussowitsch   Input Parameter:
113820f4b53cSBarry Smith . dm - a `DMSWARM`
1139d3a51819SDave May 
114060225df5SJacob Faibussowitsch   Output Parameter:
1141d3a51819SDave May . nlocal - the length of each registered field
1142d3a51819SDave May 
1143d3a51819SDave May   Level: beginner
1144d3a51819SDave May 
114520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetSize()`, `DMSwarmSetLocalSizes()`
1146d3a51819SDave May @*/
1147d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetLocalSize(DM dm, PetscInt *nlocal)
1148d71ae5a4SJacob Faibussowitsch {
1149dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1150dcf43ee8SDave May 
1151521f74f9SMatthew G. Knepley   PetscFunctionBegin;
11529566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, nlocal, NULL, NULL));
11533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1154dcf43ee8SDave May }
1155dcf43ee8SDave May 
115674d0cae8SMatthew G. Knepley /*@
1157d5b43468SJose E. Roman   DMSwarmGetSize - Retrieves the total length of fields registered
1158d3a51819SDave May 
115920f4b53cSBarry Smith   Collective
1160d3a51819SDave May 
116160225df5SJacob Faibussowitsch   Input Parameter:
116220f4b53cSBarry Smith . dm - a `DMSWARM`
1163d3a51819SDave May 
116460225df5SJacob Faibussowitsch   Output Parameter:
1165d3a51819SDave May . n - the total length of each registered field
1166d3a51819SDave May 
1167d3a51819SDave May   Level: beginner
1168d3a51819SDave May 
1169d3a51819SDave May   Note:
117020f4b53cSBarry Smith   This calls `MPI_Allreduce()` upon each call (inefficient but safe)
1171d3a51819SDave May 
117220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`, `DMSwarmSetLocalSizes()`
1173d3a51819SDave May @*/
1174d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetSize(DM dm, PetscInt *n)
1175d71ae5a4SJacob Faibussowitsch {
1176dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
11775627991aSBarry Smith   PetscInt  nlocal;
1178dcf43ee8SDave May 
1179521f74f9SMatthew G. Knepley   PetscFunctionBegin;
11809566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
1181462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&nlocal, n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
11823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1183dcf43ee8SDave May }
1184dcf43ee8SDave May 
1185cc4c1da9SBarry Smith /*@
118620f4b53cSBarry Smith   DMSwarmRegisterPetscDatatypeField - Register a field to a `DMSWARM` with a native PETSc data type
1187d3a51819SDave May 
118820f4b53cSBarry Smith   Collective
1189d3a51819SDave May 
119060225df5SJacob Faibussowitsch   Input Parameters:
119120f4b53cSBarry Smith + dm        - a `DMSWARM`
1192d3a51819SDave May . fieldname - the textual name to identify this field
1193d3a51819SDave May . blocksize - the number of each data type
119420f4b53cSBarry Smith - type      - a valid PETSc data type (`PETSC_CHAR`, `PETSC_SHORT`, `PETSC_INT`, `PETSC_FLOAT`, `PETSC_REAL`, `PETSC_LONG`)
1195d3a51819SDave May 
1196d3a51819SDave May   Level: beginner
1197d3a51819SDave May 
1198d3a51819SDave May   Notes:
11998b8a3813SDave May   The textual name for each registered field must be unique.
1200d3a51819SDave May 
120120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
1202d3a51819SDave May @*/
1203d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterPetscDatatypeField(DM dm, const char fieldname[], PetscInt blocksize, PetscDataType type)
1204d71ae5a4SJacob Faibussowitsch {
1205b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1206b62e03f8SDave May   size_t    size;
1207b62e03f8SDave May 
1208521f74f9SMatthew G. Knepley   PetscFunctionBegin;
120928b400f6SJacob Faibussowitsch   PetscCheck(swarm->field_registration_initialized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmInitializeFieldRegister() first");
121028b400f6SJacob Faibussowitsch   PetscCheck(!swarm->field_registration_finalized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Cannot register additional fields after calling DMSwarmFinalizeFieldRegister() first");
12115f50eb2eSDave May 
121208401ef6SPierre Jolivet   PetscCheck(type != PETSC_OBJECT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
121308401ef6SPierre Jolivet   PetscCheck(type != PETSC_FUNCTION, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
121408401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRING, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
121508401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRUCT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
121608401ef6SPierre Jolivet   PetscCheck(type != PETSC_DATATYPE_UNKNOWN, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
1217b62e03f8SDave May 
12189566063dSJacob Faibussowitsch   PetscCall(PetscDataTypeGetSize(type, &size));
1219b62e03f8SDave May   /* Load a specific data type into data bucket, specifying textual name and its size in bytes */
12209566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterPetscDatatypeField", fieldname, blocksize * size, NULL));
122152c3ed93SDave May   {
122277048351SPatrick Sanan     DMSwarmDataField gfield;
122352c3ed93SDave May 
12249566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
12259566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
122652c3ed93SDave May   }
1227b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = type;
12283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1229b62e03f8SDave May }
1230b62e03f8SDave May 
1231d3a51819SDave May /*@C
123220f4b53cSBarry Smith   DMSwarmRegisterUserStructField - Register a user defined struct to a `DMSWARM`
1233d3a51819SDave May 
123420f4b53cSBarry Smith   Collective
1235d3a51819SDave May 
123660225df5SJacob Faibussowitsch   Input Parameters:
123720f4b53cSBarry Smith + dm        - a `DMSWARM`
1238d3a51819SDave May . fieldname - the textual name to identify this field
123962741f57SDave May - size      - the size in bytes of the user struct of each data type
1240d3a51819SDave May 
1241d3a51819SDave May   Level: beginner
1242d3a51819SDave May 
124320f4b53cSBarry Smith   Note:
12448b8a3813SDave May   The textual name for each registered field must be unique.
1245d3a51819SDave May 
124620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserDatatypeField()`
1247d3a51819SDave May @*/
1248d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserStructField(DM dm, const char fieldname[], size_t size)
1249d71ae5a4SJacob Faibussowitsch {
1250b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1251b62e03f8SDave May 
1252521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12539566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserStructField", fieldname, size, NULL));
1254b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_STRUCT;
12553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1256b62e03f8SDave May }
1257b62e03f8SDave May 
1258d3a51819SDave May /*@C
125920f4b53cSBarry Smith   DMSwarmRegisterUserDatatypeField - Register a user defined data type to a `DMSWARM`
1260d3a51819SDave May 
126120f4b53cSBarry Smith   Collective
1262d3a51819SDave May 
126360225df5SJacob Faibussowitsch   Input Parameters:
126420f4b53cSBarry Smith + dm        - a `DMSWARM`
1265d3a51819SDave May . fieldname - the textual name to identify this field
1266d3a51819SDave May . size      - the size in bytes of the user data type
126762741f57SDave May - blocksize - the number of each data type
1268d3a51819SDave May 
1269d3a51819SDave May   Level: beginner
1270d3a51819SDave May 
127120f4b53cSBarry Smith   Note:
12728b8a3813SDave May   The textual name for each registered field must be unique.
1273d3a51819SDave May 
127442747ad1SJacob Faibussowitsch .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserStructField()`
1275d3a51819SDave May @*/
1276d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserDatatypeField(DM dm, const char fieldname[], size_t size, PetscInt blocksize)
1277d71ae5a4SJacob Faibussowitsch {
1278b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1279b62e03f8SDave May 
1280521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12819566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserDatatypeField", fieldname, blocksize * size, NULL));
1282320740a0SDave May   {
128377048351SPatrick Sanan     DMSwarmDataField gfield;
1284320740a0SDave May 
12859566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
12869566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
1287320740a0SDave May   }
1288b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_DATATYPE_UNKNOWN;
12893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1290b62e03f8SDave May }
1291b62e03f8SDave May 
1292d3a51819SDave May /*@C
1293d3a51819SDave May   DMSwarmGetField - Get access to the underlying array storing all entries associated with a registered field
1294d3a51819SDave May 
1295cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1296d3a51819SDave May 
129760225df5SJacob Faibussowitsch   Input Parameters:
129820f4b53cSBarry Smith + dm        - a `DMSWARM`
129962741f57SDave May - fieldname - the textual name to identify this field
1300d3a51819SDave May 
130160225df5SJacob Faibussowitsch   Output Parameters:
130262741f57SDave May + blocksize - the number of each data type
1303d3a51819SDave May . type      - the data type
130462741f57SDave May - data      - pointer to raw array
1305d3a51819SDave May 
1306d3a51819SDave May   Level: beginner
1307d3a51819SDave May 
1308d3a51819SDave May   Notes:
130920f4b53cSBarry Smith   The array must be returned using a matching call to `DMSwarmRestoreField()`.
1310d3a51819SDave May 
131120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreField()`
1312d3a51819SDave May @*/
1313d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1314d71ae5a4SJacob Faibussowitsch {
1315b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
131677048351SPatrick Sanan   DMSwarmDataField gfield;
1317b62e03f8SDave May 
1318521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1319ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
13209566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
13219566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
13229566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetAccess(gfield));
13239566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetEntries(gfield, data));
1324ad540459SPierre Jolivet   if (blocksize) *blocksize = gfield->bs;
1325ad540459SPierre Jolivet   if (type) *type = gfield->petsc_type;
13263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1327b62e03f8SDave May }
1328b62e03f8SDave May 
1329d3a51819SDave May /*@C
1330d3a51819SDave May   DMSwarmRestoreField - Restore access to the underlying array storing all entries associated with a registered field
1331d3a51819SDave May 
1332cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1333d3a51819SDave May 
133460225df5SJacob Faibussowitsch   Input Parameters:
133520f4b53cSBarry Smith + dm        - a `DMSWARM`
133662741f57SDave May - fieldname - the textual name to identify this field
1337d3a51819SDave May 
133860225df5SJacob Faibussowitsch   Output Parameters:
133962741f57SDave May + blocksize - the number of each data type
1340d3a51819SDave May . type      - the data type
134162741f57SDave May - data      - pointer to raw array
1342d3a51819SDave May 
1343d3a51819SDave May   Level: beginner
1344d3a51819SDave May 
1345d3a51819SDave May   Notes:
134620f4b53cSBarry Smith   The user must call `DMSwarmGetField()` prior to calling `DMSwarmRestoreField()`.
1347d3a51819SDave May 
134820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetField()`
1349d3a51819SDave May @*/
1350d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRestoreField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1351d71ae5a4SJacob Faibussowitsch {
1352b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
135377048351SPatrick Sanan   DMSwarmDataField gfield;
1354b62e03f8SDave May 
1355521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1356ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
13579566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
13589566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
1359b62e03f8SDave May   if (data) *data = NULL;
13603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1361b62e03f8SDave May }
1362b62e03f8SDave May 
1363d52c2f21SMatthew G. Knepley /*@
1364d52c2f21SMatthew G. Knepley   DMSwarmGetCoordinateField - Get the name of the field holding particle coordinates
1365d52c2f21SMatthew G. Knepley 
1366d52c2f21SMatthew G. Knepley   Not Collective
1367d52c2f21SMatthew G. Knepley 
1368d52c2f21SMatthew G. Knepley   Input Parameter:
1369d52c2f21SMatthew G. Knepley . sw - a `DMSWARM`
1370d52c2f21SMatthew G. Knepley 
1371d52c2f21SMatthew G. Knepley   Output Parameter:
1372d52c2f21SMatthew G. Knepley . fieldname - the name of  the coordinate field
1373d52c2f21SMatthew G. Knepley 
1374d52c2f21SMatthew G. Knepley   Level: intermediate
1375d52c2f21SMatthew G. Knepley 
1376d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmSetCoordinateField()`, `DMSwarmGetField()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()`
1377d52c2f21SMatthew G. Knepley @*/
1378d52c2f21SMatthew G. Knepley PetscErrorCode DMSwarmGetCoordinateField(DM sw, const char *fieldname[])
1379d52c2f21SMatthew G. Knepley {
1380d52c2f21SMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
1381d52c2f21SMatthew G. Knepley 
1382d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
1383d52c2f21SMatthew G. Knepley   PetscValidHeaderSpecificType(sw, DM_CLASSID, 1, DMSWARM);
1384d52c2f21SMatthew G. Knepley   PetscAssertPointer(fieldname, 2);
1385d52c2f21SMatthew G. Knepley   *fieldname = swarm->coord_name;
1386d52c2f21SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1387d52c2f21SMatthew G. Knepley }
1388d52c2f21SMatthew G. Knepley 
1389d52c2f21SMatthew G. Knepley /*@
1390d52c2f21SMatthew G. Knepley   DMSwarmSetCoordinateField - Set the name of the field holding particle coordinates
1391d52c2f21SMatthew G. Knepley 
1392d52c2f21SMatthew G. Knepley   Not Collective
1393d52c2f21SMatthew G. Knepley 
1394d52c2f21SMatthew G. Knepley   Input Parameters:
1395d52c2f21SMatthew G. Knepley + sw        - a `DMSWARM`
1396d52c2f21SMatthew G. Knepley - fieldname - the name of  the coordinate field
1397d52c2f21SMatthew G. Knepley 
1398d52c2f21SMatthew G. Knepley   Level: intermediate
1399d52c2f21SMatthew G. Knepley 
1400d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmGetCoordinateField()`, `DMSwarmGetField()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()`
1401d52c2f21SMatthew G. Knepley @*/
1402d52c2f21SMatthew G. Knepley PetscErrorCode DMSwarmSetCoordinateField(DM sw, const char fieldname[])
1403d52c2f21SMatthew G. Knepley {
1404d52c2f21SMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
1405d52c2f21SMatthew G. Knepley 
1406d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
1407d52c2f21SMatthew G. Knepley   PetscValidHeaderSpecificType(sw, DM_CLASSID, 1, DMSWARM);
1408d52c2f21SMatthew G. Knepley   PetscAssertPointer(fieldname, 2);
1409d52c2f21SMatthew G. Knepley   PetscCall(PetscFree(swarm->coord_name));
1410d52c2f21SMatthew G. Knepley   PetscCall(PetscStrallocpy(fieldname, (char **)&swarm->coord_name));
1411d52c2f21SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1412d52c2f21SMatthew G. Knepley }
1413d52c2f21SMatthew G. Knepley 
14140bf7c1c5SMatthew G. Knepley PetscErrorCode DMSwarmGetFieldInfo(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type)
14150bf7c1c5SMatthew G. Knepley {
14160bf7c1c5SMatthew G. Knepley   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
14170bf7c1c5SMatthew G. Knepley   DMSwarmDataField gfield;
14180bf7c1c5SMatthew G. Knepley 
14190bf7c1c5SMatthew G. Knepley   PetscFunctionBegin;
14200bf7c1c5SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
14210bf7c1c5SMatthew G. Knepley   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
14220bf7c1c5SMatthew G. Knepley   if (blocksize) *blocksize = gfield->bs;
14230bf7c1c5SMatthew G. Knepley   if (type) *type = gfield->petsc_type;
14240bf7c1c5SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
14250bf7c1c5SMatthew G. Knepley }
14260bf7c1c5SMatthew G. Knepley 
142774d0cae8SMatthew G. Knepley /*@
142820f4b53cSBarry Smith   DMSwarmAddPoint - Add space for one new point in the `DMSWARM`
1429d3a51819SDave May 
143020f4b53cSBarry Smith   Not Collective
1431d3a51819SDave May 
143260225df5SJacob Faibussowitsch   Input Parameter:
143320f4b53cSBarry Smith . dm - a `DMSWARM`
1434d3a51819SDave May 
1435d3a51819SDave May   Level: beginner
1436d3a51819SDave May 
1437d3a51819SDave May   Notes:
14388b8a3813SDave May   The new point will have all fields initialized to zero.
1439d3a51819SDave May 
144020f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmAddNPoints()`
1441d3a51819SDave May @*/
1442d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddPoint(DM dm)
1443d71ae5a4SJacob Faibussowitsch {
1444cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1445cb1d1399SDave May 
1446521f74f9SMatthew G. Knepley   PetscFunctionBegin;
14479566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
14489566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
14499566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketAddPoint(swarm->db));
14509566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
14513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1452cb1d1399SDave May }
1453cb1d1399SDave May 
145474d0cae8SMatthew G. Knepley /*@
145520f4b53cSBarry Smith   DMSwarmAddNPoints - Add space for a number of new points in the `DMSWARM`
1456d3a51819SDave May 
145720f4b53cSBarry Smith   Not Collective
1458d3a51819SDave May 
145960225df5SJacob Faibussowitsch   Input Parameters:
146020f4b53cSBarry Smith + dm      - a `DMSWARM`
146162741f57SDave May - npoints - the number of new points to add
1462d3a51819SDave May 
1463d3a51819SDave May   Level: beginner
1464d3a51819SDave May 
1465d3a51819SDave May   Notes:
14668b8a3813SDave May   The new point will have all fields initialized to zero.
1467d3a51819SDave May 
146820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmAddPoint()`
1469d3a51819SDave May @*/
1470d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddNPoints(DM dm, PetscInt npoints)
1471d71ae5a4SJacob Faibussowitsch {
1472cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1473cb1d1399SDave May   PetscInt  nlocal;
1474cb1d1399SDave May 
1475521f74f9SMatthew G. Knepley   PetscFunctionBegin;
14769566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
14779566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
1478cb1d1399SDave May   nlocal = nlocal + npoints;
14799566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
14809566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
14813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1482cb1d1399SDave May }
1483cb1d1399SDave May 
148474d0cae8SMatthew G. Knepley /*@
148520f4b53cSBarry Smith   DMSwarmRemovePoint - Remove the last point from the `DMSWARM`
1486d3a51819SDave May 
148720f4b53cSBarry Smith   Not Collective
1488d3a51819SDave May 
148960225df5SJacob Faibussowitsch   Input Parameter:
149020f4b53cSBarry Smith . dm - a `DMSWARM`
1491d3a51819SDave May 
1492d3a51819SDave May   Level: beginner
1493d3a51819SDave May 
149420f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePointAtIndex()`
1495d3a51819SDave May @*/
1496d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePoint(DM dm)
1497d71ae5a4SJacob Faibussowitsch {
1498cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1499cb1d1399SDave May 
1500521f74f9SMatthew G. Knepley   PetscFunctionBegin;
15019566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
15029566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePoint(swarm->db));
15039566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
15043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1505cb1d1399SDave May }
1506cb1d1399SDave May 
150774d0cae8SMatthew G. Knepley /*@
150820f4b53cSBarry Smith   DMSwarmRemovePointAtIndex - Removes a specific point from the `DMSWARM`
1509d3a51819SDave May 
151020f4b53cSBarry Smith   Not Collective
1511d3a51819SDave May 
151260225df5SJacob Faibussowitsch   Input Parameters:
151320f4b53cSBarry Smith + dm  - a `DMSWARM`
151462741f57SDave May - idx - index of point to remove
1515d3a51819SDave May 
1516d3a51819SDave May   Level: beginner
1517d3a51819SDave May 
151820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
1519d3a51819SDave May @*/
1520d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePointAtIndex(DM dm, PetscInt idx)
1521d71ae5a4SJacob Faibussowitsch {
1522cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1523cb1d1399SDave May 
1524521f74f9SMatthew G. Knepley   PetscFunctionBegin;
15259566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
15269566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, idx));
15279566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
15283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1529cb1d1399SDave May }
1530b62e03f8SDave May 
153174d0cae8SMatthew G. Knepley /*@
153220f4b53cSBarry Smith   DMSwarmCopyPoint - Copy point pj to point pi in the `DMSWARM`
1533ba4fc9c6SDave May 
153420f4b53cSBarry Smith   Not Collective
1535ba4fc9c6SDave May 
153660225df5SJacob Faibussowitsch   Input Parameters:
153720f4b53cSBarry Smith + dm - a `DMSWARM`
1538ba4fc9c6SDave May . pi - the index of the point to copy
1539ba4fc9c6SDave May - pj - the point index where the copy should be located
1540ba4fc9c6SDave May 
1541ba4fc9c6SDave May   Level: beginner
1542ba4fc9c6SDave May 
154320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
1544ba4fc9c6SDave May @*/
1545d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCopyPoint(DM dm, PetscInt pi, PetscInt pj)
1546d71ae5a4SJacob Faibussowitsch {
1547ba4fc9c6SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1548ba4fc9c6SDave May 
1549ba4fc9c6SDave May   PetscFunctionBegin;
15509566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
15519566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCopyPoint(swarm->db, pi, swarm->db, pj));
15523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1553ba4fc9c6SDave May }
1554ba4fc9c6SDave May 
155566976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmMigrate_Basic(DM dm, PetscBool remove_sent_points)
1556d71ae5a4SJacob Faibussowitsch {
1557521f74f9SMatthew G. Knepley   PetscFunctionBegin;
15589566063dSJacob Faibussowitsch   PetscCall(DMSwarmMigrate_Push_Basic(dm, remove_sent_points));
15593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15603454631fSDave May }
15613454631fSDave May 
156274d0cae8SMatthew G. Knepley /*@
156320f4b53cSBarry Smith   DMSwarmMigrate - Relocates points defined in the `DMSWARM` to other MPI-ranks
1564d3a51819SDave May 
156520f4b53cSBarry Smith   Collective
1566d3a51819SDave May 
156760225df5SJacob Faibussowitsch   Input Parameters:
156820f4b53cSBarry Smith + dm                 - the `DMSWARM`
156962741f57SDave May - remove_sent_points - flag indicating if sent points should be removed from the current MPI-rank
1570d3a51819SDave May 
1571d3a51819SDave May   Level: advanced
1572d3a51819SDave May 
157320f4b53cSBarry Smith   Notes:
157420f4b53cSBarry Smith   The `DM` will be modified to accommodate received points.
157520f4b53cSBarry Smith   If `remove_sent_points` is `PETSC_TRUE`, any points that were sent will be removed from the `DM`.
157620f4b53cSBarry Smith   Different styles of migration are supported. See `DMSwarmSetMigrateType()`.
157720f4b53cSBarry Smith 
157820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`
1579d3a51819SDave May @*/
1580d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmMigrate(DM dm, PetscBool remove_sent_points)
1581d71ae5a4SJacob Faibussowitsch {
1582f0cdbbbaSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1583f0cdbbbaSDave May 
1584521f74f9SMatthew G. Knepley   PetscFunctionBegin;
15859566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_Migrate, 0, 0, 0, 0));
1586f0cdbbbaSDave May   switch (swarm->migrate_type) {
1587d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_BASIC:
1588d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_Basic(dm, remove_sent_points));
1589d71ae5a4SJacob Faibussowitsch     break;
1590d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLNSCATTER:
1591d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_CellDMScatter(dm, remove_sent_points));
1592d71ae5a4SJacob Faibussowitsch     break;
1593d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLEXACT:
1594d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_DMCELLEXACT not implemented");
1595d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_USER:
1596d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_USER not implemented");
1597d71ae5a4SJacob Faibussowitsch   default:
1598d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE type unknown");
1599f0cdbbbaSDave May   }
16009566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_Migrate, 0, 0, 0, 0));
16019566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm));
16023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16033454631fSDave May }
16043454631fSDave May 
1605f0cdbbbaSDave May PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm, PetscInt *globalsize);
1606f0cdbbbaSDave May 
1607d3a51819SDave May /*
1608d3a51819SDave May  DMSwarmCollectViewCreate
1609d3a51819SDave May 
1610d3a51819SDave May  * Applies a collection method and gathers point neighbour points into dm
1611d3a51819SDave May 
1612d3a51819SDave May  Notes:
16138b8a3813SDave May  Users should call DMSwarmCollectViewDestroy() after
1614d3a51819SDave May  they have finished computations associated with the collected points
1615d3a51819SDave May */
1616d3a51819SDave May 
161774d0cae8SMatthew G. Knepley /*@
1618d3a51819SDave May   DMSwarmCollectViewCreate - Applies a collection method and gathers points
161920f4b53cSBarry Smith   in neighbour ranks into the `DMSWARM`
1620d3a51819SDave May 
162120f4b53cSBarry Smith   Collective
1622d3a51819SDave May 
162360225df5SJacob Faibussowitsch   Input Parameter:
162420f4b53cSBarry Smith . dm - the `DMSWARM`
1625d3a51819SDave May 
1626d3a51819SDave May   Level: advanced
1627d3a51819SDave May 
162820f4b53cSBarry Smith   Notes:
162920f4b53cSBarry Smith   Users should call `DMSwarmCollectViewDestroy()` after
163020f4b53cSBarry Smith   they have finished computations associated with the collected points
16310764c050SBarry Smith 
163220f4b53cSBarry Smith   Different collect methods are supported. See `DMSwarmSetCollectType()`.
163320f4b53cSBarry Smith 
16340764c050SBarry Smith   Developer Note:
16350764c050SBarry Smith   Create and Destroy routines create new objects that can get destroyed, they do not change the state
16360764c050SBarry Smith   of the current object.
16370764c050SBarry Smith 
163820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewDestroy()`, `DMSwarmSetCollectType()`
1639d3a51819SDave May @*/
1640d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewCreate(DM dm)
1641d71ae5a4SJacob Faibussowitsch {
16422712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
16432712d1f2SDave May   PetscInt  ng;
16442712d1f2SDave May 
1645521f74f9SMatthew G. Knepley   PetscFunctionBegin;
164628b400f6SJacob Faibussowitsch   PetscCheck(!swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView currently active");
16479566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &ng));
1648480eef7bSDave May   switch (swarm->collect_type) {
1649d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_BASIC:
1650d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_GlobalToLocal_Basic(dm, &ng));
1651d71ae5a4SJacob Faibussowitsch     break;
1652d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_DMDABOUNDINGBOX:
1653d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_DMDABOUNDINGBOX not implemented");
1654d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_GENERAL:
1655d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_GENERAL not implemented");
1656d71ae5a4SJacob Faibussowitsch   default:
1657d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT type unknown");
1658480eef7bSDave May   }
1659480eef7bSDave May   swarm->collect_view_active       = PETSC_TRUE;
1660480eef7bSDave May   swarm->collect_view_reset_nlocal = ng;
16613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16622712d1f2SDave May }
16632712d1f2SDave May 
166474d0cae8SMatthew G. Knepley /*@
166520f4b53cSBarry Smith   DMSwarmCollectViewDestroy - Resets the `DMSWARM` to the size prior to calling `DMSwarmCollectViewCreate()`
1666d3a51819SDave May 
166720f4b53cSBarry Smith   Collective
1668d3a51819SDave May 
166960225df5SJacob Faibussowitsch   Input Parameters:
167020f4b53cSBarry Smith . dm - the `DMSWARM`
1671d3a51819SDave May 
1672d3a51819SDave May   Notes:
167320f4b53cSBarry Smith   Users should call `DMSwarmCollectViewCreate()` before this function is called.
1674d3a51819SDave May 
1675d3a51819SDave May   Level: advanced
1676d3a51819SDave May 
16770764c050SBarry Smith   Developer Note:
16780764c050SBarry Smith   Create and Destroy routines create new objects that can get destroyed, they do not change the state
16790764c050SBarry Smith   of the current object.
16800764c050SBarry Smith 
168120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewCreate()`, `DMSwarmSetCollectType()`
1682d3a51819SDave May @*/
1683d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewDestroy(DM dm)
1684d71ae5a4SJacob Faibussowitsch {
16852712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
16862712d1f2SDave May 
1687521f74f9SMatthew G. Knepley   PetscFunctionBegin;
168828b400f6SJacob Faibussowitsch   PetscCheck(swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView is currently not active");
16899566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetLocalSizes(dm, swarm->collect_view_reset_nlocal, -1));
1690480eef7bSDave May   swarm->collect_view_active = PETSC_FALSE;
16913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16922712d1f2SDave May }
16933454631fSDave May 
169466976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmSetUpPIC(DM dm)
1695d71ae5a4SJacob Faibussowitsch {
1696f0cdbbbaSDave May   PetscInt dim;
1697f0cdbbbaSDave May 
1698521f74f9SMatthew G. Knepley   PetscFunctionBegin;
16999566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetNumSpecies(dm, 1));
17009566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
170163a3b9bcSJacob Faibussowitsch   PetscCheck(dim >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
170263a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
17039566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_coor, dim, PETSC_DOUBLE));
17049566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_cellid, 1, PETSC_INT));
1705d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmSetCoordinateField(dm, DMSwarmPICField_coor));
17063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1707f0cdbbbaSDave May }
1708f0cdbbbaSDave May 
170974d0cae8SMatthew G. Knepley /*@
171031403186SMatthew G. Knepley   DMSwarmSetPointCoordinatesRandom - Sets initial coordinates for particles in each cell
171131403186SMatthew G. Knepley 
171220f4b53cSBarry Smith   Collective
171331403186SMatthew G. Knepley 
171460225df5SJacob Faibussowitsch   Input Parameters:
171520f4b53cSBarry Smith + dm  - the `DMSWARM`
171620f4b53cSBarry Smith - Npc - The number of particles per cell in the cell `DM`
171731403186SMatthew G. Knepley 
171831403186SMatthew G. Knepley   Level: intermediate
171931403186SMatthew G. Knepley 
172020f4b53cSBarry Smith   Notes:
172120f4b53cSBarry Smith   The user must use `DMSwarmSetCellDM()` to set the cell `DM` first. The particles are placed randomly inside each cell. If only
172220f4b53cSBarry Smith   one particle is in each cell, it is placed at the centroid.
172320f4b53cSBarry Smith 
172420f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
172531403186SMatthew G. Knepley @*/
1726d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetPointCoordinatesRandom(DM dm, PetscInt Npc)
1727d71ae5a4SJacob Faibussowitsch {
172831403186SMatthew G. Knepley   DM             cdm;
172931403186SMatthew G. Knepley   PetscRandom    rnd;
173031403186SMatthew G. Knepley   DMPolytopeType ct;
173131403186SMatthew G. Knepley   PetscBool      simplex;
173231403186SMatthew G. Knepley   PetscReal     *centroid, *coords, *xi0, *v0, *J, *invJ, detJ;
173331403186SMatthew G. Knepley   PetscInt       dim, d, cStart, cEnd, c, p;
1734d52c2f21SMatthew G. Knepley   const char    *coordname;
173531403186SMatthew G. Knepley 
173631403186SMatthew G. Knepley   PetscFunctionBeginUser;
17379566063dSJacob Faibussowitsch   PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm), &rnd));
17389566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0));
17399566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetType(rnd, PETSCRAND48));
174031403186SMatthew G. Knepley 
1741d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetCoordinateField(dm, &coordname));
17429566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
17439566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(cdm, &dim));
17449566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd));
17459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(cdm, cStart, &ct));
174631403186SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
174731403186SMatthew G. Knepley 
17489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(dim, &centroid, dim, &xi0, dim, &v0, dim * dim, &J, dim * dim, &invJ));
174931403186SMatthew G. Knepley   for (d = 0; d < dim; ++d) xi0[d] = -1.0;
1750d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetField(dm, coordname, NULL, NULL, (void **)&coords));
175131403186SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
175231403186SMatthew G. Knepley     if (Npc == 1) {
17539566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(cdm, c, NULL, centroid, NULL));
175431403186SMatthew G. Knepley       for (d = 0; d < dim; ++d) coords[c * dim + d] = centroid[d];
175531403186SMatthew G. Knepley     } else {
17569566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(cdm, c, NULL, v0, J, invJ, &detJ)); /* affine */
175731403186SMatthew G. Knepley       for (p = 0; p < Npc; ++p) {
175831403186SMatthew G. Knepley         const PetscInt n   = c * Npc + p;
175931403186SMatthew G. Knepley         PetscReal      sum = 0.0, refcoords[3];
176031403186SMatthew G. Knepley 
176131403186SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
17629566063dSJacob Faibussowitsch           PetscCall(PetscRandomGetValueReal(rnd, &refcoords[d]));
176331403186SMatthew G. Knepley           sum += refcoords[d];
176431403186SMatthew G. Knepley         }
17659371c9d4SSatish Balay         if (simplex && sum > 0.0)
17669371c9d4SSatish Balay           for (d = 0; d < dim; ++d) refcoords[d] -= PetscSqrtReal(dim) * sum;
176731403186SMatthew G. Knepley         CoordinatesRefToReal(dim, dim, xi0, v0, J, refcoords, &coords[n * dim]);
176831403186SMatthew G. Knepley       }
176931403186SMatthew G. Knepley     }
177031403186SMatthew G. Knepley   }
1771d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(dm, coordname, NULL, NULL, (void **)&coords));
17729566063dSJacob Faibussowitsch   PetscCall(PetscFree5(centroid, xi0, v0, J, invJ));
17739566063dSJacob Faibussowitsch   PetscCall(PetscRandomDestroy(&rnd));
17743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
177531403186SMatthew G. Knepley }
177631403186SMatthew G. Knepley 
177731403186SMatthew G. Knepley /*@
177820f4b53cSBarry Smith   DMSwarmSetType - Set particular flavor of `DMSWARM`
1779d3a51819SDave May 
178020f4b53cSBarry Smith   Collective
1781d3a51819SDave May 
178260225df5SJacob Faibussowitsch   Input Parameters:
178320f4b53cSBarry Smith + dm    - the `DMSWARM`
178420f4b53cSBarry Smith - stype - the `DMSWARM` type (e.g. `DMSWARM_PIC`)
1785d3a51819SDave May 
1786d3a51819SDave May   Level: advanced
1787d3a51819SDave May 
178820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`, `DMSwarmSetCollectType()`, `DMSwarmType`, `DMSWARM_PIC`, `DMSWARM_BASIC`
1789d3a51819SDave May @*/
1790d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetType(DM dm, DMSwarmType stype)
1791d71ae5a4SJacob Faibussowitsch {
1792f0cdbbbaSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1793f0cdbbbaSDave May 
1794521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1795f0cdbbbaSDave May   swarm->swarm_type = stype;
179648a46eb9SPierre Jolivet   if (swarm->swarm_type == DMSWARM_PIC) PetscCall(DMSwarmSetUpPIC(dm));
17973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1798f0cdbbbaSDave May }
1799f0cdbbbaSDave May 
180066976f2fSJacob Faibussowitsch static PetscErrorCode DMSetup_Swarm(DM dm)
1801d71ae5a4SJacob Faibussowitsch {
18023454631fSDave May   DM_Swarm   *swarm = (DM_Swarm *)dm->data;
18033454631fSDave May   PetscMPIInt rank;
18043454631fSDave May   PetscInt    p, npoints, *rankval;
18053454631fSDave May 
1806521f74f9SMatthew G. Knepley   PetscFunctionBegin;
18073ba16761SJacob Faibussowitsch   if (swarm->issetup) PetscFunctionReturn(PETSC_SUCCESS);
18083454631fSDave May   swarm->issetup = PETSC_TRUE;
18093454631fSDave May 
1810f0cdbbbaSDave May   if (swarm->swarm_type == DMSWARM_PIC) {
1811f0cdbbbaSDave May     /* check dmcell exists */
1812d52c2f21SMatthew G. Knepley     PetscCheck(swarm->cellinfo && swarm->cellinfo[0].dm, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires you call DMSwarmSetCellDM() or DMSwarmPushCellDM()");
1813f0cdbbbaSDave May 
1814d52c2f21SMatthew G. Knepley     if (swarm->cellinfo[0].dm->ops->locatepointssubdomain) {
1815f0cdbbbaSDave May       /* check methods exists for exact ownership identificiation */
18169566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->ops->LocatePointsSubdomain\n"));
1817f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLEXACT;
1818f0cdbbbaSDave May     } else {
1819f0cdbbbaSDave May       /* check methods exist for point location AND rank neighbor identification */
1820d52c2f21SMatthew G. Knepley       if (swarm->cellinfo[0].dm->ops->locatepoints) {
18219566063dSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->LocatePoints\n"));
1822f0cdbbbaSDave May       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->locatepoints be defined");
1823f0cdbbbaSDave May 
1824d52c2f21SMatthew G. Knepley       if (swarm->cellinfo[0].dm->ops->getneighbors) {
18259566063dSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->GetNeigbors\n"));
1826f0cdbbbaSDave May       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->getneighbors be defined");
1827f0cdbbbaSDave May 
1828f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLNSCATTER;
1829f0cdbbbaSDave May     }
1830f0cdbbbaSDave May   }
1831f0cdbbbaSDave May 
18329566063dSJacob Faibussowitsch   PetscCall(DMSwarmFinalizeFieldRegister(dm));
1833f0cdbbbaSDave May 
18343454631fSDave May   /* check some fields were registered */
183508401ef6SPierre Jolivet   PetscCheck(swarm->db->nfields > 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "At least one field user must be registered via DMSwarmRegisterXXX()");
18363454631fSDave May 
18373454631fSDave May   /* check local sizes were set */
183808401ef6SPierre Jolivet   PetscCheck(swarm->db->L != -1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Local sizes must be set via DMSwarmSetLocalSizes()");
18393454631fSDave May 
18403454631fSDave May   /* initialize values in pid and rank placeholders */
18413454631fSDave May   /* TODO: [pid - use MPI_Scan] */
18429566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
18439566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
18449566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
1845835f2295SStefano Zampini   for (p = 0; p < npoints; p++) rankval[p] = rank;
18469566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
18473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18483454631fSDave May }
18493454631fSDave May 
1850dc5f5ce9SDave May extern PetscErrorCode DMSwarmSortDestroy(DMSwarmSort *_ctx);
1851dc5f5ce9SDave May 
185266976f2fSJacob Faibussowitsch static PetscErrorCode DMDestroy_Swarm(DM dm)
1853d71ae5a4SJacob Faibussowitsch {
185457795646SDave May   DM_Swarm  *swarm = (DM_Swarm *)dm->data;
1855d52c2f21SMatthew G. Knepley   CellDMInfo info  = swarm->cellinfo;
185657795646SDave May 
185757795646SDave May   PetscFunctionBegin;
18583ba16761SJacob Faibussowitsch   if (--swarm->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
18599566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&swarm->db));
1860d52c2f21SMatthew G. Knepley   for (PetscInt f = 0; f < swarm->vec_field_num; ++f) PetscCall(PetscFree(swarm->vec_field_names[f]));
1861d52c2f21SMatthew G. Knepley   PetscCall(PetscFree(swarm->vec_field_names));
1862d52c2f21SMatthew G. Knepley   PetscCall(PetscFree(swarm->coord_name));
186348a46eb9SPierre Jolivet   if (swarm->sort_context) PetscCall(DMSwarmSortDestroy(&swarm->sort_context));
1864d52c2f21SMatthew G. Knepley   while (info) {
1865d52c2f21SMatthew G. Knepley     CellDMInfo tmp = info;
1866d52c2f21SMatthew G. Knepley 
1867d52c2f21SMatthew G. Knepley     info = info->next;
1868d52c2f21SMatthew G. Knepley     PetscCall(CellDMInfoDestroy(&tmp));
1869d52c2f21SMatthew G. Knepley   }
18709566063dSJacob Faibussowitsch   PetscCall(PetscFree(swarm));
18713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
187257795646SDave May }
187357795646SDave May 
187466976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmView_Draw(DM dm, PetscViewer viewer)
1875d71ae5a4SJacob Faibussowitsch {
1876a9ee3421SMatthew G. Knepley   DM          cdm;
1877a9ee3421SMatthew G. Knepley   PetscDraw   draw;
187831403186SMatthew G. Knepley   PetscReal  *coords, oldPause, radius = 0.01;
1879a9ee3421SMatthew G. Knepley   PetscInt    Np, p, bs;
1880d52c2f21SMatthew G. Knepley   const char *coordname;
1881a9ee3421SMatthew G. Knepley 
1882a9ee3421SMatthew G. Knepley   PetscFunctionBegin;
18839566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetReal(NULL, ((PetscObject)dm)->prefix, "-dm_view_swarm_radius", &radius, NULL));
18849566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
18859566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
18869566063dSJacob Faibussowitsch   PetscCall(PetscDrawGetPause(draw, &oldPause));
18879566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, 0.0));
18889566063dSJacob Faibussowitsch   PetscCall(DMView(cdm, viewer));
18899566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, oldPause));
1890a9ee3421SMatthew G. Knepley 
1891d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetCoordinateField(dm, &coordname));
18929566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &Np));
1893d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetField(dm, coordname, &bs, NULL, (void **)&coords));
1894a9ee3421SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
1895a9ee3421SMatthew G. Knepley     const PetscInt i = p * bs;
1896a9ee3421SMatthew G. Knepley 
18979566063dSJacob Faibussowitsch     PetscCall(PetscDrawEllipse(draw, coords[i], coords[i + 1], radius, radius, PETSC_DRAW_BLUE));
1898a9ee3421SMatthew G. Knepley   }
1899d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(dm, coordname, &bs, NULL, (void **)&coords));
19009566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
19019566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
19029566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
19033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1904a9ee3421SMatthew G. Knepley }
1905a9ee3421SMatthew G. Knepley 
1906d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_Swarm_Ascii(DM dm, PetscViewer viewer)
1907d71ae5a4SJacob Faibussowitsch {
19086a5217c0SMatthew G. Knepley   PetscViewerFormat format;
19096a5217c0SMatthew G. Knepley   PetscInt         *sizes;
19106a5217c0SMatthew G. Knepley   PetscInt          dim, Np, maxSize = 17;
19116a5217c0SMatthew G. Knepley   MPI_Comm          comm;
19126a5217c0SMatthew G. Knepley   PetscMPIInt       rank, size, p;
19136a5217c0SMatthew G. Knepley   const char       *name;
19146a5217c0SMatthew G. Knepley 
19156a5217c0SMatthew G. Knepley   PetscFunctionBegin;
19166a5217c0SMatthew G. Knepley   PetscCall(PetscViewerGetFormat(viewer, &format));
19176a5217c0SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
19186a5217c0SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(dm, &Np));
19196a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
19206a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
19216a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(comm, &size));
19226a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetName((PetscObject)dm, &name));
192363a3b9bcSJacob Faibussowitsch   if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
192463a3b9bcSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(viewer, "Swarm in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
19256a5217c0SMatthew G. Knepley   if (size < maxSize) PetscCall(PetscCalloc1(size, &sizes));
19266a5217c0SMatthew G. Knepley   else PetscCall(PetscCalloc1(3, &sizes));
19276a5217c0SMatthew G. Knepley   if (size < maxSize) {
19286a5217c0SMatthew G. Knepley     PetscCallMPI(MPI_Gather(&Np, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
19296a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of particles per rank:"));
19306a5217c0SMatthew G. Knepley     for (p = 0; p < size; ++p) {
19316a5217c0SMatthew G. Knepley       if (rank == 0) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]));
19326a5217c0SMatthew G. Knepley     }
19336a5217c0SMatthew G. Knepley   } else {
19346a5217c0SMatthew G. Knepley     PetscInt locMinMax[2] = {Np, Np};
19356a5217c0SMatthew G. Knepley 
19366a5217c0SMatthew G. Knepley     PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
19376a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of particles per rank: %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
19386a5217c0SMatthew G. Knepley   }
19396a5217c0SMatthew G. Knepley   PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
19406a5217c0SMatthew G. Knepley   PetscCall(PetscFree(sizes));
19416a5217c0SMatthew G. Knepley   if (format == PETSC_VIEWER_ASCII_INFO) {
19426a5217c0SMatthew G. Knepley     PetscInt *cell;
19436a5217c0SMatthew G. Knepley 
19446a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells containing each particle:\n"));
19456a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
19466a5217c0SMatthew G. Knepley     PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell));
194763a3b9bcSJacob Faibussowitsch     for (p = 0; p < Np; ++p) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  p%d: %" PetscInt_FMT "\n", p, cell[p]));
19486a5217c0SMatthew G. Knepley     PetscCall(PetscViewerFlush(viewer));
19496a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
19506a5217c0SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell));
19516a5217c0SMatthew G. Knepley   }
19523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19536a5217c0SMatthew G. Knepley }
19546a5217c0SMatthew G. Knepley 
195566976f2fSJacob Faibussowitsch static PetscErrorCode DMView_Swarm(DM dm, PetscViewer viewer)
1956d71ae5a4SJacob Faibussowitsch {
19575f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
19584fc69c0aSMatthew G. Knepley   PetscBool iascii, ibinary, isvtk, isdraw, ispython;
19595627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
19605627991aSBarry Smith   PetscBool ishdf5;
19615627991aSBarry Smith #endif
19625f50eb2eSDave May 
19635f50eb2eSDave May   PetscFunctionBegin;
19645f50eb2eSDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
19655f50eb2eSDave May   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
19669566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
19679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary));
19689566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
19695627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
19709566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
19715627991aSBarry Smith #endif
19729566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
19734fc69c0aSMatthew G. Knepley   PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython));
19745f50eb2eSDave May   if (iascii) {
19756a5217c0SMatthew G. Knepley     PetscViewerFormat format;
19766a5217c0SMatthew G. Knepley 
19776a5217c0SMatthew G. Knepley     PetscCall(PetscViewerGetFormat(viewer, &format));
19786a5217c0SMatthew G. Knepley     switch (format) {
1979d71ae5a4SJacob Faibussowitsch     case PETSC_VIEWER_ASCII_INFO_DETAIL:
1980d71ae5a4SJacob Faibussowitsch       PetscCall(DMSwarmDataBucketView(PetscObjectComm((PetscObject)dm), swarm->db, NULL, DATABUCKET_VIEW_STDOUT));
1981d71ae5a4SJacob Faibussowitsch       break;
1982d71ae5a4SJacob Faibussowitsch     default:
1983d71ae5a4SJacob Faibussowitsch       PetscCall(DMView_Swarm_Ascii(dm, viewer));
19846a5217c0SMatthew G. Knepley     }
1985f7d195e4SLawrence Mitchell   } else {
19865f50eb2eSDave May #if defined(PETSC_HAVE_HDF5)
198748a46eb9SPierre Jolivet     if (ishdf5) PetscCall(DMSwarmView_HDF5(dm, viewer));
19885f50eb2eSDave May #endif
198948a46eb9SPierre Jolivet     if (isdraw) PetscCall(DMSwarmView_Draw(dm, viewer));
19904fc69c0aSMatthew G. Knepley     if (ispython) PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm));
1991f7d195e4SLawrence Mitchell   }
19923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19935f50eb2eSDave May }
19945f50eb2eSDave May 
1995cc4c1da9SBarry Smith /*@
199620f4b53cSBarry Smith   DMSwarmGetCellSwarm - Extracts a single cell from the `DMSWARM` object, returns it as a single cell `DMSWARM`.
199720f4b53cSBarry Smith   The cell `DM` is filtered for fields of that cell, and the filtered `DM` is used as the cell `DM` of the new swarm object.
1998d0c080abSJoseph Pusztay 
1999d0c080abSJoseph Pusztay   Noncollective
2000d0c080abSJoseph Pusztay 
200160225df5SJacob Faibussowitsch   Input Parameters:
200220f4b53cSBarry Smith + sw        - the `DMSWARM`
20035627991aSBarry Smith . cellID    - the integer id of the cell to be extracted and filtered
200420f4b53cSBarry Smith - cellswarm - The `DMSWARM` to receive the cell
2005d0c080abSJoseph Pusztay 
2006d0c080abSJoseph Pusztay   Level: beginner
2007d0c080abSJoseph Pusztay 
20085627991aSBarry Smith   Notes:
200920f4b53cSBarry Smith   This presently only supports `DMSWARM_PIC` type
20105627991aSBarry Smith 
201120f4b53cSBarry Smith   Should be restored with `DMSwarmRestoreCellSwarm()`
2012d0c080abSJoseph Pusztay 
201320f4b53cSBarry Smith   Changes to this cell of the swarm will be lost if they are made prior to restoring this cell.
201420f4b53cSBarry Smith 
201520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreCellSwarm()`
2016d0c080abSJoseph Pusztay @*/
2017cc4c1da9SBarry Smith PetscErrorCode DMSwarmGetCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
2018d71ae5a4SJacob Faibussowitsch {
2019d0c080abSJoseph Pusztay   DM_Swarm *original = (DM_Swarm *)sw->data;
2020d0c080abSJoseph Pusztay   DMLabel   label;
2021d0c080abSJoseph Pusztay   DM        dmc, subdmc;
2022d0c080abSJoseph Pusztay   PetscInt *pids, particles, dim;
2023d0c080abSJoseph Pusztay 
2024d0c080abSJoseph Pusztay   PetscFunctionBegin;
2025d0c080abSJoseph Pusztay   /* Configure new swarm */
20269566063dSJacob Faibussowitsch   PetscCall(DMSetType(cellswarm, DMSWARM));
20279566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(sw, &dim));
20289566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(cellswarm, dim));
20299566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(cellswarm, DMSWARM_PIC));
2030d0c080abSJoseph Pusztay   /* Destroy the unused, unconfigured data bucket to prevent stragglers in memory */
20319566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&((DM_Swarm *)cellswarm->data)->db));
20329566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
20339566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, cellID, &particles));
20349566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
20359566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreateFromSubset(original->db, particles, pids, &((DM_Swarm *)cellswarm->data)->db));
20369566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
2037fe11354eSMatthew G. Knepley   PetscCall(DMSwarmSortRestorePointsPerCell(sw, cellID, &particles, &pids));
20389566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(sw, &dmc));
20399566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)sw), "singlecell", &label));
20409566063dSJacob Faibussowitsch   PetscCall(DMAddLabel(dmc, label));
20419566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cellID, 1));
204230cbcd5dSksagiyam   PetscCall(DMPlexFilter(dmc, label, 1, PETSC_FALSE, PETSC_FALSE, NULL, &subdmc));
20439566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetCellDM(cellswarm, subdmc));
20449566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&label));
20453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2046d0c080abSJoseph Pusztay }
2047d0c080abSJoseph Pusztay 
2048cc4c1da9SBarry Smith /*@
204920f4b53cSBarry Smith   DMSwarmRestoreCellSwarm - Restores a `DMSWARM` object obtained with `DMSwarmGetCellSwarm()`. All fields are copied back into the parent swarm.
2050d0c080abSJoseph Pusztay 
2051d0c080abSJoseph Pusztay   Noncollective
2052d0c080abSJoseph Pusztay 
205360225df5SJacob Faibussowitsch   Input Parameters:
205420f4b53cSBarry Smith + sw        - the parent `DMSWARM`
2055d0c080abSJoseph Pusztay . cellID    - the integer id of the cell to be copied back into the parent swarm
2056d0c080abSJoseph Pusztay - cellswarm - the cell swarm object
2057d0c080abSJoseph Pusztay 
2058d0c080abSJoseph Pusztay   Level: beginner
2059d0c080abSJoseph Pusztay 
20605627991aSBarry Smith   Note:
206120f4b53cSBarry Smith   This only supports `DMSWARM_PIC` types of `DMSWARM`s
2062d0c080abSJoseph Pusztay 
206320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetCellSwarm()`
2064d0c080abSJoseph Pusztay @*/
2065cc4c1da9SBarry Smith PetscErrorCode DMSwarmRestoreCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
2066d71ae5a4SJacob Faibussowitsch {
2067d0c080abSJoseph Pusztay   DM        dmc;
2068d0c080abSJoseph Pusztay   PetscInt *pids, particles, p;
2069d0c080abSJoseph Pusztay 
2070d0c080abSJoseph Pusztay   PetscFunctionBegin;
20719566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
20729566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
20739566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
2074d0c080abSJoseph Pusztay   /* Pointwise copy of each particle based on pid. The parent swarm may not be altered during this process. */
207548a46eb9SPierre Jolivet   for (p = 0; p < particles; ++p) PetscCall(DMSwarmDataBucketCopyPoint(((DM_Swarm *)cellswarm->data)->db, pids[p], ((DM_Swarm *)sw->data)->db, pids[p]));
2076d0c080abSJoseph Pusztay   /* Free memory, destroy cell dm */
20779566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(cellswarm, &dmc));
20789566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
2079fe11354eSMatthew G. Knepley   PetscCall(DMSwarmSortRestorePointsPerCell(sw, cellID, &particles, &pids));
20803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2081d0c080abSJoseph Pusztay }
2082d0c080abSJoseph Pusztay 
2083d52c2f21SMatthew G. Knepley /*@
2084d52c2f21SMatthew G. Knepley   DMSwarmComputeMoments - Compute the first three particle moments for a given field
2085d52c2f21SMatthew G. Knepley 
2086d52c2f21SMatthew G. Knepley   Noncollective
2087d52c2f21SMatthew G. Knepley 
2088d52c2f21SMatthew G. Knepley   Input Parameters:
2089d52c2f21SMatthew G. Knepley + sw         - the `DMSWARM`
2090d52c2f21SMatthew G. Knepley . coordinate - the coordinate field name
2091d52c2f21SMatthew G. Knepley - weight     - the weight field name
2092d52c2f21SMatthew G. Knepley 
2093d52c2f21SMatthew G. Knepley   Output Parameter:
2094d52c2f21SMatthew G. Knepley . moments - the field moments
2095d52c2f21SMatthew G. Knepley 
2096d52c2f21SMatthew G. Knepley   Level: intermediate
2097d52c2f21SMatthew G. Knepley 
2098d52c2f21SMatthew G. Knepley   Notes:
2099d52c2f21SMatthew G. Knepley   The `moments` array should be of length bs + 2, where bs is the block size of the coordinate field.
2100d52c2f21SMatthew G. Knepley 
2101d52c2f21SMatthew G. Knepley   The weight field must be a scalar, having blocksize 1.
2102d52c2f21SMatthew G. Knepley 
2103d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMPlexComputeMoments()`
2104d52c2f21SMatthew G. Knepley @*/
2105d52c2f21SMatthew G. Knepley PetscErrorCode DMSwarmComputeMoments(DM sw, const char coordinate[], const char weight[], PetscReal moments[])
2106d52c2f21SMatthew G. Knepley {
2107d52c2f21SMatthew G. Knepley   const PetscReal *coords;
2108d52c2f21SMatthew G. Knepley   const PetscReal *w;
2109d52c2f21SMatthew G. Knepley   PetscReal       *mom;
2110d52c2f21SMatthew G. Knepley   PetscDataType    dtc, dtw;
2111d52c2f21SMatthew G. Knepley   PetscInt         bsc, bsw, Np;
2112d52c2f21SMatthew G. Knepley   MPI_Comm         comm;
2113d52c2f21SMatthew G. Knepley 
2114d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
2115d52c2f21SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
2116d52c2f21SMatthew G. Knepley   PetscAssertPointer(coordinate, 2);
2117d52c2f21SMatthew G. Knepley   PetscAssertPointer(weight, 3);
2118d52c2f21SMatthew G. Knepley   PetscAssertPointer(moments, 4);
2119d52c2f21SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
2120d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, coordinate, &bsc, &dtc, (void **)&coords));
2121d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, weight, &bsw, &dtw, (void **)&w));
2122d52c2f21SMatthew G. Knepley   PetscCheck(dtc == PETSC_REAL, comm, PETSC_ERR_ARG_WRONG, "Coordinate field %s must be real, not %s", coordinate, PetscDataTypes[dtc]);
2123d52c2f21SMatthew G. Knepley   PetscCheck(dtw == PETSC_REAL, comm, PETSC_ERR_ARG_WRONG, "Weight field %s must be real, not %s", weight, PetscDataTypes[dtw]);
2124d52c2f21SMatthew G. Knepley   PetscCheck(bsw == 1, comm, PETSC_ERR_ARG_WRONG, "Weight field %s must be a scalar, not blocksize %" PetscInt_FMT, weight, bsw);
2125d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2126d52c2f21SMatthew G. Knepley   PetscCall(DMGetWorkArray(sw, bsc + 2, MPIU_REAL, &mom));
2127d52c2f21SMatthew G. Knepley   PetscCall(PetscArrayzero(mom, bsc + 2));
2128d52c2f21SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
2129d52c2f21SMatthew G. Knepley     const PetscReal *c  = &coords[p * bsc];
2130d52c2f21SMatthew G. Knepley     const PetscReal  wp = w[p];
2131d52c2f21SMatthew G. Knepley 
2132d52c2f21SMatthew G. Knepley     mom[0] += wp;
2133d52c2f21SMatthew G. Knepley     for (PetscInt d = 0; d < bsc; ++d) {
2134d52c2f21SMatthew G. Knepley       mom[d + 1] += wp * c[d];
2135d52c2f21SMatthew G. Knepley       mom[d + bsc + 1] += wp * PetscSqr(c[d]);
2136d52c2f21SMatthew G. Knepley     }
2137d52c2f21SMatthew G. Knepley   }
2138d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&coords));
2139d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w));
2140d52c2f21SMatthew G. Knepley   PetscCallMPI(MPIU_Allreduce(mom, moments, bsc + 2, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)sw)));
2141d52c2f21SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(sw, bsc + 2, MPIU_REAL, &mom));
2142d0c080abSJoseph Pusztay   PetscFunctionReturn(PETSC_SUCCESS);
2143d0c080abSJoseph Pusztay }
2144d0c080abSJoseph Pusztay 
2145d0c080abSJoseph Pusztay PETSC_INTERN PetscErrorCode DMClone_Swarm(DM, DM *);
2146d0c080abSJoseph Pusztay 
2147d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMInitialize_Swarm(DM sw)
2148d71ae5a4SJacob Faibussowitsch {
2149d0c080abSJoseph Pusztay   PetscFunctionBegin;
2150d0c080abSJoseph Pusztay   sw->ops->view                     = DMView_Swarm;
2151d0c080abSJoseph Pusztay   sw->ops->load                     = NULL;
2152d0c080abSJoseph Pusztay   sw->ops->setfromoptions           = NULL;
2153d0c080abSJoseph Pusztay   sw->ops->clone                    = DMClone_Swarm;
2154d0c080abSJoseph Pusztay   sw->ops->setup                    = DMSetup_Swarm;
2155d0c080abSJoseph Pusztay   sw->ops->createlocalsection       = NULL;
2156adc21957SMatthew G. Knepley   sw->ops->createsectionpermutation = NULL;
2157d0c080abSJoseph Pusztay   sw->ops->createdefaultconstraints = NULL;
2158d0c080abSJoseph Pusztay   sw->ops->createglobalvector       = DMCreateGlobalVector_Swarm;
2159d0c080abSJoseph Pusztay   sw->ops->createlocalvector        = DMCreateLocalVector_Swarm;
2160d0c080abSJoseph Pusztay   sw->ops->getlocaltoglobalmapping  = NULL;
2161d0c080abSJoseph Pusztay   sw->ops->createfieldis            = NULL;
2162d0c080abSJoseph Pusztay   sw->ops->createcoordinatedm       = NULL;
2163d0c080abSJoseph Pusztay   sw->ops->getcoloring              = NULL;
2164d0c080abSJoseph Pusztay   sw->ops->creatematrix             = DMCreateMatrix_Swarm;
2165d0c080abSJoseph Pusztay   sw->ops->createinterpolation      = NULL;
2166d0c080abSJoseph Pusztay   sw->ops->createinjection          = NULL;
2167d0c080abSJoseph Pusztay   sw->ops->createmassmatrix         = DMCreateMassMatrix_Swarm;
2168d0c080abSJoseph Pusztay   sw->ops->refine                   = NULL;
2169d0c080abSJoseph Pusztay   sw->ops->coarsen                  = NULL;
2170d0c080abSJoseph Pusztay   sw->ops->refinehierarchy          = NULL;
2171d0c080abSJoseph Pusztay   sw->ops->coarsenhierarchy         = NULL;
2172d0c080abSJoseph Pusztay   sw->ops->globaltolocalbegin       = NULL;
2173d0c080abSJoseph Pusztay   sw->ops->globaltolocalend         = NULL;
2174d0c080abSJoseph Pusztay   sw->ops->localtoglobalbegin       = NULL;
2175d0c080abSJoseph Pusztay   sw->ops->localtoglobalend         = NULL;
2176d0c080abSJoseph Pusztay   sw->ops->destroy                  = DMDestroy_Swarm;
2177d0c080abSJoseph Pusztay   sw->ops->createsubdm              = NULL;
2178d0c080abSJoseph Pusztay   sw->ops->getdimpoints             = NULL;
2179d0c080abSJoseph Pusztay   sw->ops->locatepoints             = NULL;
21803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2181d0c080abSJoseph Pusztay }
2182d0c080abSJoseph Pusztay 
2183d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMClone_Swarm(DM dm, DM *newdm)
2184d71ae5a4SJacob Faibussowitsch {
2185d0c080abSJoseph Pusztay   DM_Swarm *swarm = (DM_Swarm *)dm->data;
2186d0c080abSJoseph Pusztay 
2187d0c080abSJoseph Pusztay   PetscFunctionBegin;
2188d0c080abSJoseph Pusztay   swarm->refct++;
2189d0c080abSJoseph Pusztay   (*newdm)->data = swarm;
21909566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMSWARM));
21919566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(*newdm));
21922e56dffeSJoe Pusztay   (*newdm)->dim = dm->dim;
21933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2194d0c080abSJoseph Pusztay }
2195d0c080abSJoseph Pusztay 
2196d3a51819SDave May /*MC
219720f4b53cSBarry Smith  DMSWARM = "swarm" - A `DM` object used to represent arrays of data (fields) of arbitrary data type.
219862741f57SDave May  This implementation was designed for particle methods in which the underlying
2199d3a51819SDave May  data required to be represented is both (i) dynamic in length, (ii) and of arbitrary data type.
2200d3a51819SDave May 
220120f4b53cSBarry Smith  Level: intermediate
220220f4b53cSBarry Smith 
220320f4b53cSBarry Smith   Notes:
220420f4b53cSBarry Smith  User data can be represented by `DMSWARM` through a registering "fields".
220562741f57SDave May  To register a field, the user must provide;
220662741f57SDave May  (a) a unique name;
220762741f57SDave May  (b) the data type (or size in bytes);
220862741f57SDave May  (c) the block size of the data.
2209d3a51819SDave May 
2210d3a51819SDave May  For example, suppose the application requires a unique id, energy, momentum and density to be stored
2211c215a47eSMatthew Knepley  on a set of particles. Then the following code could be used
221220f4b53cSBarry Smith .vb
221320f4b53cSBarry Smith     DMSwarmInitializeFieldRegister(dm)
221420f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"uid",1,PETSC_LONG);
221520f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"energy",1,PETSC_REAL);
221620f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"momentum",3,PETSC_REAL);
221720f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"density",1,PETSC_FLOAT);
221820f4b53cSBarry Smith     DMSwarmFinalizeFieldRegister(dm)
221920f4b53cSBarry Smith .ve
2220d3a51819SDave May 
222120f4b53cSBarry Smith  The fields represented by `DMSWARM` are dynamic and can be re-sized at any time.
222220f4b53cSBarry Smith  The only restriction imposed by `DMSWARM` is that all fields contain the same number of points.
2223d3a51819SDave May 
2224d3a51819SDave May  To support particle methods, "migration" techniques are provided. These methods migrate data
22255627991aSBarry Smith  between ranks.
2226d3a51819SDave May 
222720f4b53cSBarry Smith  `DMSWARM` supports the methods `DMCreateGlobalVector()` and `DMCreateLocalVector()`.
222820f4b53cSBarry Smith  As a `DMSWARM` may internally define and store values of different data types,
222920f4b53cSBarry Smith  before calling `DMCreateGlobalVector()` or `DMCreateLocalVector()`, the user must inform `DMSWARM` which
223020f4b53cSBarry Smith  fields should be used to define a `Vec` object via
223120f4b53cSBarry Smith    `DMSwarmVectorDefineField()`
2232c215a47eSMatthew Knepley  The specified field can be changed at any time - thereby permitting vectors
2233c215a47eSMatthew Knepley  compatible with different fields to be created.
2234d3a51819SDave May 
223520f4b53cSBarry Smith  A dual representation of fields in the `DMSWARM` and a Vec object is permitted via
223620f4b53cSBarry Smith    `DMSwarmCreateGlobalVectorFromField()`
223720f4b53cSBarry Smith  Here the data defining the field in the `DMSWARM` is shared with a Vec.
2238d3a51819SDave May  This is inherently unsafe if you alter the size of the field at any time between
223920f4b53cSBarry Smith  calls to `DMSwarmCreateGlobalVectorFromField()` and `DMSwarmDestroyGlobalVectorFromField()`.
224020f4b53cSBarry Smith  If the local size of the `DMSWARM` does not match the local size of the global vector
224120f4b53cSBarry Smith  when `DMSwarmDestroyGlobalVectorFromField()` is called, an error is thrown.
2242d3a51819SDave May 
224362741f57SDave May  Additional high-level support is provided for Particle-In-Cell methods.
224420f4b53cSBarry Smith  Please refer to `DMSwarmSetType()`.
224562741f57SDave May 
224620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMType`, `DMCreate()`, `DMSetType()`
2247d3a51819SDave May M*/
2248cc4c1da9SBarry Smith 
2249d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMCreate_Swarm(DM dm)
2250d71ae5a4SJacob Faibussowitsch {
225157795646SDave May   DM_Swarm *swarm;
225257795646SDave May 
225357795646SDave May   PetscFunctionBegin;
225457795646SDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22554dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&swarm));
2256f0cdbbbaSDave May   dm->data = swarm;
22579566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreate(&swarm->db));
22589566063dSJacob Faibussowitsch   PetscCall(DMSwarmInitializeFieldRegister(dm));
2259d52c2f21SMatthew G. Knepley   dm->dim                               = 0;
2260d0c080abSJoseph Pusztay   swarm->refct                          = 1;
22613454631fSDave May   swarm->issetup                        = PETSC_FALSE;
2262480eef7bSDave May   swarm->swarm_type                     = DMSWARM_BASIC;
2263480eef7bSDave May   swarm->migrate_type                   = DMSWARM_MIGRATE_BASIC;
2264480eef7bSDave May   swarm->collect_type                   = DMSWARM_COLLECT_BASIC;
226540c453e9SDave May   swarm->migrate_error_on_missing_point = PETSC_FALSE;
2266d52c2f21SMatthew G. Knepley   swarm->cellinfo                       = NULL;
2267f0cdbbbaSDave May   swarm->collect_view_active            = PETSC_FALSE;
2268f0cdbbbaSDave May   swarm->collect_view_reset_nlocal      = -1;
22699566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(dm));
22702e956fe4SStefano Zampini   if (SwarmDataFieldId == -1) PetscCall(PetscObjectComposedDataRegister(&SwarmDataFieldId));
22713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
227257795646SDave May }
2273