xref: /petsc/src/dm/impls/swarm/swarm.c (revision 8c5add6abd9f0e97420a8d072677ee1e39293c49)
119307e5cSMatthew G. Knepley #include "petscdmswarm.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};
21fca3fa51SMatthew G. Knepley const char *DMSwarmRemapTypeNames[]     = {"none", "pfak", "colella", "DMSwarmRemapType", "DMSWARM_REMAP_", NULL};
22ea78f98cSLisandro Dalcin const char *DMSwarmPICLayoutTypeNames[] = {"regular", "gauss", "subdivision", NULL};
23f0cdbbbaSDave May 
24f0cdbbbaSDave May const char DMSwarmField_pid[]     = "DMSwarm_pid";
25f0cdbbbaSDave May const char DMSwarmField_rank[]    = "DMSwarm_rank";
26f0cdbbbaSDave May const char DMSwarmPICField_coor[] = "DMSwarmPIC_coor";
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 
3366976f2fSJacob Faibussowitsch static PetscErrorCode VecView_Swarm_HDF5_Internal(Vec v, PetscViewer viewer)
34d71ae5a4SJacob Faibussowitsch {
3574d0cae8SMatthew G. Knepley   DM        dm;
3674d0cae8SMatthew G. Knepley   PetscReal seqval;
3774d0cae8SMatthew G. Knepley   PetscInt  seqnum, bs;
38eb0c6899SMatthew G. Knepley   PetscBool isseq, ists;
3974d0cae8SMatthew G. Knepley 
4074d0cae8SMatthew G. Knepley   PetscFunctionBegin;
419566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
429566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v, &bs));
439566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PushGroup(viewer, "/particle_fields"));
449566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
459566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, &seqval));
46eb0c6899SMatthew G. Knepley   PetscCall(PetscViewerHDF5IsTimestepping(viewer, &ists));
47eb0c6899SMatthew G. Knepley   if (ists) PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum));
489566063dSJacob Faibussowitsch   /* PetscCall(DMSequenceView_HDF5(dm, "time", seqnum, (PetscScalar) seqval, viewer)); */
499566063dSJacob Faibussowitsch   PetscCall(VecViewNative(v, viewer));
509566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)v, "Nc", PETSC_INT, (void *)&bs));
519566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PopGroup(viewer));
523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5374d0cae8SMatthew G. Knepley }
5474d0cae8SMatthew G. Knepley 
5566976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmView_HDF5(DM dm, PetscViewer viewer)
56d71ae5a4SJacob Faibussowitsch {
5719307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
5874d0cae8SMatthew G. Knepley   Vec           coordinates;
5919307e5cSMatthew G. Knepley   PetscInt      Np, Nfc;
6074d0cae8SMatthew G. Knepley   PetscBool     isseq;
6119307e5cSMatthew G. Knepley   const char  **coordFields;
6274d0cae8SMatthew G. Knepley 
6374d0cae8SMatthew G. Knepley   PetscFunctionBegin;
6419307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(dm, &celldm));
6519307e5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields));
6619307e5cSMatthew G. Knepley   PetscCheck(Nfc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "We only support a single coordinate field right now, not %" PetscInt_FMT, Nfc);
679566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetSize(dm, &Np));
6819307e5cSMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(dm, coordFields[0], &coordinates));
699566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
709566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PushGroup(viewer, "/particles"));
719566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)coordinates, VECSEQ, &isseq));
729566063dSJacob Faibussowitsch   PetscCall(VecViewNative(coordinates, viewer));
739566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)coordinates, "Np", PETSC_INT, (void *)&Np));
749566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PopGroup(viewer));
7519307e5cSMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(dm, coordFields[0], &coordinates));
763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7774d0cae8SMatthew G. Knepley }
7874d0cae8SMatthew G. Knepley #endif
7974d0cae8SMatthew G. Knepley 
8066976f2fSJacob Faibussowitsch static PetscErrorCode VecView_Swarm(Vec v, PetscViewer viewer)
81d71ae5a4SJacob Faibussowitsch {
8274d0cae8SMatthew G. Knepley   DM dm;
83f9558f5cSBarry Smith #if defined(PETSC_HAVE_HDF5)
8474d0cae8SMatthew G. Knepley   PetscBool ishdf5;
85f9558f5cSBarry Smith #endif
8674d0cae8SMatthew G. Knepley 
8774d0cae8SMatthew G. Knepley   PetscFunctionBegin;
889566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
8928b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
90f9558f5cSBarry Smith #if defined(PETSC_HAVE_HDF5)
919566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
9274d0cae8SMatthew G. Knepley   if (ishdf5) {
939566063dSJacob Faibussowitsch     PetscCall(VecView_Swarm_HDF5_Internal(v, viewer));
943ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
9574d0cae8SMatthew G. Knepley   }
96f9558f5cSBarry Smith #endif
979566063dSJacob Faibussowitsch   PetscCall(VecViewNative(v, viewer));
983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9974d0cae8SMatthew G. Knepley }
10074d0cae8SMatthew G. Knepley 
101d52c2f21SMatthew G. Knepley /*@C
102d52c2f21SMatthew G. Knepley   DMSwarmVectorGetField - Gets the fields from which to define a `Vec` object
1030bf7c1c5SMatthew G. Knepley   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
1040bf7c1c5SMatthew G. Knepley 
1050bf7c1c5SMatthew G. Knepley   Not collective
1060bf7c1c5SMatthew G. Knepley 
1070bf7c1c5SMatthew G. Knepley   Input Parameter:
10819307e5cSMatthew G. Knepley . sw - a `DMSWARM`
1090bf7c1c5SMatthew G. Knepley 
110d52c2f21SMatthew G. Knepley   Output Parameters:
111d52c2f21SMatthew G. Knepley + Nf         - the number of fields
112d52c2f21SMatthew G. Knepley - fieldnames - the textual name given to each registered field, or NULL if it has not been set
1130bf7c1c5SMatthew G. Knepley 
1140bf7c1c5SMatthew G. Knepley   Level: beginner
1150bf7c1c5SMatthew G. Knepley 
116d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
1170bf7c1c5SMatthew G. Knepley @*/
11819307e5cSMatthew G. Knepley PetscErrorCode DMSwarmVectorGetField(DM sw, PetscInt *Nf, const char **fieldnames[])
1190bf7c1c5SMatthew G. Knepley {
12019307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
12119307e5cSMatthew G. Knepley 
1220bf7c1c5SMatthew G. Knepley   PetscFunctionBegin;
12319307e5cSMatthew G. Knepley   PetscValidHeaderSpecificType(sw, DM_CLASSID, 1, DMSWARM);
12419307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
12519307e5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetFields(celldm, Nf, fieldnames));
1260bf7c1c5SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1270bf7c1c5SMatthew G. Knepley }
1280bf7c1c5SMatthew G. Knepley 
129cc4c1da9SBarry Smith /*@
13020f4b53cSBarry Smith   DMSwarmVectorDefineField - Sets the field from which to define a `Vec` object
13120f4b53cSBarry Smith   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
13257795646SDave May 
13320f4b53cSBarry Smith   Collective
13457795646SDave May 
13560225df5SJacob Faibussowitsch   Input Parameters:
13620f4b53cSBarry Smith + dm        - a `DMSWARM`
137d52c2f21SMatthew G. Knepley - fieldname - the textual name given to each registered field
13857795646SDave May 
139d3a51819SDave May   Level: beginner
14057795646SDave May 
141d3a51819SDave May   Notes:
14220f4b53cSBarry Smith   The field with name `fieldname` must be defined as having a data type of `PetscScalar`.
143e7af74c8SDave May 
14420f4b53cSBarry Smith   This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`.
14520f4b53cSBarry Smith   Multiple calls to `DMSwarmVectorDefineField()` are permitted.
146e7af74c8SDave May 
147d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineFields()`, `DMSwarmVectorGetField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
148d3a51819SDave May @*/
149d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmVectorDefineField(DM dm, const char fieldname[])
150d71ae5a4SJacob Faibussowitsch {
151d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
152d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmVectorDefineFields(dm, 1, &fieldname));
153d52c2f21SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
154d52c2f21SMatthew G. Knepley }
155d52c2f21SMatthew G. Knepley 
156d52c2f21SMatthew G. Knepley /*@C
157d52c2f21SMatthew G. Knepley   DMSwarmVectorDefineFields - Sets the fields from which to define a `Vec` object
158d52c2f21SMatthew G. Knepley   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
159d52c2f21SMatthew G. Knepley 
160d52c2f21SMatthew G. Knepley   Collective, No Fortran support
161d52c2f21SMatthew G. Knepley 
162d52c2f21SMatthew G. Knepley   Input Parameters:
16319307e5cSMatthew G. Knepley + sw         - a `DMSWARM`
164d52c2f21SMatthew G. Knepley . Nf         - the number of fields
165d52c2f21SMatthew G. Knepley - fieldnames - the textual name given to each registered field
166d52c2f21SMatthew G. Knepley 
167d52c2f21SMatthew G. Knepley   Level: beginner
168d52c2f21SMatthew G. Knepley 
169d52c2f21SMatthew G. Knepley   Notes:
170d52c2f21SMatthew G. Knepley   Each field with name in `fieldnames` must be defined as having a data type of `PetscScalar`.
171d52c2f21SMatthew G. Knepley 
172d52c2f21SMatthew G. Knepley   This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`.
173d52c2f21SMatthew G. Knepley   Multiple calls to `DMSwarmVectorDefineField()` are permitted.
174d52c2f21SMatthew G. Knepley 
175d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineField()`, `DMSwarmVectorGetField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
176d52c2f21SMatthew G. Knepley @*/
17719307e5cSMatthew G. Knepley PetscErrorCode DMSwarmVectorDefineFields(DM sw, PetscInt Nf, const char *fieldnames[])
178d52c2f21SMatthew G. Knepley {
17919307e5cSMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
18019307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
181b5bcf523SDave May 
182a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
18319307e5cSMatthew G. Knepley   PetscValidHeaderSpecificType(sw, DM_CLASSID, 1, DMSWARM);
184d52c2f21SMatthew G. Knepley   if (fieldnames) PetscAssertPointer(fieldnames, 3);
18519307e5cSMatthew G. Knepley   if (!swarm->issetup) PetscCall(DMSetUp(sw));
18619307e5cSMatthew G. Knepley   PetscCheck(Nf >= 0, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields must be non-negative, not %" PetscInt_FMT, Nf);
18719307e5cSMatthew G. Knepley   // Create a dummy cell DM if none has been specified (I think we should not support this mode)
18819307e5cSMatthew G. Knepley   if (!swarm->activeCellDM) {
18919307e5cSMatthew G. Knepley     DM            dm;
19019307e5cSMatthew G. Knepley     DMSwarmCellDM celldm;
191b5bcf523SDave May 
19219307e5cSMatthew G. Knepley     PetscCall(DMCreate(PetscObjectComm((PetscObject)sw), &dm));
19319307e5cSMatthew G. Knepley     PetscCall(DMSetType(dm, DMSHELL));
19419307e5cSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)dm, "dummy"));
19519307e5cSMatthew G. Knepley     PetscCall(DMSwarmCellDMCreate(dm, 0, NULL, 0, NULL, &celldm));
19619307e5cSMatthew G. Knepley     PetscCall(DMDestroy(&dm));
19719307e5cSMatthew G. Knepley     PetscCall(DMSwarmAddCellDM(sw, celldm));
19819307e5cSMatthew G. Knepley     PetscCall(DMSwarmCellDMDestroy(&celldm));
19919307e5cSMatthew G. Knepley     PetscCall(DMSwarmSetCellDMActive(sw, "dummy"));
20019307e5cSMatthew G. Knepley   }
20119307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
20219307e5cSMatthew G. Knepley   for (PetscInt f = 0; f < celldm->Nf; ++f) PetscCall(PetscFree(celldm->dmFields[f]));
20319307e5cSMatthew G. Knepley   PetscCall(PetscFree(celldm->dmFields));
20419307e5cSMatthew G. Knepley 
20519307e5cSMatthew G. Knepley   celldm->Nf = Nf;
20619307e5cSMatthew G. Knepley   PetscCall(PetscMalloc1(Nf, &celldm->dmFields));
207d52c2f21SMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) {
208d52c2f21SMatthew G. Knepley     PetscDataType type;
209d52c2f21SMatthew G. Knepley 
210d52c2f21SMatthew G. Knepley     // Check all fields are of type PETSC_REAL or PETSC_SCALAR
21119307e5cSMatthew G. Knepley     PetscCall(DMSwarmGetFieldInfo(sw, fieldnames[f], NULL, &type));
21219307e5cSMatthew G. Knepley     PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)sw), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
21319307e5cSMatthew G. Knepley     PetscCall(PetscStrallocpy(fieldnames[f], (char **)&celldm->dmFields[f]));
214d52c2f21SMatthew G. Knepley   }
2153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
216b5bcf523SDave May }
217b5bcf523SDave May 
218cc651181SDave May /* requires DMSwarmDefineFieldVector has been called */
21919307e5cSMatthew G. Knepley static PetscErrorCode DMCreateGlobalVector_Swarm(DM sw, Vec *vec)
220d71ae5a4SJacob Faibussowitsch {
22119307e5cSMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
22219307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
223b5bcf523SDave May   Vec           x;
224b5bcf523SDave May   char          name[PETSC_MAX_PATH_LEN];
22519307e5cSMatthew G. Knepley   PetscInt      bs = 0, n;
226b5bcf523SDave May 
227a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
22819307e5cSMatthew G. Knepley   if (!swarm->issetup) PetscCall(DMSetUp(sw));
22919307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
23019307e5cSMatthew G. Knepley   PetscCheck(celldm->Nf, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "Active cell DM does not define any fields");
23119307e5cSMatthew G. Knepley   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
232cc651181SDave May 
233d52c2f21SMatthew G. Knepley   PetscCall(PetscStrncpy(name, "DMSwarmField", PETSC_MAX_PATH_LEN));
23419307e5cSMatthew G. Knepley   for (PetscInt f = 0; f < celldm->Nf; ++f) {
23519307e5cSMatthew G. Knepley     PetscInt fbs;
236d52c2f21SMatthew G. Knepley     PetscCall(PetscStrlcat(name, "_", PETSC_MAX_PATH_LEN));
23719307e5cSMatthew G. Knepley     PetscCall(PetscStrlcat(name, celldm->dmFields[f], PETSC_MAX_PATH_LEN));
23819307e5cSMatthew G. Knepley     PetscCall(DMSwarmGetFieldInfo(sw, celldm->dmFields[f], &fbs, NULL));
23919307e5cSMatthew G. Knepley     bs += fbs;
240d52c2f21SMatthew G. Knepley   }
24119307e5cSMatthew G. Knepley   PetscCall(VecCreate(PetscObjectComm((PetscObject)sw), &x));
2429566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)x, name));
24319307e5cSMatthew G. Knepley   PetscCall(VecSetSizes(x, n * bs, PETSC_DETERMINE));
24419307e5cSMatthew G. Knepley   PetscCall(VecSetBlockSize(x, bs));
24519307e5cSMatthew G. Knepley   PetscCall(VecSetDM(x, sw));
2469566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(x));
24757d50842SBarry Smith   PetscCall(VecSetOperation(x, VECOP_VIEW, (PetscErrorCodeFn *)VecView_Swarm));
248b5bcf523SDave May   *vec = x;
2493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
250b5bcf523SDave May }
251b5bcf523SDave May 
252b5bcf523SDave May /* requires DMSwarmDefineFieldVector has been called */
25319307e5cSMatthew G. Knepley static PetscErrorCode DMCreateLocalVector_Swarm(DM sw, Vec *vec)
254d71ae5a4SJacob Faibussowitsch {
25519307e5cSMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
25619307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
257b5bcf523SDave May   Vec           x;
258b5bcf523SDave May   char          name[PETSC_MAX_PATH_LEN];
25919307e5cSMatthew G. Knepley   PetscInt      bs = 0, n;
260b5bcf523SDave May 
261a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
26219307e5cSMatthew G. Knepley   if (!swarm->issetup) PetscCall(DMSetUp(sw));
26319307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
26419307e5cSMatthew G. Knepley   PetscCheck(celldm->Nf, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "Active cell DM does not define any fields");
26519307e5cSMatthew G. Knepley   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
266cc651181SDave May 
267d52c2f21SMatthew G. Knepley   PetscCall(PetscStrncpy(name, "DMSwarmField", PETSC_MAX_PATH_LEN));
26819307e5cSMatthew G. Knepley   for (PetscInt f = 0; f < celldm->Nf; ++f) {
26919307e5cSMatthew G. Knepley     PetscInt fbs;
270d52c2f21SMatthew G. Knepley     PetscCall(PetscStrlcat(name, "_", PETSC_MAX_PATH_LEN));
27119307e5cSMatthew G. Knepley     PetscCall(PetscStrlcat(name, celldm->dmFields[f], PETSC_MAX_PATH_LEN));
27219307e5cSMatthew G. Knepley     PetscCall(DMSwarmGetFieldInfo(sw, celldm->dmFields[f], &fbs, NULL));
27319307e5cSMatthew G. Knepley     bs += fbs;
274d52c2f21SMatthew G. Knepley   }
2759566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &x));
2769566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)x, name));
27719307e5cSMatthew G. Knepley   PetscCall(VecSetSizes(x, n * bs, PETSC_DETERMINE));
27819307e5cSMatthew G. Knepley   PetscCall(VecSetBlockSize(x, bs));
27919307e5cSMatthew G. Knepley   PetscCall(VecSetDM(x, sw));
2809566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(x));
281b5bcf523SDave May   *vec = x;
2823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
283b5bcf523SDave May }
284b5bcf523SDave May 
285d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmDestroyVectorFromField_Private(DM dm, const char fieldname[], Vec *vec)
286d71ae5a4SJacob Faibussowitsch {
287fb1bcc12SMatthew G. Knepley   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
28877048351SPatrick Sanan   DMSwarmDataField gfield;
2892e956fe4SStefano Zampini   PetscInt         bs, nlocal, fid = -1, cfid = -2;
2902e956fe4SStefano Zampini   PetscBool        flg;
291d3a51819SDave May 
292fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
2932e956fe4SStefano Zampini   /* check vector is an inplace array */
2942e956fe4SStefano Zampini   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
2952e956fe4SStefano Zampini   PetscCall(PetscObjectComposedDataGetInt((PetscObject)*vec, SwarmDataFieldId, cfid, flg));
296ea17275aSJose E. Roman   (void)flg; /* avoid compiler warning */
297e978a55eSPierre 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);
2989566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(*vec, &nlocal));
2999566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(*vec, &bs));
30008401ef6SPierre 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");
3019566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
3029566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
3038df78e51SMark Adams   PetscCall(VecResetArray(*vec));
3049566063dSJacob Faibussowitsch   PetscCall(VecDestroy(vec));
3053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
306fb1bcc12SMatthew G. Knepley }
307fb1bcc12SMatthew G. Knepley 
308d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmCreateVectorFromField_Private(DM dm, const char fieldname[], MPI_Comm comm, Vec *vec)
309d71ae5a4SJacob Faibussowitsch {
310fb1bcc12SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
311fb1bcc12SMatthew G. Knepley   PetscDataType type;
312fb1bcc12SMatthew G. Knepley   PetscScalar  *array;
3132e956fe4SStefano Zampini   PetscInt      bs, n, fid;
314fb1bcc12SMatthew G. Knepley   char          name[PETSC_MAX_PATH_LEN];
315e4fbd051SBarry Smith   PetscMPIInt   size;
3167f92dde0SRylanor   PetscBool     iscuda, iskokkos, iship;
317fb1bcc12SMatthew G. Knepley 
318fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
3199566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
3209566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
3219566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array));
32208401ef6SPierre Jolivet   PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
323fb1bcc12SMatthew G. Knepley 
3249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
3258df78e51SMark Adams   PetscCall(PetscStrcmp(dm->vectype, VECKOKKOS, &iskokkos));
3268df78e51SMark Adams   PetscCall(PetscStrcmp(dm->vectype, VECCUDA, &iscuda));
3277f92dde0SRylanor   PetscCall(PetscStrcmp(dm->vectype, VECHIP, &iship));
3288df78e51SMark Adams   PetscCall(VecCreate(comm, vec));
3298df78e51SMark Adams   PetscCall(VecSetSizes(*vec, n * bs, PETSC_DETERMINE));
3308df78e51SMark Adams   PetscCall(VecSetBlockSize(*vec, bs));
3318df78e51SMark Adams   if (iskokkos) PetscCall(VecSetType(*vec, VECKOKKOS));
3328df78e51SMark Adams   else if (iscuda) PetscCall(VecSetType(*vec, VECCUDA));
3337f92dde0SRylanor   else if (iship) PetscCall(VecSetType(*vec, VECHIP));
3348df78e51SMark Adams   else PetscCall(VecSetType(*vec, VECSTANDARD));
3358df78e51SMark Adams   PetscCall(VecPlaceArray(*vec, array));
3368df78e51SMark Adams 
3379566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmSharedField_%s", fieldname));
3389566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*vec, name));
339fb1bcc12SMatthew G. Knepley 
340fb1bcc12SMatthew G. Knepley   /* Set guard */
3412e956fe4SStefano Zampini   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
3422e956fe4SStefano Zampini   PetscCall(PetscObjectComposedDataSetInt((PetscObject)*vec, SwarmDataFieldId, fid));
34374d0cae8SMatthew G. Knepley 
3449566063dSJacob Faibussowitsch   PetscCall(VecSetDM(*vec, dm));
34557d50842SBarry Smith   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (PetscErrorCodeFn *)VecView_Swarm));
3463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
347fb1bcc12SMatthew G. Knepley }
348fb1bcc12SMatthew G. Knepley 
34919307e5cSMatthew G. Knepley static PetscErrorCode DMSwarmDestroyVectorFromFields_Private(DM sw, PetscInt Nf, const char *fieldnames[], Vec *vec)
35019307e5cSMatthew G. Knepley {
35119307e5cSMatthew G. Knepley   DM_Swarm          *swarm = (DM_Swarm *)sw->data;
35219307e5cSMatthew G. Knepley   const PetscScalar *array;
35319307e5cSMatthew G. Knepley   PetscInt           bs, n, id = 0, cid = -2;
35419307e5cSMatthew G. Knepley   PetscBool          flg;
35519307e5cSMatthew G. Knepley 
35619307e5cSMatthew G. Knepley   PetscFunctionBegin;
35719307e5cSMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) {
35819307e5cSMatthew G. Knepley     PetscInt fid;
35919307e5cSMatthew G. Knepley 
36019307e5cSMatthew G. Knepley     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldnames[f], &fid));
36119307e5cSMatthew G. Knepley     id += fid;
36219307e5cSMatthew G. Knepley   }
36319307e5cSMatthew G. Knepley   PetscCall(PetscObjectComposedDataGetInt((PetscObject)*vec, SwarmDataFieldId, cid, flg));
36419307e5cSMatthew G. Knepley   (void)flg; /* avoid compiler warning */
36519307e5cSMatthew G. Knepley   PetscCheck(cid == id, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "Vector being destroyed was not created from DMSwarm field(%s)! %" PetscInt_FMT " != %" PetscInt_FMT, fieldnames[0], cid, id);
36619307e5cSMatthew G. Knepley   PetscCall(VecGetLocalSize(*vec, &n));
36719307e5cSMatthew G. Knepley   PetscCall(VecGetBlockSize(*vec, &bs));
36819307e5cSMatthew G. Knepley   n /= bs;
36919307e5cSMatthew G. Knepley   PetscCheck(n == swarm->db->L, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "DMSwarm sizes have changed since vector was created - cannot ensure pointers are valid");
37019307e5cSMatthew G. Knepley   PetscCall(VecGetArrayRead(*vec, &array));
37119307e5cSMatthew G. Knepley   for (PetscInt f = 0, off = 0; f < Nf; ++f) {
37219307e5cSMatthew G. Knepley     PetscScalar  *farray;
37319307e5cSMatthew G. Knepley     PetscDataType ftype;
37419307e5cSMatthew G. Knepley     PetscInt      fbs;
37519307e5cSMatthew G. Knepley 
37619307e5cSMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray));
37719307e5cSMatthew G. Knepley     PetscCheck(off + fbs <= bs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid blocksize %" PetscInt_FMT " < %" PetscInt_FMT, bs, off + fbs);
37819307e5cSMatthew G. Knepley     for (PetscInt i = 0; i < n; ++i) {
37919307e5cSMatthew G. Knepley       for (PetscInt b = 0; b < fbs; ++b) farray[i * fbs + b] = array[i * bs + off + b];
38019307e5cSMatthew G. Knepley     }
38119307e5cSMatthew G. Knepley     off += fbs;
38219307e5cSMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray));
38319307e5cSMatthew G. Knepley   }
38419307e5cSMatthew G. Knepley   PetscCall(VecRestoreArrayRead(*vec, &array));
38519307e5cSMatthew G. Knepley   PetscCall(VecDestroy(vec));
38619307e5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
38719307e5cSMatthew G. Knepley }
38819307e5cSMatthew G. Knepley 
38919307e5cSMatthew G. Knepley static PetscErrorCode DMSwarmCreateVectorFromFields_Private(DM sw, PetscInt Nf, const char *fieldnames[], MPI_Comm comm, Vec *vec)
39019307e5cSMatthew G. Knepley {
39119307e5cSMatthew G. Knepley   DM_Swarm    *swarm = (DM_Swarm *)sw->data;
39219307e5cSMatthew G. Knepley   PetscScalar *array;
39319307e5cSMatthew G. Knepley   PetscInt     n, bs = 0, id = 0;
39419307e5cSMatthew G. Knepley   char         name[PETSC_MAX_PATH_LEN];
39519307e5cSMatthew G. Knepley 
39619307e5cSMatthew G. Knepley   PetscFunctionBegin;
39719307e5cSMatthew G. Knepley   if (!swarm->issetup) PetscCall(DMSetUp(sw));
39819307e5cSMatthew G. Knepley   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
39919307e5cSMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) {
40019307e5cSMatthew G. Knepley     PetscDataType ftype;
40119307e5cSMatthew G. Knepley     PetscInt      fbs;
40219307e5cSMatthew G. Knepley 
40319307e5cSMatthew G. Knepley     PetscCall(DMSwarmGetFieldInfo(sw, fieldnames[f], &fbs, &ftype));
40419307e5cSMatthew G. Knepley     PetscCheck(ftype == PETSC_REAL, PetscObjectComm((PetscObject)sw), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
40519307e5cSMatthew G. Knepley     bs += fbs;
40619307e5cSMatthew G. Knepley   }
40719307e5cSMatthew G. Knepley 
40819307e5cSMatthew G. Knepley   PetscCall(VecCreate(comm, vec));
40919307e5cSMatthew G. Knepley   PetscCall(VecSetSizes(*vec, n * bs, PETSC_DETERMINE));
41019307e5cSMatthew G. Knepley   PetscCall(VecSetBlockSize(*vec, bs));
41119307e5cSMatthew G. Knepley   PetscCall(VecSetType(*vec, sw->vectype));
41219307e5cSMatthew G. Knepley 
41319307e5cSMatthew G. Knepley   PetscCall(VecGetArrayWrite(*vec, &array));
41419307e5cSMatthew G. Knepley   for (PetscInt f = 0, off = 0; f < Nf; ++f) {
41519307e5cSMatthew G. Knepley     PetscScalar  *farray;
41619307e5cSMatthew G. Knepley     PetscDataType ftype;
41719307e5cSMatthew G. Knepley     PetscInt      fbs;
41819307e5cSMatthew G. Knepley 
41919307e5cSMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray));
42019307e5cSMatthew G. Knepley     for (PetscInt i = 0; i < n; ++i) {
42119307e5cSMatthew G. Knepley       for (PetscInt b = 0; b < fbs; ++b) array[i * bs + off + b] = farray[i * fbs + b];
42219307e5cSMatthew G. Knepley     }
42319307e5cSMatthew G. Knepley     off += fbs;
42419307e5cSMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, fieldnames[f], &fbs, &ftype, (void **)&farray));
42519307e5cSMatthew G. Knepley   }
42619307e5cSMatthew G. Knepley   PetscCall(VecRestoreArrayWrite(*vec, &array));
42719307e5cSMatthew G. Knepley 
42819307e5cSMatthew G. Knepley   PetscCall(PetscStrncpy(name, "DMSwarmField", PETSC_MAX_PATH_LEN));
42919307e5cSMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) {
43019307e5cSMatthew G. Knepley     PetscCall(PetscStrlcat(name, "_", PETSC_MAX_PATH_LEN));
43119307e5cSMatthew G. Knepley     PetscCall(PetscStrlcat(name, fieldnames[f], PETSC_MAX_PATH_LEN));
43219307e5cSMatthew G. Knepley   }
43319307e5cSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*vec, name));
43419307e5cSMatthew G. Knepley 
43519307e5cSMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) {
43619307e5cSMatthew G. Knepley     PetscInt fid;
43719307e5cSMatthew G. Knepley 
43819307e5cSMatthew G. Knepley     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldnames[f], &fid));
43919307e5cSMatthew G. Knepley     id += fid;
44019307e5cSMatthew G. Knepley   }
44119307e5cSMatthew G. Knepley   PetscCall(PetscObjectComposedDataSetInt((PetscObject)*vec, SwarmDataFieldId, id));
44219307e5cSMatthew G. Knepley 
44319307e5cSMatthew G. Knepley   PetscCall(VecSetDM(*vec, sw));
44457d50842SBarry Smith   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (PetscErrorCodeFn *)VecView_Swarm));
44519307e5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
44619307e5cSMatthew G. Knepley }
44719307e5cSMatthew G. Knepley 
4480643ed39SMatthew G. Knepley /* This creates a "mass matrix" between a finite element and particle space. If a finite element interpolant is given by
4490643ed39SMatthew G. Knepley 
4500643ed39SMatthew G. Knepley      \hat f = \sum_i f_i \phi_i
4510643ed39SMatthew G. Knepley 
4520643ed39SMatthew G. Knepley    and a particle function is given by
4530643ed39SMatthew G. Knepley 
4540643ed39SMatthew G. Knepley      f = \sum_i w_i \delta(x - x_i)
4550643ed39SMatthew G. Knepley 
4560643ed39SMatthew G. Knepley    then we want to require that
4570643ed39SMatthew G. Knepley 
4580643ed39SMatthew G. Knepley      M \hat f = M_p f
4590643ed39SMatthew G. Knepley 
4600643ed39SMatthew G. Knepley    where the particle mass matrix is given by
4610643ed39SMatthew G. Knepley 
4620643ed39SMatthew G. Knepley      (M_p)_{ij} = \int \phi_i \delta(x - x_j)
4630643ed39SMatthew G. Knepley 
4640643ed39SMatthew G. Knepley    The way Dave May does particles, they amount to quadratue weights rather than delta functions, so he has |J| is in
4650643ed39SMatthew G. Knepley    his integral. We allow this with the boolean flag.
4660643ed39SMatthew G. Knepley */
467d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmComputeMassMatrix_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
468d71ae5a4SJacob Faibussowitsch {
46983c47955SMatthew G. Knepley   const char   *name = "Mass Matrix";
4700643ed39SMatthew G. Knepley   MPI_Comm      comm;
47119307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
47283c47955SMatthew G. Knepley   PetscDS       prob;
47383c47955SMatthew G. Knepley   PetscSection  fsection, globalFSection;
474e8f14785SLisandro Dalcin   PetscHSetIJ   ht;
4750643ed39SMatthew G. Knepley   PetscLayout   rLayout, colLayout;
47683c47955SMatthew G. Knepley   PetscInt     *dnz, *onz;
477adb2528bSMark Adams   PetscInt      locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
4780643ed39SMatthew G. Knepley   PetscReal    *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
47983c47955SMatthew G. Knepley   PetscScalar  *elemMat;
48019307e5cSMatthew G. Knepley   PetscInt      dim, Nf, Nfc, cStart, cEnd, totDim, maxC = 0, totNc = 0;
48119307e5cSMatthew G. Knepley   const char  **coordFields;
48219307e5cSMatthew G. Knepley   PetscReal   **coordVals;
48319307e5cSMatthew G. Knepley   PetscInt     *bs;
48483c47955SMatthew G. Knepley 
48583c47955SMatthew G. Knepley   PetscFunctionBegin;
4869566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
4879566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmf, &dim));
4889566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmf, &prob));
4899566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
4909566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
4919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
4929566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
4939566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
4949566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
4959566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
49683c47955SMatthew G. Knepley 
49719307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(dmc, &celldm));
49819307e5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields));
49919307e5cSMatthew G. Knepley   PetscCall(PetscMalloc2(Nfc, &coordVals, Nfc, &bs));
500d52c2f21SMatthew G. Knepley 
5019566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &colLayout));
5029566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
5039566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
5049566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colLayout));
5059566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
5069566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&colLayout));
5070643ed39SMatthew G. Knepley 
5089566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &rLayout));
5099566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
5109566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
5119566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
5129566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
5139566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
5140643ed39SMatthew G. Knepley 
5159566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
5169566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
51753e60ab4SJoseph Pusztay 
5189566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(comm, NULL));
51919307e5cSMatthew G. Knepley   for (PetscInt field = 0; field < Nf; ++field) {
5200bf7c1c5SMatthew G. Knepley     PetscObject  obj;
5210bf7c1c5SMatthew G. Knepley     PetscClassId id;
5220bf7c1c5SMatthew G. Knepley     PetscInt     Nc;
5230bf7c1c5SMatthew G. Knepley 
5240bf7c1c5SMatthew G. Knepley     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
5250bf7c1c5SMatthew G. Knepley     PetscCall(PetscObjectGetClassId(obj, &id));
5260bf7c1c5SMatthew G. Knepley     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
5270bf7c1c5SMatthew G. Knepley     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
5280bf7c1c5SMatthew G. Knepley     totNc += Nc;
5290bf7c1c5SMatthew G. Knepley   }
5300643ed39SMatthew G. Knepley   /* count non-zeros */
5319566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(dmc));
53219307e5cSMatthew G. Knepley   for (PetscInt field = 0; field < Nf; ++field) {
5330bf7c1c5SMatthew G. Knepley     PetscObject  obj;
5340bf7c1c5SMatthew G. Knepley     PetscClassId id;
5350bf7c1c5SMatthew G. Knepley     PetscInt     Nc;
5360bf7c1c5SMatthew G. Knepley 
5370bf7c1c5SMatthew G. Knepley     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
5380bf7c1c5SMatthew G. Knepley     PetscCall(PetscObjectGetClassId(obj, &id));
5390bf7c1c5SMatthew G. Knepley     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
5400bf7c1c5SMatthew G. Knepley     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
5410bf7c1c5SMatthew G. Knepley 
54219307e5cSMatthew G. Knepley     for (PetscInt cell = cStart; cell < cEnd; ++cell) {
5430643ed39SMatthew G. Knepley       PetscInt *findices, *cindices; /* fine is vertices, coarse is particles */
54483c47955SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
54583c47955SMatthew G. Knepley 
5469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
5479566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
548fc7c92abSMatthew G. Knepley       maxC = PetscMax(maxC, numCIndices);
54983c47955SMatthew G. Knepley       {
550e8f14785SLisandro Dalcin         PetscHashIJKey key;
551e8f14785SLisandro Dalcin         PetscBool      missing;
5520bf7c1c5SMatthew G. Knepley         for (PetscInt i = 0; i < numFIndices; ++i) {
553adb2528bSMark Adams           key.j = findices[i]; /* global column (from Plex) */
554adb2528bSMark Adams           if (key.j >= 0) {
55583c47955SMatthew G. Knepley             /* Get indices for coarse elements */
5560bf7c1c5SMatthew G. Knepley             for (PetscInt j = 0; j < numCIndices; ++j) {
5570bf7c1c5SMatthew G. Knepley               for (PetscInt c = 0; c < Nc; ++c) {
5580bf7c1c5SMatthew G. Knepley                 // TODO Need field offset on particle here
5590bf7c1c5SMatthew G. Knepley                 key.i = cindices[j] * totNc + c + rStart; /* global cols (from Swarm) */
560adb2528bSMark Adams                 if (key.i < 0) continue;
5619566063dSJacob Faibussowitsch                 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
562966bd95aSPierre Jolivet                 PetscCheck(missing, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Set new value at %" PetscInt_FMT ",%" PetscInt_FMT, key.i, key.j);
5630643ed39SMatthew G. Knepley                 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
564e8f14785SLisandro Dalcin                 else ++onz[key.i - rStart];
56583c47955SMatthew G. Knepley               }
566fc7c92abSMatthew G. Knepley             }
567fc7c92abSMatthew G. Knepley           }
5680bf7c1c5SMatthew G. Knepley         }
569fe11354eSMatthew G. Knepley         PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
57083c47955SMatthew G. Knepley       }
5719566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
57283c47955SMatthew G. Knepley     }
57383c47955SMatthew G. Knepley   }
5749566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
5759566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
5769566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
5779566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
5780bf7c1c5SMatthew G. Knepley   PetscCall(PetscMalloc3(maxC * totNc * totDim, &elemMat, maxC * totNc, &rowIDXs, maxC * dim, &xi));
57919307e5cSMatthew G. Knepley   for (PetscInt field = 0; field < Nf; ++field) {
580ef0bb6c7SMatthew G. Knepley     PetscTabulation Tcoarse;
58183c47955SMatthew G. Knepley     PetscObject     obj;
582ad9634fcSMatthew G. Knepley     PetscClassId    id;
58319307e5cSMatthew G. Knepley     PetscInt        Nc;
58483c47955SMatthew G. Knepley 
5859566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
586ad9634fcSMatthew G. Knepley     PetscCall(PetscObjectGetClassId(obj, &id));
587ad9634fcSMatthew G. Knepley     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
588ad9634fcSMatthew G. Knepley     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
589ea7032a0SMatthew G. Knepley 
59019307e5cSMatthew G. Knepley     for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmGetField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i]));
59119307e5cSMatthew G. Knepley     for (PetscInt cell = cStart; cell < cEnd; ++cell) {
59283c47955SMatthew G. Knepley       PetscInt *findices, *cindices;
59383c47955SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
59483c47955SMatthew G. Knepley 
5950643ed39SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
5969566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
5979566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
5989566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
59919307e5cSMatthew G. Knepley       for (PetscInt j = 0; j < numCIndices; ++j) {
60019307e5cSMatthew G. Knepley         PetscReal xr[8];
60119307e5cSMatthew G. Knepley         PetscInt  off = 0;
60219307e5cSMatthew G. Knepley 
60319307e5cSMatthew G. Knepley         for (PetscInt i = 0; i < Nfc; ++i) {
60419307e5cSMatthew G. Knepley           for (PetscInt b = 0; b < bs[i]; ++b, ++off) xr[off] = coordVals[i][cindices[j] * bs[i] + b];
60519307e5cSMatthew G. Knepley         }
60619307e5cSMatthew G. Knepley         PetscCheck(off == dim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The total block size of coordinates is %" PetscInt_FMT " != %" PetscInt_FMT " the DM coordinate dimension", off, dim);
60719307e5cSMatthew G. Knepley         CoordinatesRealToRef(dim, dim, v0ref, v0, invJ, xr, &xi[j * dim]);
60819307e5cSMatthew G. Knepley       }
609ad9634fcSMatthew G. Knepley       if (id == PETSCFE_CLASSID) PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
610ad9634fcSMatthew G. Knepley       else PetscCall(PetscFVCreateTabulation((PetscFV)obj, 1, numCIndices, xi, 0, &Tcoarse));
61183c47955SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
6120bf7c1c5SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMat, numCIndices * Nc * totDim));
6130bf7c1c5SMatthew G. Knepley       for (PetscInt i = 0; i < numFIndices / Nc; ++i) {
6140bf7c1c5SMatthew G. Knepley         for (PetscInt j = 0; j < numCIndices; ++j) {
6150bf7c1c5SMatthew G. Knepley           for (PetscInt c = 0; c < Nc; ++c) {
6160bf7c1c5SMatthew G. Knepley             // TODO Need field offset on particle and field here
6170643ed39SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
6180bf7c1c5SMatthew G. Knepley             elemMat[(j * totNc + c) * numFIndices + i * Nc + c] += Tcoarse->T[0][(j * numFIndices + i * Nc + c) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
61983c47955SMatthew G. Knepley           }
6200643ed39SMatthew G. Knepley         }
6210643ed39SMatthew G. Knepley       }
6220bf7c1c5SMatthew G. Knepley       for (PetscInt j = 0; j < numCIndices; ++j)
6230bf7c1c5SMatthew G. Knepley         // TODO Need field offset on particle here
6240bf7c1c5SMatthew G. Knepley         for (PetscInt c = 0; c < Nc; ++c) rowIDXs[j * Nc + c] = cindices[j] * totNc + c + rStart;
6250bf7c1c5SMatthew G. Knepley       if (0) PetscCall(DMPrintCellMatrix(cell, name, numCIndices * Nc, numFIndices, elemMat));
6260bf7c1c5SMatthew G. Knepley       PetscCall(MatSetValues(mass, numCIndices * Nc, rowIDXs, numFIndices, findices, elemMat, ADD_VALUES));
627fe11354eSMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
6289566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
6299566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
63083c47955SMatthew G. Knepley     }
63119307e5cSMatthew G. Knepley     for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmRestoreField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i]));
63283c47955SMatthew G. Knepley   }
6339566063dSJacob Faibussowitsch   PetscCall(PetscFree3(elemMat, rowIDXs, xi));
6349566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
6359566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
63619307e5cSMatthew G. Knepley   PetscCall(PetscFree2(coordVals, bs));
6379566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
6389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
6393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64083c47955SMatthew G. Knepley }
64183c47955SMatthew G. Knepley 
642d0c080abSJoseph Pusztay /* Returns empty matrix for use with SNES FD */
643d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMatrix_Swarm(DM sw, Mat *m)
644d71ae5a4SJacob Faibussowitsch {
645d0c080abSJoseph Pusztay   Vec      field;
646d0c080abSJoseph Pusztay   PetscInt size;
647d0c080abSJoseph Pusztay 
648d0c080abSJoseph Pusztay   PetscFunctionBegin;
6499566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(sw, &field));
6509566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(field, &size));
6519566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(sw, &field));
6529566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD, m));
6539566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*m));
6549566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*m, PETSC_DECIDE, PETSC_DECIDE, size, size));
6559566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*m, 1, NULL));
6569566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(*m));
6579566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*m, MAT_FINAL_ASSEMBLY));
6589566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*m, MAT_FINAL_ASSEMBLY));
6599566063dSJacob Faibussowitsch   PetscCall(MatShift(*m, 1.0));
6609566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*m, sw));
6613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
662d0c080abSJoseph Pusztay }
663d0c080abSJoseph Pusztay 
664adb2528bSMark Adams /* FEM cols, Particle rows */
665d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMassMatrix_Swarm(DM dmCoarse, DM dmFine, Mat *mass)
666d71ae5a4SJacob Faibussowitsch {
66719307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
668895a1698SMatthew G. Knepley   PetscSection  gsf;
66919307e5cSMatthew G. Knepley   PetscInt      m, n, Np, bs;
67083c47955SMatthew G. Knepley   void         *ctx;
67183c47955SMatthew G. Knepley 
67283c47955SMatthew G. Knepley   PetscFunctionBegin;
67319307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(dmCoarse, &celldm));
67419307e5cSMatthew G. Knepley   PetscCheck(celldm->Nf, PetscObjectComm((PetscObject)dmCoarse), PETSC_ERR_USER, "Active cell DM does not define any fields");
6759566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
6769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
6770bf7c1c5SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(dmCoarse, &Np));
67819307e5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetBlockSize(celldm, dmCoarse, &bs));
67919307e5cSMatthew G. Knepley   n = Np * bs;
6809566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
6819566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, m, PETSC_DETERMINE, PETSC_DETERMINE));
6829566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
6839566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
68483c47955SMatthew G. Knepley 
6859566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrix_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
6869566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
6873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
68883c47955SMatthew G. Knepley }
68983c47955SMatthew G. Knepley 
690d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmComputeMassMatrixSquare_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
691d71ae5a4SJacob Faibussowitsch {
6924cc7f7b2SMatthew G. Knepley   const char   *name = "Mass Matrix Square";
6934cc7f7b2SMatthew G. Knepley   MPI_Comm      comm;
69419307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
6954cc7f7b2SMatthew G. Knepley   PetscDS       prob;
6964cc7f7b2SMatthew G. Knepley   PetscSection  fsection, globalFSection;
6974cc7f7b2SMatthew G. Knepley   PetscHSetIJ   ht;
6984cc7f7b2SMatthew G. Knepley   PetscLayout   rLayout, colLayout;
6994cc7f7b2SMatthew G. Knepley   PetscInt     *dnz, *onz, *adj, depth, maxConeSize, maxSupportSize, maxAdjSize;
7004cc7f7b2SMatthew G. Knepley   PetscInt      locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
7014cc7f7b2SMatthew G. Knepley   PetscReal    *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
7024cc7f7b2SMatthew G. Knepley   PetscScalar  *elemMat, *elemMatSq;
70319307e5cSMatthew G. Knepley   PetscInt      cdim, Nf, Nfc, cStart, cEnd, totDim, maxC = 0;
70419307e5cSMatthew G. Knepley   const char  **coordFields;
70519307e5cSMatthew G. Knepley   PetscReal   **coordVals;
70619307e5cSMatthew G. Knepley   PetscInt     *bs;
7074cc7f7b2SMatthew G. Knepley 
7084cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
7099566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
7109566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmf, &cdim));
7119566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmf, &prob));
7129566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
7139566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
7149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(cdim, &v0, cdim * cdim, &J, cdim * cdim, &invJ));
7159566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
7169566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
7179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
7189566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
7194cc7f7b2SMatthew G. Knepley 
72019307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(dmc, &celldm));
72119307e5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields));
72219307e5cSMatthew G. Knepley   PetscCall(PetscMalloc2(Nfc, &coordVals, Nfc, &bs));
723d52c2f21SMatthew G. Knepley 
7249566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &colLayout));
7259566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
7269566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
7279566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colLayout));
7289566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
7299566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&colLayout));
7304cc7f7b2SMatthew G. Knepley 
7319566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &rLayout));
7329566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
7339566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
7349566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
7359566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
7369566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
7374cc7f7b2SMatthew G. Knepley 
7389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmf, &depth));
7399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dmf, &maxConeSize, &maxSupportSize));
7404cc7f7b2SMatthew G. Knepley   maxAdjSize = PetscPowInt(maxConeSize * maxSupportSize, depth);
7419566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxAdjSize, &adj));
7424cc7f7b2SMatthew G. Knepley 
7439566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
7449566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
7454cc7f7b2SMatthew G. Knepley   /* Count nonzeros
7464cc7f7b2SMatthew G. Knepley        This is just FVM++, but we cannot use the Plex P0 allocation since unknowns in a cell will not be contiguous
7474cc7f7b2SMatthew G. Knepley   */
7489566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(dmc));
74919307e5cSMatthew G. Knepley   for (PetscInt cell = cStart; cell < cEnd; ++cell) {
7504cc7f7b2SMatthew G. Knepley     PetscInt *cindices;
7514cc7f7b2SMatthew G. Knepley     PetscInt  numCIndices;
7524cc7f7b2SMatthew G. Knepley #if 0
7534cc7f7b2SMatthew G. Knepley     PetscInt  adjSize = maxAdjSize, a, j;
7544cc7f7b2SMatthew G. Knepley #endif
7554cc7f7b2SMatthew G. Knepley 
7569566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
7574cc7f7b2SMatthew G. Knepley     maxC = PetscMax(maxC, numCIndices);
7584cc7f7b2SMatthew G. Knepley     /* Diagonal block */
75919307e5cSMatthew G. Knepley     for (PetscInt i = 0; i < numCIndices; ++i) dnz[cindices[i]] += numCIndices;
7604cc7f7b2SMatthew G. Knepley #if 0
7614cc7f7b2SMatthew G. Knepley     /* Off-diagonal blocks */
7629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(dmf, cell, &adjSize, &adj));
7634cc7f7b2SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
7644cc7f7b2SMatthew G. Knepley       if (adj[a] >= cStart && adj[a] < cEnd && adj[a] != cell) {
7654cc7f7b2SMatthew G. Knepley         const PetscInt ncell = adj[a];
7664cc7f7b2SMatthew G. Knepley         PetscInt      *ncindices;
7674cc7f7b2SMatthew G. Knepley         PetscInt       numNCIndices;
7684cc7f7b2SMatthew G. Knepley 
7699566063dSJacob Faibussowitsch         PetscCall(DMSwarmSortGetPointsPerCell(dmc, ncell, &numNCIndices, &ncindices));
7704cc7f7b2SMatthew G. Knepley         {
7714cc7f7b2SMatthew G. Knepley           PetscHashIJKey key;
7724cc7f7b2SMatthew G. Knepley           PetscBool      missing;
7734cc7f7b2SMatthew G. Knepley 
7744cc7f7b2SMatthew G. Knepley           for (i = 0; i < numCIndices; ++i) {
7754cc7f7b2SMatthew G. Knepley             key.i = cindices[i] + rStart; /* global rows (from Swarm) */
7764cc7f7b2SMatthew G. Knepley             if (key.i < 0) continue;
7774cc7f7b2SMatthew G. Knepley             for (j = 0; j < numNCIndices; ++j) {
7784cc7f7b2SMatthew G. Knepley               key.j = ncindices[j] + rStart; /* global column (from Swarm) */
7794cc7f7b2SMatthew G. Knepley               if (key.j < 0) continue;
7809566063dSJacob Faibussowitsch               PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
7814cc7f7b2SMatthew G. Knepley               if (missing) {
7824cc7f7b2SMatthew G. Knepley                 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
7834cc7f7b2SMatthew G. Knepley                 else                                         ++onz[key.i - rStart];
7844cc7f7b2SMatthew G. Knepley               }
7854cc7f7b2SMatthew G. Knepley             }
7864cc7f7b2SMatthew G. Knepley           }
7874cc7f7b2SMatthew G. Knepley         }
788fe11354eSMatthew G. Knepley         PetscCall(DMSwarmSortRestorePointsPerCell(dmc, ncell, &numNCIndices, &ncindices));
7894cc7f7b2SMatthew G. Knepley       }
7904cc7f7b2SMatthew G. Knepley     }
7914cc7f7b2SMatthew G. Knepley #endif
792fe11354eSMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
7934cc7f7b2SMatthew G. Knepley   }
7949566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
7959566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
7969566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
7979566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
7989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(maxC * totDim, &elemMat, maxC * maxC, &elemMatSq, maxC, &rowIDXs, maxC * cdim, &xi));
7994cc7f7b2SMatthew G. Knepley   /* Fill in values
8004cc7f7b2SMatthew G. Knepley        Each entry is a sum of terms \phi_i(x_p) \phi_i(x_q)
8014cc7f7b2SMatthew G. Knepley        Start just by producing block diagonal
8024cc7f7b2SMatthew G. Knepley        Could loop over adjacent cells
8034cc7f7b2SMatthew G. Knepley          Produce neighboring element matrix
8044cc7f7b2SMatthew G. Knepley          TODO Determine which columns and rows correspond to shared dual vector
8054cc7f7b2SMatthew G. Knepley          Do MatMatMult with rectangular matrices
8064cc7f7b2SMatthew G. Knepley          Insert block
8074cc7f7b2SMatthew G. Knepley   */
80819307e5cSMatthew G. Knepley   for (PetscInt field = 0; field < Nf; ++field) {
8094cc7f7b2SMatthew G. Knepley     PetscTabulation Tcoarse;
8104cc7f7b2SMatthew G. Knepley     PetscObject     obj;
81119307e5cSMatthew G. Knepley     PetscInt        Nc;
8124cc7f7b2SMatthew G. Knepley 
8139566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
8149566063dSJacob Faibussowitsch     PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
81563a3b9bcSJacob Faibussowitsch     PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc);
81619307e5cSMatthew G. Knepley     for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmGetField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i]));
81719307e5cSMatthew G. Knepley     for (PetscInt cell = cStart; cell < cEnd; ++cell) {
8184cc7f7b2SMatthew G. Knepley       PetscInt *findices, *cindices;
8194cc7f7b2SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
8204cc7f7b2SMatthew G. Knepley 
8214cc7f7b2SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
8229566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
8239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
8249566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
82519307e5cSMatthew G. Knepley       for (PetscInt p = 0; p < numCIndices; ++p) {
82619307e5cSMatthew G. Knepley         PetscReal xr[8];
82719307e5cSMatthew G. Knepley         PetscInt  off = 0;
82819307e5cSMatthew G. Knepley 
82919307e5cSMatthew G. Knepley         for (PetscInt i = 0; i < Nfc; ++i) {
83019307e5cSMatthew G. Knepley           for (PetscInt b = 0; b < bs[i]; ++b, ++off) xr[off] = coordVals[i][cindices[p] * bs[i] + b];
83119307e5cSMatthew G. Knepley         }
83219307e5cSMatthew G. Knepley         PetscCheck(off == cdim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The total block size of coordinates is %" PetscInt_FMT " != %" PetscInt_FMT " the DM coordinate dimension", off, cdim);
83319307e5cSMatthew G. Knepley         CoordinatesRealToRef(cdim, cdim, v0ref, v0, invJ, xr, &xi[p * cdim]);
83419307e5cSMatthew G. Knepley       }
8359566063dSJacob Faibussowitsch       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
8364cc7f7b2SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
8379566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemMat, numCIndices * totDim));
83819307e5cSMatthew G. Knepley       for (PetscInt i = 0; i < numFIndices; ++i) {
83919307e5cSMatthew G. Knepley         for (PetscInt p = 0; p < numCIndices; ++p) {
84019307e5cSMatthew G. Knepley           for (PetscInt c = 0; c < Nc; ++c) {
8414cc7f7b2SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
8424cc7f7b2SMatthew G. Knepley             elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
8434cc7f7b2SMatthew G. Knepley           }
8444cc7f7b2SMatthew G. Knepley         }
8454cc7f7b2SMatthew G. Knepley       }
8469566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
84719307e5cSMatthew G. Knepley       for (PetscInt p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart;
8489566063dSJacob Faibussowitsch       if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
8494cc7f7b2SMatthew G. Knepley       /* Block diagonal */
85078884ca7SMatthew G. Knepley       if (numCIndices) {
8514cc7f7b2SMatthew G. Knepley         PetscBLASInt blasn, blask;
8524cc7f7b2SMatthew G. Knepley         PetscScalar  one = 1.0, zero = 0.0;
8534cc7f7b2SMatthew G. Knepley 
8549566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numCIndices, &blasn));
8559566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numFIndices, &blask));
856792fecdfSBarry Smith         PetscCallBLAS("BLASgemm", BLASgemm_("T", "N", &blasn, &blasn, &blask, &one, elemMat, &blask, elemMat, &blask, &zero, elemMatSq, &blasn));
8574cc7f7b2SMatthew G. Knepley       }
8589566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numCIndices, rowIDXs, elemMatSq, ADD_VALUES));
8594cf0e950SBarry Smith       /* TODO off-diagonal */
860fe11354eSMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(dmc, cell, &numCIndices, &cindices));
8619566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
8624cc7f7b2SMatthew G. Knepley     }
86319307e5cSMatthew G. Knepley     for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmRestoreField(dmc, coordFields[i], &bs[i], NULL, (void **)&coordVals[i]));
8644cc7f7b2SMatthew G. Knepley   }
8659566063dSJacob Faibussowitsch   PetscCall(PetscFree4(elemMat, elemMatSq, rowIDXs, xi));
8669566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
8679566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
8689566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
86919307e5cSMatthew G. Knepley   PetscCall(PetscFree2(coordVals, bs));
8709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
8719566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
8723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8734cc7f7b2SMatthew G. Knepley }
8744cc7f7b2SMatthew G. Knepley 
875cc4c1da9SBarry Smith /*@
8764cc7f7b2SMatthew G. Knepley   DMSwarmCreateMassMatrixSquare - Creates the block-diagonal of the square, M^T_p M_p, of the particle mass matrix M_p
8774cc7f7b2SMatthew G. Knepley 
87820f4b53cSBarry Smith   Collective
8794cc7f7b2SMatthew G. Knepley 
88060225df5SJacob Faibussowitsch   Input Parameters:
88120f4b53cSBarry Smith + dmCoarse - a `DMSWARM`
88220f4b53cSBarry Smith - dmFine   - a `DMPLEX`
8834cc7f7b2SMatthew G. Knepley 
88460225df5SJacob Faibussowitsch   Output Parameter:
8854cc7f7b2SMatthew G. Knepley . mass - the square of the particle mass matrix
8864cc7f7b2SMatthew G. Knepley 
8874cc7f7b2SMatthew G. Knepley   Level: advanced
8884cc7f7b2SMatthew G. Knepley 
88920f4b53cSBarry Smith   Note:
8904cc7f7b2SMatthew G. Knepley   We only compute the block diagonal since this provides a good preconditioner and is completely local. It would be possible in the
8914cc7f7b2SMatthew G. Knepley   future to compute the full normal equations.
8924cc7f7b2SMatthew G. Knepley 
89320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMCreateMassMatrix()`
8944cc7f7b2SMatthew G. Knepley @*/
895d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateMassMatrixSquare(DM dmCoarse, DM dmFine, Mat *mass)
896d71ae5a4SJacob Faibussowitsch {
8974cc7f7b2SMatthew G. Knepley   PetscInt n;
8984cc7f7b2SMatthew G. Knepley   void    *ctx;
8994cc7f7b2SMatthew G. Knepley 
9004cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
9019566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dmCoarse, &n));
9029566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
9039566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, n, PETSC_DETERMINE, PETSC_DETERMINE));
9049566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
9059566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
9064cc7f7b2SMatthew G. Knepley 
9079566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrixSquare_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
9089566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_sq_mat_view"));
9093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9104cc7f7b2SMatthew G. Knepley }
9114cc7f7b2SMatthew G. Knepley 
9121898fd5cSMatthew G. Knepley /* This creates a "gradient matrix" between a finite element and particle space, which is meant to enforce a weak divergence condition on the particle space. We are looking for a finite element field that has the same divergence as our particle field, so that
9131898fd5cSMatthew G. Knepley 
9141898fd5cSMatthew G. Knepley      \int_X \psi_i \nabla \cdot \hat f = \int_X \psi_i \nabla \cdot f
9151898fd5cSMatthew G. Knepley 
9161898fd5cSMatthew G. Knepley    and then integrate by parts
9171898fd5cSMatthew G. Knepley 
9181898fd5cSMatthew G. Knepley      \int_X \nabla \psi_i \cdot \hat f = \int_X \nabla \psi_i \cdot f
9191898fd5cSMatthew G. Knepley 
9201898fd5cSMatthew G. Knepley    where \psi is from a scalar FE space. If a finite element interpolant is given by
9211898fd5cSMatthew G. Knepley 
9221898fd5cSMatthew G. Knepley      \hat f^c = \sum_i f_i \phi^c_i
9231898fd5cSMatthew G. Knepley 
9241898fd5cSMatthew G. Knepley    and a particle function is given by
9251898fd5cSMatthew G. Knepley 
9261898fd5cSMatthew G. Knepley      f^c = \sum_p f^c_p \delta(x - x_p)
9271898fd5cSMatthew G. Knepley 
9281898fd5cSMatthew G. Knepley    then we want to require that
9291898fd5cSMatthew G. Knepley 
9301898fd5cSMatthew G. Knepley      D_f \hat f = D_p f
9311898fd5cSMatthew G. Knepley 
9321898fd5cSMatthew G. Knepley    where the gradient matrices are given by
9331898fd5cSMatthew G. Knepley 
9341898fd5cSMatthew G. Knepley      (D_f)_{i(jc)} = \int \partial_c \psi_i \phi_j
9351898fd5cSMatthew G. Knepley      (D_p)_{i(jc)} = \int \partial_c \psi_i \delta(x - x_j)
9361898fd5cSMatthew G. Knepley 
9371898fd5cSMatthew G. Knepley    Thus we need two finite element spaces, a scalar and a vector. The vector space holds the representer for the
9381898fd5cSMatthew G. Knepley    vector particle field. The scalar space holds the output of D_p or D_f, which is the weak divergence of the field.
9391898fd5cSMatthew G. Knepley 
9401898fd5cSMatthew G. Knepley    The way Dave May does particles, they amount to quadratue weights rather than delta functions, so he has |J| is in
9411898fd5cSMatthew G. Knepley    his integral. We allow this with the boolean flag.
9421898fd5cSMatthew G. Knepley */
9431898fd5cSMatthew G. Knepley static PetscErrorCode DMSwarmComputeGradientMatrix_Private(DM sw, DM dm, Mat derv, PetscBool useDeltaFunction, void *ctx)
9441898fd5cSMatthew G. Knepley {
9451898fd5cSMatthew G. Knepley   const char   *name = "Derivative Matrix";
9461898fd5cSMatthew G. Knepley   MPI_Comm      comm;
9471898fd5cSMatthew G. Knepley   DMSwarmCellDM celldm;
9481898fd5cSMatthew G. Knepley   PetscDS       ds;
9491898fd5cSMatthew G. Knepley   PetscSection  fsection, globalFSection;
9501898fd5cSMatthew G. Knepley   PetscLayout   rLayout;
9511898fd5cSMatthew G. Knepley   PetscInt      locRows, rStart, *rowIDXs;
9521898fd5cSMatthew G. Knepley   PetscReal    *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
9531898fd5cSMatthew G. Knepley   PetscScalar  *elemMat;
9541898fd5cSMatthew G. Knepley   PetscInt      cdim, Nf, Nfc, cStart, cEnd, totDim, maxNpc = 0, totNc = 0;
9551898fd5cSMatthew G. Knepley   const char  **coordFields;
9561898fd5cSMatthew G. Knepley   PetscReal   **coordVals;
9571898fd5cSMatthew G. Knepley   PetscInt     *bs;
9581898fd5cSMatthew G. Knepley 
9591898fd5cSMatthew G. Knepley   PetscFunctionBegin;
9601898fd5cSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)derv, &comm));
9611898fd5cSMatthew G. Knepley   PetscCall(DMGetCoordinateDim(dm, &cdim));
9621898fd5cSMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
9631898fd5cSMatthew G. Knepley   PetscCall(PetscDSGetNumFields(ds, &Nf));
9641898fd5cSMatthew G. Knepley   PetscCheck(Nf == 1, comm, PETSC_ERR_SUP, "Currently, we only support a single field");
9651898fd5cSMatthew G. Knepley   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
9661898fd5cSMatthew G. Knepley   PetscCall(PetscMalloc3(cdim, &v0, cdim * cdim, &J, cdim * cdim, &invJ));
9671898fd5cSMatthew G. Knepley   PetscCall(DMGetLocalSection(dm, &fsection));
9681898fd5cSMatthew G. Knepley   PetscCall(DMGetGlobalSection(dm, &globalFSection));
9691898fd5cSMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
9701898fd5cSMatthew G. Knepley   PetscCall(MatGetLocalSize(derv, &locRows, NULL));
9711898fd5cSMatthew G. Knepley 
9721898fd5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
9731898fd5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields));
9741898fd5cSMatthew G. Knepley   PetscCheck(Nfc == 1, comm, PETSC_ERR_SUP, "Currently, we only support a single field");
9751898fd5cSMatthew G. Knepley   PetscCall(PetscMalloc2(Nfc, &coordVals, Nfc, &bs));
9761898fd5cSMatthew G. Knepley 
9771898fd5cSMatthew G. Knepley   PetscCall(PetscLayoutCreate(comm, &rLayout));
9781898fd5cSMatthew G. Knepley   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
9791898fd5cSMatthew G. Knepley   PetscCall(PetscLayoutSetBlockSize(rLayout, cdim));
9801898fd5cSMatthew G. Knepley   PetscCall(PetscLayoutSetUp(rLayout));
9811898fd5cSMatthew G. Knepley   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
9821898fd5cSMatthew G. Knepley   PetscCall(PetscLayoutDestroy(&rLayout));
9831898fd5cSMatthew G. Knepley 
9841898fd5cSMatthew G. Knepley   for (PetscInt field = 0; field < Nf; ++field) {
9851898fd5cSMatthew G. Knepley     PetscObject obj;
9861898fd5cSMatthew G. Knepley     PetscInt    Nc;
9871898fd5cSMatthew G. Knepley 
9881898fd5cSMatthew G. Knepley     PetscCall(PetscDSGetDiscretization(ds, field, &obj));
9891898fd5cSMatthew G. Knepley     PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
9901898fd5cSMatthew G. Knepley     totNc += Nc;
9911898fd5cSMatthew G. Knepley   }
9921898fd5cSMatthew G. Knepley   PetscCheck(totNc == 1, comm, PETSC_ERR_ARG_WRONG, "The number of field components %" PetscInt_FMT " != 1", totNc);
9931898fd5cSMatthew G. Knepley   /* count non-zeros */
9941898fd5cSMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
9951898fd5cSMatthew G. Knepley   for (PetscInt field = 0; field < Nf; ++field) {
9961898fd5cSMatthew G. Knepley     PetscObject obj;
9971898fd5cSMatthew G. Knepley     PetscInt    Nc;
9981898fd5cSMatthew G. Knepley 
9991898fd5cSMatthew G. Knepley     PetscCall(PetscDSGetDiscretization(ds, field, &obj));
10001898fd5cSMatthew G. Knepley     PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
10011898fd5cSMatthew G. Knepley     for (PetscInt cell = cStart; cell < cEnd; ++cell) {
10021898fd5cSMatthew G. Knepley       PetscInt *pind;
10031898fd5cSMatthew G. Knepley       PetscInt  Npc;
10041898fd5cSMatthew G. Knepley 
10051898fd5cSMatthew G. Knepley       PetscCall(DMSwarmSortGetPointsPerCell(sw, cell, &Npc, &pind));
10061898fd5cSMatthew G. Knepley       maxNpc = PetscMax(maxNpc, Npc);
10071898fd5cSMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(sw, cell, &Npc, &pind));
10081898fd5cSMatthew G. Knepley     }
10091898fd5cSMatthew G. Knepley   }
10101898fd5cSMatthew G. Knepley   PetscCall(PetscMalloc3(maxNpc * cdim * totDim, &elemMat, maxNpc * cdim, &rowIDXs, maxNpc * cdim, &xi));
10111898fd5cSMatthew G. Knepley   for (PetscInt field = 0; field < Nf; ++field) {
10121898fd5cSMatthew G. Knepley     PetscTabulation Tcoarse;
10131898fd5cSMatthew G. Knepley     PetscFE         fe;
10141898fd5cSMatthew G. Knepley 
10151898fd5cSMatthew G. Knepley     PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
10161898fd5cSMatthew G. Knepley     for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmGetField(sw, coordFields[i], &bs[i], NULL, (void **)&coordVals[i]));
10171898fd5cSMatthew G. Knepley     for (PetscInt cell = cStart; cell < cEnd; ++cell) {
10181898fd5cSMatthew G. Knepley       PetscInt *findices, *pind;
10191898fd5cSMatthew G. Knepley       PetscInt  numFIndices, Npc;
10201898fd5cSMatthew G. Knepley 
10211898fd5cSMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
10221898fd5cSMatthew G. Knepley       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, invJ, &detJ));
10231898fd5cSMatthew G. Knepley       PetscCall(DMPlexGetClosureIndices(dm, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
10241898fd5cSMatthew G. Knepley       PetscCall(DMSwarmSortGetPointsPerCell(sw, cell, &Npc, &pind));
10251898fd5cSMatthew G. Knepley       for (PetscInt j = 0; j < Npc; ++j) {
10261898fd5cSMatthew G. Knepley         PetscReal xr[8];
10271898fd5cSMatthew G. Knepley         PetscInt  off = 0;
10281898fd5cSMatthew G. Knepley 
10291898fd5cSMatthew G. Knepley         for (PetscInt i = 0; i < Nfc; ++i) {
10301898fd5cSMatthew G. Knepley           for (PetscInt b = 0; b < bs[i]; ++b, ++off) xr[off] = coordVals[i][pind[j] * bs[i] + b];
10311898fd5cSMatthew G. Knepley         }
10321898fd5cSMatthew G. Knepley         PetscCheck(off == cdim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The total block size of coordinates is %" PetscInt_FMT " != %" PetscInt_FMT " the DM coordinate dimension", off, cdim);
10331898fd5cSMatthew G. Knepley         CoordinatesRealToRef(cdim, cdim, v0ref, v0, invJ, xr, &xi[j * cdim]);
10341898fd5cSMatthew G. Knepley       }
10351898fd5cSMatthew G. Knepley       PetscCall(PetscFECreateTabulation(fe, 1, Npc, xi, 1, &Tcoarse));
10361898fd5cSMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
10371898fd5cSMatthew G. Knepley       PetscCall(PetscArrayzero(elemMat, Npc * cdim * totDim));
10381898fd5cSMatthew G. Knepley       for (PetscInt i = 0; i < numFIndices; ++i) {
10391898fd5cSMatthew G. Knepley         for (PetscInt j = 0; j < Npc; ++j) {
1040*8c5add6aSPierre Jolivet           /* D[((p*pdim + i)*Nc + c)*cdim + d] is the value at point p for basis function i, component c, derivative d */
10411898fd5cSMatthew G. Knepley           for (PetscInt d = 0; d < cdim; ++d) {
10421898fd5cSMatthew G. Knepley             xi[d] = 0.;
10431898fd5cSMatthew G. Knepley             for (PetscInt e = 0; e < cdim; ++e) xi[d] += invJ[e * cdim + d] * Tcoarse->T[1][(j * numFIndices + i) * cdim + e];
10441898fd5cSMatthew G. Knepley             elemMat[(j * cdim + d) * numFIndices + i] += xi[d] * (useDeltaFunction ? 1.0 : detJ);
10451898fd5cSMatthew G. Knepley           }
10461898fd5cSMatthew G. Knepley         }
10471898fd5cSMatthew G. Knepley       }
10481898fd5cSMatthew G. Knepley       for (PetscInt j = 0; j < Npc; ++j)
10491898fd5cSMatthew G. Knepley         for (PetscInt d = 0; d < cdim; ++d) rowIDXs[j * cdim + d] = pind[j] * cdim + d + rStart;
10501898fd5cSMatthew G. Knepley       if (0) PetscCall(DMPrintCellMatrix(cell, name, Npc * cdim, numFIndices, elemMat));
10511898fd5cSMatthew G. Knepley       PetscCall(MatSetValues(derv, Npc * cdim, rowIDXs, numFIndices, findices, elemMat, ADD_VALUES));
10521898fd5cSMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(sw, cell, &Npc, &pind));
10531898fd5cSMatthew G. Knepley       PetscCall(DMPlexRestoreClosureIndices(dm, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
10541898fd5cSMatthew G. Knepley       PetscCall(PetscTabulationDestroy(&Tcoarse));
10551898fd5cSMatthew G. Knepley     }
10561898fd5cSMatthew G. Knepley     for (PetscInt i = 0; i < Nfc; ++i) PetscCall(DMSwarmRestoreField(sw, coordFields[i], &bs[i], NULL, (void **)&coordVals[i]));
10571898fd5cSMatthew G. Knepley   }
10581898fd5cSMatthew G. Knepley   PetscCall(PetscFree3(elemMat, rowIDXs, xi));
10591898fd5cSMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
10601898fd5cSMatthew G. Knepley   PetscCall(PetscFree3(v0, J, invJ));
10611898fd5cSMatthew G. Knepley   PetscCall(PetscFree2(coordVals, bs));
10621898fd5cSMatthew G. Knepley   PetscCall(MatAssemblyBegin(derv, MAT_FINAL_ASSEMBLY));
10631898fd5cSMatthew G. Knepley   PetscCall(MatAssemblyEnd(derv, MAT_FINAL_ASSEMBLY));
10641898fd5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
10651898fd5cSMatthew G. Knepley }
10661898fd5cSMatthew G. Knepley 
10671898fd5cSMatthew G. Knepley /* FEM cols:      this is a scalar space
10681898fd5cSMatthew G. Knepley    Particle rows: this is a vector space that contracts with the derivative
10691898fd5cSMatthew G. Knepley */
10701898fd5cSMatthew G. Knepley static PetscErrorCode DMCreateGradientMatrix_Swarm(DM sw, DM dm, Mat *derv)
10711898fd5cSMatthew G. Knepley {
10721898fd5cSMatthew G. Knepley   DMSwarmCellDM celldm;
10731898fd5cSMatthew G. Knepley   PetscSection  gs;
10741898fd5cSMatthew G. Knepley   PetscInt      cdim, m, n, Np, bs;
10751898fd5cSMatthew G. Knepley   void         *ctx;
10761898fd5cSMatthew G. Knepley   MPI_Comm      comm;
10771898fd5cSMatthew G. Knepley 
10781898fd5cSMatthew G. Knepley   PetscFunctionBegin;
10791898fd5cSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
10801898fd5cSMatthew G. Knepley   PetscCall(DMGetCoordinateDim(dm, &cdim));
10811898fd5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
10821898fd5cSMatthew G. Knepley   PetscCheck(celldm->Nf, comm, PETSC_ERR_USER, "Active cell DM does not define any fields");
10831898fd5cSMatthew G. Knepley   PetscCall(DMGetGlobalSection(dm, &gs));
10841898fd5cSMatthew G. Knepley   PetscCall(PetscSectionGetConstrainedStorageSize(gs, &n));
10851898fd5cSMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
10861898fd5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetBlockSize(celldm, sw, &bs));
10871898fd5cSMatthew G. Knepley   PetscCheck(cdim == bs, comm, PETSC_ERR_ARG_WRONG, "Coordinate dimension %" PetscInt_FMT " != %" PetscInt_FMT " swarm field block size", cdim, bs);
10881898fd5cSMatthew G. Knepley   m = Np * bs;
10891898fd5cSMatthew G. Knepley   PetscCall(MatCreate(PetscObjectComm((PetscObject)sw), derv));
10901898fd5cSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*derv, "Swarm Derivative Matrix"));
10911898fd5cSMatthew G. Knepley   PetscCall(MatSetSizes(*derv, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
10921898fd5cSMatthew G. Knepley   PetscCall(MatSetType(*derv, sw->mattype));
10931898fd5cSMatthew G. Knepley   PetscCall(DMGetApplicationContext(dm, &ctx));
10941898fd5cSMatthew G. Knepley 
10951898fd5cSMatthew G. Knepley   PetscCall(DMSwarmComputeGradientMatrix_Private(sw, dm, *derv, PETSC_TRUE, ctx));
10961898fd5cSMatthew G. Knepley   PetscCall(MatViewFromOptions(*derv, NULL, "-gradient_mat_view"));
10971898fd5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
10981898fd5cSMatthew G. Knepley }
10991898fd5cSMatthew G. Knepley 
1100cc4c1da9SBarry Smith /*@
110120f4b53cSBarry Smith   DMSwarmCreateGlobalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
1102d3a51819SDave May 
110320f4b53cSBarry Smith   Collective
1104d3a51819SDave May 
110560225df5SJacob Faibussowitsch   Input Parameters:
110620f4b53cSBarry Smith + dm        - a `DMSWARM`
110762741f57SDave May - fieldname - the textual name given to a registered field
1108d3a51819SDave May 
110960225df5SJacob Faibussowitsch   Output Parameter:
1110d3a51819SDave May . vec - the vector
1111d3a51819SDave May 
1112d3a51819SDave May   Level: beginner
1113d3a51819SDave May 
1114cc4c1da9SBarry Smith   Note:
111520f4b53cSBarry Smith   The vector must be returned using a matching call to `DMSwarmDestroyGlobalVectorFromField()`.
11168b8a3813SDave May 
111720f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromField()`
1118d3a51819SDave May @*/
1119d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
1120d71ae5a4SJacob Faibussowitsch {
1121fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PetscObjectComm((PetscObject)dm);
1122b5bcf523SDave May 
1123fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
1124ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
11259566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
11263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1127b5bcf523SDave May }
1128b5bcf523SDave May 
1129cc4c1da9SBarry Smith /*@
113020f4b53cSBarry Smith   DMSwarmDestroyGlobalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
1131d3a51819SDave May 
113220f4b53cSBarry Smith   Collective
1133d3a51819SDave May 
113460225df5SJacob Faibussowitsch   Input Parameters:
113520f4b53cSBarry Smith + dm        - a `DMSWARM`
113662741f57SDave May - fieldname - the textual name given to a registered field
1137d3a51819SDave May 
113860225df5SJacob Faibussowitsch   Output Parameter:
1139d3a51819SDave May . vec - the vector
1140d3a51819SDave May 
1141d3a51819SDave May   Level: beginner
1142d3a51819SDave May 
114320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()`
1144d3a51819SDave May @*/
1145d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
1146d71ae5a4SJacob Faibussowitsch {
1147fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
1148ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
11499566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
11503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1151b5bcf523SDave May }
1152b5bcf523SDave May 
1153cc4c1da9SBarry Smith /*@
115420f4b53cSBarry Smith   DMSwarmCreateLocalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
1155fb1bcc12SMatthew G. Knepley 
115620f4b53cSBarry Smith   Collective
1157fb1bcc12SMatthew G. Knepley 
115860225df5SJacob Faibussowitsch   Input Parameters:
115920f4b53cSBarry Smith + dm        - a `DMSWARM`
116062741f57SDave May - fieldname - the textual name given to a registered field
1161fb1bcc12SMatthew G. Knepley 
116260225df5SJacob Faibussowitsch   Output Parameter:
1163fb1bcc12SMatthew G. Knepley . vec - the vector
1164fb1bcc12SMatthew G. Knepley 
1165fb1bcc12SMatthew G. Knepley   Level: beginner
1166fb1bcc12SMatthew G. Knepley 
116720f4b53cSBarry Smith   Note:
11688b8a3813SDave May   The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField().
11698b8a3813SDave May 
117020f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()`
1171fb1bcc12SMatthew G. Knepley @*/
1172d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
1173d71ae5a4SJacob Faibussowitsch {
1174fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PETSC_COMM_SELF;
1175bbe8250bSMatthew G. Knepley 
1176fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
11779566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
11783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1179bbe8250bSMatthew G. Knepley }
1180fb1bcc12SMatthew G. Knepley 
1181cc4c1da9SBarry Smith /*@
118220f4b53cSBarry Smith   DMSwarmDestroyLocalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
1183fb1bcc12SMatthew G. Knepley 
118420f4b53cSBarry Smith   Collective
1185fb1bcc12SMatthew G. Knepley 
118660225df5SJacob Faibussowitsch   Input Parameters:
118720f4b53cSBarry Smith + dm        - a `DMSWARM`
118862741f57SDave May - fieldname - the textual name given to a registered field
1189fb1bcc12SMatthew G. Knepley 
119060225df5SJacob Faibussowitsch   Output Parameter:
1191fb1bcc12SMatthew G. Knepley . vec - the vector
1192fb1bcc12SMatthew G. Knepley 
1193fb1bcc12SMatthew G. Knepley   Level: beginner
1194fb1bcc12SMatthew G. Knepley 
119520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromField()`
1196fb1bcc12SMatthew G. Knepley @*/
1197d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
1198d71ae5a4SJacob Faibussowitsch {
1199fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
1200ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
12019566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
12023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1203bbe8250bSMatthew G. Knepley }
1204bbe8250bSMatthew G. Knepley 
1205cc4c1da9SBarry Smith /*@
120619307e5cSMatthew G. Knepley   DMSwarmCreateGlobalVectorFromFields - Creates a `Vec` object sharing the array associated with a given field set
120719307e5cSMatthew G. Knepley 
120819307e5cSMatthew G. Knepley   Collective
120919307e5cSMatthew G. Knepley 
121019307e5cSMatthew G. Knepley   Input Parameters:
121119307e5cSMatthew G. Knepley + dm         - a `DMSWARM`
121219307e5cSMatthew G. Knepley . Nf         - the number of fields
121319307e5cSMatthew G. Knepley - fieldnames - the textual names given to the registered fields
121419307e5cSMatthew G. Knepley 
121519307e5cSMatthew G. Knepley   Output Parameter:
121619307e5cSMatthew G. Knepley . vec - the vector
121719307e5cSMatthew G. Knepley 
121819307e5cSMatthew G. Knepley   Level: beginner
121919307e5cSMatthew G. Knepley 
122019307e5cSMatthew G. Knepley   Notes:
122119307e5cSMatthew G. Knepley   The vector must be returned using a matching call to `DMSwarmDestroyGlobalVectorFromFields()`.
122219307e5cSMatthew G. Knepley 
122319307e5cSMatthew G. Knepley   This vector is copyin-copyout, rather than a direct pointer like `DMSwarmCreateGlobalVectorFromField()`
122419307e5cSMatthew G. Knepley 
122519307e5cSMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromFields()`
122619307e5cSMatthew G. Knepley @*/
122719307e5cSMatthew G. Knepley PetscErrorCode DMSwarmCreateGlobalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec)
122819307e5cSMatthew G. Knepley {
122919307e5cSMatthew G. Knepley   MPI_Comm comm = PetscObjectComm((PetscObject)dm);
123019307e5cSMatthew G. Knepley 
123119307e5cSMatthew G. Knepley   PetscFunctionBegin;
123219307e5cSMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
123319307e5cSMatthew G. Knepley   PetscCall(DMSwarmCreateVectorFromFields_Private(dm, Nf, fieldnames, comm, vec));
123419307e5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
123519307e5cSMatthew G. Knepley }
123619307e5cSMatthew G. Knepley 
123719307e5cSMatthew G. Knepley /*@
123819307e5cSMatthew G. Knepley   DMSwarmDestroyGlobalVectorFromFields - Destroys the `Vec` object which share the array associated with a given field set
123919307e5cSMatthew G. Knepley 
124019307e5cSMatthew G. Knepley   Collective
124119307e5cSMatthew G. Knepley 
124219307e5cSMatthew G. Knepley   Input Parameters:
124319307e5cSMatthew G. Knepley + dm         - a `DMSWARM`
124419307e5cSMatthew G. Knepley . Nf         - the number of fields
124519307e5cSMatthew G. Knepley - fieldnames - the textual names given to the registered fields
124619307e5cSMatthew G. Knepley 
124719307e5cSMatthew G. Knepley   Output Parameter:
124819307e5cSMatthew G. Knepley . vec - the vector
124919307e5cSMatthew G. Knepley 
125019307e5cSMatthew G. Knepley   Level: beginner
125119307e5cSMatthew G. Knepley 
125219307e5cSMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()`
125319307e5cSMatthew G. Knepley @*/
125419307e5cSMatthew G. Knepley PetscErrorCode DMSwarmDestroyGlobalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec)
125519307e5cSMatthew G. Knepley {
125619307e5cSMatthew G. Knepley   PetscFunctionBegin;
125719307e5cSMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
125819307e5cSMatthew G. Knepley   PetscCall(DMSwarmDestroyVectorFromFields_Private(dm, Nf, fieldnames, vec));
125919307e5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
126019307e5cSMatthew G. Knepley }
126119307e5cSMatthew G. Knepley 
126219307e5cSMatthew G. Knepley /*@
126319307e5cSMatthew G. Knepley   DMSwarmCreateLocalVectorFromFields - Creates a `Vec` object sharing the array associated with a given field set
126419307e5cSMatthew G. Knepley 
126519307e5cSMatthew G. Knepley   Collective
126619307e5cSMatthew G. Knepley 
126719307e5cSMatthew G. Knepley   Input Parameters:
126819307e5cSMatthew G. Knepley + dm         - a `DMSWARM`
126919307e5cSMatthew G. Knepley . Nf         - the number of fields
127019307e5cSMatthew G. Knepley - fieldnames - the textual names given to the registered fields
127119307e5cSMatthew G. Knepley 
127219307e5cSMatthew G. Knepley   Output Parameter:
127319307e5cSMatthew G. Knepley . vec - the vector
127419307e5cSMatthew G. Knepley 
127519307e5cSMatthew G. Knepley   Level: beginner
127619307e5cSMatthew G. Knepley 
127719307e5cSMatthew G. Knepley   Notes:
127819307e5cSMatthew G. Knepley   The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField().
127919307e5cSMatthew G. Knepley 
128019307e5cSMatthew G. Knepley   This vector is copyin-copyout, rather than a direct pointer like `DMSwarmCreateLocalVectorFromField()`
128119307e5cSMatthew G. Knepley 
128219307e5cSMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()`
128319307e5cSMatthew G. Knepley @*/
128419307e5cSMatthew G. Knepley PetscErrorCode DMSwarmCreateLocalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec)
128519307e5cSMatthew G. Knepley {
128619307e5cSMatthew G. Knepley   MPI_Comm comm = PETSC_COMM_SELF;
128719307e5cSMatthew G. Knepley 
128819307e5cSMatthew G. Knepley   PetscFunctionBegin;
128919307e5cSMatthew G. Knepley   PetscCall(DMSwarmCreateVectorFromFields_Private(dm, Nf, fieldnames, comm, vec));
129019307e5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
129119307e5cSMatthew G. Knepley }
129219307e5cSMatthew G. Knepley 
129319307e5cSMatthew G. Knepley /*@
129419307e5cSMatthew G. Knepley   DMSwarmDestroyLocalVectorFromFields - Destroys the `Vec` object which share the array associated with a given field set
129519307e5cSMatthew G. Knepley 
129619307e5cSMatthew G. Knepley   Collective
129719307e5cSMatthew G. Knepley 
129819307e5cSMatthew G. Knepley   Input Parameters:
129919307e5cSMatthew G. Knepley + dm         - a `DMSWARM`
130019307e5cSMatthew G. Knepley . Nf         - the number of fields
130119307e5cSMatthew G. Knepley - fieldnames - the textual names given to the registered fields
130219307e5cSMatthew G. Knepley 
130319307e5cSMatthew G. Knepley   Output Parameter:
130419307e5cSMatthew G. Knepley . vec - the vector
130519307e5cSMatthew G. Knepley 
130619307e5cSMatthew G. Knepley   Level: beginner
130719307e5cSMatthew G. Knepley 
130819307e5cSMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromFields()`
130919307e5cSMatthew G. Knepley @*/
131019307e5cSMatthew G. Knepley PetscErrorCode DMSwarmDestroyLocalVectorFromFields(DM dm, PetscInt Nf, const char *fieldnames[], Vec *vec)
131119307e5cSMatthew G. Knepley {
131219307e5cSMatthew G. Knepley   PetscFunctionBegin;
131319307e5cSMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
131419307e5cSMatthew G. Knepley   PetscCall(DMSwarmDestroyVectorFromFields_Private(dm, Nf, fieldnames, vec));
131519307e5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
131619307e5cSMatthew G. Knepley }
131719307e5cSMatthew G. Knepley 
131819307e5cSMatthew G. Knepley /*@
131920f4b53cSBarry Smith   DMSwarmInitializeFieldRegister - Initiates the registration of fields to a `DMSWARM`
1320d3a51819SDave May 
132120f4b53cSBarry Smith   Collective
1322d3a51819SDave May 
132360225df5SJacob Faibussowitsch   Input Parameter:
132420f4b53cSBarry Smith . dm - a `DMSWARM`
1325d3a51819SDave May 
1326d3a51819SDave May   Level: beginner
1327d3a51819SDave May 
132820f4b53cSBarry Smith   Note:
132920f4b53cSBarry Smith   After all fields have been registered, you must call `DMSwarmFinalizeFieldRegister()`.
1330d3a51819SDave May 
133120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmFinalizeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
1332db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
1333d3a51819SDave May @*/
1334d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmInitializeFieldRegister(DM dm)
1335d71ae5a4SJacob Faibussowitsch {
13365f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
13373454631fSDave May 
1338521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1339cc651181SDave May   if (!swarm->field_registration_initialized) {
13405f50eb2eSDave May     swarm->field_registration_initialized = PETSC_TRUE;
1341da81f932SPierre Jolivet     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_pid, 1, PETSC_INT64)); /* unique identifier */
13429566063dSJacob Faibussowitsch     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_rank, 1, PETSC_INT));  /* used for communication */
1343cc651181SDave May   }
13443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13455f50eb2eSDave May }
13465f50eb2eSDave May 
134774d0cae8SMatthew G. Knepley /*@
134820f4b53cSBarry Smith   DMSwarmFinalizeFieldRegister - Finalizes the registration of fields to a `DMSWARM`
1349d3a51819SDave May 
135020f4b53cSBarry Smith   Collective
1351d3a51819SDave May 
135260225df5SJacob Faibussowitsch   Input Parameter:
135320f4b53cSBarry Smith . dm - a `DMSWARM`
1354d3a51819SDave May 
1355d3a51819SDave May   Level: beginner
1356d3a51819SDave May 
135720f4b53cSBarry Smith   Note:
135820f4b53cSBarry Smith   After `DMSwarmFinalizeFieldRegister()` has been called, no new fields can be defined on the `DMSWARM`.
1359d3a51819SDave May 
136020f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmInitializeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
1361db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
1362d3a51819SDave May @*/
1363d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmFinalizeFieldRegister(DM dm)
1364d71ae5a4SJacob Faibussowitsch {
13655f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
13666845f8f5SDave May 
1367521f74f9SMatthew G. Knepley   PetscFunctionBegin;
136848a46eb9SPierre Jolivet   if (!swarm->field_registration_finalized) PetscCall(DMSwarmDataBucketFinalize(swarm->db));
1369f0cdbbbaSDave May   swarm->field_registration_finalized = PETSC_TRUE;
13703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13715f50eb2eSDave May }
13725f50eb2eSDave May 
137374d0cae8SMatthew G. Knepley /*@
137420f4b53cSBarry Smith   DMSwarmSetLocalSizes - Sets the length of all registered fields on the `DMSWARM`
1375d3a51819SDave May 
137620f4b53cSBarry Smith   Not Collective
1377d3a51819SDave May 
137860225df5SJacob Faibussowitsch   Input Parameters:
1379fca3fa51SMatthew G. Knepley + sw     - a `DMSWARM`
1380d3a51819SDave May . nlocal - the length of each registered field
138162741f57SDave May - buffer - the length of the buffer used to efficient dynamic re-sizing
1382d3a51819SDave May 
1383d3a51819SDave May   Level: beginner
1384d3a51819SDave May 
138520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`
1386d3a51819SDave May @*/
1387fca3fa51SMatthew G. Knepley PetscErrorCode DMSwarmSetLocalSizes(DM sw, PetscInt nlocal, PetscInt buffer)
1388d71ae5a4SJacob Faibussowitsch {
1389fca3fa51SMatthew G. Knepley   DM_Swarm   *swarm = (DM_Swarm *)sw->data;
1390fca3fa51SMatthew G. Knepley   PetscMPIInt rank;
1391fca3fa51SMatthew G. Knepley   PetscInt   *rankval;
13925f50eb2eSDave May 
1393521f74f9SMatthew G. Knepley   PetscFunctionBegin;
13949566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_SetSizes, 0, 0, 0, 0));
13959566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, buffer));
13969566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_SetSizes, 0, 0, 0, 0));
1397fca3fa51SMatthew G. Knepley 
1398fca3fa51SMatthew G. Knepley   // Initialize values in pid and rank placeholders
1399fca3fa51SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sw), &rank));
1400fca3fa51SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
1401fca3fa51SMatthew G. Knepley   for (PetscInt p = 0; p < nlocal; p++) rankval[p] = rank;
1402fca3fa51SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
1403fca3fa51SMatthew G. Knepley   /* TODO: [pid - use MPI_Scan] */
14043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14055f50eb2eSDave May }
14065f50eb2eSDave May 
140774d0cae8SMatthew G. Knepley /*@
140820f4b53cSBarry Smith   DMSwarmSetCellDM - Attaches a `DM` to a `DMSWARM`
1409d3a51819SDave May 
141020f4b53cSBarry Smith   Collective
1411d3a51819SDave May 
141260225df5SJacob Faibussowitsch   Input Parameters:
141319307e5cSMatthew G. Knepley + sw - a `DMSWARM`
141419307e5cSMatthew G. Knepley - dm - the `DM` to attach to the `DMSWARM`
1415d3a51819SDave May 
1416d3a51819SDave May   Level: beginner
1417d3a51819SDave May 
141820f4b53cSBarry Smith   Note:
141919307e5cSMatthew G. Knepley   The attached `DM` (dm) will be queried for point location and
142020f4b53cSBarry Smith   neighbor MPI-rank information if `DMSwarmMigrate()` is called.
1421d3a51819SDave May 
142220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmGetCellDM()`, `DMSwarmMigrate()`
1423d3a51819SDave May @*/
142419307e5cSMatthew G. Knepley PetscErrorCode DMSwarmSetCellDM(DM sw, DM dm)
1425d71ae5a4SJacob Faibussowitsch {
142619307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
142719307e5cSMatthew G. Knepley   const char   *name;
142819307e5cSMatthew G. Knepley   char         *coordName;
1429d52c2f21SMatthew G. Knepley 
1430d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
1431d52c2f21SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
143219307e5cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
143319307e5cSMatthew G. Knepley   PetscCall(PetscStrallocpy(DMSwarmPICField_coor, &coordName));
143419307e5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(dm, 0, NULL, 1, (const char **)&coordName, &celldm));
143519307e5cSMatthew G. Knepley   PetscCall(PetscFree(coordName));
143619307e5cSMatthew G. Knepley   PetscCall(PetscObjectGetName((PetscObject)celldm, &name));
143719307e5cSMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(sw, celldm));
143819307e5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
143919307e5cSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, name));
1440d52c2f21SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1441d52c2f21SMatthew G. Knepley }
1442d52c2f21SMatthew G. Knepley 
1443d52c2f21SMatthew G. Knepley /*@
144419307e5cSMatthew G. Knepley   DMSwarmGetCellDM - Fetches the active cell `DM`
1445d52c2f21SMatthew G. Knepley 
1446d52c2f21SMatthew G. Knepley   Collective
1447d52c2f21SMatthew G. Knepley 
1448d52c2f21SMatthew G. Knepley   Input Parameter:
1449d52c2f21SMatthew G. Knepley . sw - a `DMSWARM`
1450d52c2f21SMatthew G. Knepley 
145119307e5cSMatthew G. Knepley   Output Parameter:
145219307e5cSMatthew G. Knepley . dm - the active `DM` for the `DMSWARM`
145319307e5cSMatthew G. Knepley 
1454d52c2f21SMatthew G. Knepley   Level: beginner
1455d52c2f21SMatthew G. Knepley 
145619307e5cSMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
1457d52c2f21SMatthew G. Knepley @*/
145819307e5cSMatthew G. Knepley PetscErrorCode DMSwarmGetCellDM(DM sw, DM *dm)
1459d52c2f21SMatthew G. Knepley {
1460d52c2f21SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
146119307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
146219307e5cSMatthew G. Knepley 
146319307e5cSMatthew G. Knepley   PetscFunctionBegin;
1464fca3fa51SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
146519307e5cSMatthew G. Knepley   PetscCall(PetscObjectListFind(swarm->cellDMs, swarm->activeCellDM, (PetscObject *)&celldm));
146619307e5cSMatthew G. Knepley   PetscCheck(celldm, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONG, "There is no cell DM named %s in this Swarm", swarm->activeCellDM);
146719307e5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, dm));
146819307e5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
146919307e5cSMatthew G. Knepley }
147019307e5cSMatthew G. Knepley 
1471fca3fa51SMatthew G. Knepley /*@C
1472fca3fa51SMatthew G. Knepley   DMSwarmGetCellDMNames - Get the list of cell `DM` names
1473fca3fa51SMatthew G. Knepley 
1474fca3fa51SMatthew G. Knepley   Not collective
1475fca3fa51SMatthew G. Knepley 
1476fca3fa51SMatthew G. Knepley   Input Parameter:
1477fca3fa51SMatthew G. Knepley . sw - a `DMSWARM`
1478fca3fa51SMatthew G. Knepley 
1479fca3fa51SMatthew G. Knepley   Output Parameters:
1480fca3fa51SMatthew G. Knepley + Ndm     - the number of `DMSwarmCellDM` in the `DMSWARM`
1481fca3fa51SMatthew G. Knepley - celldms - the name of each `DMSwarmCellDM`
1482fca3fa51SMatthew G. Knepley 
1483fca3fa51SMatthew G. Knepley   Level: beginner
1484fca3fa51SMatthew G. Knepley 
1485fca3fa51SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`, `DMSwarmGetCellDMByName()`
1486fca3fa51SMatthew G. Knepley @*/
1487fca3fa51SMatthew G. Knepley PetscErrorCode DMSwarmGetCellDMNames(DM sw, PetscInt *Ndm, const char **celldms[])
1488fca3fa51SMatthew G. Knepley {
1489fca3fa51SMatthew G. Knepley   DM_Swarm       *swarm = (DM_Swarm *)sw->data;
1490fca3fa51SMatthew G. Knepley   PetscObjectList next  = swarm->cellDMs;
1491fca3fa51SMatthew G. Knepley   PetscInt        n     = 0;
1492fca3fa51SMatthew G. Knepley 
1493fca3fa51SMatthew G. Knepley   PetscFunctionBegin;
1494fca3fa51SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
1495fca3fa51SMatthew G. Knepley   PetscAssertPointer(Ndm, 2);
1496fca3fa51SMatthew G. Knepley   PetscAssertPointer(celldms, 3);
1497fca3fa51SMatthew G. Knepley   while (next) {
1498fca3fa51SMatthew G. Knepley     next = next->next;
1499fca3fa51SMatthew G. Knepley     ++n;
1500fca3fa51SMatthew G. Knepley   }
1501fca3fa51SMatthew G. Knepley   PetscCall(PetscMalloc1(n, celldms));
1502fca3fa51SMatthew G. Knepley   next = swarm->cellDMs;
1503fca3fa51SMatthew G. Knepley   n    = 0;
1504fca3fa51SMatthew G. Knepley   while (next) {
1505fca3fa51SMatthew G. Knepley     (*celldms)[n] = (const char *)next->obj->name;
1506fca3fa51SMatthew G. Knepley     next          = next->next;
1507fca3fa51SMatthew G. Knepley     ++n;
1508fca3fa51SMatthew G. Knepley   }
1509fca3fa51SMatthew G. Knepley   *Ndm = n;
1510fca3fa51SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1511fca3fa51SMatthew G. Knepley }
1512fca3fa51SMatthew G. Knepley 
151319307e5cSMatthew G. Knepley /*@
151419307e5cSMatthew G. Knepley   DMSwarmSetCellDMActive - Activates a cell `DM` for a `DMSWARM`
151519307e5cSMatthew G. Knepley 
151619307e5cSMatthew G. Knepley   Collective
151719307e5cSMatthew G. Knepley 
151819307e5cSMatthew G. Knepley   Input Parameters:
151919307e5cSMatthew G. Knepley + sw   - a `DMSWARM`
152019307e5cSMatthew G. Knepley - name - name of the cell `DM` to active for the `DMSWARM`
152119307e5cSMatthew G. Knepley 
152219307e5cSMatthew G. Knepley   Level: beginner
152319307e5cSMatthew G. Knepley 
152419307e5cSMatthew G. Knepley   Note:
152519307e5cSMatthew G. Knepley   The attached `DM` (dmcell) will be queried for point location and
152619307e5cSMatthew G. Knepley   neighbor MPI-rank information if `DMSwarmMigrate()` is called.
152719307e5cSMatthew G. Knepley 
152819307e5cSMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmCellDM`, `DMSwarmSetType()`, `DMSwarmAddCellDM()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()`
152919307e5cSMatthew G. Knepley @*/
153019307e5cSMatthew G. Knepley PetscErrorCode DMSwarmSetCellDMActive(DM sw, const char name[])
153119307e5cSMatthew G. Knepley {
153219307e5cSMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
153319307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
1534d52c2f21SMatthew G. Knepley 
1535d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
1536d52c2f21SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
153719307e5cSMatthew G. Knepley   PetscCall(PetscInfo(sw, "Setting cell DM to %s\n", name));
153819307e5cSMatthew G. Knepley   PetscCall(PetscFree(swarm->activeCellDM));
153919307e5cSMatthew G. Knepley   PetscCall(PetscStrallocpy(name, (char **)&swarm->activeCellDM));
154019307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
154119307e5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1542d52c2f21SMatthew G. Knepley }
154319307e5cSMatthew G. Knepley 
154419307e5cSMatthew G. Knepley /*@
154519307e5cSMatthew G. Knepley   DMSwarmGetCellDMActive - Returns the active cell `DM` for a `DMSWARM`
154619307e5cSMatthew G. Knepley 
154719307e5cSMatthew G. Knepley   Collective
154819307e5cSMatthew G. Knepley 
154919307e5cSMatthew G. Knepley   Input Parameter:
155019307e5cSMatthew G. Knepley . sw - a `DMSWARM`
155119307e5cSMatthew G. Knepley 
155219307e5cSMatthew G. Knepley   Output Parameter:
155319307e5cSMatthew G. Knepley . celldm - the active `DMSwarmCellDM`
155419307e5cSMatthew G. Knepley 
155519307e5cSMatthew G. Knepley   Level: beginner
155619307e5cSMatthew G. Knepley 
155719307e5cSMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmCellDM`, `DMSwarmSetType()`, `DMSwarmAddCellDM()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()`
155819307e5cSMatthew G. Knepley @*/
155919307e5cSMatthew G. Knepley PetscErrorCode DMSwarmGetCellDMActive(DM sw, DMSwarmCellDM *celldm)
156019307e5cSMatthew G. Knepley {
156119307e5cSMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
156219307e5cSMatthew G. Knepley 
156319307e5cSMatthew G. Knepley   PetscFunctionBegin;
156419307e5cSMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
1565fca3fa51SMatthew G. Knepley   PetscAssertPointer(celldm, 2);
156619307e5cSMatthew G. Knepley   PetscCheck(swarm->activeCellDM, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONGSTATE, "Swarm has no active cell DM");
156719307e5cSMatthew G. Knepley   PetscCall(PetscObjectListFind(swarm->cellDMs, swarm->activeCellDM, (PetscObject *)celldm));
1568fca3fa51SMatthew G. Knepley   PetscCheck(*celldm, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONGSTATE, "Swarm has no valid cell DM for %s", swarm->activeCellDM);
1569fca3fa51SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1570fca3fa51SMatthew G. Knepley }
1571fca3fa51SMatthew G. Knepley 
1572fca3fa51SMatthew G. Knepley /*@C
1573fca3fa51SMatthew G. Knepley   DMSwarmGetCellDMByName - Get a `DMSwarmCellDM` from its name
1574fca3fa51SMatthew G. Knepley 
1575fca3fa51SMatthew G. Knepley   Not collective
1576fca3fa51SMatthew G. Knepley 
1577fca3fa51SMatthew G. Knepley   Input Parameters:
1578fca3fa51SMatthew G. Knepley + sw   - a `DMSWARM`
1579fca3fa51SMatthew G. Knepley - name - the name
1580fca3fa51SMatthew G. Knepley 
1581fca3fa51SMatthew G. Knepley   Output Parameter:
1582fca3fa51SMatthew G. Knepley . celldm - the `DMSwarmCellDM`
1583fca3fa51SMatthew G. Knepley 
1584fca3fa51SMatthew G. Knepley   Level: beginner
1585fca3fa51SMatthew G. Knepley 
1586fca3fa51SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`, `DMSwarmGetCellDMNames()`
1587fca3fa51SMatthew G. Knepley @*/
1588fca3fa51SMatthew G. Knepley PetscErrorCode DMSwarmGetCellDMByName(DM sw, const char name[], DMSwarmCellDM *celldm)
1589fca3fa51SMatthew G. Knepley {
1590fca3fa51SMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
1591fca3fa51SMatthew G. Knepley 
1592fca3fa51SMatthew G. Knepley   PetscFunctionBegin;
1593fca3fa51SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
1594fca3fa51SMatthew G. Knepley   PetscAssertPointer(name, 2);
1595fca3fa51SMatthew G. Knepley   PetscAssertPointer(celldm, 3);
1596fca3fa51SMatthew G. Knepley   PetscCall(PetscObjectListFind(swarm->cellDMs, name, (PetscObject *)celldm));
1597fca3fa51SMatthew G. Knepley   PetscCheck(*celldm, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONGSTATE, "Swarm has no valid cell DM for %s", name);
159819307e5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
159919307e5cSMatthew G. Knepley }
160019307e5cSMatthew G. Knepley 
160119307e5cSMatthew G. Knepley /*@
160219307e5cSMatthew G. Knepley   DMSwarmAddCellDM - Adds a cell `DM` to the `DMSWARM`
160319307e5cSMatthew G. Knepley 
160419307e5cSMatthew G. Knepley   Collective
160519307e5cSMatthew G. Knepley 
160619307e5cSMatthew G. Knepley   Input Parameters:
160719307e5cSMatthew G. Knepley + sw     - a `DMSWARM`
160819307e5cSMatthew G. Knepley - celldm - the `DMSwarmCellDM`
160919307e5cSMatthew G. Knepley 
161019307e5cSMatthew G. Knepley   Level: beginner
161119307e5cSMatthew G. Knepley 
161219307e5cSMatthew G. Knepley   Note:
161319307e5cSMatthew G. Knepley   Cell DMs with the same name will share the cellid field
161419307e5cSMatthew G. Knepley 
161519307e5cSMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmPushCellDM()`, `DMSwarmSetCellDM()`, `DMSwarmMigrate()`
161619307e5cSMatthew G. Knepley @*/
161719307e5cSMatthew G. Knepley PetscErrorCode DMSwarmAddCellDM(DM sw, DMSwarmCellDM celldm)
161819307e5cSMatthew G. Knepley {
161919307e5cSMatthew G. Knepley   DM_Swarm   *swarm = (DM_Swarm *)sw->data;
162019307e5cSMatthew G. Knepley   const char *name;
162119307e5cSMatthew G. Knepley   PetscInt    dim;
162219307e5cSMatthew G. Knepley   PetscBool   flg;
162319307e5cSMatthew G. Knepley   MPI_Comm    comm;
162419307e5cSMatthew G. Knepley 
162519307e5cSMatthew G. Knepley   PetscFunctionBegin;
162619307e5cSMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
162719307e5cSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
162819307e5cSMatthew G. Knepley   PetscValidHeaderSpecific(celldm, DMSWARMCELLDM_CLASSID, 2);
162919307e5cSMatthew G. Knepley   PetscCall(PetscObjectGetName((PetscObject)celldm, &name));
163019307e5cSMatthew G. Knepley   PetscCall(PetscObjectListAdd(&swarm->cellDMs, name, (PetscObject)celldm));
163119307e5cSMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
163219307e5cSMatthew G. Knepley   for (PetscInt f = 0; f < celldm->Nfc; ++f) {
163319307e5cSMatthew G. Knepley     PetscCall(DMSwarmDataFieldStringInList(celldm->coordFields[f], swarm->db->nfields, (const DMSwarmDataField *)swarm->db->field, &flg));
163419307e5cSMatthew G. Knepley     if (!flg) {
163519307e5cSMatthew G. Knepley       PetscCall(DMSwarmRegisterPetscDatatypeField(sw, celldm->coordFields[f], dim, PETSC_DOUBLE));
163619307e5cSMatthew G. Knepley     } else {
163719307e5cSMatthew G. Knepley       PetscDataType dt;
163819307e5cSMatthew G. Knepley       PetscInt      bs;
163919307e5cSMatthew G. Knepley 
164019307e5cSMatthew G. Knepley       PetscCall(DMSwarmGetFieldInfo(sw, celldm->coordFields[f], &bs, &dt));
164119307e5cSMatthew G. Knepley       PetscCheck(bs == dim, comm, PETSC_ERR_ARG_WRONG, "Coordinate field %s has blocksize %" PetscInt_FMT " != %" PetscInt_FMT " spatial dimension", celldm->coordFields[f], bs, dim);
164219307e5cSMatthew G. Knepley       PetscCheck(dt == PETSC_DOUBLE, comm, PETSC_ERR_ARG_WRONG, "Coordinate field %s has datatype %s != PETSC_DOUBLE", celldm->coordFields[f], PetscDataTypes[dt]);
164319307e5cSMatthew G. Knepley     }
164419307e5cSMatthew G. Knepley   }
164519307e5cSMatthew G. Knepley   // Assume that DMs with the same name share the cellid field
164619307e5cSMatthew G. Knepley   PetscCall(DMSwarmDataFieldStringInList(celldm->cellid, swarm->db->nfields, (const DMSwarmDataField *)swarm->db->field, &flg));
164719307e5cSMatthew G. Knepley   if (!flg) {
164819307e5cSMatthew G. Knepley     PetscBool   isShell, isDummy;
164919307e5cSMatthew G. Knepley     const char *name;
165019307e5cSMatthew G. Knepley 
165119307e5cSMatthew G. Knepley     // Allow dummy DMSHELL (I don't think we should support this mode)
165219307e5cSMatthew G. Knepley     PetscCall(PetscObjectTypeCompare((PetscObject)celldm->dm, DMSHELL, &isShell));
165319307e5cSMatthew G. Knepley     PetscCall(PetscObjectGetName((PetscObject)celldm->dm, &name));
165419307e5cSMatthew G. Knepley     PetscCall(PetscStrcmp(name, "dummy", &isDummy));
165519307e5cSMatthew G. Knepley     if (!isShell || !isDummy) PetscCall(DMSwarmRegisterPetscDatatypeField(sw, celldm->cellid, 1, PETSC_INT));
165619307e5cSMatthew G. Knepley   }
165719307e5cSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, name));
16583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1659fe39f135SDave May }
1660fe39f135SDave May 
166174d0cae8SMatthew G. Knepley /*@
1662d5b43468SJose E. Roman   DMSwarmGetLocalSize - Retrieves the local length of fields registered
1663d3a51819SDave May 
166420f4b53cSBarry Smith   Not Collective
1665d3a51819SDave May 
166660225df5SJacob Faibussowitsch   Input Parameter:
166720f4b53cSBarry Smith . dm - a `DMSWARM`
1668d3a51819SDave May 
166960225df5SJacob Faibussowitsch   Output Parameter:
1670d3a51819SDave May . nlocal - the length of each registered field
1671d3a51819SDave May 
1672d3a51819SDave May   Level: beginner
1673d3a51819SDave May 
167420f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetSize()`, `DMSwarmSetLocalSizes()`
1675d3a51819SDave May @*/
1676d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetLocalSize(DM dm, PetscInt *nlocal)
1677d71ae5a4SJacob Faibussowitsch {
1678dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1679dcf43ee8SDave May 
1680521f74f9SMatthew G. Knepley   PetscFunctionBegin;
16819566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, nlocal, NULL, NULL));
16823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1683dcf43ee8SDave May }
1684dcf43ee8SDave May 
168574d0cae8SMatthew G. Knepley /*@
1686d5b43468SJose E. Roman   DMSwarmGetSize - Retrieves the total length of fields registered
1687d3a51819SDave May 
168820f4b53cSBarry Smith   Collective
1689d3a51819SDave May 
169060225df5SJacob Faibussowitsch   Input Parameter:
169120f4b53cSBarry Smith . dm - a `DMSWARM`
1692d3a51819SDave May 
169360225df5SJacob Faibussowitsch   Output Parameter:
1694d3a51819SDave May . n - the total length of each registered field
1695d3a51819SDave May 
1696d3a51819SDave May   Level: beginner
1697d3a51819SDave May 
1698d3a51819SDave May   Note:
169920f4b53cSBarry Smith   This calls `MPI_Allreduce()` upon each call (inefficient but safe)
1700d3a51819SDave May 
170120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`, `DMSwarmSetLocalSizes()`
1702d3a51819SDave May @*/
1703d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetSize(DM dm, PetscInt *n)
1704d71ae5a4SJacob Faibussowitsch {
1705dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
17065627991aSBarry Smith   PetscInt  nlocal;
1707dcf43ee8SDave May 
1708521f74f9SMatthew G. Knepley   PetscFunctionBegin;
17099566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
1710462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&nlocal, n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
17113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1712dcf43ee8SDave May }
1713dcf43ee8SDave May 
1714ce78bad3SBarry Smith /*@C
171520f4b53cSBarry Smith   DMSwarmRegisterPetscDatatypeField - Register a field to a `DMSWARM` with a native PETSc data type
1716d3a51819SDave May 
171720f4b53cSBarry Smith   Collective
1718d3a51819SDave May 
171960225df5SJacob Faibussowitsch   Input Parameters:
172020f4b53cSBarry Smith + dm        - a `DMSWARM`
1721d3a51819SDave May . fieldname - the textual name to identify this field
1722d3a51819SDave May . blocksize - the number of each data type
172320f4b53cSBarry Smith - type      - a valid PETSc data type (`PETSC_CHAR`, `PETSC_SHORT`, `PETSC_INT`, `PETSC_FLOAT`, `PETSC_REAL`, `PETSC_LONG`)
1724d3a51819SDave May 
1725d3a51819SDave May   Level: beginner
1726d3a51819SDave May 
1727d3a51819SDave May   Notes:
17288b8a3813SDave May   The textual name for each registered field must be unique.
1729d3a51819SDave May 
173020f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
1731d3a51819SDave May @*/
1732d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterPetscDatatypeField(DM dm, const char fieldname[], PetscInt blocksize, PetscDataType type)
1733d71ae5a4SJacob Faibussowitsch {
1734b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1735b62e03f8SDave May   size_t    size;
1736b62e03f8SDave May 
1737521f74f9SMatthew G. Knepley   PetscFunctionBegin;
173828b400f6SJacob Faibussowitsch   PetscCheck(swarm->field_registration_initialized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmInitializeFieldRegister() first");
173928b400f6SJacob Faibussowitsch   PetscCheck(!swarm->field_registration_finalized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Cannot register additional fields after calling DMSwarmFinalizeFieldRegister() first");
17405f50eb2eSDave May 
174108401ef6SPierre Jolivet   PetscCheck(type != PETSC_OBJECT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
174208401ef6SPierre Jolivet   PetscCheck(type != PETSC_FUNCTION, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
174308401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRING, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
174408401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRUCT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
174508401ef6SPierre Jolivet   PetscCheck(type != PETSC_DATATYPE_UNKNOWN, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
1746b62e03f8SDave May 
17479566063dSJacob Faibussowitsch   PetscCall(PetscDataTypeGetSize(type, &size));
1748b62e03f8SDave May   /* Load a specific data type into data bucket, specifying textual name and its size in bytes */
17499566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterPetscDatatypeField", fieldname, blocksize * size, NULL));
175052c3ed93SDave May   {
175177048351SPatrick Sanan     DMSwarmDataField gfield;
175252c3ed93SDave May 
17539566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
17549566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
175552c3ed93SDave May   }
1756b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = type;
17573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1758b62e03f8SDave May }
1759b62e03f8SDave May 
1760d3a51819SDave May /*@C
176120f4b53cSBarry Smith   DMSwarmRegisterUserStructField - Register a user defined struct to a `DMSWARM`
1762d3a51819SDave May 
176320f4b53cSBarry Smith   Collective
1764d3a51819SDave May 
176560225df5SJacob Faibussowitsch   Input Parameters:
176620f4b53cSBarry Smith + dm        - a `DMSWARM`
1767d3a51819SDave May . fieldname - the textual name to identify this field
176862741f57SDave May - size      - the size in bytes of the user struct of each data type
1769d3a51819SDave May 
1770d3a51819SDave May   Level: beginner
1771d3a51819SDave May 
177220f4b53cSBarry Smith   Note:
17738b8a3813SDave May   The textual name for each registered field must be unique.
1774d3a51819SDave May 
177520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserDatatypeField()`
1776d3a51819SDave May @*/
1777d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserStructField(DM dm, const char fieldname[], size_t size)
1778d71ae5a4SJacob Faibussowitsch {
1779b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1780b62e03f8SDave May 
1781521f74f9SMatthew G. Knepley   PetscFunctionBegin;
17829566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserStructField", fieldname, size, NULL));
1783b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_STRUCT;
17843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1785b62e03f8SDave May }
1786b62e03f8SDave May 
1787d3a51819SDave May /*@C
178820f4b53cSBarry Smith   DMSwarmRegisterUserDatatypeField - Register a user defined data type to a `DMSWARM`
1789d3a51819SDave May 
179020f4b53cSBarry Smith   Collective
1791d3a51819SDave May 
179260225df5SJacob Faibussowitsch   Input Parameters:
179320f4b53cSBarry Smith + dm        - a `DMSWARM`
1794d3a51819SDave May . fieldname - the textual name to identify this field
1795d3a51819SDave May . size      - the size in bytes of the user data type
179662741f57SDave May - blocksize - the number of each data type
1797d3a51819SDave May 
1798d3a51819SDave May   Level: beginner
1799d3a51819SDave May 
180020f4b53cSBarry Smith   Note:
18018b8a3813SDave May   The textual name for each registered field must be unique.
1802d3a51819SDave May 
180342747ad1SJacob Faibussowitsch .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserStructField()`
1804d3a51819SDave May @*/
1805d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserDatatypeField(DM dm, const char fieldname[], size_t size, PetscInt blocksize)
1806d71ae5a4SJacob Faibussowitsch {
1807b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1808b62e03f8SDave May 
1809521f74f9SMatthew G. Knepley   PetscFunctionBegin;
18109566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserDatatypeField", fieldname, blocksize * size, NULL));
1811320740a0SDave May   {
181277048351SPatrick Sanan     DMSwarmDataField gfield;
1813320740a0SDave May 
18149566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
18159566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
1816320740a0SDave May   }
1817b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_DATATYPE_UNKNOWN;
18183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1819b62e03f8SDave May }
1820b62e03f8SDave May 
1821d3a51819SDave May /*@C
1822d3a51819SDave May   DMSwarmGetField - Get access to the underlying array storing all entries associated with a registered field
1823d3a51819SDave May 
1824cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1825d3a51819SDave May 
182660225df5SJacob Faibussowitsch   Input Parameters:
182720f4b53cSBarry Smith + dm        - a `DMSWARM`
182862741f57SDave May - fieldname - the textual name to identify this field
1829d3a51819SDave May 
183060225df5SJacob Faibussowitsch   Output Parameters:
183162741f57SDave May + blocksize - the number of each data type
1832d3a51819SDave May . type      - the data type
183362741f57SDave May - data      - pointer to raw array
1834d3a51819SDave May 
1835d3a51819SDave May   Level: beginner
1836d3a51819SDave May 
1837d3a51819SDave May   Notes:
183820f4b53cSBarry Smith   The array must be returned using a matching call to `DMSwarmRestoreField()`.
1839d3a51819SDave May 
1840ce78bad3SBarry Smith   Fortran Note:
1841ce78bad3SBarry Smith   Only works for `type` of `PETSC_SCALAR`
1842ce78bad3SBarry Smith 
184320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreField()`
1844d3a51819SDave May @*/
1845ce78bad3SBarry Smith PetscErrorCode DMSwarmGetField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data) PeNS
1846d71ae5a4SJacob Faibussowitsch {
1847b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
184877048351SPatrick Sanan   DMSwarmDataField gfield;
1849b62e03f8SDave May 
1850521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1851ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
18529566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
18539566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
18549566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetAccess(gfield));
18559566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetEntries(gfield, data));
1856ad540459SPierre Jolivet   if (blocksize) *blocksize = gfield->bs;
1857ad540459SPierre Jolivet   if (type) *type = gfield->petsc_type;
18583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1859b62e03f8SDave May }
1860b62e03f8SDave May 
1861d3a51819SDave May /*@C
1862d3a51819SDave May   DMSwarmRestoreField - Restore access to the underlying array storing all entries associated with a registered field
1863d3a51819SDave May 
1864ce78bad3SBarry Smith   Not Collective
1865d3a51819SDave May 
186660225df5SJacob Faibussowitsch   Input Parameters:
186720f4b53cSBarry Smith + dm        - a `DMSWARM`
186862741f57SDave May - fieldname - the textual name to identify this field
1869d3a51819SDave May 
187060225df5SJacob Faibussowitsch   Output Parameters:
187162741f57SDave May + blocksize - the number of each data type
1872d3a51819SDave May . type      - the data type
187362741f57SDave May - data      - pointer to raw array
1874d3a51819SDave May 
1875d3a51819SDave May   Level: beginner
1876d3a51819SDave May 
1877d3a51819SDave May   Notes:
187820f4b53cSBarry Smith   The user must call `DMSwarmGetField()` prior to calling `DMSwarmRestoreField()`.
1879d3a51819SDave May 
1880ce78bad3SBarry Smith   Fortran Note:
1881ce78bad3SBarry Smith   Only works for `type` of `PETSC_SCALAR`
1882ce78bad3SBarry Smith 
188320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetField()`
1884d3a51819SDave May @*/
1885ce78bad3SBarry Smith PetscErrorCode DMSwarmRestoreField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data) PeNS
1886d71ae5a4SJacob Faibussowitsch {
1887b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
188877048351SPatrick Sanan   DMSwarmDataField gfield;
1889b62e03f8SDave May 
1890521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1891ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
18929566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
18939566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
1894b62e03f8SDave May   if (data) *data = NULL;
18953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1896b62e03f8SDave May }
1897b62e03f8SDave May 
18980bf7c1c5SMatthew G. Knepley PetscErrorCode DMSwarmGetFieldInfo(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type)
18990bf7c1c5SMatthew G. Knepley {
19000bf7c1c5SMatthew G. Knepley   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
19010bf7c1c5SMatthew G. Knepley   DMSwarmDataField gfield;
19020bf7c1c5SMatthew G. Knepley 
19030bf7c1c5SMatthew G. Knepley   PetscFunctionBegin;
19040bf7c1c5SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
19050bf7c1c5SMatthew G. Knepley   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
19060bf7c1c5SMatthew G. Knepley   if (blocksize) *blocksize = gfield->bs;
19070bf7c1c5SMatthew G. Knepley   if (type) *type = gfield->petsc_type;
19080bf7c1c5SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
19090bf7c1c5SMatthew G. Knepley }
19100bf7c1c5SMatthew G. Knepley 
191174d0cae8SMatthew G. Knepley /*@
191220f4b53cSBarry Smith   DMSwarmAddPoint - Add space for one new point in the `DMSWARM`
1913d3a51819SDave May 
191420f4b53cSBarry Smith   Not Collective
1915d3a51819SDave May 
191660225df5SJacob Faibussowitsch   Input Parameter:
191720f4b53cSBarry Smith . dm - a `DMSWARM`
1918d3a51819SDave May 
1919d3a51819SDave May   Level: beginner
1920d3a51819SDave May 
1921d3a51819SDave May   Notes:
19228b8a3813SDave May   The new point will have all fields initialized to zero.
1923d3a51819SDave May 
192420f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmAddNPoints()`
1925d3a51819SDave May @*/
1926d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddPoint(DM dm)
1927d71ae5a4SJacob Faibussowitsch {
1928cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1929cb1d1399SDave May 
1930521f74f9SMatthew G. Knepley   PetscFunctionBegin;
19319566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
19329566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
19339566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketAddPoint(swarm->db));
19349566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
19353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1936cb1d1399SDave May }
1937cb1d1399SDave May 
193874d0cae8SMatthew G. Knepley /*@
193920f4b53cSBarry Smith   DMSwarmAddNPoints - Add space for a number of new points in the `DMSWARM`
1940d3a51819SDave May 
194120f4b53cSBarry Smith   Not Collective
1942d3a51819SDave May 
194360225df5SJacob Faibussowitsch   Input Parameters:
194420f4b53cSBarry Smith + dm      - a `DMSWARM`
194562741f57SDave May - npoints - the number of new points to add
1946d3a51819SDave May 
1947d3a51819SDave May   Level: beginner
1948d3a51819SDave May 
1949d3a51819SDave May   Notes:
19508b8a3813SDave May   The new point will have all fields initialized to zero.
1951d3a51819SDave May 
195220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmAddPoint()`
1953d3a51819SDave May @*/
1954d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddNPoints(DM dm, PetscInt npoints)
1955d71ae5a4SJacob Faibussowitsch {
1956cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1957cb1d1399SDave May   PetscInt  nlocal;
1958cb1d1399SDave May 
1959521f74f9SMatthew G. Knepley   PetscFunctionBegin;
19609566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
19619566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
1962670292f5SMatthew Knepley   nlocal = PetscMax(nlocal, 0) + npoints;
19639566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
19649566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
19653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1966cb1d1399SDave May }
1967cb1d1399SDave May 
196874d0cae8SMatthew G. Knepley /*@
196920f4b53cSBarry Smith   DMSwarmRemovePoint - Remove the last point from the `DMSWARM`
1970d3a51819SDave May 
197120f4b53cSBarry Smith   Not Collective
1972d3a51819SDave May 
197360225df5SJacob Faibussowitsch   Input Parameter:
197420f4b53cSBarry Smith . dm - a `DMSWARM`
1975d3a51819SDave May 
1976d3a51819SDave May   Level: beginner
1977d3a51819SDave May 
197820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePointAtIndex()`
1979d3a51819SDave May @*/
1980d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePoint(DM dm)
1981d71ae5a4SJacob Faibussowitsch {
1982cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1983cb1d1399SDave May 
1984521f74f9SMatthew G. Knepley   PetscFunctionBegin;
19859566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
19869566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePoint(swarm->db));
19879566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
19883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1989cb1d1399SDave May }
1990cb1d1399SDave May 
199174d0cae8SMatthew G. Knepley /*@
199220f4b53cSBarry Smith   DMSwarmRemovePointAtIndex - Removes a specific point from the `DMSWARM`
1993d3a51819SDave May 
199420f4b53cSBarry Smith   Not Collective
1995d3a51819SDave May 
199660225df5SJacob Faibussowitsch   Input Parameters:
199720f4b53cSBarry Smith + dm  - a `DMSWARM`
199862741f57SDave May - idx - index of point to remove
1999d3a51819SDave May 
2000d3a51819SDave May   Level: beginner
2001d3a51819SDave May 
200220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
2003d3a51819SDave May @*/
2004d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePointAtIndex(DM dm, PetscInt idx)
2005d71ae5a4SJacob Faibussowitsch {
2006cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
2007cb1d1399SDave May 
2008521f74f9SMatthew G. Knepley   PetscFunctionBegin;
20099566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
20109566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, idx));
20119566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
20123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2013cb1d1399SDave May }
2014b62e03f8SDave May 
201574d0cae8SMatthew G. Knepley /*@
201620f4b53cSBarry Smith   DMSwarmCopyPoint - Copy point pj to point pi in the `DMSWARM`
2017ba4fc9c6SDave May 
201820f4b53cSBarry Smith   Not Collective
2019ba4fc9c6SDave May 
202060225df5SJacob Faibussowitsch   Input Parameters:
202120f4b53cSBarry Smith + dm - a `DMSWARM`
2022ba4fc9c6SDave May . pi - the index of the point to copy
2023ba4fc9c6SDave May - pj - the point index where the copy should be located
2024ba4fc9c6SDave May 
2025ba4fc9c6SDave May   Level: beginner
2026ba4fc9c6SDave May 
202720f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
2028ba4fc9c6SDave May @*/
2029d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCopyPoint(DM dm, PetscInt pi, PetscInt pj)
2030d71ae5a4SJacob Faibussowitsch {
2031ba4fc9c6SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
2032ba4fc9c6SDave May 
2033ba4fc9c6SDave May   PetscFunctionBegin;
20349566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
20359566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCopyPoint(swarm->db, pi, swarm->db, pj));
20363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2037ba4fc9c6SDave May }
2038ba4fc9c6SDave May 
203966976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmMigrate_Basic(DM dm, PetscBool remove_sent_points)
2040d71ae5a4SJacob Faibussowitsch {
2041521f74f9SMatthew G. Knepley   PetscFunctionBegin;
20429566063dSJacob Faibussowitsch   PetscCall(DMSwarmMigrate_Push_Basic(dm, remove_sent_points));
20433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20443454631fSDave May }
20453454631fSDave May 
204674d0cae8SMatthew G. Knepley /*@
204720f4b53cSBarry Smith   DMSwarmMigrate - Relocates points defined in the `DMSWARM` to other MPI-ranks
2048d3a51819SDave May 
204920f4b53cSBarry Smith   Collective
2050d3a51819SDave May 
205160225df5SJacob Faibussowitsch   Input Parameters:
205220f4b53cSBarry Smith + dm                 - the `DMSWARM`
205362741f57SDave May - remove_sent_points - flag indicating if sent points should be removed from the current MPI-rank
2054d3a51819SDave May 
2055d3a51819SDave May   Level: advanced
2056d3a51819SDave May 
205720f4b53cSBarry Smith   Notes:
205820f4b53cSBarry Smith   The `DM` will be modified to accommodate received points.
205920f4b53cSBarry Smith   If `remove_sent_points` is `PETSC_TRUE`, any points that were sent will be removed from the `DM`.
206020f4b53cSBarry Smith   Different styles of migration are supported. See `DMSwarmSetMigrateType()`.
206120f4b53cSBarry Smith 
206220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`
2063d3a51819SDave May @*/
2064d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmMigrate(DM dm, PetscBool remove_sent_points)
2065d71ae5a4SJacob Faibussowitsch {
2066f0cdbbbaSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
2067f0cdbbbaSDave May 
2068521f74f9SMatthew G. Knepley   PetscFunctionBegin;
20699566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_Migrate, 0, 0, 0, 0));
2070f0cdbbbaSDave May   switch (swarm->migrate_type) {
2071d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_BASIC:
2072d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_Basic(dm, remove_sent_points));
2073d71ae5a4SJacob Faibussowitsch     break;
2074d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLNSCATTER:
2075d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_CellDMScatter(dm, remove_sent_points));
2076d71ae5a4SJacob Faibussowitsch     break;
2077d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLEXACT:
2078d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_DMCELLEXACT not implemented");
2079d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_USER:
2080d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_USER not implemented");
2081d71ae5a4SJacob Faibussowitsch   default:
2082d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE type unknown");
2083f0cdbbbaSDave May   }
20849566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_Migrate, 0, 0, 0, 0));
20859566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm));
20863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20873454631fSDave May }
20883454631fSDave May 
2089f0cdbbbaSDave May PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm, PetscInt *globalsize);
2090f0cdbbbaSDave May 
2091d3a51819SDave May /*
2092d3a51819SDave May  DMSwarmCollectViewCreate
2093d3a51819SDave May 
2094d3a51819SDave May  * Applies a collection method and gathers point neighbour points into dm
2095d3a51819SDave May 
2096d3a51819SDave May  Notes:
20978b8a3813SDave May  Users should call DMSwarmCollectViewDestroy() after
2098d3a51819SDave May  they have finished computations associated with the collected points
2099d3a51819SDave May */
2100d3a51819SDave May 
210174d0cae8SMatthew G. Knepley /*@
2102d3a51819SDave May   DMSwarmCollectViewCreate - Applies a collection method and gathers points
210320f4b53cSBarry Smith   in neighbour ranks into the `DMSWARM`
2104d3a51819SDave May 
210520f4b53cSBarry Smith   Collective
2106d3a51819SDave May 
210760225df5SJacob Faibussowitsch   Input Parameter:
210820f4b53cSBarry Smith . dm - the `DMSWARM`
2109d3a51819SDave May 
2110d3a51819SDave May   Level: advanced
2111d3a51819SDave May 
211220f4b53cSBarry Smith   Notes:
211320f4b53cSBarry Smith   Users should call `DMSwarmCollectViewDestroy()` after
211420f4b53cSBarry Smith   they have finished computations associated with the collected points
21150764c050SBarry Smith 
211620f4b53cSBarry Smith   Different collect methods are supported. See `DMSwarmSetCollectType()`.
211720f4b53cSBarry Smith 
21180764c050SBarry Smith   Developer Note:
21190764c050SBarry Smith   Create and Destroy routines create new objects that can get destroyed, they do not change the state
21200764c050SBarry Smith   of the current object.
21210764c050SBarry Smith 
212220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewDestroy()`, `DMSwarmSetCollectType()`
2123d3a51819SDave May @*/
2124d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewCreate(DM dm)
2125d71ae5a4SJacob Faibussowitsch {
21262712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
21272712d1f2SDave May   PetscInt  ng;
21282712d1f2SDave May 
2129521f74f9SMatthew G. Knepley   PetscFunctionBegin;
213028b400f6SJacob Faibussowitsch   PetscCheck(!swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView currently active");
21319566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &ng));
2132480eef7bSDave May   switch (swarm->collect_type) {
2133d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_BASIC:
2134d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_GlobalToLocal_Basic(dm, &ng));
2135d71ae5a4SJacob Faibussowitsch     break;
2136d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_DMDABOUNDINGBOX:
2137d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_DMDABOUNDINGBOX not implemented");
2138d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_GENERAL:
2139d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_GENERAL not implemented");
2140d71ae5a4SJacob Faibussowitsch   default:
2141d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT type unknown");
2142480eef7bSDave May   }
2143480eef7bSDave May   swarm->collect_view_active       = PETSC_TRUE;
2144480eef7bSDave May   swarm->collect_view_reset_nlocal = ng;
21453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21462712d1f2SDave May }
21472712d1f2SDave May 
214874d0cae8SMatthew G. Knepley /*@
214920f4b53cSBarry Smith   DMSwarmCollectViewDestroy - Resets the `DMSWARM` to the size prior to calling `DMSwarmCollectViewCreate()`
2150d3a51819SDave May 
215120f4b53cSBarry Smith   Collective
2152d3a51819SDave May 
215360225df5SJacob Faibussowitsch   Input Parameters:
215420f4b53cSBarry Smith . dm - the `DMSWARM`
2155d3a51819SDave May 
2156d3a51819SDave May   Notes:
215720f4b53cSBarry Smith   Users should call `DMSwarmCollectViewCreate()` before this function is called.
2158d3a51819SDave May 
2159d3a51819SDave May   Level: advanced
2160d3a51819SDave May 
21610764c050SBarry Smith   Developer Note:
21620764c050SBarry Smith   Create and Destroy routines create new objects that can get destroyed, they do not change the state
21630764c050SBarry Smith   of the current object.
21640764c050SBarry Smith 
216520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewCreate()`, `DMSwarmSetCollectType()`
2166d3a51819SDave May @*/
2167d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewDestroy(DM dm)
2168d71ae5a4SJacob Faibussowitsch {
21692712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
21702712d1f2SDave May 
2171521f74f9SMatthew G. Knepley   PetscFunctionBegin;
217228b400f6SJacob Faibussowitsch   PetscCheck(swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView is currently not active");
21739566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetLocalSizes(dm, swarm->collect_view_reset_nlocal, -1));
2174480eef7bSDave May   swarm->collect_view_active = PETSC_FALSE;
21753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21762712d1f2SDave May }
21773454631fSDave May 
217866976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmSetUpPIC(DM dm)
2179d71ae5a4SJacob Faibussowitsch {
2180f0cdbbbaSDave May   PetscInt dim;
2181f0cdbbbaSDave May 
2182521f74f9SMatthew G. Knepley   PetscFunctionBegin;
21839566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetNumSpecies(dm, 1));
21849566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
218563a3b9bcSJacob Faibussowitsch   PetscCheck(dim >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
218663a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
21873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2188f0cdbbbaSDave May }
2189f0cdbbbaSDave May 
219074d0cae8SMatthew G. Knepley /*@
219131403186SMatthew G. Knepley   DMSwarmSetPointCoordinatesRandom - Sets initial coordinates for particles in each cell
219231403186SMatthew G. Knepley 
219320f4b53cSBarry Smith   Collective
219431403186SMatthew G. Knepley 
219560225df5SJacob Faibussowitsch   Input Parameters:
219620f4b53cSBarry Smith + dm  - the `DMSWARM`
219720f4b53cSBarry Smith - Npc - The number of particles per cell in the cell `DM`
219831403186SMatthew G. Knepley 
219931403186SMatthew G. Knepley   Level: intermediate
220031403186SMatthew G. Knepley 
220120f4b53cSBarry Smith   Notes:
220220f4b53cSBarry Smith   The user must use `DMSwarmSetCellDM()` to set the cell `DM` first. The particles are placed randomly inside each cell. If only
220320f4b53cSBarry Smith   one particle is in each cell, it is placed at the centroid.
220420f4b53cSBarry Smith 
220520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
220631403186SMatthew G. Knepley @*/
2207d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetPointCoordinatesRandom(DM dm, PetscInt Npc)
2208d71ae5a4SJacob Faibussowitsch {
220931403186SMatthew G. Knepley   DM             cdm;
221019307e5cSMatthew G. Knepley   DMSwarmCellDM  celldm;
221131403186SMatthew G. Knepley   PetscRandom    rnd;
221231403186SMatthew G. Knepley   DMPolytopeType ct;
221331403186SMatthew G. Knepley   PetscBool      simplex;
221431403186SMatthew G. Knepley   PetscReal     *centroid, *coords, *xi0, *v0, *J, *invJ, detJ;
221519307e5cSMatthew G. Knepley   PetscInt       dim, d, cStart, cEnd, c, p, Nfc;
221619307e5cSMatthew G. Knepley   const char   **coordFields;
221731403186SMatthew G. Knepley 
221831403186SMatthew G. Knepley   PetscFunctionBeginUser;
22199566063dSJacob Faibussowitsch   PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm), &rnd));
22209566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0));
22219566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetType(rnd, PETSCRAND48));
222231403186SMatthew G. Knepley 
222319307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(dm, &celldm));
222419307e5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields));
222519307e5cSMatthew G. Knepley   PetscCheck(Nfc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "We only support a single coordinate field right now, not %" PetscInt_FMT, Nfc);
22269566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
22279566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(cdm, &dim));
22289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd));
22299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(cdm, cStart, &ct));
223031403186SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
223131403186SMatthew G. Knepley 
22329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(dim, &centroid, dim, &xi0, dim, &v0, dim * dim, &J, dim * dim, &invJ));
223331403186SMatthew G. Knepley   for (d = 0; d < dim; ++d) xi0[d] = -1.0;
223419307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetField(dm, coordFields[0], NULL, NULL, (void **)&coords));
223531403186SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
223631403186SMatthew G. Knepley     if (Npc == 1) {
22379566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(cdm, c, NULL, centroid, NULL));
223831403186SMatthew G. Knepley       for (d = 0; d < dim; ++d) coords[c * dim + d] = centroid[d];
223931403186SMatthew G. Knepley     } else {
22409566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(cdm, c, NULL, v0, J, invJ, &detJ)); /* affine */
224131403186SMatthew G. Knepley       for (p = 0; p < Npc; ++p) {
224231403186SMatthew G. Knepley         const PetscInt n   = c * Npc + p;
224331403186SMatthew G. Knepley         PetscReal      sum = 0.0, refcoords[3];
224431403186SMatthew G. Knepley 
224531403186SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
22469566063dSJacob Faibussowitsch           PetscCall(PetscRandomGetValueReal(rnd, &refcoords[d]));
224731403186SMatthew G. Knepley           sum += refcoords[d];
224831403186SMatthew G. Knepley         }
22499371c9d4SSatish Balay         if (simplex && sum > 0.0)
22509371c9d4SSatish Balay           for (d = 0; d < dim; ++d) refcoords[d] -= PetscSqrtReal(dim) * sum;
225131403186SMatthew G. Knepley         CoordinatesRefToReal(dim, dim, xi0, v0, J, refcoords, &coords[n * dim]);
225231403186SMatthew G. Knepley       }
225331403186SMatthew G. Knepley     }
225431403186SMatthew G. Knepley   }
225519307e5cSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(dm, coordFields[0], NULL, NULL, (void **)&coords));
22569566063dSJacob Faibussowitsch   PetscCall(PetscFree5(centroid, xi0, v0, J, invJ));
22579566063dSJacob Faibussowitsch   PetscCall(PetscRandomDestroy(&rnd));
22583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
225931403186SMatthew G. Knepley }
226031403186SMatthew G. Knepley 
226131403186SMatthew G. Knepley /*@
2262fca3fa51SMatthew G. Knepley   DMSwarmGetType - Get particular flavor of `DMSWARM`
2263fca3fa51SMatthew G. Knepley 
2264fca3fa51SMatthew G. Knepley   Collective
2265fca3fa51SMatthew G. Knepley 
2266fca3fa51SMatthew G. Knepley   Input Parameter:
2267fca3fa51SMatthew G. Knepley . sw - the `DMSWARM`
2268fca3fa51SMatthew G. Knepley 
2269fca3fa51SMatthew G. Knepley   Output Parameter:
2270fca3fa51SMatthew G. Knepley . stype - the `DMSWARM` type (e.g. `DMSWARM_PIC`)
2271fca3fa51SMatthew G. Knepley 
2272fca3fa51SMatthew G. Knepley   Level: advanced
2273fca3fa51SMatthew G. Knepley 
2274fca3fa51SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`, `DMSwarmSetCollectType()`, `DMSwarmType`, `DMSWARM_PIC`, `DMSWARM_BASIC`
2275fca3fa51SMatthew G. Knepley @*/
2276fca3fa51SMatthew G. Knepley PetscErrorCode DMSwarmGetType(DM sw, DMSwarmType *stype)
2277fca3fa51SMatthew G. Knepley {
2278fca3fa51SMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
2279fca3fa51SMatthew G. Knepley 
2280fca3fa51SMatthew G. Knepley   PetscFunctionBegin;
2281fca3fa51SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
2282fca3fa51SMatthew G. Knepley   PetscAssertPointer(stype, 2);
2283fca3fa51SMatthew G. Knepley   *stype = swarm->swarm_type;
2284fca3fa51SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2285fca3fa51SMatthew G. Knepley }
2286fca3fa51SMatthew G. Knepley 
2287fca3fa51SMatthew G. Knepley /*@
228820f4b53cSBarry Smith   DMSwarmSetType - Set particular flavor of `DMSWARM`
2289d3a51819SDave May 
229020f4b53cSBarry Smith   Collective
2291d3a51819SDave May 
229260225df5SJacob Faibussowitsch   Input Parameters:
2293fca3fa51SMatthew G. Knepley + sw    - the `DMSWARM`
229420f4b53cSBarry Smith - stype - the `DMSWARM` type (e.g. `DMSWARM_PIC`)
2295d3a51819SDave May 
2296d3a51819SDave May   Level: advanced
2297d3a51819SDave May 
229820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`, `DMSwarmSetCollectType()`, `DMSwarmType`, `DMSWARM_PIC`, `DMSWARM_BASIC`
2299d3a51819SDave May @*/
2300fca3fa51SMatthew G. Knepley PetscErrorCode DMSwarmSetType(DM sw, DMSwarmType stype)
2301d71ae5a4SJacob Faibussowitsch {
2302fca3fa51SMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
2303f0cdbbbaSDave May 
2304521f74f9SMatthew G. Knepley   PetscFunctionBegin;
2305fca3fa51SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
2306f0cdbbbaSDave May   swarm->swarm_type = stype;
2307fca3fa51SMatthew G. Knepley   if (swarm->swarm_type == DMSWARM_PIC) PetscCall(DMSwarmSetUpPIC(sw));
23083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2309f0cdbbbaSDave May }
2310f0cdbbbaSDave May 
2311fca3fa51SMatthew G. Knepley static PetscErrorCode DMSwarmCreateRemapDM_Private(DM sw, DM *rdm)
2312d71ae5a4SJacob Faibussowitsch {
2313fca3fa51SMatthew G. Knepley   PetscFE        fe;
2314fca3fa51SMatthew G. Knepley   DMPolytopeType ct;
2315fca3fa51SMatthew G. Knepley   PetscInt       dim, cStart;
2316fca3fa51SMatthew G. Knepley   const char    *prefix = "remap_";
2317fca3fa51SMatthew G. Knepley 
2318fca3fa51SMatthew G. Knepley   PetscFunctionBegin;
2319fca3fa51SMatthew G. Knepley   PetscCall(DMCreate(PetscObjectComm((PetscObject)sw), rdm));
2320fca3fa51SMatthew G. Knepley   PetscCall(DMSetType(*rdm, DMPLEX));
2321fca3fa51SMatthew G. Knepley   PetscCall(DMPlexSetOptionsPrefix(*rdm, prefix));
2322fca3fa51SMatthew G. Knepley   PetscCall(DMSetFromOptions(*rdm));
2323fca3fa51SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*rdm, "remap"));
2324fca3fa51SMatthew G. Knepley   PetscCall(DMViewFromOptions(*rdm, NULL, "-dm_view"));
2325fca3fa51SMatthew G. Knepley 
2326fca3fa51SMatthew G. Knepley   PetscCall(DMGetDimension(*rdm, &dim));
2327fca3fa51SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*rdm, 0, &cStart, NULL));
2328fca3fa51SMatthew G. Knepley   PetscCall(DMPlexGetCellType(*rdm, cStart, &ct));
2329fca3fa51SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe));
2330fca3fa51SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "distribution"));
2331fca3fa51SMatthew G. Knepley   PetscCall(DMSetField(*rdm, 0, NULL, (PetscObject)fe));
2332fca3fa51SMatthew G. Knepley   PetscCall(DMCreateDS(*rdm));
2333fca3fa51SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
2334fca3fa51SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2335fca3fa51SMatthew G. Knepley }
2336fca3fa51SMatthew G. Knepley 
2337fca3fa51SMatthew G. Knepley static PetscErrorCode DMSetup_Swarm(DM sw)
2338fca3fa51SMatthew G. Knepley {
2339fca3fa51SMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)sw->data;
23403454631fSDave May 
2341521f74f9SMatthew G. Knepley   PetscFunctionBegin;
23423ba16761SJacob Faibussowitsch   if (swarm->issetup) PetscFunctionReturn(PETSC_SUCCESS);
23433454631fSDave May   swarm->issetup = PETSC_TRUE;
23443454631fSDave May 
2345fca3fa51SMatthew G. Knepley   if (swarm->remap_type != DMSWARM_REMAP_NONE) {
2346fca3fa51SMatthew G. Knepley     DMSwarmCellDM celldm;
2347fca3fa51SMatthew G. Knepley     DM            rdm;
2348fca3fa51SMatthew G. Knepley     const char   *fieldnames[2]  = {DMSwarmPICField_coor, "velocity"};
2349fca3fa51SMatthew G. Knepley     const char   *vfieldnames[1] = {"w_q"};
2350fca3fa51SMatthew G. Knepley 
2351fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmCreateRemapDM_Private(sw, &rdm));
2352fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmCellDMCreate(rdm, 1, vfieldnames, 2, fieldnames, &celldm));
2353fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmAddCellDM(sw, celldm));
2354fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmCellDMDestroy(&celldm));
2355fca3fa51SMatthew G. Knepley     PetscCall(DMDestroy(&rdm));
2356fca3fa51SMatthew G. Knepley   }
2357fca3fa51SMatthew G. Knepley 
2358f0cdbbbaSDave May   if (swarm->swarm_type == DMSWARM_PIC) {
235919307e5cSMatthew G. Knepley     DMSwarmCellDM celldm;
2360f0cdbbbaSDave May 
2361fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
2362fca3fa51SMatthew G. Knepley     PetscCheck(celldm, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "No active cell DM. DMSWARM_PIC requires you call DMSwarmSetCellDM() or DMSwarmAddCellDM()");
236319307e5cSMatthew G. Knepley     if (celldm->dm->ops->locatepointssubdomain) {
2364f0cdbbbaSDave May       /* check methods exists for exact ownership identificiation */
2365fca3fa51SMatthew G. Knepley       PetscCall(PetscInfo(sw, "DMSWARM_PIC: Using method CellDM->ops->LocatePointsSubdomain\n"));
2366f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLEXACT;
2367f0cdbbbaSDave May     } else {
2368f0cdbbbaSDave May       /* check methods exist for point location AND rank neighbor identification */
2369966bd95aSPierre Jolivet       PetscCheck(celldm->dm->ops->locatepoints, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->locatepoints be defined");
2370fca3fa51SMatthew G. Knepley       PetscCall(PetscInfo(sw, "DMSWARM_PIC: Using method CellDM->LocatePoints\n"));
2371f0cdbbbaSDave May 
2372966bd95aSPierre Jolivet       PetscCheck(celldm->dm->ops->getneighbors, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->getneighbors be defined");
2373fca3fa51SMatthew G. Knepley       PetscCall(PetscInfo(sw, "DMSWARM_PIC: Using method CellDM->GetNeigbors\n"));
2374f0cdbbbaSDave May 
2375f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLNSCATTER;
2376f0cdbbbaSDave May     }
2377f0cdbbbaSDave May   }
2378f0cdbbbaSDave May 
2379fca3fa51SMatthew G. Knepley   PetscCall(DMSwarmFinalizeFieldRegister(sw));
2380f0cdbbbaSDave May 
23813454631fSDave May   /* check some fields were registered */
2382fca3fa51SMatthew G. Knepley   PetscCheck(swarm->db->nfields > 2, PetscObjectComm((PetscObject)sw), PETSC_ERR_USER, "At least one field user must be registered via DMSwarmRegisterXXX()");
23833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23843454631fSDave May }
23853454631fSDave May 
238666976f2fSJacob Faibussowitsch static PetscErrorCode DMDestroy_Swarm(DM dm)
2387d71ae5a4SJacob Faibussowitsch {
238857795646SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
238957795646SDave May 
239057795646SDave May   PetscFunctionBegin;
23913ba16761SJacob Faibussowitsch   if (--swarm->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
239219307e5cSMatthew G. Knepley   PetscCall(PetscObjectListDestroy(&swarm->cellDMs));
239319307e5cSMatthew G. Knepley   PetscCall(PetscFree(swarm->activeCellDM));
23949566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&swarm->db));
23959566063dSJacob Faibussowitsch   PetscCall(PetscFree(swarm));
23963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
239757795646SDave May }
239857795646SDave May 
239966976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmView_Draw(DM dm, PetscViewer viewer)
2400d71ae5a4SJacob Faibussowitsch {
2401a9ee3421SMatthew G. Knepley   DM            cdm;
240219307e5cSMatthew G. Knepley   DMSwarmCellDM celldm;
2403a9ee3421SMatthew G. Knepley   PetscDraw     draw;
240431403186SMatthew G. Knepley   PetscReal    *coords, oldPause, radius = 0.01;
240519307e5cSMatthew G. Knepley   PetscInt      Np, p, bs, Nfc;
240619307e5cSMatthew G. Knepley   const char  **coordFields;
2407a9ee3421SMatthew G. Knepley 
2408a9ee3421SMatthew G. Knepley   PetscFunctionBegin;
24099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetReal(NULL, ((PetscObject)dm)->prefix, "-dm_view_swarm_radius", &radius, NULL));
24109566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
24119566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
24129566063dSJacob Faibussowitsch   PetscCall(PetscDrawGetPause(draw, &oldPause));
24139566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, 0.0));
24149566063dSJacob Faibussowitsch   PetscCall(DMView(cdm, viewer));
24159566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, oldPause));
2416a9ee3421SMatthew G. Knepley 
241719307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(dm, &celldm));
241819307e5cSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields));
241919307e5cSMatthew G. Knepley   PetscCheck(Nfc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "We only support a single coordinate field right now, not %" PetscInt_FMT, Nfc);
24209566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &Np));
242119307e5cSMatthew G. Knepley   PetscCall(DMSwarmGetField(dm, coordFields[0], &bs, NULL, (void **)&coords));
2422a9ee3421SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
2423a9ee3421SMatthew G. Knepley     const PetscInt i = p * bs;
2424a9ee3421SMatthew G. Knepley 
24259566063dSJacob Faibussowitsch     PetscCall(PetscDrawEllipse(draw, coords[i], coords[i + 1], radius, radius, PETSC_DRAW_BLUE));
2426a9ee3421SMatthew G. Knepley   }
242719307e5cSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(dm, coordFields[0], &bs, NULL, (void **)&coords));
24289566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
24299566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
24309566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
24313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2432a9ee3421SMatthew G. Knepley }
2433a9ee3421SMatthew G. Knepley 
2434d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_Swarm_Ascii(DM dm, PetscViewer viewer)
2435d71ae5a4SJacob Faibussowitsch {
24366a5217c0SMatthew G. Knepley   PetscViewerFormat format;
24376a5217c0SMatthew G. Knepley   PetscInt         *sizes;
24386a5217c0SMatthew G. Knepley   PetscInt          dim, Np, maxSize = 17;
24396a5217c0SMatthew G. Knepley   MPI_Comm          comm;
24406a5217c0SMatthew G. Knepley   PetscMPIInt       rank, size, p;
244119307e5cSMatthew G. Knepley   const char       *name, *cellid;
24426a5217c0SMatthew G. Knepley 
24436a5217c0SMatthew G. Knepley   PetscFunctionBegin;
24446a5217c0SMatthew G. Knepley   PetscCall(PetscViewerGetFormat(viewer, &format));
24456a5217c0SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
24466a5217c0SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(dm, &Np));
24476a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
24486a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
24496a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(comm, &size));
24506a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetName((PetscObject)dm, &name));
245163a3b9bcSJacob Faibussowitsch   if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
245263a3b9bcSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(viewer, "Swarm in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
24536a5217c0SMatthew G. Knepley   if (size < maxSize) PetscCall(PetscCalloc1(size, &sizes));
24546a5217c0SMatthew G. Knepley   else PetscCall(PetscCalloc1(3, &sizes));
24556a5217c0SMatthew G. Knepley   if (size < maxSize) {
24566a5217c0SMatthew G. Knepley     PetscCallMPI(MPI_Gather(&Np, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
24576a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of particles per rank:"));
24586a5217c0SMatthew G. Knepley     for (p = 0; p < size; ++p) {
24596a5217c0SMatthew G. Knepley       if (rank == 0) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]));
24606a5217c0SMatthew G. Knepley     }
24616a5217c0SMatthew G. Knepley   } else {
24626a5217c0SMatthew G. Knepley     PetscInt locMinMax[2] = {Np, Np};
24636a5217c0SMatthew G. Knepley 
24646a5217c0SMatthew G. Knepley     PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
24656a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of particles per rank: %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
24666a5217c0SMatthew G. Knepley   }
24676a5217c0SMatthew G. Knepley   PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
24686a5217c0SMatthew G. Knepley   PetscCall(PetscFree(sizes));
24696a5217c0SMatthew G. Knepley   if (format == PETSC_VIEWER_ASCII_INFO) {
247019307e5cSMatthew G. Knepley     DMSwarmCellDM celldm;
24716a5217c0SMatthew G. Knepley     PetscInt     *cell;
24726a5217c0SMatthew G. Knepley 
24736a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells containing each particle:\n"));
24746a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
247519307e5cSMatthew G. Knepley     PetscCall(DMSwarmGetCellDMActive(dm, &celldm));
247619307e5cSMatthew G. Knepley     PetscCall(DMSwarmCellDMGetCellID(celldm, &cellid));
247719307e5cSMatthew G. Knepley     PetscCall(DMSwarmGetField(dm, cellid, NULL, NULL, (void **)&cell));
247863a3b9bcSJacob Faibussowitsch     for (p = 0; p < Np; ++p) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  p%d: %" PetscInt_FMT "\n", p, cell[p]));
24796a5217c0SMatthew G. Knepley     PetscCall(PetscViewerFlush(viewer));
24806a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
248119307e5cSMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dm, cellid, NULL, NULL, (void **)&cell));
24826a5217c0SMatthew G. Knepley   }
24833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24846a5217c0SMatthew G. Knepley }
24856a5217c0SMatthew G. Knepley 
248666976f2fSJacob Faibussowitsch static PetscErrorCode DMView_Swarm(DM dm, PetscViewer viewer)
2487d71ae5a4SJacob Faibussowitsch {
24885f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
24899f196a02SMartin Diehl   PetscBool isascii, ibinary, isvtk, isdraw, ispython;
24905627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
24915627991aSBarry Smith   PetscBool ishdf5;
24925627991aSBarry Smith #endif
24935f50eb2eSDave May 
24945f50eb2eSDave May   PetscFunctionBegin;
24955f50eb2eSDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24965f50eb2eSDave May   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
24979f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
24989566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary));
24999566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
25005627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
25019566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
25025627991aSBarry Smith #endif
25039566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
25044fc69c0aSMatthew G. Knepley   PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython));
25059f196a02SMartin Diehl   if (isascii) {
25066a5217c0SMatthew G. Knepley     PetscViewerFormat format;
25076a5217c0SMatthew G. Knepley 
25086a5217c0SMatthew G. Knepley     PetscCall(PetscViewerGetFormat(viewer, &format));
25096a5217c0SMatthew G. Knepley     switch (format) {
2510d71ae5a4SJacob Faibussowitsch     case PETSC_VIEWER_ASCII_INFO_DETAIL:
2511d71ae5a4SJacob Faibussowitsch       PetscCall(DMSwarmDataBucketView(PetscObjectComm((PetscObject)dm), swarm->db, NULL, DATABUCKET_VIEW_STDOUT));
2512d71ae5a4SJacob Faibussowitsch       break;
2513d71ae5a4SJacob Faibussowitsch     default:
2514d71ae5a4SJacob Faibussowitsch       PetscCall(DMView_Swarm_Ascii(dm, viewer));
25156a5217c0SMatthew G. Knepley     }
2516f7d195e4SLawrence Mitchell   } else {
25175f50eb2eSDave May #if defined(PETSC_HAVE_HDF5)
251848a46eb9SPierre Jolivet     if (ishdf5) PetscCall(DMSwarmView_HDF5(dm, viewer));
25195f50eb2eSDave May #endif
252048a46eb9SPierre Jolivet     if (isdraw) PetscCall(DMSwarmView_Draw(dm, viewer));
25214fc69c0aSMatthew G. Knepley     if (ispython) PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm));
2522f7d195e4SLawrence Mitchell   }
25233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25245f50eb2eSDave May }
25255f50eb2eSDave May 
2526cc4c1da9SBarry Smith /*@
252720f4b53cSBarry Smith   DMSwarmGetCellSwarm - Extracts a single cell from the `DMSWARM` object, returns it as a single cell `DMSWARM`.
252820f4b53cSBarry 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.
2529d0c080abSJoseph Pusztay 
2530d0c080abSJoseph Pusztay   Noncollective
2531d0c080abSJoseph Pusztay 
253260225df5SJacob Faibussowitsch   Input Parameters:
253320f4b53cSBarry Smith + sw        - the `DMSWARM`
25345627991aSBarry Smith . cellID    - the integer id of the cell to be extracted and filtered
253520f4b53cSBarry Smith - cellswarm - The `DMSWARM` to receive the cell
2536d0c080abSJoseph Pusztay 
2537d0c080abSJoseph Pusztay   Level: beginner
2538d0c080abSJoseph Pusztay 
25395627991aSBarry Smith   Notes:
254020f4b53cSBarry Smith   This presently only supports `DMSWARM_PIC` type
25415627991aSBarry Smith 
254220f4b53cSBarry Smith   Should be restored with `DMSwarmRestoreCellSwarm()`
2543d0c080abSJoseph Pusztay 
254420f4b53cSBarry Smith   Changes to this cell of the swarm will be lost if they are made prior to restoring this cell.
254520f4b53cSBarry Smith 
254620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreCellSwarm()`
2547d0c080abSJoseph Pusztay @*/
2548cc4c1da9SBarry Smith PetscErrorCode DMSwarmGetCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
2549d71ae5a4SJacob Faibussowitsch {
2550d0c080abSJoseph Pusztay   DM_Swarm   *original = (DM_Swarm *)sw->data;
2551d0c080abSJoseph Pusztay   DMLabel     label;
2552d0c080abSJoseph Pusztay   DM          dmc, subdmc;
2553d0c080abSJoseph Pusztay   PetscInt   *pids, particles, dim;
255419307e5cSMatthew G. Knepley   const char *name;
2555d0c080abSJoseph Pusztay 
2556d0c080abSJoseph Pusztay   PetscFunctionBegin;
2557d0c080abSJoseph Pusztay   /* Configure new swarm */
25589566063dSJacob Faibussowitsch   PetscCall(DMSetType(cellswarm, DMSWARM));
25599566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(sw, &dim));
25609566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(cellswarm, dim));
25619566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(cellswarm, DMSWARM_PIC));
2562d0c080abSJoseph Pusztay   /* Destroy the unused, unconfigured data bucket to prevent stragglers in memory */
25639566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&((DM_Swarm *)cellswarm->data)->db));
25649566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
25659566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, cellID, &particles));
25669566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
25679566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreateFromSubset(original->db, particles, pids, &((DM_Swarm *)cellswarm->data)->db));
25689566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
2569fe11354eSMatthew G. Knepley   PetscCall(DMSwarmSortRestorePointsPerCell(sw, cellID, &particles, &pids));
25709566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(sw, &dmc));
25719566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)sw), "singlecell", &label));
25729566063dSJacob Faibussowitsch   PetscCall(DMAddLabel(dmc, label));
25739566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cellID, 1));
257430cbcd5dSksagiyam   PetscCall(DMPlexFilter(dmc, label, 1, PETSC_FALSE, PETSC_FALSE, NULL, &subdmc));
257519307e5cSMatthew G. Knepley   PetscCall(PetscObjectGetName((PetscObject)dmc, &name));
257619307e5cSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)subdmc, name));
25779566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetCellDM(cellswarm, subdmc));
25789566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&label));
25793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2580d0c080abSJoseph Pusztay }
2581d0c080abSJoseph Pusztay 
2582cc4c1da9SBarry Smith /*@
258320f4b53cSBarry Smith   DMSwarmRestoreCellSwarm - Restores a `DMSWARM` object obtained with `DMSwarmGetCellSwarm()`. All fields are copied back into the parent swarm.
2584d0c080abSJoseph Pusztay 
2585d0c080abSJoseph Pusztay   Noncollective
2586d0c080abSJoseph Pusztay 
258760225df5SJacob Faibussowitsch   Input Parameters:
258820f4b53cSBarry Smith + sw        - the parent `DMSWARM`
2589d0c080abSJoseph Pusztay . cellID    - the integer id of the cell to be copied back into the parent swarm
2590d0c080abSJoseph Pusztay - cellswarm - the cell swarm object
2591d0c080abSJoseph Pusztay 
2592d0c080abSJoseph Pusztay   Level: beginner
2593d0c080abSJoseph Pusztay 
25945627991aSBarry Smith   Note:
259520f4b53cSBarry Smith   This only supports `DMSWARM_PIC` types of `DMSWARM`s
2596d0c080abSJoseph Pusztay 
259720f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetCellSwarm()`
2598d0c080abSJoseph Pusztay @*/
2599cc4c1da9SBarry Smith PetscErrorCode DMSwarmRestoreCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
2600d71ae5a4SJacob Faibussowitsch {
2601d0c080abSJoseph Pusztay   DM        dmc;
2602d0c080abSJoseph Pusztay   PetscInt *pids, particles, p;
2603d0c080abSJoseph Pusztay 
2604d0c080abSJoseph Pusztay   PetscFunctionBegin;
26059566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
26069566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
26079566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
2608d0c080abSJoseph Pusztay   /* Pointwise copy of each particle based on pid. The parent swarm may not be altered during this process. */
260948a46eb9SPierre Jolivet   for (p = 0; p < particles; ++p) PetscCall(DMSwarmDataBucketCopyPoint(((DM_Swarm *)cellswarm->data)->db, pids[p], ((DM_Swarm *)sw->data)->db, pids[p]));
2610d0c080abSJoseph Pusztay   /* Free memory, destroy cell dm */
26119566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(cellswarm, &dmc));
26129566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
2613fe11354eSMatthew G. Knepley   PetscCall(DMSwarmSortRestorePointsPerCell(sw, cellID, &particles, &pids));
26143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2615d0c080abSJoseph Pusztay }
2616d0c080abSJoseph Pusztay 
2617d52c2f21SMatthew G. Knepley /*@
2618d52c2f21SMatthew G. Knepley   DMSwarmComputeMoments - Compute the first three particle moments for a given field
2619d52c2f21SMatthew G. Knepley 
2620d52c2f21SMatthew G. Knepley   Noncollective
2621d52c2f21SMatthew G. Knepley 
2622d52c2f21SMatthew G. Knepley   Input Parameters:
2623d52c2f21SMatthew G. Knepley + sw         - the `DMSWARM`
2624d52c2f21SMatthew G. Knepley . coordinate - the coordinate field name
2625d52c2f21SMatthew G. Knepley - weight     - the weight field name
2626d52c2f21SMatthew G. Knepley 
2627d52c2f21SMatthew G. Knepley   Output Parameter:
2628d52c2f21SMatthew G. Knepley . moments - the field moments
2629d52c2f21SMatthew G. Knepley 
2630d52c2f21SMatthew G. Knepley   Level: intermediate
2631d52c2f21SMatthew G. Knepley 
2632d52c2f21SMatthew G. Knepley   Notes:
2633d52c2f21SMatthew G. Knepley   The `moments` array should be of length bs + 2, where bs is the block size of the coordinate field.
2634d52c2f21SMatthew G. Knepley 
2635d52c2f21SMatthew G. Knepley   The weight field must be a scalar, having blocksize 1.
2636d52c2f21SMatthew G. Knepley 
2637d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMPlexComputeMoments()`
2638d52c2f21SMatthew G. Knepley @*/
2639d52c2f21SMatthew G. Knepley PetscErrorCode DMSwarmComputeMoments(DM sw, const char coordinate[], const char weight[], PetscReal moments[])
2640d52c2f21SMatthew G. Knepley {
2641d52c2f21SMatthew G. Knepley   const PetscReal *coords;
2642d52c2f21SMatthew G. Knepley   const PetscReal *w;
2643d52c2f21SMatthew G. Knepley   PetscReal       *mom;
2644d52c2f21SMatthew G. Knepley   PetscDataType    dtc, dtw;
2645d52c2f21SMatthew G. Knepley   PetscInt         bsc, bsw, Np;
2646d52c2f21SMatthew G. Knepley   MPI_Comm         comm;
2647d52c2f21SMatthew G. Knepley 
2648d52c2f21SMatthew G. Knepley   PetscFunctionBegin;
2649d52c2f21SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 1);
2650d52c2f21SMatthew G. Knepley   PetscAssertPointer(coordinate, 2);
2651d52c2f21SMatthew G. Knepley   PetscAssertPointer(weight, 3);
2652d52c2f21SMatthew G. Knepley   PetscAssertPointer(moments, 4);
2653d52c2f21SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
2654d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, coordinate, &bsc, &dtc, (void **)&coords));
2655d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, weight, &bsw, &dtw, (void **)&w));
2656d52c2f21SMatthew G. Knepley   PetscCheck(dtc == PETSC_REAL, comm, PETSC_ERR_ARG_WRONG, "Coordinate field %s must be real, not %s", coordinate, PetscDataTypes[dtc]);
2657d52c2f21SMatthew G. Knepley   PetscCheck(dtw == PETSC_REAL, comm, PETSC_ERR_ARG_WRONG, "Weight field %s must be real, not %s", weight, PetscDataTypes[dtw]);
2658d52c2f21SMatthew G. Knepley   PetscCheck(bsw == 1, comm, PETSC_ERR_ARG_WRONG, "Weight field %s must be a scalar, not blocksize %" PetscInt_FMT, weight, bsw);
2659d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2660d52c2f21SMatthew G. Knepley   PetscCall(DMGetWorkArray(sw, bsc + 2, MPIU_REAL, &mom));
2661d52c2f21SMatthew G. Knepley   PetscCall(PetscArrayzero(mom, bsc + 2));
2662d52c2f21SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
2663d52c2f21SMatthew G. Knepley     const PetscReal *c  = &coords[p * bsc];
2664d52c2f21SMatthew G. Knepley     const PetscReal  wp = w[p];
2665d52c2f21SMatthew G. Knepley 
2666d52c2f21SMatthew G. Knepley     mom[0] += wp;
2667d52c2f21SMatthew G. Knepley     for (PetscInt d = 0; d < bsc; ++d) {
2668d52c2f21SMatthew G. Knepley       mom[d + 1] += wp * c[d];
2669d52c2f21SMatthew G. Knepley       mom[d + bsc + 1] += wp * PetscSqr(c[d]);
2670d52c2f21SMatthew G. Knepley     }
2671d52c2f21SMatthew G. Knepley   }
2672d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&coords));
2673d52c2f21SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w));
2674d52c2f21SMatthew G. Knepley   PetscCallMPI(MPIU_Allreduce(mom, moments, bsc + 2, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)sw)));
2675d52c2f21SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(sw, bsc + 2, MPIU_REAL, &mom));
2676d0c080abSJoseph Pusztay   PetscFunctionReturn(PETSC_SUCCESS);
2677d0c080abSJoseph Pusztay }
2678d0c080abSJoseph Pusztay 
2679ce78bad3SBarry Smith static PetscErrorCode DMSetFromOptions_Swarm(DM dm, PetscOptionItems PetscOptionsObject)
2680fca3fa51SMatthew G. Knepley {
2681fca3fa51SMatthew G. Knepley   DM_Swarm *swarm = (DM_Swarm *)dm->data;
2682fca3fa51SMatthew G. Knepley 
2683fca3fa51SMatthew G. Knepley   PetscFunctionBegin;
2684fca3fa51SMatthew G. Knepley   PetscOptionsHeadBegin(PetscOptionsObject, "DMSwarm Options");
2685fca3fa51SMatthew G. Knepley   PetscCall(PetscOptionsEnum("-dm_swarm_remap_type", "Remap algorithm", "DMSwarmSetRemapType", DMSwarmRemapTypeNames, (PetscEnum)swarm->remap_type, (PetscEnum *)&swarm->remap_type, NULL));
2686fca3fa51SMatthew G. Knepley   PetscOptionsHeadEnd();
2687fca3fa51SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2688fca3fa51SMatthew G. Knepley }
2689fca3fa51SMatthew G. Knepley 
2690d0c080abSJoseph Pusztay PETSC_INTERN PetscErrorCode DMClone_Swarm(DM, DM *);
2691d0c080abSJoseph Pusztay 
2692d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMInitialize_Swarm(DM sw)
2693d71ae5a4SJacob Faibussowitsch {
2694d0c080abSJoseph Pusztay   PetscFunctionBegin;
2695d0c080abSJoseph Pusztay   sw->ops->view                     = DMView_Swarm;
2696d0c080abSJoseph Pusztay   sw->ops->load                     = NULL;
2697fca3fa51SMatthew G. Knepley   sw->ops->setfromoptions           = DMSetFromOptions_Swarm;
2698d0c080abSJoseph Pusztay   sw->ops->clone                    = DMClone_Swarm;
2699d0c080abSJoseph Pusztay   sw->ops->setup                    = DMSetup_Swarm;
2700d0c080abSJoseph Pusztay   sw->ops->createlocalsection       = NULL;
2701adc21957SMatthew G. Knepley   sw->ops->createsectionpermutation = NULL;
2702d0c080abSJoseph Pusztay   sw->ops->createdefaultconstraints = NULL;
2703d0c080abSJoseph Pusztay   sw->ops->createglobalvector       = DMCreateGlobalVector_Swarm;
2704d0c080abSJoseph Pusztay   sw->ops->createlocalvector        = DMCreateLocalVector_Swarm;
2705d0c080abSJoseph Pusztay   sw->ops->getlocaltoglobalmapping  = NULL;
2706d0c080abSJoseph Pusztay   sw->ops->createfieldis            = NULL;
2707d0c080abSJoseph Pusztay   sw->ops->createcoordinatedm       = NULL;
270899acd26cSksagiyam   sw->ops->createcellcoordinatedm   = NULL;
2709d0c080abSJoseph Pusztay   sw->ops->getcoloring              = NULL;
2710d0c080abSJoseph Pusztay   sw->ops->creatematrix             = DMCreateMatrix_Swarm;
2711d0c080abSJoseph Pusztay   sw->ops->createinterpolation      = NULL;
2712d0c080abSJoseph Pusztay   sw->ops->createinjection          = NULL;
2713d0c080abSJoseph Pusztay   sw->ops->createmassmatrix         = DMCreateMassMatrix_Swarm;
27141898fd5cSMatthew G. Knepley   sw->ops->creategradientmatrix     = DMCreateGradientMatrix_Swarm;
2715d0c080abSJoseph Pusztay   sw->ops->refine                   = NULL;
2716d0c080abSJoseph Pusztay   sw->ops->coarsen                  = NULL;
2717d0c080abSJoseph Pusztay   sw->ops->refinehierarchy          = NULL;
2718d0c080abSJoseph Pusztay   sw->ops->coarsenhierarchy         = NULL;
27199d50c5ebSMatthew G. Knepley   sw->ops->globaltolocalbegin       = DMGlobalToLocalBegin_Swarm;
27209d50c5ebSMatthew G. Knepley   sw->ops->globaltolocalend         = DMGlobalToLocalEnd_Swarm;
27219d50c5ebSMatthew G. Knepley   sw->ops->localtoglobalbegin       = DMLocalToGlobalBegin_Swarm;
27229d50c5ebSMatthew G. Knepley   sw->ops->localtoglobalend         = DMLocalToGlobalEnd_Swarm;
2723d0c080abSJoseph Pusztay   sw->ops->destroy                  = DMDestroy_Swarm;
2724d0c080abSJoseph Pusztay   sw->ops->createsubdm              = NULL;
2725d0c080abSJoseph Pusztay   sw->ops->getdimpoints             = NULL;
2726d0c080abSJoseph Pusztay   sw->ops->locatepoints             = NULL;
27279d50c5ebSMatthew G. Knepley   sw->ops->projectfieldlocal        = DMProjectFieldLocal_Swarm;
27283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2729d0c080abSJoseph Pusztay }
2730d0c080abSJoseph Pusztay 
2731d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMClone_Swarm(DM dm, DM *newdm)
2732d71ae5a4SJacob Faibussowitsch {
2733d0c080abSJoseph Pusztay   DM_Swarm *swarm = (DM_Swarm *)dm->data;
2734d0c080abSJoseph Pusztay 
2735d0c080abSJoseph Pusztay   PetscFunctionBegin;
2736d0c080abSJoseph Pusztay   swarm->refct++;
2737d0c080abSJoseph Pusztay   (*newdm)->data = swarm;
27389566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMSWARM));
27399566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(*newdm));
27402e56dffeSJoe Pusztay   (*newdm)->dim = dm->dim;
27413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2742d0c080abSJoseph Pusztay }
2743d0c080abSJoseph Pusztay 
2744d3a51819SDave May /*MC
27450b4b7b1cSBarry Smith  DMSWARM = "swarm" - A `DM` object for particle methods, such as particle-in-cell (PIC), in which the underlying
27460b4b7b1cSBarry Smith            data is both (i) dynamic in length, (ii) and of arbitrary data type.
2747d3a51819SDave May 
274820f4b53cSBarry Smith  Level: intermediate
274920f4b53cSBarry Smith 
275020f4b53cSBarry Smith  Notes:
27510b4b7b1cSBarry Smith  User data can be represented by `DMSWARM` through a registering "fields" which are to be stored on particles.
275262741f57SDave May  To register a field, the user must provide;
275362741f57SDave May  (a) a unique name;
275462741f57SDave May  (b) the data type (or size in bytes);
275562741f57SDave May  (c) the block size of the data.
2756d3a51819SDave May 
2757d3a51819SDave May  For example, suppose the application requires a unique id, energy, momentum and density to be stored
2758c215a47eSMatthew Knepley  on a set of particles. Then the following code could be used
275920f4b53cSBarry Smith .vb
276020f4b53cSBarry Smith     DMSwarmInitializeFieldRegister(dm)
276120f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"uid",1,PETSC_LONG);
276220f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"energy",1,PETSC_REAL);
276320f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"momentum",3,PETSC_REAL);
276420f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"density",1,PETSC_FLOAT);
276520f4b53cSBarry Smith     DMSwarmFinalizeFieldRegister(dm)
276620f4b53cSBarry Smith .ve
2767d3a51819SDave May 
276820f4b53cSBarry Smith  The fields represented by `DMSWARM` are dynamic and can be re-sized at any time.
27690b4b7b1cSBarry Smith  The only restriction imposed by `DMSWARM` is that all fields contain the same number of particles.
2770d3a51819SDave May 
2771d3a51819SDave May  To support particle methods, "migration" techniques are provided. These methods migrate data
27725627991aSBarry Smith  between ranks.
2773d3a51819SDave May 
277420f4b53cSBarry Smith  `DMSWARM` supports the methods `DMCreateGlobalVector()` and `DMCreateLocalVector()`.
277520f4b53cSBarry Smith  As a `DMSWARM` may internally define and store values of different data types,
277620f4b53cSBarry Smith  before calling `DMCreateGlobalVector()` or `DMCreateLocalVector()`, the user must inform `DMSWARM` which
27770b4b7b1cSBarry Smith  fields should be used to define a `Vec` object via `DMSwarmVectorDefineField()`
2778c215a47eSMatthew Knepley  The specified field can be changed at any time - thereby permitting vectors
2779c215a47eSMatthew Knepley  compatible with different fields to be created.
2780d3a51819SDave May 
27810b4b7b1cSBarry Smith  A dual representation of fields in the `DMSWARM` and a Vec object is permitted via `DMSwarmCreateGlobalVectorFromField()`
27820b4b7b1cSBarry Smith  Here the data defining the field in the `DMSWARM` is shared with a `Vec`.
2783d3a51819SDave May  This is inherently unsafe if you alter the size of the field at any time between
278420f4b53cSBarry Smith  calls to `DMSwarmCreateGlobalVectorFromField()` and `DMSwarmDestroyGlobalVectorFromField()`.
278520f4b53cSBarry Smith  If the local size of the `DMSWARM` does not match the local size of the global vector
278620f4b53cSBarry Smith  when `DMSwarmDestroyGlobalVectorFromField()` is called, an error is thrown.
2787d3a51819SDave May 
27880b4b7b1cSBarry Smith  Additional high-level support is provided for Particle-In-Cell methods. Refer to `DMSwarmSetType()`.
278962741f57SDave May 
27900b4b7b1cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMType`, `DMCreate()`, `DMSetType()`, `DMSwarmSetType()`, `DMSwarmType`, `DMSwarmCreateGlobalVectorFromField()`,
27910b4b7b1cSBarry Smith          `DMCreateGlobalVector()`, `DMCreateLocalVector()`
2792d3a51819SDave May M*/
2793cc4c1da9SBarry Smith 
2794d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMCreate_Swarm(DM dm)
2795d71ae5a4SJacob Faibussowitsch {
279657795646SDave May   DM_Swarm *swarm;
279757795646SDave May 
279857795646SDave May   PetscFunctionBegin;
279957795646SDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28004dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&swarm));
2801f0cdbbbaSDave May   dm->data = swarm;
28029566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreate(&swarm->db));
28039566063dSJacob Faibussowitsch   PetscCall(DMSwarmInitializeFieldRegister(dm));
2804d52c2f21SMatthew G. Knepley   dm->dim                               = 0;
2805d0c080abSJoseph Pusztay   swarm->refct                          = 1;
28063454631fSDave May   swarm->issetup                        = PETSC_FALSE;
2807480eef7bSDave May   swarm->swarm_type                     = DMSWARM_BASIC;
2808480eef7bSDave May   swarm->migrate_type                   = DMSWARM_MIGRATE_BASIC;
2809480eef7bSDave May   swarm->collect_type                   = DMSWARM_COLLECT_BASIC;
281040c453e9SDave May   swarm->migrate_error_on_missing_point = PETSC_FALSE;
2811f0cdbbbaSDave May   swarm->collect_view_active            = PETSC_FALSE;
2812f0cdbbbaSDave May   swarm->collect_view_reset_nlocal      = -1;
28139566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(dm));
28142e956fe4SStefano Zampini   if (SwarmDataFieldId == -1) PetscCall(PetscObjectComposedDataRegister(&SwarmDataFieldId));
28153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
281657795646SDave May }
281719307e5cSMatthew G. Knepley 
281819307e5cSMatthew G. Knepley /* Replace dm with the contents of ndm, and then destroy ndm
281919307e5cSMatthew G. Knepley    - Share the DM_Swarm structure
282019307e5cSMatthew G. Knepley */
282119307e5cSMatthew G. Knepley PetscErrorCode DMSwarmReplace(DM dm, DM *ndm)
282219307e5cSMatthew G. Knepley {
282319307e5cSMatthew G. Knepley   DM               dmNew = *ndm;
282419307e5cSMatthew G. Knepley   const PetscReal *maxCell, *Lstart, *L;
282519307e5cSMatthew G. Knepley   PetscInt         dim;
282619307e5cSMatthew G. Knepley 
282719307e5cSMatthew G. Knepley   PetscFunctionBegin;
282819307e5cSMatthew G. Knepley   if (dm == dmNew) {
282919307e5cSMatthew G. Knepley     PetscCall(DMDestroy(ndm));
283019307e5cSMatthew G. Knepley     PetscFunctionReturn(PETSC_SUCCESS);
283119307e5cSMatthew G. Knepley   }
283219307e5cSMatthew G. Knepley   dm->setupcalled = dmNew->setupcalled;
283319307e5cSMatthew G. Knepley   if (!dm->hdr.name) {
283419307e5cSMatthew G. Knepley     const char *name;
283519307e5cSMatthew G. Knepley 
283619307e5cSMatthew G. Knepley     PetscCall(PetscObjectGetName((PetscObject)*ndm, &name));
283719307e5cSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)dm, name));
283819307e5cSMatthew G. Knepley   }
283919307e5cSMatthew G. Knepley   PetscCall(DMGetDimension(dmNew, &dim));
284019307e5cSMatthew G. Knepley   PetscCall(DMSetDimension(dm, dim));
284119307e5cSMatthew G. Knepley   PetscCall(DMGetPeriodicity(dmNew, &maxCell, &Lstart, &L));
284219307e5cSMatthew G. Knepley   PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
284319307e5cSMatthew G. Knepley   PetscCall(DMDestroy_Swarm(dm));
284419307e5cSMatthew G. Knepley   PetscCall(DMInitialize_Swarm(dm));
284519307e5cSMatthew G. Knepley   dm->data = dmNew->data;
284619307e5cSMatthew G. Knepley   ((DM_Swarm *)dmNew->data)->refct++;
284719307e5cSMatthew G. Knepley   PetscCall(DMDestroy(ndm));
284819307e5cSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
284919307e5cSMatthew G. Knepley }
2850fca3fa51SMatthew G. Knepley 
2851fca3fa51SMatthew G. Knepley /*@
2852fca3fa51SMatthew G. Knepley   DMSwarmDuplicate - Creates a new `DMSWARM` with the same fields and cell `DM`s but no particles
2853fca3fa51SMatthew G. Knepley 
2854fca3fa51SMatthew G. Knepley   Collective
2855fca3fa51SMatthew G. Knepley 
2856fca3fa51SMatthew G. Knepley   Input Parameter:
2857fca3fa51SMatthew G. Knepley . sw - the `DMSWARM`
2858fca3fa51SMatthew G. Knepley 
2859fca3fa51SMatthew G. Knepley   Output Parameter:
2860fca3fa51SMatthew G. Knepley . nsw - the new `DMSWARM`
2861fca3fa51SMatthew G. Knepley 
2862fca3fa51SMatthew G. Knepley   Level: beginner
2863fca3fa51SMatthew G. Knepley 
2864fca3fa51SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmCreate()`, `DMClone()`
2865fca3fa51SMatthew G. Knepley @*/
2866fca3fa51SMatthew G. Knepley PetscErrorCode DMSwarmDuplicate(DM sw, DM *nsw)
2867fca3fa51SMatthew G. Knepley {
2868fca3fa51SMatthew G. Knepley   DM_Swarm         *swarm = (DM_Swarm *)sw->data;
2869fca3fa51SMatthew G. Knepley   DMSwarmDataField *fields;
2870fca3fa51SMatthew G. Knepley   DMSwarmCellDM     celldm, ncelldm;
2871fca3fa51SMatthew G. Knepley   DMSwarmType       stype;
2872fca3fa51SMatthew G. Knepley   const char       *name, **celldmnames;
2873fca3fa51SMatthew G. Knepley   void             *ctx;
2874fca3fa51SMatthew G. Knepley   PetscInt          dim, Nf, Ndm;
2875fca3fa51SMatthew G. Knepley   PetscBool         flg;
2876fca3fa51SMatthew G. Knepley 
2877fca3fa51SMatthew G. Knepley   PetscFunctionBegin;
2878fca3fa51SMatthew G. Knepley   PetscCall(DMCreate(PetscObjectComm((PetscObject)sw), nsw));
2879fca3fa51SMatthew G. Knepley   PetscCall(DMSetType(*nsw, DMSWARM));
2880fca3fa51SMatthew G. Knepley   PetscCall(PetscObjectGetName((PetscObject)sw, &name));
2881fca3fa51SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*nsw, name));
2882fca3fa51SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2883fca3fa51SMatthew G. Knepley   PetscCall(DMSetDimension(*nsw, dim));
2884fca3fa51SMatthew G. Knepley   PetscCall(DMSwarmGetType(sw, &stype));
2885fca3fa51SMatthew G. Knepley   PetscCall(DMSwarmSetType(*nsw, stype));
2886fca3fa51SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &ctx));
2887fca3fa51SMatthew G. Knepley   PetscCall(DMSetApplicationContext(*nsw, ctx));
2888fca3fa51SMatthew G. Knepley 
2889fca3fa51SMatthew G. Knepley   PetscCall(DMSwarmDataBucketGetDMSwarmDataFields(swarm->db, &Nf, &fields));
2890fca3fa51SMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) {
2891fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmDataFieldStringInList(fields[f]->name, ((DM_Swarm *)(*nsw)->data)->db->nfields, (const DMSwarmDataField *)((DM_Swarm *)(*nsw)->data)->db->field, &flg));
2892fca3fa51SMatthew G. Knepley     if (!flg) PetscCall(DMSwarmRegisterPetscDatatypeField(*nsw, fields[f]->name, fields[f]->bs, fields[f]->petsc_type));
2893fca3fa51SMatthew G. Knepley   }
2894fca3fa51SMatthew G. Knepley 
2895fca3fa51SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMNames(sw, &Ndm, &celldmnames));
2896fca3fa51SMatthew G. Knepley   for (PetscInt c = 0; c < Ndm; ++c) {
2897fca3fa51SMatthew G. Knepley     DM           dm;
2898fca3fa51SMatthew G. Knepley     PetscInt     Ncf;
2899fca3fa51SMatthew G. Knepley     const char **coordfields, **fields;
2900fca3fa51SMatthew G. Knepley 
2901fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmGetCellDMByName(sw, celldmnames[c], &celldm));
2902fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmCellDMGetDM(celldm, &dm));
2903fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Ncf, &coordfields));
2904fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmCellDMGetFields(celldm, &Nf, &fields));
2905fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmCellDMCreate(dm, Nf, fields, Ncf, coordfields, &ncelldm));
2906fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmAddCellDM(*nsw, ncelldm));
2907fca3fa51SMatthew G. Knepley     PetscCall(DMSwarmCellDMDestroy(&ncelldm));
2908fca3fa51SMatthew G. Knepley   }
2909fca3fa51SMatthew G. Knepley   PetscCall(PetscFree(celldmnames));
2910fca3fa51SMatthew G. Knepley 
2911fca3fa51SMatthew G. Knepley   PetscCall(DMSetFromOptions(*nsw));
2912fca3fa51SMatthew G. Knepley   PetscCall(DMSetUp(*nsw));
2913fca3fa51SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
2914fca3fa51SMatthew G. Knepley   PetscCall(PetscObjectGetName((PetscObject)celldm, &name));
2915fca3fa51SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(*nsw, name));
2916fca3fa51SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2917fca3fa51SMatthew G. Knepley }
29189d50c5ebSMatthew G. Knepley 
29199d50c5ebSMatthew G. Knepley PetscErrorCode DMLocalToGlobalBegin_Swarm(DM dm, Vec l, InsertMode mode, Vec g)
29209d50c5ebSMatthew G. Knepley {
29219d50c5ebSMatthew G. Knepley   PetscFunctionBegin;
29229d50c5ebSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
29239d50c5ebSMatthew G. Knepley }
29249d50c5ebSMatthew G. Knepley 
29259d50c5ebSMatthew G. Knepley PetscErrorCode DMLocalToGlobalEnd_Swarm(DM dm, Vec l, InsertMode mode, Vec g)
29269d50c5ebSMatthew G. Knepley {
29279d50c5ebSMatthew G. Knepley   PetscFunctionBegin;
29289d50c5ebSMatthew G. Knepley   switch (mode) {
29299d50c5ebSMatthew G. Knepley   case INSERT_VALUES:
29309d50c5ebSMatthew G. Knepley     PetscCall(VecCopy(l, g));
29319d50c5ebSMatthew G. Knepley     break;
29329d50c5ebSMatthew G. Knepley   case ADD_VALUES:
29339d50c5ebSMatthew G. Knepley     PetscCall(VecAXPY(g, 1., l));
29349d50c5ebSMatthew G. Knepley     break;
29359d50c5ebSMatthew G. Knepley   default:
29369d50c5ebSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mode not supported: %d", mode);
29379d50c5ebSMatthew G. Knepley   }
29389d50c5ebSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
29399d50c5ebSMatthew G. Knepley }
29409d50c5ebSMatthew G. Knepley 
29419d50c5ebSMatthew G. Knepley PetscErrorCode DMGlobalToLocalBegin_Swarm(DM dm, Vec g, InsertMode mode, Vec l)
29429d50c5ebSMatthew G. Knepley {
29439d50c5ebSMatthew G. Knepley   PetscFunctionBegin;
29449d50c5ebSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
29459d50c5ebSMatthew G. Knepley }
29469d50c5ebSMatthew G. Knepley 
29479d50c5ebSMatthew G. Knepley PetscErrorCode DMGlobalToLocalEnd_Swarm(DM dm, Vec g, InsertMode mode, Vec l)
29489d50c5ebSMatthew G. Knepley {
29499d50c5ebSMatthew G. Knepley   PetscFunctionBegin;
29509d50c5ebSMatthew G. Knepley   PetscCall(DMLocalToGlobalEnd_Swarm(dm, g, mode, l));
29519d50c5ebSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
29529d50c5ebSMatthew G. Knepley }
2953