xref: /petsc/src/dm/impls/swarm/swarm.c (revision 20f4b53cbb5e9bd9ef12b76a8697d60d197cda17)
157795646SDave May #define PETSCDM_DLL
257795646SDave May #include <petsc/private/dmswarmimpl.h> /*I   "petscdmswarm.h"   I*/
3e8f14785SLisandro Dalcin #include <petsc/private/hashsetij.h>
40643ed39SMatthew G. Knepley #include <petsc/private/petscfeimpl.h>
55917a6f0SStefano Zampini #include <petscviewer.h>
65917a6f0SStefano Zampini #include <petscdraw.h>
783c47955SMatthew G. Knepley #include <petscdmplex.h>
84cc7f7b2SMatthew G. Knepley #include <petscblaslapack.h>
9279f676cSBarry Smith #include "../src/dm/impls/swarm/data_bucket.h"
10d0c080abSJoseph Pusztay #include <petscdmlabel.h>
11d0c080abSJoseph Pusztay #include <petscsection.h>
1257795646SDave May 
13f2b2bee7SDave May PetscLogEvent DMSWARM_Migrate, DMSWARM_SetSizes, DMSWARM_AddPoints, DMSWARM_RemovePoints, DMSWARM_Sort;
14ed923d71SDave May PetscLogEvent DMSWARM_DataExchangerTopologySetup, DMSWARM_DataExchangerBegin, DMSWARM_DataExchangerEnd;
15ed923d71SDave May PetscLogEvent DMSWARM_DataExchangerSendCount, DMSWARM_DataExchangerPack;
16ed923d71SDave May 
17ea78f98cSLisandro Dalcin const char *DMSwarmTypeNames[]          = {"basic", "pic", NULL};
18ea78f98cSLisandro Dalcin const char *DMSwarmMigrateTypeNames[]   = {"basic", "dmcellnscatter", "dmcellexact", "user", NULL};
19ea78f98cSLisandro Dalcin const char *DMSwarmCollectTypeNames[]   = {"basic", "boundingbox", "general", "user", NULL};
20ea78f98cSLisandro Dalcin const char *DMSwarmPICLayoutTypeNames[] = {"regular", "gauss", "subdivision", NULL};
21f0cdbbbaSDave May 
22f0cdbbbaSDave May const char DMSwarmField_pid[]       = "DMSwarm_pid";
23f0cdbbbaSDave May const char DMSwarmField_rank[]      = "DMSwarm_rank";
24f0cdbbbaSDave May const char DMSwarmPICField_coor[]   = "DMSwarmPIC_coor";
25e2d107dbSDave May const char DMSwarmPICField_cellid[] = "DMSwarm_cellid";
26f0cdbbbaSDave May 
272e956fe4SStefano Zampini PetscInt SwarmDataFieldId = -1;
282e956fe4SStefano Zampini 
2974d0cae8SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
3074d0cae8SMatthew G. Knepley   #include <petscviewerhdf5.h>
3174d0cae8SMatthew G. Knepley 
32d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Swarm_HDF5_Internal(Vec v, PetscViewer viewer)
33d71ae5a4SJacob Faibussowitsch {
3474d0cae8SMatthew G. Knepley   DM        dm;
3574d0cae8SMatthew G. Knepley   PetscReal seqval;
3674d0cae8SMatthew G. Knepley   PetscInt  seqnum, bs;
3774d0cae8SMatthew G. Knepley   PetscBool isseq;
3874d0cae8SMatthew G. Knepley 
3974d0cae8SMatthew G. Knepley   PetscFunctionBegin;
409566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
419566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v, &bs));
429566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PushGroup(viewer, "/particle_fields"));
439566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
449566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, &seqval));
459566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum));
469566063dSJacob Faibussowitsch   /* PetscCall(DMSequenceView_HDF5(dm, "time", seqnum, (PetscScalar) seqval, viewer)); */
479566063dSJacob Faibussowitsch   PetscCall(VecViewNative(v, viewer));
489566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)v, "Nc", PETSC_INT, (void *)&bs));
499566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PopGroup(viewer));
503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5174d0cae8SMatthew G. Knepley }
5274d0cae8SMatthew G. Knepley 
53d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmView_HDF5(DM dm, PetscViewer viewer)
54d71ae5a4SJacob Faibussowitsch {
5574d0cae8SMatthew G. Knepley   Vec       coordinates;
5674d0cae8SMatthew G. Knepley   PetscInt  Np;
5774d0cae8SMatthew G. Knepley   PetscBool isseq;
5874d0cae8SMatthew G. Knepley 
5974d0cae8SMatthew G. Knepley   PetscFunctionBegin;
609566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetSize(dm, &Np));
619566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateGlobalVectorFromField(dm, DMSwarmPICField_coor, &coordinates));
629566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
639566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PushGroup(viewer, "/particles"));
649566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)coordinates, VECSEQ, &isseq));
659566063dSJacob Faibussowitsch   PetscCall(VecViewNative(coordinates, viewer));
669566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)coordinates, "Np", PETSC_INT, (void *)&Np));
679566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PopGroup(viewer));
689566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyGlobalVectorFromField(dm, DMSwarmPICField_coor, &coordinates));
693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7074d0cae8SMatthew G. Knepley }
7174d0cae8SMatthew G. Knepley #endif
7274d0cae8SMatthew G. Knepley 
73d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Swarm(Vec v, PetscViewer viewer)
74d71ae5a4SJacob Faibussowitsch {
7574d0cae8SMatthew G. Knepley   DM dm;
76f9558f5cSBarry Smith #if defined(PETSC_HAVE_HDF5)
7774d0cae8SMatthew G. Knepley   PetscBool ishdf5;
78f9558f5cSBarry Smith #endif
7974d0cae8SMatthew G. Knepley 
8074d0cae8SMatthew G. Knepley   PetscFunctionBegin;
819566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
8228b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
83f9558f5cSBarry Smith #if defined(PETSC_HAVE_HDF5)
849566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
8574d0cae8SMatthew G. Knepley   if (ishdf5) {
869566063dSJacob Faibussowitsch     PetscCall(VecView_Swarm_HDF5_Internal(v, viewer));
873ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
8874d0cae8SMatthew G. Knepley   }
89f9558f5cSBarry Smith #endif
909566063dSJacob Faibussowitsch   PetscCall(VecViewNative(v, viewer));
913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9274d0cae8SMatthew G. Knepley }
9374d0cae8SMatthew G. Knepley 
94d3a51819SDave May /*@C
95*20f4b53cSBarry Smith    DMSwarmVectorDefineField - Sets the field from which to define a `Vec` object
96*20f4b53cSBarry Smith                              when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
9757795646SDave May 
98*20f4b53cSBarry Smith    Collective
9957795646SDave May 
100d3a51819SDave May    Input parameters:
101*20f4b53cSBarry Smith +  dm - a `DMSWARM`
10262741f57SDave May -  fieldname - the textual name given to a registered field
10357795646SDave May 
104d3a51819SDave May    Level: beginner
10557795646SDave May 
106d3a51819SDave May    Notes:
107*20f4b53cSBarry Smith    The field with name `fieldname` must be defined as having a data type of `PetscScalar`.
108e7af74c8SDave May 
109*20f4b53cSBarry Smith    This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`.
110*20f4b53cSBarry Smith    Multiple calls to `DMSwarmVectorDefineField()` are permitted.
111e7af74c8SDave May 
112*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
113d3a51819SDave May @*/
114d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmVectorDefineField(DM dm, const char fieldname[])
115d71ae5a4SJacob Faibussowitsch {
116b5bcf523SDave May   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
117b5bcf523SDave May   PetscInt      bs, n;
118b5bcf523SDave May   PetscScalar  *array;
119b5bcf523SDave May   PetscDataType type;
120b5bcf523SDave May 
121a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
1229566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
1239566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
1249566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array));
125b5bcf523SDave May 
126b5bcf523SDave May   /* Check all fields are of type PETSC_REAL or PETSC_SCALAR */
12708401ef6SPierre Jolivet   PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
1289566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(swarm->vec_field_name, PETSC_MAX_PATH_LEN - 1, "%s", fieldname));
129b5bcf523SDave May   swarm->vec_field_set    = PETSC_TRUE;
1301b1ea282SDave May   swarm->vec_field_bs     = bs;
131b5bcf523SDave May   swarm->vec_field_nlocal = n;
1329566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, fieldname, &bs, &type, (void **)&array));
1333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
134b5bcf523SDave May }
135b5bcf523SDave May 
136cc651181SDave May /* requires DMSwarmDefineFieldVector has been called */
137d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateGlobalVector_Swarm(DM dm, Vec *vec)
138d71ae5a4SJacob Faibussowitsch {
139b5bcf523SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
140b5bcf523SDave May   Vec       x;
141b5bcf523SDave May   char      name[PETSC_MAX_PATH_LEN];
142b5bcf523SDave May 
143a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
1449566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
14528b400f6SJacob Faibussowitsch   PetscCheck(swarm->vec_field_set, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmVectorDefineField first");
14608401ef6SPierre Jolivet   PetscCheck(swarm->vec_field_nlocal == swarm->db->L, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSwarm sizes have changed since last call to VectorDefineField first"); /* Stale data */
147cc651181SDave May 
1489566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmField_%s", swarm->vec_field_name));
1499566063dSJacob Faibussowitsch   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &x));
1509566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)x, name));
1519566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(x, swarm->db->L * swarm->vec_field_bs, PETSC_DETERMINE));
1529566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(x, swarm->vec_field_bs));
1539566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
1549566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(x));
1559566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
1569566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(x, VECOP_VIEW, (void (*)(void))VecView_Swarm));
157b5bcf523SDave May   *vec = x;
1583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
159b5bcf523SDave May }
160b5bcf523SDave May 
161b5bcf523SDave May /* requires DMSwarmDefineFieldVector has been called */
162d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateLocalVector_Swarm(DM dm, Vec *vec)
163d71ae5a4SJacob Faibussowitsch {
164b5bcf523SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
165b5bcf523SDave May   Vec       x;
166b5bcf523SDave May   char      name[PETSC_MAX_PATH_LEN];
167b5bcf523SDave May 
168a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
1699566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
17028b400f6SJacob Faibussowitsch   PetscCheck(swarm->vec_field_set, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmVectorDefineField first");
17108401ef6SPierre Jolivet   PetscCheck(swarm->vec_field_nlocal == swarm->db->L, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSwarm sizes have changed since last call to VectorDefineField first");
172cc651181SDave May 
1739566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmField_%s", swarm->vec_field_name));
1749566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &x));
1759566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)x, name));
1769566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(x, swarm->db->L * swarm->vec_field_bs, PETSC_DETERMINE));
1779566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(x, swarm->vec_field_bs));
1789566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
1799566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(x));
180b5bcf523SDave May   *vec = x;
1813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
182b5bcf523SDave May }
183b5bcf523SDave May 
184d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmDestroyVectorFromField_Private(DM dm, const char fieldname[], Vec *vec)
185d71ae5a4SJacob Faibussowitsch {
186fb1bcc12SMatthew G. Knepley   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
18777048351SPatrick Sanan   DMSwarmDataField gfield;
1882e956fe4SStefano Zampini   PetscInt         bs, nlocal, fid = -1, cfid = -2;
1892e956fe4SStefano Zampini   PetscBool        flg;
190d3a51819SDave May 
191fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
1922e956fe4SStefano Zampini   /* check vector is an inplace array */
1932e956fe4SStefano Zampini   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
1942e956fe4SStefano Zampini   PetscCall(PetscObjectComposedDataGetInt((PetscObject)*vec, SwarmDataFieldId, cfid, flg));
1952e956fe4SStefano Zampini   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);
1969566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(*vec, &nlocal));
1979566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(*vec, &bs));
19808401ef6SPierre 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");
1999566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
2009566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
2018df78e51SMark Adams   PetscCall(VecResetArray(*vec));
2029566063dSJacob Faibussowitsch   PetscCall(VecDestroy(vec));
2033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
204fb1bcc12SMatthew G. Knepley }
205fb1bcc12SMatthew G. Knepley 
206d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmCreateVectorFromField_Private(DM dm, const char fieldname[], MPI_Comm comm, Vec *vec)
207d71ae5a4SJacob Faibussowitsch {
208fb1bcc12SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
209fb1bcc12SMatthew G. Knepley   PetscDataType type;
210fb1bcc12SMatthew G. Knepley   PetscScalar  *array;
2112e956fe4SStefano Zampini   PetscInt      bs, n, fid;
212fb1bcc12SMatthew G. Knepley   char          name[PETSC_MAX_PATH_LEN];
213e4fbd051SBarry Smith   PetscMPIInt   size;
2148df78e51SMark Adams   PetscBool     iscuda, iskokkos;
215fb1bcc12SMatthew G. Knepley 
216fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
2179566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
2189566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
2199566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array));
22008401ef6SPierre Jolivet   PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
221fb1bcc12SMatthew G. Knepley 
2229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
2238df78e51SMark Adams   PetscCall(PetscStrcmp(dm->vectype, VECKOKKOS, &iskokkos));
2248df78e51SMark Adams   PetscCall(PetscStrcmp(dm->vectype, VECCUDA, &iscuda));
2258df78e51SMark Adams   PetscCall(VecCreate(comm, vec));
2268df78e51SMark Adams   PetscCall(VecSetSizes(*vec, n * bs, PETSC_DETERMINE));
2278df78e51SMark Adams   PetscCall(VecSetBlockSize(*vec, bs));
2288df78e51SMark Adams   if (iskokkos) PetscCall(VecSetType(*vec, VECKOKKOS));
2298df78e51SMark Adams   else if (iscuda) PetscCall(VecSetType(*vec, VECCUDA));
2308df78e51SMark Adams   else PetscCall(VecSetType(*vec, VECSTANDARD));
2318df78e51SMark Adams   PetscCall(VecPlaceArray(*vec, array));
2328df78e51SMark Adams 
2339566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmSharedField_%s", fieldname));
2349566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*vec, name));
235fb1bcc12SMatthew G. Knepley 
236fb1bcc12SMatthew G. Knepley   /* Set guard */
2372e956fe4SStefano Zampini   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
2382e956fe4SStefano Zampini   PetscCall(PetscObjectComposedDataSetInt((PetscObject)*vec, SwarmDataFieldId, fid));
23974d0cae8SMatthew G. Knepley 
2409566063dSJacob Faibussowitsch   PetscCall(VecSetDM(*vec, dm));
2419566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Swarm));
2423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
243fb1bcc12SMatthew G. Knepley }
244fb1bcc12SMatthew G. Knepley 
2450643ed39SMatthew G. Knepley /* This creates a "mass matrix" between a finite element and particle space. If a finite element interpolant is given by
2460643ed39SMatthew G. Knepley 
2470643ed39SMatthew G. Knepley      \hat f = \sum_i f_i \phi_i
2480643ed39SMatthew G. Knepley 
2490643ed39SMatthew G. Knepley    and a particle function is given by
2500643ed39SMatthew G. Knepley 
2510643ed39SMatthew G. Knepley      f = \sum_i w_i \delta(x - x_i)
2520643ed39SMatthew G. Knepley 
2530643ed39SMatthew G. Knepley    then we want to require that
2540643ed39SMatthew G. Knepley 
2550643ed39SMatthew G. Knepley      M \hat f = M_p f
2560643ed39SMatthew G. Knepley 
2570643ed39SMatthew G. Knepley    where the particle mass matrix is given by
2580643ed39SMatthew G. Knepley 
2590643ed39SMatthew G. Knepley      (M_p)_{ij} = \int \phi_i \delta(x - x_j)
2600643ed39SMatthew G. Knepley 
2610643ed39SMatthew G. Knepley    The way Dave May does particles, they amount to quadratue weights rather than delta functions, so he has |J| is in
2620643ed39SMatthew G. Knepley    his integral. We allow this with the boolean flag.
2630643ed39SMatthew G. Knepley */
264d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmComputeMassMatrix_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
265d71ae5a4SJacob Faibussowitsch {
26683c47955SMatthew G. Knepley   const char  *name = "Mass Matrix";
2670643ed39SMatthew G. Knepley   MPI_Comm     comm;
26883c47955SMatthew G. Knepley   PetscDS      prob;
26983c47955SMatthew G. Knepley   PetscSection fsection, globalFSection;
270e8f14785SLisandro Dalcin   PetscHSetIJ  ht;
2710643ed39SMatthew G. Knepley   PetscLayout  rLayout, colLayout;
27283c47955SMatthew G. Knepley   PetscInt    *dnz, *onz;
273adb2528bSMark Adams   PetscInt     locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
2740643ed39SMatthew G. Knepley   PetscReal   *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
27583c47955SMatthew G. Knepley   PetscScalar *elemMat;
2760643ed39SMatthew G. Knepley   PetscInt     dim, Nf, field, cStart, cEnd, cell, totDim, maxC = 0;
27783c47955SMatthew G. Knepley 
27883c47955SMatthew G. Knepley   PetscFunctionBegin;
2799566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
2809566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmf, &dim));
2819566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmf, &prob));
2829566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
2839566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
2849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
2859566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
2869566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
2879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
2889566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
28983c47955SMatthew G. Knepley 
2909566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &colLayout));
2919566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
2929566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
2939566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colLayout));
2949566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
2959566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&colLayout));
2960643ed39SMatthew G. Knepley 
2979566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &rLayout));
2989566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
2999566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
3009566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
3019566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
3029566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
3030643ed39SMatthew G. Knepley 
3049566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
3059566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
30653e60ab4SJoseph Pusztay 
3079566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(comm, NULL));
3080643ed39SMatthew G. Knepley   /* count non-zeros */
3099566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(dmc));
31083c47955SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
31183c47955SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
3120643ed39SMatthew G. Knepley       PetscInt  c, i;
3130643ed39SMatthew G. Knepley       PetscInt *findices, *cindices; /* fine is vertices, coarse is particles */
31483c47955SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
31583c47955SMatthew G. Knepley 
3169566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3179566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
318fc7c92abSMatthew G. Knepley       maxC = PetscMax(maxC, numCIndices);
31983c47955SMatthew G. Knepley       {
320e8f14785SLisandro Dalcin         PetscHashIJKey key;
321e8f14785SLisandro Dalcin         PetscBool      missing;
32283c47955SMatthew G. Knepley         for (i = 0; i < numFIndices; ++i) {
323adb2528bSMark Adams           key.j = findices[i]; /* global column (from Plex) */
324adb2528bSMark Adams           if (key.j >= 0) {
32583c47955SMatthew G. Knepley             /* Get indices for coarse elements */
32683c47955SMatthew G. Knepley             for (c = 0; c < numCIndices; ++c) {
327adb2528bSMark Adams               key.i = cindices[c] + rStart; /* global cols (from Swarm) */
328adb2528bSMark Adams               if (key.i < 0) continue;
3299566063dSJacob Faibussowitsch               PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
33083c47955SMatthew G. Knepley               if (missing) {
3310643ed39SMatthew G. Knepley                 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
332e8f14785SLisandro Dalcin                 else ++onz[key.i - rStart];
33363a3b9bcSJacob Faibussowitsch               } else SETERRQ(PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Set new value at %" PetscInt_FMT ",%" PetscInt_FMT, key.i, key.j);
33483c47955SMatthew G. Knepley             }
335fc7c92abSMatthew G. Knepley           }
336fc7c92abSMatthew G. Knepley         }
3379566063dSJacob Faibussowitsch         PetscCall(PetscFree(cindices));
33883c47955SMatthew G. Knepley       }
3399566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
34083c47955SMatthew G. Knepley     }
34183c47955SMatthew G. Knepley   }
3429566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
3439566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
3449566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
3459566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
3469566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(maxC * totDim, &elemMat, maxC, &rowIDXs, maxC * dim, &xi));
34783c47955SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
348ef0bb6c7SMatthew G. Knepley     PetscTabulation Tcoarse;
34983c47955SMatthew G. Knepley     PetscObject     obj;
350ea7032a0SMatthew G. Knepley     PetscReal      *fieldVals;
3510643ed39SMatthew G. Knepley     PetscInt        Nc, i;
35283c47955SMatthew G. Knepley 
3539566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
3549566063dSJacob Faibussowitsch     PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
35563a3b9bcSJacob Faibussowitsch     PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc);
356ea7032a0SMatthew G. Knepley 
357ea7032a0SMatthew G. Knepley     PetscCall(DMSwarmGetField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&fieldVals));
35883c47955SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
35983c47955SMatthew G. Knepley       PetscInt *findices, *cindices;
36083c47955SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
3610643ed39SMatthew G. Knepley       PetscInt  p, c;
36283c47955SMatthew G. Knepley 
3630643ed39SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
3649566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
3659566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3669566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
367ea7032a0SMatthew G. Knepley       for (p = 0; p < numCIndices; ++p) CoordinatesRealToRef(dim, dim, v0ref, v0, invJ, &fieldVals[cindices[p] * dim], &xi[p * dim]);
3689566063dSJacob Faibussowitsch       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
36983c47955SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
3709566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemMat, numCIndices * totDim));
37183c47955SMatthew G. Knepley       for (i = 0; i < numFIndices; ++i) {
3720643ed39SMatthew G. Knepley         for (p = 0; p < numCIndices; ++p) {
3730643ed39SMatthew G. Knepley           for (c = 0; c < Nc; ++c) {
3740643ed39SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
375ef0bb6c7SMatthew G. Knepley             elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
37683c47955SMatthew G. Knepley           }
3770643ed39SMatthew G. Knepley         }
3780643ed39SMatthew G. Knepley       }
379adb2528bSMark Adams       for (p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart;
3809566063dSJacob Faibussowitsch       if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
3819566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numFIndices, findices, elemMat, ADD_VALUES));
3829566063dSJacob Faibussowitsch       PetscCall(PetscFree(cindices));
3839566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3849566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
38583c47955SMatthew G. Knepley     }
386ea7032a0SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&fieldVals));
38783c47955SMatthew G. Knepley   }
3889566063dSJacob Faibussowitsch   PetscCall(PetscFree3(elemMat, rowIDXs, xi));
3899566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
3909566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
3919566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
3929566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
3933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39483c47955SMatthew G. Knepley }
39583c47955SMatthew G. Knepley 
396d0c080abSJoseph Pusztay /* Returns empty matrix for use with SNES FD */
397d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMatrix_Swarm(DM sw, Mat *m)
398d71ae5a4SJacob Faibussowitsch {
399d0c080abSJoseph Pusztay   Vec      field;
400d0c080abSJoseph Pusztay   PetscInt size;
401d0c080abSJoseph Pusztay 
402d0c080abSJoseph Pusztay   PetscFunctionBegin;
4039566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(sw, &field));
4049566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(field, &size));
4059566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(sw, &field));
4069566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD, m));
4079566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*m));
4089566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*m, PETSC_DECIDE, PETSC_DECIDE, size, size));
4099566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*m, 1, NULL));
4109566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(*m));
4119566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*m, MAT_FINAL_ASSEMBLY));
4129566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*m, MAT_FINAL_ASSEMBLY));
4139566063dSJacob Faibussowitsch   PetscCall(MatShift(*m, 1.0));
4149566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*m, sw));
4153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
416d0c080abSJoseph Pusztay }
417d0c080abSJoseph Pusztay 
418adb2528bSMark Adams /* FEM cols, Particle rows */
419d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMassMatrix_Swarm(DM dmCoarse, DM dmFine, Mat *mass)
420d71ae5a4SJacob Faibussowitsch {
421895a1698SMatthew G. Knepley   PetscSection gsf;
42283c47955SMatthew G. Knepley   PetscInt     m, n;
42383c47955SMatthew G. Knepley   void        *ctx;
42483c47955SMatthew G. Knepley 
42583c47955SMatthew G. Knepley   PetscFunctionBegin;
4269566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
4279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
4289566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dmCoarse, &n));
4299566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
4309566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, m, PETSC_DETERMINE, PETSC_DETERMINE));
4319566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
4329566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
43383c47955SMatthew G. Knepley 
4349566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrix_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
4359566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
4363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43783c47955SMatthew G. Knepley }
43883c47955SMatthew G. Knepley 
439d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmComputeMassMatrixSquare_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
440d71ae5a4SJacob Faibussowitsch {
4414cc7f7b2SMatthew G. Knepley   const char  *name = "Mass Matrix Square";
4424cc7f7b2SMatthew G. Knepley   MPI_Comm     comm;
4434cc7f7b2SMatthew G. Knepley   PetscDS      prob;
4444cc7f7b2SMatthew G. Knepley   PetscSection fsection, globalFSection;
4454cc7f7b2SMatthew G. Knepley   PetscHSetIJ  ht;
4464cc7f7b2SMatthew G. Knepley   PetscLayout  rLayout, colLayout;
4474cc7f7b2SMatthew G. Knepley   PetscInt    *dnz, *onz, *adj, depth, maxConeSize, maxSupportSize, maxAdjSize;
4484cc7f7b2SMatthew G. Knepley   PetscInt     locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
4494cc7f7b2SMatthew G. Knepley   PetscReal   *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
4504cc7f7b2SMatthew G. Knepley   PetscScalar *elemMat, *elemMatSq;
4514cc7f7b2SMatthew G. Knepley   PetscInt     cdim, Nf, field, cStart, cEnd, cell, totDim, maxC = 0;
4524cc7f7b2SMatthew G. Knepley 
4534cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
4549566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
4559566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmf, &cdim));
4569566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmf, &prob));
4579566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
4589566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
4599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(cdim, &v0, cdim * cdim, &J, cdim * cdim, &invJ));
4609566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
4619566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
4629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
4639566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
4644cc7f7b2SMatthew G. Knepley 
4659566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &colLayout));
4669566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
4679566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
4689566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colLayout));
4699566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
4709566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&colLayout));
4714cc7f7b2SMatthew G. Knepley 
4729566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &rLayout));
4739566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
4749566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
4759566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
4769566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
4779566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
4784cc7f7b2SMatthew G. Knepley 
4799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmf, &depth));
4809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dmf, &maxConeSize, &maxSupportSize));
4814cc7f7b2SMatthew G. Knepley   maxAdjSize = PetscPowInt(maxConeSize * maxSupportSize, depth);
4829566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxAdjSize, &adj));
4834cc7f7b2SMatthew G. Knepley 
4849566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
4859566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
4864cc7f7b2SMatthew G. Knepley   /* Count nonzeros
4874cc7f7b2SMatthew G. Knepley        This is just FVM++, but we cannot use the Plex P0 allocation since unknowns in a cell will not be contiguous
4884cc7f7b2SMatthew G. Knepley   */
4899566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(dmc));
4904cc7f7b2SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
4914cc7f7b2SMatthew G. Knepley     PetscInt  i;
4924cc7f7b2SMatthew G. Knepley     PetscInt *cindices;
4934cc7f7b2SMatthew G. Knepley     PetscInt  numCIndices;
4944cc7f7b2SMatthew G. Knepley #if 0
4954cc7f7b2SMatthew G. Knepley     PetscInt  adjSize = maxAdjSize, a, j;
4964cc7f7b2SMatthew G. Knepley #endif
4974cc7f7b2SMatthew G. Knepley 
4989566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
4994cc7f7b2SMatthew G. Knepley     maxC = PetscMax(maxC, numCIndices);
5004cc7f7b2SMatthew G. Knepley     /* Diagonal block */
501ad540459SPierre Jolivet     for (i = 0; i < numCIndices; ++i) dnz[cindices[i]] += numCIndices;
5024cc7f7b2SMatthew G. Knepley #if 0
5034cc7f7b2SMatthew G. Knepley     /* Off-diagonal blocks */
5049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(dmf, cell, &adjSize, &adj));
5054cc7f7b2SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
5064cc7f7b2SMatthew G. Knepley       if (adj[a] >= cStart && adj[a] < cEnd && adj[a] != cell) {
5074cc7f7b2SMatthew G. Knepley         const PetscInt ncell = adj[a];
5084cc7f7b2SMatthew G. Knepley         PetscInt      *ncindices;
5094cc7f7b2SMatthew G. Knepley         PetscInt       numNCIndices;
5104cc7f7b2SMatthew G. Knepley 
5119566063dSJacob Faibussowitsch         PetscCall(DMSwarmSortGetPointsPerCell(dmc, ncell, &numNCIndices, &ncindices));
5124cc7f7b2SMatthew G. Knepley         {
5134cc7f7b2SMatthew G. Knepley           PetscHashIJKey key;
5144cc7f7b2SMatthew G. Knepley           PetscBool      missing;
5154cc7f7b2SMatthew G. Knepley 
5164cc7f7b2SMatthew G. Knepley           for (i = 0; i < numCIndices; ++i) {
5174cc7f7b2SMatthew G. Knepley             key.i = cindices[i] + rStart; /* global rows (from Swarm) */
5184cc7f7b2SMatthew G. Knepley             if (key.i < 0) continue;
5194cc7f7b2SMatthew G. Knepley             for (j = 0; j < numNCIndices; ++j) {
5204cc7f7b2SMatthew G. Knepley               key.j = ncindices[j] + rStart; /* global column (from Swarm) */
5214cc7f7b2SMatthew G. Knepley               if (key.j < 0) continue;
5229566063dSJacob Faibussowitsch               PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
5234cc7f7b2SMatthew G. Knepley               if (missing) {
5244cc7f7b2SMatthew G. Knepley                 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
5254cc7f7b2SMatthew G. Knepley                 else                                         ++onz[key.i - rStart];
5264cc7f7b2SMatthew G. Knepley               }
5274cc7f7b2SMatthew G. Knepley             }
5284cc7f7b2SMatthew G. Knepley           }
5294cc7f7b2SMatthew G. Knepley         }
5309566063dSJacob Faibussowitsch         PetscCall(PetscFree(ncindices));
5314cc7f7b2SMatthew G. Knepley       }
5324cc7f7b2SMatthew G. Knepley     }
5334cc7f7b2SMatthew G. Knepley #endif
5349566063dSJacob Faibussowitsch     PetscCall(PetscFree(cindices));
5354cc7f7b2SMatthew G. Knepley   }
5369566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
5379566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
5389566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
5399566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
5409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(maxC * totDim, &elemMat, maxC * maxC, &elemMatSq, maxC, &rowIDXs, maxC * cdim, &xi));
5414cc7f7b2SMatthew G. Knepley   /* Fill in values
5424cc7f7b2SMatthew G. Knepley        Each entry is a sum of terms \phi_i(x_p) \phi_i(x_q)
5434cc7f7b2SMatthew G. Knepley        Start just by producing block diagonal
5444cc7f7b2SMatthew G. Knepley        Could loop over adjacent cells
5454cc7f7b2SMatthew G. Knepley          Produce neighboring element matrix
5464cc7f7b2SMatthew G. Knepley          TODO Determine which columns and rows correspond to shared dual vector
5474cc7f7b2SMatthew G. Knepley          Do MatMatMult with rectangular matrices
5484cc7f7b2SMatthew G. Knepley          Insert block
5494cc7f7b2SMatthew G. Knepley   */
5504cc7f7b2SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
5514cc7f7b2SMatthew G. Knepley     PetscTabulation Tcoarse;
5524cc7f7b2SMatthew G. Knepley     PetscObject     obj;
5534cc7f7b2SMatthew G. Knepley     PetscReal      *coords;
5544cc7f7b2SMatthew G. Knepley     PetscInt        Nc, i;
5554cc7f7b2SMatthew G. Knepley 
5569566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
5579566063dSJacob Faibussowitsch     PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
55863a3b9bcSJacob Faibussowitsch     PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc);
5599566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
5604cc7f7b2SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
5614cc7f7b2SMatthew G. Knepley       PetscInt *findices, *cindices;
5624cc7f7b2SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
5634cc7f7b2SMatthew G. Knepley       PetscInt  p, c;
5644cc7f7b2SMatthew G. Knepley 
5654cc7f7b2SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
5669566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
5679566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
5689566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
569ad540459SPierre Jolivet       for (p = 0; p < numCIndices; ++p) CoordinatesRealToRef(cdim, cdim, v0ref, v0, invJ, &coords[cindices[p] * cdim], &xi[p * cdim]);
5709566063dSJacob Faibussowitsch       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
5714cc7f7b2SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
5729566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemMat, numCIndices * totDim));
5734cc7f7b2SMatthew G. Knepley       for (i = 0; i < numFIndices; ++i) {
5744cc7f7b2SMatthew G. Knepley         for (p = 0; p < numCIndices; ++p) {
5754cc7f7b2SMatthew G. Knepley           for (c = 0; c < Nc; ++c) {
5764cc7f7b2SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
5774cc7f7b2SMatthew G. Knepley             elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
5784cc7f7b2SMatthew G. Knepley           }
5794cc7f7b2SMatthew G. Knepley         }
5804cc7f7b2SMatthew G. Knepley       }
5819566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
5824cc7f7b2SMatthew G. Knepley       for (p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart;
5839566063dSJacob Faibussowitsch       if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
5844cc7f7b2SMatthew G. Knepley       /* Block diagonal */
58578884ca7SMatthew G. Knepley       if (numCIndices) {
5864cc7f7b2SMatthew G. Knepley         PetscBLASInt blasn, blask;
5874cc7f7b2SMatthew G. Knepley         PetscScalar  one = 1.0, zero = 0.0;
5884cc7f7b2SMatthew G. Knepley 
5899566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numCIndices, &blasn));
5909566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numFIndices, &blask));
591792fecdfSBarry Smith         PetscCallBLAS("BLASgemm", BLASgemm_("T", "N", &blasn, &blasn, &blask, &one, elemMat, &blask, elemMat, &blask, &zero, elemMatSq, &blasn));
5924cc7f7b2SMatthew G. Knepley       }
5939566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numCIndices, rowIDXs, elemMatSq, ADD_VALUES));
5944cc7f7b2SMatthew G. Knepley       /* TODO Off-diagonal */
5959566063dSJacob Faibussowitsch       PetscCall(PetscFree(cindices));
5969566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
5974cc7f7b2SMatthew G. Knepley     }
5989566063dSJacob Faibussowitsch     PetscCall(DMSwarmRestoreField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
5994cc7f7b2SMatthew G. Knepley   }
6009566063dSJacob Faibussowitsch   PetscCall(PetscFree4(elemMat, elemMatSq, rowIDXs, xi));
6019566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
6029566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
6039566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
6049566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
6059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
6063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6074cc7f7b2SMatthew G. Knepley }
6084cc7f7b2SMatthew G. Knepley 
6094cc7f7b2SMatthew G. Knepley /*@C
6104cc7f7b2SMatthew G. Knepley   DMSwarmCreateMassMatrixSquare - Creates the block-diagonal of the square, M^T_p M_p, of the particle mass matrix M_p
6114cc7f7b2SMatthew G. Knepley 
612*20f4b53cSBarry Smith   Collective
6134cc7f7b2SMatthew G. Knepley 
6144cc7f7b2SMatthew G. Knepley   Input parameters:
615*20f4b53cSBarry Smith + dmCoarse - a `DMSWARM`
616*20f4b53cSBarry Smith - dmFine   - a `DMPLEX`
6174cc7f7b2SMatthew G. Knepley 
6184cc7f7b2SMatthew G. Knepley   Output parameter:
6194cc7f7b2SMatthew G. Knepley . mass     - the square of the particle mass matrix
6204cc7f7b2SMatthew G. Knepley 
6214cc7f7b2SMatthew G. Knepley   Level: advanced
6224cc7f7b2SMatthew G. Knepley 
623*20f4b53cSBarry Smith   Note:
6244cc7f7b2SMatthew G. Knepley   We only compute the block diagonal since this provides a good preconditioner and is completely local. It would be possible in the
6254cc7f7b2SMatthew G. Knepley   future to compute the full normal equations.
6264cc7f7b2SMatthew G. Knepley 
627*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMCreateMassMatrix()`
6284cc7f7b2SMatthew G. Knepley @*/
629d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateMassMatrixSquare(DM dmCoarse, DM dmFine, Mat *mass)
630d71ae5a4SJacob Faibussowitsch {
6314cc7f7b2SMatthew G. Knepley   PetscInt n;
6324cc7f7b2SMatthew G. Knepley   void    *ctx;
6334cc7f7b2SMatthew G. Knepley 
6344cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
6359566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dmCoarse, &n));
6369566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
6379566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, n, PETSC_DETERMINE, PETSC_DETERMINE));
6389566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
6399566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
6404cc7f7b2SMatthew G. Knepley 
6419566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrixSquare_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
6429566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_sq_mat_view"));
6433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6444cc7f7b2SMatthew G. Knepley }
6454cc7f7b2SMatthew G. Knepley 
646fb1bcc12SMatthew G. Knepley /*@C
647*20f4b53cSBarry Smith    DMSwarmCreateGlobalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
648d3a51819SDave May 
649*20f4b53cSBarry Smith    Collective
650d3a51819SDave May 
651d3a51819SDave May    Input parameters:
652*20f4b53cSBarry Smith +  dm - a `DMSWARM`
65362741f57SDave May -  fieldname - the textual name given to a registered field
654d3a51819SDave May 
6558b8a3813SDave May    Output parameter:
656d3a51819SDave May .  vec - the vector
657d3a51819SDave May 
658d3a51819SDave May    Level: beginner
659d3a51819SDave May 
6608b8a3813SDave May    Notes:
661*20f4b53cSBarry Smith    The vector must be returned using a matching call to `DMSwarmDestroyGlobalVectorFromField()`.
6628b8a3813SDave May 
663*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromField()`
664d3a51819SDave May @*/
665d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
666d71ae5a4SJacob Faibussowitsch {
667fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PetscObjectComm((PetscObject)dm);
668b5bcf523SDave May 
669fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
670ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
6719566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
6723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
673b5bcf523SDave May }
674b5bcf523SDave May 
675d3a51819SDave May /*@C
676*20f4b53cSBarry Smith    DMSwarmDestroyGlobalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
677d3a51819SDave May 
678*20f4b53cSBarry Smith    Collective
679d3a51819SDave May 
680d3a51819SDave May    Input parameters:
681*20f4b53cSBarry Smith +  dm - a `DMSWARM`
68262741f57SDave May -  fieldname - the textual name given to a registered field
683d3a51819SDave May 
6848b8a3813SDave May    Output parameter:
685d3a51819SDave May .  vec - the vector
686d3a51819SDave May 
687d3a51819SDave May    Level: beginner
688d3a51819SDave May 
689*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()`
690d3a51819SDave May @*/
691d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
692d71ae5a4SJacob Faibussowitsch {
693fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
694ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
6959566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
6963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
697b5bcf523SDave May }
698b5bcf523SDave May 
699fb1bcc12SMatthew G. Knepley /*@C
700*20f4b53cSBarry Smith    DMSwarmCreateLocalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
701fb1bcc12SMatthew G. Knepley 
702*20f4b53cSBarry Smith    Collective
703fb1bcc12SMatthew G. Knepley 
704fb1bcc12SMatthew G. Knepley    Input parameters:
705*20f4b53cSBarry Smith +  dm - a `DMSWARM`
70662741f57SDave May -  fieldname - the textual name given to a registered field
707fb1bcc12SMatthew G. Knepley 
7088b8a3813SDave May    Output parameter:
709fb1bcc12SMatthew G. Knepley .  vec - the vector
710fb1bcc12SMatthew G. Knepley 
711fb1bcc12SMatthew G. Knepley    Level: beginner
712fb1bcc12SMatthew G. Knepley 
713*20f4b53cSBarry Smith    Note:
7148b8a3813SDave May    The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField().
7158b8a3813SDave May 
716*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()`
717fb1bcc12SMatthew G. Knepley @*/
718d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
719d71ae5a4SJacob Faibussowitsch {
720fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PETSC_COMM_SELF;
721bbe8250bSMatthew G. Knepley 
722fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
7239566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
7243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
725bbe8250bSMatthew G. Knepley }
726fb1bcc12SMatthew G. Knepley 
727fb1bcc12SMatthew G. Knepley /*@C
728*20f4b53cSBarry Smith    DMSwarmDestroyLocalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
729fb1bcc12SMatthew G. Knepley 
730*20f4b53cSBarry Smith    Collective
731fb1bcc12SMatthew G. Knepley 
732fb1bcc12SMatthew G. Knepley    Input parameters:
733*20f4b53cSBarry Smith +  dm - a `DMSWARM`
73462741f57SDave May -  fieldname - the textual name given to a registered field
735fb1bcc12SMatthew G. Knepley 
7368b8a3813SDave May    Output parameter:
737fb1bcc12SMatthew G. Knepley .  vec - the vector
738fb1bcc12SMatthew G. Knepley 
739fb1bcc12SMatthew G. Knepley    Level: beginner
740fb1bcc12SMatthew G. Knepley 
741*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromField()`
742fb1bcc12SMatthew G. Knepley @*/
743d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
744d71ae5a4SJacob Faibussowitsch {
745fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
746ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
7479566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
7483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
749bbe8250bSMatthew G. Knepley }
750bbe8250bSMatthew G. Knepley 
751d3a51819SDave May /*@C
752*20f4b53cSBarry Smith    DMSwarmInitializeFieldRegister - Initiates the registration of fields to a `DMSWARM`
753d3a51819SDave May 
754*20f4b53cSBarry Smith    Collective
755d3a51819SDave May 
756d3a51819SDave May    Input parameter:
757*20f4b53cSBarry Smith .  dm - a `DMSWARM`
758d3a51819SDave May 
759d3a51819SDave May    Level: beginner
760d3a51819SDave May 
761*20f4b53cSBarry Smith    Note:
762*20f4b53cSBarry Smith    After all fields have been registered, you must call `DMSwarmFinalizeFieldRegister()`.
763d3a51819SDave May 
764*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmFinalizeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
765db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
766d3a51819SDave May @*/
767d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmInitializeFieldRegister(DM dm)
768d71ae5a4SJacob Faibussowitsch {
7695f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
7703454631fSDave May 
771521f74f9SMatthew G. Knepley   PetscFunctionBegin;
772cc651181SDave May   if (!swarm->field_registration_initialized) {
7735f50eb2eSDave May     swarm->field_registration_initialized = PETSC_TRUE;
774da81f932SPierre Jolivet     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_pid, 1, PETSC_INT64)); /* unique identifier */
7759566063dSJacob Faibussowitsch     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_rank, 1, PETSC_INT));  /* used for communication */
776cc651181SDave May   }
7773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7785f50eb2eSDave May }
7795f50eb2eSDave May 
78074d0cae8SMatthew G. Knepley /*@
781*20f4b53cSBarry Smith    DMSwarmFinalizeFieldRegister - Finalizes the registration of fields to a `DMSWARM`
782d3a51819SDave May 
783*20f4b53cSBarry Smith    Collective
784d3a51819SDave May 
785d3a51819SDave May    Input parameter:
786*20f4b53cSBarry Smith .  dm - a `DMSWARM`
787d3a51819SDave May 
788d3a51819SDave May    Level: beginner
789d3a51819SDave May 
790*20f4b53cSBarry Smith    Note:
791*20f4b53cSBarry Smith    After `DMSwarmFinalizeFieldRegister()` has been called, no new fields can be defined on the `DMSWARM`.
792d3a51819SDave May 
793*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmInitializeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
794db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
795d3a51819SDave May @*/
796d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmFinalizeFieldRegister(DM dm)
797d71ae5a4SJacob Faibussowitsch {
7985f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
7996845f8f5SDave May 
800521f74f9SMatthew G. Knepley   PetscFunctionBegin;
80148a46eb9SPierre Jolivet   if (!swarm->field_registration_finalized) PetscCall(DMSwarmDataBucketFinalize(swarm->db));
802f0cdbbbaSDave May   swarm->field_registration_finalized = PETSC_TRUE;
8033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8045f50eb2eSDave May }
8055f50eb2eSDave May 
80674d0cae8SMatthew G. Knepley /*@
807*20f4b53cSBarry Smith    DMSwarmSetLocalSizes - Sets the length of all registered fields on the `DMSWARM`
808d3a51819SDave May 
809*20f4b53cSBarry Smith    Not Collective
810d3a51819SDave May 
811d3a51819SDave May    Input parameters:
812*20f4b53cSBarry Smith +  dm - a `DMSWARM`
813d3a51819SDave May .  nlocal - the length of each registered field
81462741f57SDave May -  buffer - the length of the buffer used to efficient dynamic re-sizing
815d3a51819SDave May 
816d3a51819SDave May    Level: beginner
817d3a51819SDave May 
818*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`
819d3a51819SDave May @*/
820d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetLocalSizes(DM dm, PetscInt nlocal, PetscInt buffer)
821d71ae5a4SJacob Faibussowitsch {
8225f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
8235f50eb2eSDave May 
824521f74f9SMatthew G. Knepley   PetscFunctionBegin;
8259566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_SetSizes, 0, 0, 0, 0));
8269566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, buffer));
8279566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_SetSizes, 0, 0, 0, 0));
8283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8295f50eb2eSDave May }
8305f50eb2eSDave May 
83174d0cae8SMatthew G. Knepley /*@
832*20f4b53cSBarry Smith    DMSwarmSetCellDM - Attaches a `DM` to a `DMSWARM`
833d3a51819SDave May 
834*20f4b53cSBarry Smith    Collective
835d3a51819SDave May 
836d3a51819SDave May    Input parameters:
837*20f4b53cSBarry Smith +  dm - a `DMSWARM`
838*20f4b53cSBarry Smith -  dmcell - the `DM` to attach to the `DMSWARM`
839d3a51819SDave May 
840d3a51819SDave May    Level: beginner
841d3a51819SDave May 
842*20f4b53cSBarry Smith    Note:
843*20f4b53cSBarry Smith    The attached `DM` (dmcell) will be queried for point location and
844*20f4b53cSBarry Smith    neighbor MPI-rank information if `DMSwarmMigrate()` is called.
845d3a51819SDave May 
846*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmGetCellDM()`, `DMSwarmMigrate()`
847d3a51819SDave May @*/
848d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetCellDM(DM dm, DM dmcell)
849d71ae5a4SJacob Faibussowitsch {
850b16650c8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
851521f74f9SMatthew G. Knepley 
852521f74f9SMatthew G. Knepley   PetscFunctionBegin;
853b16650c8SDave May   swarm->dmcell = dmcell;
8543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
855b16650c8SDave May }
856b16650c8SDave May 
85774d0cae8SMatthew G. Knepley /*@
858*20f4b53cSBarry Smith    DMSwarmGetCellDM - Fetches the attached cell `DM`
859d3a51819SDave May 
860*20f4b53cSBarry Smith    Collective
861d3a51819SDave May 
862d3a51819SDave May    Input parameter:
863*20f4b53cSBarry Smith .  dm - a `DMSWARM`
864d3a51819SDave May 
865d3a51819SDave May    Output parameter:
866*20f4b53cSBarry Smith .  dmcell - the `DM` which was attached to the `DMSWARM`
867d3a51819SDave May 
868d3a51819SDave May    Level: beginner
869d3a51819SDave May 
870*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
871d3a51819SDave May @*/
872d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetCellDM(DM dm, DM *dmcell)
873d71ae5a4SJacob Faibussowitsch {
874fe39f135SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
875521f74f9SMatthew G. Knepley 
876521f74f9SMatthew G. Knepley   PetscFunctionBegin;
877fe39f135SDave May   *dmcell = swarm->dmcell;
8783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
879fe39f135SDave May }
880fe39f135SDave May 
88174d0cae8SMatthew G. Knepley /*@
882d5b43468SJose E. Roman    DMSwarmGetLocalSize - Retrieves the local length of fields registered
883d3a51819SDave May 
884*20f4b53cSBarry Smith    Not Collective
885d3a51819SDave May 
886d3a51819SDave May    Input parameter:
887*20f4b53cSBarry Smith .  dm - a `DMSWARM`
888d3a51819SDave May 
889d3a51819SDave May    Output parameter:
890d3a51819SDave May .  nlocal - the length of each registered field
891d3a51819SDave May 
892d3a51819SDave May    Level: beginner
893d3a51819SDave May 
894*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetSize()`, `DMSwarmSetLocalSizes()`
895d3a51819SDave May @*/
896d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetLocalSize(DM dm, PetscInt *nlocal)
897d71ae5a4SJacob Faibussowitsch {
898dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
899dcf43ee8SDave May 
900521f74f9SMatthew G. Knepley   PetscFunctionBegin;
9019566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, nlocal, NULL, NULL));
9023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
903dcf43ee8SDave May }
904dcf43ee8SDave May 
90574d0cae8SMatthew G. Knepley /*@
906d5b43468SJose E. Roman    DMSwarmGetSize - Retrieves the total length of fields registered
907d3a51819SDave May 
908*20f4b53cSBarry Smith    Collective
909d3a51819SDave May 
910d3a51819SDave May    Input parameter:
911*20f4b53cSBarry Smith .  dm - a `DMSWARM`
912d3a51819SDave May 
913d3a51819SDave May    Output parameter:
914d3a51819SDave May .  n - the total length of each registered field
915d3a51819SDave May 
916d3a51819SDave May    Level: beginner
917d3a51819SDave May 
918d3a51819SDave May    Note:
919*20f4b53cSBarry Smith    This calls `MPI_Allreduce()` upon each call (inefficient but safe)
920d3a51819SDave May 
921*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`, `DMSwarmSetLocalSizes()`
922d3a51819SDave May @*/
923d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetSize(DM dm, PetscInt *n)
924d71ae5a4SJacob Faibussowitsch {
925dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
9265627991aSBarry Smith   PetscInt  nlocal;
927dcf43ee8SDave May 
928521f74f9SMatthew G. Knepley   PetscFunctionBegin;
9299566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
9309566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&nlocal, n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
9313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
932dcf43ee8SDave May }
933dcf43ee8SDave May 
934d3a51819SDave May /*@C
935*20f4b53cSBarry Smith    DMSwarmRegisterPetscDatatypeField - Register a field to a `DMSWARM` with a native PETSc data type
936d3a51819SDave May 
937*20f4b53cSBarry Smith    Collective
938d3a51819SDave May 
939d3a51819SDave May    Input parameters:
940*20f4b53cSBarry Smith +  dm - a `DMSWARM`
941d3a51819SDave May .  fieldname - the textual name to identify this field
942d3a51819SDave May .  blocksize - the number of each data type
943*20f4b53cSBarry Smith -  type - a valid PETSc data type (`PETSC_CHAR`, `PETSC_SHORT`, `PETSC_INT`, `PETSC_FLOAT`, `PETSC_REAL`, `PETSC_LONG`)
944d3a51819SDave May 
945d3a51819SDave May    Level: beginner
946d3a51819SDave May 
947d3a51819SDave May    Notes:
9488b8a3813SDave May    The textual name for each registered field must be unique.
949d3a51819SDave May 
950*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
951d3a51819SDave May @*/
952d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterPetscDatatypeField(DM dm, const char fieldname[], PetscInt blocksize, PetscDataType type)
953d71ae5a4SJacob Faibussowitsch {
954b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
955b62e03f8SDave May   size_t    size;
956b62e03f8SDave May 
957521f74f9SMatthew G. Knepley   PetscFunctionBegin;
95828b400f6SJacob Faibussowitsch   PetscCheck(swarm->field_registration_initialized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmInitializeFieldRegister() first");
95928b400f6SJacob Faibussowitsch   PetscCheck(!swarm->field_registration_finalized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Cannot register additional fields after calling DMSwarmFinalizeFieldRegister() first");
9605f50eb2eSDave May 
96108401ef6SPierre Jolivet   PetscCheck(type != PETSC_OBJECT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96208401ef6SPierre Jolivet   PetscCheck(type != PETSC_FUNCTION, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96308401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRING, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96408401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRUCT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96508401ef6SPierre Jolivet   PetscCheck(type != PETSC_DATATYPE_UNKNOWN, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
966b62e03f8SDave May 
9679566063dSJacob Faibussowitsch   PetscCall(PetscDataTypeGetSize(type, &size));
968b62e03f8SDave May   /* Load a specific data type into data bucket, specifying textual name and its size in bytes */
9699566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterPetscDatatypeField", fieldname, blocksize * size, NULL));
97052c3ed93SDave May   {
97177048351SPatrick Sanan     DMSwarmDataField gfield;
97252c3ed93SDave May 
9739566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
9749566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
97552c3ed93SDave May   }
976b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = type;
9773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
978b62e03f8SDave May }
979b62e03f8SDave May 
980d3a51819SDave May /*@C
981*20f4b53cSBarry Smith    DMSwarmRegisterUserStructField - Register a user defined struct to a `DMSWARM`
982d3a51819SDave May 
983*20f4b53cSBarry Smith    Collective
984d3a51819SDave May 
985d3a51819SDave May    Input parameters:
986*20f4b53cSBarry Smith +  dm - a `DMSWARM`
987d3a51819SDave May .  fieldname - the textual name to identify this field
98862741f57SDave May -  size - the size in bytes of the user struct of each data type
989d3a51819SDave May 
990d3a51819SDave May    Level: beginner
991d3a51819SDave May 
992*20f4b53cSBarry Smith    Note:
9938b8a3813SDave May    The textual name for each registered field must be unique.
994d3a51819SDave May 
995*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserDatatypeField()`
996d3a51819SDave May @*/
997d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserStructField(DM dm, const char fieldname[], size_t size)
998d71ae5a4SJacob Faibussowitsch {
999b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1000b62e03f8SDave May 
1001521f74f9SMatthew G. Knepley   PetscFunctionBegin;
10029566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserStructField", fieldname, size, NULL));
1003b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_STRUCT;
10043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1005b62e03f8SDave May }
1006b62e03f8SDave May 
1007d3a51819SDave May /*@C
1008*20f4b53cSBarry Smith    DMSwarmRegisterUserDatatypeField - Register a user defined data type to a `DMSWARM`
1009d3a51819SDave May 
1010*20f4b53cSBarry Smith    Collective
1011d3a51819SDave May 
1012d3a51819SDave May    Input parameters:
1013*20f4b53cSBarry Smith +  dm - a `DMSWARM`
1014d3a51819SDave May .  fieldname - the textual name to identify this field
1015d3a51819SDave May .  size - the size in bytes of the user data type
101662741f57SDave May -  blocksize - the number of each data type
1017d3a51819SDave May 
1018d3a51819SDave May    Level: beginner
1019d3a51819SDave May 
1020*20f4b53cSBarry Smith    Note:
10218b8a3813SDave May    The textual name for each registered field must be unique.
1022d3a51819SDave May 
1023*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
1024d3a51819SDave May @*/
1025d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserDatatypeField(DM dm, const char fieldname[], size_t size, PetscInt blocksize)
1026d71ae5a4SJacob Faibussowitsch {
1027b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1028b62e03f8SDave May 
1029521f74f9SMatthew G. Knepley   PetscFunctionBegin;
10309566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserDatatypeField", fieldname, blocksize * size, NULL));
1031320740a0SDave May   {
103277048351SPatrick Sanan     DMSwarmDataField gfield;
1033320740a0SDave May 
10349566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
10359566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
1036320740a0SDave May   }
1037b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_DATATYPE_UNKNOWN;
10383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1039b62e03f8SDave May }
1040b62e03f8SDave May 
1041d3a51819SDave May /*@C
1042d3a51819SDave May    DMSwarmGetField - Get access to the underlying array storing all entries associated with a registered field
1043d3a51819SDave May 
1044*20f4b53cSBarry Smith    Not Collective
1045d3a51819SDave May 
1046d3a51819SDave May    Input parameters:
1047*20f4b53cSBarry Smith +  dm - a `DMSWARM`
104862741f57SDave May -  fieldname - the textual name to identify this field
1049d3a51819SDave May 
1050d3a51819SDave May    Output parameters:
105162741f57SDave May +  blocksize - the number of each data type
1052d3a51819SDave May .  type - the data type
105362741f57SDave May -  data - pointer to raw array
1054d3a51819SDave May 
1055d3a51819SDave May    Level: beginner
1056d3a51819SDave May 
1057d3a51819SDave May    Notes:
1058*20f4b53cSBarry Smith    The array must be returned using a matching call to `DMSwarmRestoreField()`.
1059d3a51819SDave May 
1060*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreField()`
1061d3a51819SDave May @*/
1062d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1063d71ae5a4SJacob Faibussowitsch {
1064b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
106577048351SPatrick Sanan   DMSwarmDataField gfield;
1066b62e03f8SDave May 
1067521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1068ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
10699566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
10709566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
10719566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetAccess(gfield));
10729566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetEntries(gfield, data));
1073ad540459SPierre Jolivet   if (blocksize) *blocksize = gfield->bs;
1074ad540459SPierre Jolivet   if (type) *type = gfield->petsc_type;
10753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1076b62e03f8SDave May }
1077b62e03f8SDave May 
1078d3a51819SDave May /*@C
1079d3a51819SDave May    DMSwarmRestoreField - Restore access to the underlying array storing all entries associated with a registered field
1080d3a51819SDave May 
1081*20f4b53cSBarry Smith    Not Collective
1082d3a51819SDave May 
1083d3a51819SDave May    Input parameters:
1084*20f4b53cSBarry Smith +  dm - a `DMSWARM`
108562741f57SDave May -  fieldname - the textual name to identify this field
1086d3a51819SDave May 
1087d3a51819SDave May    Output parameters:
108862741f57SDave May +  blocksize - the number of each data type
1089d3a51819SDave May .  type - the data type
109062741f57SDave May -  data - pointer to raw array
1091d3a51819SDave May 
1092d3a51819SDave May    Level: beginner
1093d3a51819SDave May 
1094d3a51819SDave May    Notes:
1095*20f4b53cSBarry Smith    The user must call `DMSwarmGetField()` prior to calling `DMSwarmRestoreField()`.
1096d3a51819SDave May 
1097*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetField()`
1098d3a51819SDave May @*/
1099d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRestoreField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1100d71ae5a4SJacob Faibussowitsch {
1101b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
110277048351SPatrick Sanan   DMSwarmDataField gfield;
1103b62e03f8SDave May 
1104521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1105ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
11069566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
11079566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
1108b62e03f8SDave May   if (data) *data = NULL;
11093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1110b62e03f8SDave May }
1111b62e03f8SDave May 
111274d0cae8SMatthew G. Knepley /*@
1113*20f4b53cSBarry Smith    DMSwarmAddPoint - Add space for one new point in the `DMSWARM`
1114d3a51819SDave May 
1115*20f4b53cSBarry Smith    Not Collective
1116d3a51819SDave May 
1117d3a51819SDave May    Input parameter:
1118*20f4b53cSBarry Smith .  dm - a `DMSWARM`
1119d3a51819SDave May 
1120d3a51819SDave May    Level: beginner
1121d3a51819SDave May 
1122d3a51819SDave May    Notes:
11238b8a3813SDave May    The new point will have all fields initialized to zero.
1124d3a51819SDave May 
1125*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmAddNPoints()`
1126d3a51819SDave May @*/
1127d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddPoint(DM dm)
1128d71ae5a4SJacob Faibussowitsch {
1129cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1130cb1d1399SDave May 
1131521f74f9SMatthew G. Knepley   PetscFunctionBegin;
11329566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
11339566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
11349566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketAddPoint(swarm->db));
11359566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
11363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1137cb1d1399SDave May }
1138cb1d1399SDave May 
113974d0cae8SMatthew G. Knepley /*@
1140*20f4b53cSBarry Smith    DMSwarmAddNPoints - Add space for a number of new points in the `DMSWARM`
1141d3a51819SDave May 
1142*20f4b53cSBarry Smith    Not Collective
1143d3a51819SDave May 
1144d3a51819SDave May    Input parameters:
1145*20f4b53cSBarry Smith +  dm - a `DMSWARM`
114662741f57SDave May -  npoints - the number of new points to add
1147d3a51819SDave May 
1148d3a51819SDave May    Level: beginner
1149d3a51819SDave May 
1150d3a51819SDave May    Notes:
11518b8a3813SDave May    The new point will have all fields initialized to zero.
1152d3a51819SDave May 
1153*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmAddPoint()`
1154d3a51819SDave May @*/
1155d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddNPoints(DM dm, PetscInt npoints)
1156d71ae5a4SJacob Faibussowitsch {
1157cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1158cb1d1399SDave May   PetscInt  nlocal;
1159cb1d1399SDave May 
1160521f74f9SMatthew G. Knepley   PetscFunctionBegin;
11619566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
11629566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
1163cb1d1399SDave May   nlocal = nlocal + npoints;
11649566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
11659566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
11663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1167cb1d1399SDave May }
1168cb1d1399SDave May 
116974d0cae8SMatthew G. Knepley /*@
1170*20f4b53cSBarry Smith    DMSwarmRemovePoint - Remove the last point from the `DMSWARM`
1171d3a51819SDave May 
1172*20f4b53cSBarry Smith    Not Collective
1173d3a51819SDave May 
1174d3a51819SDave May    Input parameter:
1175*20f4b53cSBarry Smith .  dm - a `DMSWARM`
1176d3a51819SDave May 
1177d3a51819SDave May    Level: beginner
1178d3a51819SDave May 
1179*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePointAtIndex()`
1180d3a51819SDave May @*/
1181d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePoint(DM dm)
1182d71ae5a4SJacob Faibussowitsch {
1183cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1184cb1d1399SDave May 
1185521f74f9SMatthew G. Knepley   PetscFunctionBegin;
11869566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
11879566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePoint(swarm->db));
11889566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
11893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1190cb1d1399SDave May }
1191cb1d1399SDave May 
119274d0cae8SMatthew G. Knepley /*@
1193*20f4b53cSBarry Smith    DMSwarmRemovePointAtIndex - Removes a specific point from the `DMSWARM`
1194d3a51819SDave May 
1195*20f4b53cSBarry Smith    Not Collective
1196d3a51819SDave May 
1197d3a51819SDave May    Input parameters:
1198*20f4b53cSBarry Smith +  dm - a `DMSWARM`
119962741f57SDave May -  idx - index of point to remove
1200d3a51819SDave May 
1201d3a51819SDave May    Level: beginner
1202d3a51819SDave May 
1203*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
1204d3a51819SDave May @*/
1205d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePointAtIndex(DM dm, PetscInt idx)
1206d71ae5a4SJacob Faibussowitsch {
1207cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1208cb1d1399SDave May 
1209521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12109566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
12119566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, idx));
12129566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
12133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1214cb1d1399SDave May }
1215b62e03f8SDave May 
121674d0cae8SMatthew G. Knepley /*@
1217*20f4b53cSBarry Smith    DMSwarmCopyPoint - Copy point pj to point pi in the `DMSWARM`
1218ba4fc9c6SDave May 
1219*20f4b53cSBarry Smith    Not Collective
1220ba4fc9c6SDave May 
1221ba4fc9c6SDave May    Input parameters:
1222*20f4b53cSBarry Smith +  dm - a `DMSWARM`
1223ba4fc9c6SDave May .  pi - the index of the point to copy
1224ba4fc9c6SDave May -  pj - the point index where the copy should be located
1225ba4fc9c6SDave May 
1226ba4fc9c6SDave May  Level: beginner
1227ba4fc9c6SDave May 
1228*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
1229ba4fc9c6SDave May @*/
1230d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCopyPoint(DM dm, PetscInt pi, PetscInt pj)
1231d71ae5a4SJacob Faibussowitsch {
1232ba4fc9c6SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1233ba4fc9c6SDave May 
1234ba4fc9c6SDave May   PetscFunctionBegin;
12359566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
12369566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCopyPoint(swarm->db, pi, swarm->db, pj));
12373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1238ba4fc9c6SDave May }
1239ba4fc9c6SDave May 
1240d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmMigrate_Basic(DM dm, PetscBool remove_sent_points)
1241d71ae5a4SJacob Faibussowitsch {
1242521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12439566063dSJacob Faibussowitsch   PetscCall(DMSwarmMigrate_Push_Basic(dm, remove_sent_points));
12443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12453454631fSDave May }
12463454631fSDave May 
124774d0cae8SMatthew G. Knepley /*@
1248*20f4b53cSBarry Smith    DMSwarmMigrate - Relocates points defined in the `DMSWARM` to other MPI-ranks
1249d3a51819SDave May 
1250*20f4b53cSBarry Smith    Collective
1251d3a51819SDave May 
1252d3a51819SDave May    Input parameters:
1253*20f4b53cSBarry Smith +  dm - the `DMSWARM`
125462741f57SDave May -  remove_sent_points - flag indicating if sent points should be removed from the current MPI-rank
1255d3a51819SDave May 
1256d3a51819SDave May    Level: advanced
1257d3a51819SDave May 
1258*20f4b53cSBarry Smith    Notes:
1259*20f4b53cSBarry Smith    The `DM` will be modified to accommodate received points.
1260*20f4b53cSBarry Smith    If `remove_sent_points` is `PETSC_TRUE`, any points that were sent will be removed from the `DM`.
1261*20f4b53cSBarry Smith    Different styles of migration are supported. See `DMSwarmSetMigrateType()`.
1262*20f4b53cSBarry Smith 
1263*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`
1264d3a51819SDave May @*/
1265d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmMigrate(DM dm, PetscBool remove_sent_points)
1266d71ae5a4SJacob Faibussowitsch {
1267f0cdbbbaSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1268f0cdbbbaSDave May 
1269521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12709566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_Migrate, 0, 0, 0, 0));
1271f0cdbbbaSDave May   switch (swarm->migrate_type) {
1272d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_BASIC:
1273d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_Basic(dm, remove_sent_points));
1274d71ae5a4SJacob Faibussowitsch     break;
1275d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLNSCATTER:
1276d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_CellDMScatter(dm, remove_sent_points));
1277d71ae5a4SJacob Faibussowitsch     break;
1278d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLEXACT:
1279d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_DMCELLEXACT not implemented");
1280d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_USER:
1281d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_USER not implemented");
1282d71ae5a4SJacob Faibussowitsch   default:
1283d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE type unknown");
1284f0cdbbbaSDave May   }
12859566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_Migrate, 0, 0, 0, 0));
12869566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm));
12873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12883454631fSDave May }
12893454631fSDave May 
1290f0cdbbbaSDave May PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm, PetscInt *globalsize);
1291f0cdbbbaSDave May 
1292d3a51819SDave May /*
1293d3a51819SDave May  DMSwarmCollectViewCreate
1294d3a51819SDave May 
1295d3a51819SDave May  * Applies a collection method and gathers point neighbour points into dm
1296d3a51819SDave May 
1297d3a51819SDave May  Notes:
12988b8a3813SDave May  Users should call DMSwarmCollectViewDestroy() after
1299d3a51819SDave May  they have finished computations associated with the collected points
1300d3a51819SDave May */
1301d3a51819SDave May 
130274d0cae8SMatthew G. Knepley /*@
1303d3a51819SDave May    DMSwarmCollectViewCreate - Applies a collection method and gathers points
1304*20f4b53cSBarry Smith                               in neighbour ranks into the `DMSWARM`
1305d3a51819SDave May 
1306*20f4b53cSBarry Smith    Collective
1307d3a51819SDave May 
1308d3a51819SDave May    Input parameter:
1309*20f4b53cSBarry Smith .  dm - the `DMSWARM`
1310d3a51819SDave May 
1311d3a51819SDave May    Level: advanced
1312d3a51819SDave May 
1313*20f4b53cSBarry Smith    Notes:
1314*20f4b53cSBarry Smith    Users should call `DMSwarmCollectViewDestroy()` after
1315*20f4b53cSBarry Smith    they have finished computations associated with the collected points
1316*20f4b53cSBarry Smith    Different collect methods are supported. See `DMSwarmSetCollectType()`.
1317*20f4b53cSBarry Smith 
1318*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewDestroy()`, `DMSwarmSetCollectType()`
1319d3a51819SDave May @*/
1320d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewCreate(DM dm)
1321d71ae5a4SJacob Faibussowitsch {
13222712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
13232712d1f2SDave May   PetscInt  ng;
13242712d1f2SDave May 
1325521f74f9SMatthew G. Knepley   PetscFunctionBegin;
132628b400f6SJacob Faibussowitsch   PetscCheck(!swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView currently active");
13279566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &ng));
1328480eef7bSDave May   switch (swarm->collect_type) {
1329d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_BASIC:
1330d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_GlobalToLocal_Basic(dm, &ng));
1331d71ae5a4SJacob Faibussowitsch     break;
1332d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_DMDABOUNDINGBOX:
1333d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_DMDABOUNDINGBOX not implemented");
1334d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_GENERAL:
1335d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_GENERAL not implemented");
1336d71ae5a4SJacob Faibussowitsch   default:
1337d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT type unknown");
1338480eef7bSDave May   }
1339480eef7bSDave May   swarm->collect_view_active       = PETSC_TRUE;
1340480eef7bSDave May   swarm->collect_view_reset_nlocal = ng;
13413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13422712d1f2SDave May }
13432712d1f2SDave May 
134474d0cae8SMatthew G. Knepley /*@
1345*20f4b53cSBarry Smith    DMSwarmCollectViewDestroy - Resets the `DMSWARM` to the size prior to calling `DMSwarmCollectViewCreate()`
1346d3a51819SDave May 
1347*20f4b53cSBarry Smith    Collective
1348d3a51819SDave May 
1349d3a51819SDave May    Input parameters:
1350*20f4b53cSBarry Smith .  dm - the `DMSWARM`
1351d3a51819SDave May 
1352d3a51819SDave May    Notes:
1353*20f4b53cSBarry Smith    Users should call `DMSwarmCollectViewCreate()` before this function is called.
1354d3a51819SDave May 
1355d3a51819SDave May    Level: advanced
1356d3a51819SDave May 
1357*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewCreate()`, `DMSwarmSetCollectType()`
1358d3a51819SDave May @*/
1359d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewDestroy(DM dm)
1360d71ae5a4SJacob Faibussowitsch {
13612712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
13622712d1f2SDave May 
1363521f74f9SMatthew G. Knepley   PetscFunctionBegin;
136428b400f6SJacob Faibussowitsch   PetscCheck(swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView is currently not active");
13659566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetLocalSizes(dm, swarm->collect_view_reset_nlocal, -1));
1366480eef7bSDave May   swarm->collect_view_active = PETSC_FALSE;
13673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13682712d1f2SDave May }
13693454631fSDave May 
1370d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetUpPIC(DM dm)
1371d71ae5a4SJacob Faibussowitsch {
1372f0cdbbbaSDave May   PetscInt dim;
1373f0cdbbbaSDave May 
1374521f74f9SMatthew G. Knepley   PetscFunctionBegin;
13759566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetNumSpecies(dm, 1));
13769566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
137763a3b9bcSJacob Faibussowitsch   PetscCheck(dim >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
137863a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
13799566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_coor, dim, PETSC_DOUBLE));
13809566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_cellid, 1, PETSC_INT));
13813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1382f0cdbbbaSDave May }
1383f0cdbbbaSDave May 
138474d0cae8SMatthew G. Knepley /*@
138531403186SMatthew G. Knepley   DMSwarmSetPointCoordinatesRandom - Sets initial coordinates for particles in each cell
138631403186SMatthew G. Knepley 
1387*20f4b53cSBarry Smith   Collective
138831403186SMatthew G. Knepley 
138931403186SMatthew G. Knepley   Input parameters:
1390*20f4b53cSBarry Smith + dm  - the `DMSWARM`
1391*20f4b53cSBarry Smith - Npc - The number of particles per cell in the cell `DM`
139231403186SMatthew G. Knepley 
139331403186SMatthew G. Knepley   Level: intermediate
139431403186SMatthew G. Knepley 
1395*20f4b53cSBarry Smith   Notes:
1396*20f4b53cSBarry Smith   The user must use `DMSwarmSetCellDM()` to set the cell `DM` first. The particles are placed randomly inside each cell. If only
1397*20f4b53cSBarry Smith   one particle is in each cell, it is placed at the centroid.
1398*20f4b53cSBarry Smith 
1399*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
140031403186SMatthew G. Knepley @*/
1401d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetPointCoordinatesRandom(DM dm, PetscInt Npc)
1402d71ae5a4SJacob Faibussowitsch {
140331403186SMatthew G. Knepley   DM             cdm;
140431403186SMatthew G. Knepley   PetscRandom    rnd;
140531403186SMatthew G. Knepley   DMPolytopeType ct;
140631403186SMatthew G. Knepley   PetscBool      simplex;
140731403186SMatthew G. Knepley   PetscReal     *centroid, *coords, *xi0, *v0, *J, *invJ, detJ;
140831403186SMatthew G. Knepley   PetscInt       dim, d, cStart, cEnd, c, p;
140931403186SMatthew G. Knepley 
141031403186SMatthew G. Knepley   PetscFunctionBeginUser;
14119566063dSJacob Faibussowitsch   PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm), &rnd));
14129566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0));
14139566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetType(rnd, PETSCRAND48));
141431403186SMatthew G. Knepley 
14159566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
14169566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(cdm, &dim));
14179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd));
14189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(cdm, cStart, &ct));
141931403186SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
142031403186SMatthew G. Knepley 
14219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(dim, &centroid, dim, &xi0, dim, &v0, dim * dim, &J, dim * dim, &invJ));
142231403186SMatthew G. Knepley   for (d = 0; d < dim; ++d) xi0[d] = -1.0;
14239566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
142431403186SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
142531403186SMatthew G. Knepley     if (Npc == 1) {
14269566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(cdm, c, NULL, centroid, NULL));
142731403186SMatthew G. Knepley       for (d = 0; d < dim; ++d) coords[c * dim + d] = centroid[d];
142831403186SMatthew G. Knepley     } else {
14299566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(cdm, c, NULL, v0, J, invJ, &detJ)); /* affine */
143031403186SMatthew G. Knepley       for (p = 0; p < Npc; ++p) {
143131403186SMatthew G. Knepley         const PetscInt n   = c * Npc + p;
143231403186SMatthew G. Knepley         PetscReal      sum = 0.0, refcoords[3];
143331403186SMatthew G. Knepley 
143431403186SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
14359566063dSJacob Faibussowitsch           PetscCall(PetscRandomGetValueReal(rnd, &refcoords[d]));
143631403186SMatthew G. Knepley           sum += refcoords[d];
143731403186SMatthew G. Knepley         }
14389371c9d4SSatish Balay         if (simplex && sum > 0.0)
14399371c9d4SSatish Balay           for (d = 0; d < dim; ++d) refcoords[d] -= PetscSqrtReal(dim) * sum;
144031403186SMatthew G. Knepley         CoordinatesRefToReal(dim, dim, xi0, v0, J, refcoords, &coords[n * dim]);
144131403186SMatthew G. Knepley       }
144231403186SMatthew G. Knepley     }
144331403186SMatthew G. Knepley   }
14449566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
14459566063dSJacob Faibussowitsch   PetscCall(PetscFree5(centroid, xi0, v0, J, invJ));
14469566063dSJacob Faibussowitsch   PetscCall(PetscRandomDestroy(&rnd));
14473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
144831403186SMatthew G. Knepley }
144931403186SMatthew G. Knepley 
145031403186SMatthew G. Knepley /*@
1451*20f4b53cSBarry Smith    DMSwarmSetType - Set particular flavor of `DMSWARM`
1452d3a51819SDave May 
1453*20f4b53cSBarry Smith    Collective
1454d3a51819SDave May 
1455d3a51819SDave May    Input parameters:
1456*20f4b53cSBarry Smith +  dm - the `DMSWARM`
1457*20f4b53cSBarry Smith -  stype - the `DMSWARM` type (e.g. `DMSWARM_PIC`)
1458d3a51819SDave May 
1459d3a51819SDave May    Level: advanced
1460d3a51819SDave May 
1461*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`, `DMSwarmSetCollectType()`, `DMSwarmType`, `DMSWARM_PIC`, `DMSWARM_BASIC`
1462d3a51819SDave May @*/
1463d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetType(DM dm, DMSwarmType stype)
1464d71ae5a4SJacob Faibussowitsch {
1465f0cdbbbaSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1466f0cdbbbaSDave May 
1467521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1468f0cdbbbaSDave May   swarm->swarm_type = stype;
146948a46eb9SPierre Jolivet   if (swarm->swarm_type == DMSWARM_PIC) PetscCall(DMSwarmSetUpPIC(dm));
14703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1471f0cdbbbaSDave May }
1472f0cdbbbaSDave May 
1473d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSetup_Swarm(DM dm)
1474d71ae5a4SJacob Faibussowitsch {
14753454631fSDave May   DM_Swarm   *swarm = (DM_Swarm *)dm->data;
14763454631fSDave May   PetscMPIInt rank;
14773454631fSDave May   PetscInt    p, npoints, *rankval;
14783454631fSDave May 
1479521f74f9SMatthew G. Knepley   PetscFunctionBegin;
14803ba16761SJacob Faibussowitsch   if (swarm->issetup) PetscFunctionReturn(PETSC_SUCCESS);
14813454631fSDave May   swarm->issetup = PETSC_TRUE;
14823454631fSDave May 
1483f0cdbbbaSDave May   if (swarm->swarm_type == DMSWARM_PIC) {
1484f0cdbbbaSDave May     /* check dmcell exists */
148528b400f6SJacob Faibussowitsch     PetscCheck(swarm->dmcell, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires you call DMSwarmSetCellDM");
1486f0cdbbbaSDave May 
1487f0cdbbbaSDave May     if (swarm->dmcell->ops->locatepointssubdomain) {
1488f0cdbbbaSDave May       /* check methods exists for exact ownership identificiation */
14899566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->ops->LocatePointsSubdomain\n"));
1490f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLEXACT;
1491f0cdbbbaSDave May     } else {
1492f0cdbbbaSDave May       /* check methods exist for point location AND rank neighbor identification */
1493f0cdbbbaSDave May       if (swarm->dmcell->ops->locatepoints) {
14949566063dSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->LocatePoints\n"));
1495f0cdbbbaSDave May       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->locatepoints be defined");
1496f0cdbbbaSDave May 
1497f0cdbbbaSDave May       if (swarm->dmcell->ops->getneighbors) {
14989566063dSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->GetNeigbors\n"));
1499f0cdbbbaSDave May       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->getneighbors be defined");
1500f0cdbbbaSDave May 
1501f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLNSCATTER;
1502f0cdbbbaSDave May     }
1503f0cdbbbaSDave May   }
1504f0cdbbbaSDave May 
15059566063dSJacob Faibussowitsch   PetscCall(DMSwarmFinalizeFieldRegister(dm));
1506f0cdbbbaSDave May 
15073454631fSDave May   /* check some fields were registered */
150808401ef6SPierre Jolivet   PetscCheck(swarm->db->nfields > 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "At least one field user must be registered via DMSwarmRegisterXXX()");
15093454631fSDave May 
15103454631fSDave May   /* check local sizes were set */
151108401ef6SPierre Jolivet   PetscCheck(swarm->db->L != -1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Local sizes must be set via DMSwarmSetLocalSizes()");
15123454631fSDave May 
15133454631fSDave May   /* initialize values in pid and rank placeholders */
15143454631fSDave May   /* TODO: [pid - use MPI_Scan] */
15159566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
15169566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
15179566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
1518ad540459SPierre Jolivet   for (p = 0; p < npoints; p++) rankval[p] = (PetscInt)rank;
15199566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
15203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15213454631fSDave May }
15223454631fSDave May 
1523dc5f5ce9SDave May extern PetscErrorCode DMSwarmSortDestroy(DMSwarmSort *_ctx);
1524dc5f5ce9SDave May 
1525d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDestroy_Swarm(DM dm)
1526d71ae5a4SJacob Faibussowitsch {
152757795646SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
152857795646SDave May 
152957795646SDave May   PetscFunctionBegin;
15303ba16761SJacob Faibussowitsch   if (--swarm->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
15319566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&swarm->db));
153248a46eb9SPierre Jolivet   if (swarm->sort_context) PetscCall(DMSwarmSortDestroy(&swarm->sort_context));
15339566063dSJacob Faibussowitsch   PetscCall(PetscFree(swarm));
15343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153557795646SDave May }
153657795646SDave May 
1537d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmView_Draw(DM dm, PetscViewer viewer)
1538d71ae5a4SJacob Faibussowitsch {
1539a9ee3421SMatthew G. Knepley   DM         cdm;
1540a9ee3421SMatthew G. Knepley   PetscDraw  draw;
154131403186SMatthew G. Knepley   PetscReal *coords, oldPause, radius = 0.01;
1542a9ee3421SMatthew G. Knepley   PetscInt   Np, p, bs;
1543a9ee3421SMatthew G. Knepley 
1544a9ee3421SMatthew G. Knepley   PetscFunctionBegin;
15459566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetReal(NULL, ((PetscObject)dm)->prefix, "-dm_view_swarm_radius", &radius, NULL));
15469566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
15479566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
15489566063dSJacob Faibussowitsch   PetscCall(PetscDrawGetPause(draw, &oldPause));
15499566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, 0.0));
15509566063dSJacob Faibussowitsch   PetscCall(DMView(cdm, viewer));
15519566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, oldPause));
1552a9ee3421SMatthew G. Knepley 
15539566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &Np));
15549566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&coords));
1555a9ee3421SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
1556a9ee3421SMatthew G. Knepley     const PetscInt i = p * bs;
1557a9ee3421SMatthew G. Knepley 
15589566063dSJacob Faibussowitsch     PetscCall(PetscDrawEllipse(draw, coords[i], coords[i + 1], radius, radius, PETSC_DRAW_BLUE));
1559a9ee3421SMatthew G. Knepley   }
15609566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&coords));
15619566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
15629566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
15639566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
15643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1565a9ee3421SMatthew G. Knepley }
1566a9ee3421SMatthew G. Knepley 
1567d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_Swarm_Ascii(DM dm, PetscViewer viewer)
1568d71ae5a4SJacob Faibussowitsch {
15696a5217c0SMatthew G. Knepley   PetscViewerFormat format;
15706a5217c0SMatthew G. Knepley   PetscInt         *sizes;
15716a5217c0SMatthew G. Knepley   PetscInt          dim, Np, maxSize = 17;
15726a5217c0SMatthew G. Knepley   MPI_Comm          comm;
15736a5217c0SMatthew G. Knepley   PetscMPIInt       rank, size, p;
15746a5217c0SMatthew G. Knepley   const char       *name;
15756a5217c0SMatthew G. Knepley 
15766a5217c0SMatthew G. Knepley   PetscFunctionBegin;
15776a5217c0SMatthew G. Knepley   PetscCall(PetscViewerGetFormat(viewer, &format));
15786a5217c0SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
15796a5217c0SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(dm, &Np));
15806a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
15816a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
15826a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(comm, &size));
15836a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetName((PetscObject)dm, &name));
158463a3b9bcSJacob Faibussowitsch   if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
158563a3b9bcSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(viewer, "Swarm in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
15866a5217c0SMatthew G. Knepley   if (size < maxSize) PetscCall(PetscCalloc1(size, &sizes));
15876a5217c0SMatthew G. Knepley   else PetscCall(PetscCalloc1(3, &sizes));
15886a5217c0SMatthew G. Knepley   if (size < maxSize) {
15896a5217c0SMatthew G. Knepley     PetscCallMPI(MPI_Gather(&Np, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
15906a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of particles per rank:"));
15916a5217c0SMatthew G. Knepley     for (p = 0; p < size; ++p) {
15926a5217c0SMatthew G. Knepley       if (rank == 0) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]));
15936a5217c0SMatthew G. Knepley     }
15946a5217c0SMatthew G. Knepley   } else {
15956a5217c0SMatthew G. Knepley     PetscInt locMinMax[2] = {Np, Np};
15966a5217c0SMatthew G. Knepley 
15976a5217c0SMatthew G. Knepley     PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
15986a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of particles per rank: %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
15996a5217c0SMatthew G. Knepley   }
16006a5217c0SMatthew G. Knepley   PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
16016a5217c0SMatthew G. Knepley   PetscCall(PetscFree(sizes));
16026a5217c0SMatthew G. Knepley   if (format == PETSC_VIEWER_ASCII_INFO) {
16036a5217c0SMatthew G. Knepley     PetscInt *cell;
16046a5217c0SMatthew G. Knepley 
16056a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells containing each particle:\n"));
16066a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
16076a5217c0SMatthew G. Knepley     PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell));
160863a3b9bcSJacob Faibussowitsch     for (p = 0; p < Np; ++p) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  p%d: %" PetscInt_FMT "\n", p, cell[p]));
16096a5217c0SMatthew G. Knepley     PetscCall(PetscViewerFlush(viewer));
16106a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
16116a5217c0SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell));
16126a5217c0SMatthew G. Knepley   }
16133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16146a5217c0SMatthew G. Knepley }
16156a5217c0SMatthew G. Knepley 
1616d71ae5a4SJacob Faibussowitsch PetscErrorCode DMView_Swarm(DM dm, PetscViewer viewer)
1617d71ae5a4SJacob Faibussowitsch {
16185f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
16195627991aSBarry Smith   PetscBool iascii, ibinary, isvtk, isdraw;
16205627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
16215627991aSBarry Smith   PetscBool ishdf5;
16225627991aSBarry Smith #endif
16235f50eb2eSDave May 
16245f50eb2eSDave May   PetscFunctionBegin;
16255f50eb2eSDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
16265f50eb2eSDave May   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
16279566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
16289566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary));
16299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
16305627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
16319566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
16325627991aSBarry Smith #endif
16339566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
16345f50eb2eSDave May   if (iascii) {
16356a5217c0SMatthew G. Knepley     PetscViewerFormat format;
16366a5217c0SMatthew G. Knepley 
16376a5217c0SMatthew G. Knepley     PetscCall(PetscViewerGetFormat(viewer, &format));
16386a5217c0SMatthew G. Knepley     switch (format) {
1639d71ae5a4SJacob Faibussowitsch     case PETSC_VIEWER_ASCII_INFO_DETAIL:
1640d71ae5a4SJacob Faibussowitsch       PetscCall(DMSwarmDataBucketView(PetscObjectComm((PetscObject)dm), swarm->db, NULL, DATABUCKET_VIEW_STDOUT));
1641d71ae5a4SJacob Faibussowitsch       break;
1642d71ae5a4SJacob Faibussowitsch     default:
1643d71ae5a4SJacob Faibussowitsch       PetscCall(DMView_Swarm_Ascii(dm, viewer));
16446a5217c0SMatthew G. Knepley     }
1645f7d195e4SLawrence Mitchell   } else {
16465f50eb2eSDave May #if defined(PETSC_HAVE_HDF5)
164748a46eb9SPierre Jolivet     if (ishdf5) PetscCall(DMSwarmView_HDF5(dm, viewer));
16485f50eb2eSDave May #endif
164948a46eb9SPierre Jolivet     if (isdraw) PetscCall(DMSwarmView_Draw(dm, viewer));
1650f7d195e4SLawrence Mitchell   }
16513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16525f50eb2eSDave May }
16535f50eb2eSDave May 
1654d0c080abSJoseph Pusztay /*@C
1655*20f4b53cSBarry Smith    DMSwarmGetCellSwarm - Extracts a single cell from the `DMSWARM` object, returns it as a single cell `DMSWARM`.
1656*20f4b53cSBarry 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.
1657d0c080abSJoseph Pusztay 
1658d0c080abSJoseph Pusztay    Noncollective
1659d0c080abSJoseph Pusztay 
1660d0c080abSJoseph Pusztay    Input parameters:
1661*20f4b53cSBarry Smith +  sw - the `DMSWARM`
16625627991aSBarry Smith .  cellID - the integer id of the cell to be extracted and filtered
1663*20f4b53cSBarry Smith -  cellswarm - The `DMSWARM` to receive the cell
1664d0c080abSJoseph Pusztay 
1665d0c080abSJoseph Pusztay    Level: beginner
1666d0c080abSJoseph Pusztay 
16675627991aSBarry Smith    Notes:
1668*20f4b53cSBarry Smith       This presently only supports `DMSWARM_PIC` type
16695627991aSBarry Smith 
1670*20f4b53cSBarry Smith       Should be restored with `DMSwarmRestoreCellSwarm()`
1671d0c080abSJoseph Pusztay 
1672*20f4b53cSBarry Smith      Changes to this cell of the swarm will be lost if they are made prior to restoring this cell.
1673*20f4b53cSBarry Smith 
1674*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreCellSwarm()`
1675d0c080abSJoseph Pusztay @*/
1676d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMSwarmGetCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
1677d71ae5a4SJacob Faibussowitsch {
1678d0c080abSJoseph Pusztay   DM_Swarm *original = (DM_Swarm *)sw->data;
1679d0c080abSJoseph Pusztay   DMLabel   label;
1680d0c080abSJoseph Pusztay   DM        dmc, subdmc;
1681d0c080abSJoseph Pusztay   PetscInt *pids, particles, dim;
1682d0c080abSJoseph Pusztay 
1683d0c080abSJoseph Pusztay   PetscFunctionBegin;
1684d0c080abSJoseph Pusztay   /* Configure new swarm */
16859566063dSJacob Faibussowitsch   PetscCall(DMSetType(cellswarm, DMSWARM));
16869566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(sw, &dim));
16879566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(cellswarm, dim));
16889566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(cellswarm, DMSWARM_PIC));
1689d0c080abSJoseph Pusztay   /* Destroy the unused, unconfigured data bucket to prevent stragglers in memory */
16909566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&((DM_Swarm *)cellswarm->data)->db));
16919566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
16929566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, cellID, &particles));
16939566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
16949566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreateFromSubset(original->db, particles, pids, &((DM_Swarm *)cellswarm->data)->db));
16959566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
16969566063dSJacob Faibussowitsch   PetscCall(PetscFree(pids));
16979566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(sw, &dmc));
16989566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)sw), "singlecell", &label));
16999566063dSJacob Faibussowitsch   PetscCall(DMAddLabel(dmc, label));
17009566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cellID, 1));
17019566063dSJacob Faibussowitsch   PetscCall(DMPlexFilter(dmc, label, 1, &subdmc));
17029566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetCellDM(cellswarm, subdmc));
17039566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&label));
17043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1705d0c080abSJoseph Pusztay }
1706d0c080abSJoseph Pusztay 
1707d0c080abSJoseph Pusztay /*@C
1708*20f4b53cSBarry Smith    DMSwarmRestoreCellSwarm - Restores a `DMSWARM` object obtained with `DMSwarmGetCellSwarm()`. All fields are copied back into the parent swarm.
1709d0c080abSJoseph Pusztay 
1710d0c080abSJoseph Pusztay    Noncollective
1711d0c080abSJoseph Pusztay 
1712d0c080abSJoseph Pusztay    Input parameters:
1713*20f4b53cSBarry Smith +  sw - the parent `DMSWARM`
1714d0c080abSJoseph Pusztay .  cellID - the integer id of the cell to be copied back into the parent swarm
1715d0c080abSJoseph Pusztay -  cellswarm - the cell swarm object
1716d0c080abSJoseph Pusztay 
1717d0c080abSJoseph Pusztay    Level: beginner
1718d0c080abSJoseph Pusztay 
17195627991aSBarry Smith    Note:
1720*20f4b53cSBarry Smith     This only supports `DMSWARM_PIC` types of `DMSWARM`s
1721d0c080abSJoseph Pusztay 
1722*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetCellSwarm()`
1723d0c080abSJoseph Pusztay @*/
1724d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMSwarmRestoreCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
1725d71ae5a4SJacob Faibussowitsch {
1726d0c080abSJoseph Pusztay   DM        dmc;
1727d0c080abSJoseph Pusztay   PetscInt *pids, particles, p;
1728d0c080abSJoseph Pusztay 
1729d0c080abSJoseph Pusztay   PetscFunctionBegin;
17309566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
17319566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
17329566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
1733d0c080abSJoseph Pusztay   /* Pointwise copy of each particle based on pid. The parent swarm may not be altered during this process. */
173448a46eb9SPierre Jolivet   for (p = 0; p < particles; ++p) PetscCall(DMSwarmDataBucketCopyPoint(((DM_Swarm *)cellswarm->data)->db, pids[p], ((DM_Swarm *)sw->data)->db, pids[p]));
1735d0c080abSJoseph Pusztay   /* Free memory, destroy cell dm */
17369566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(cellswarm, &dmc));
17379566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
17389566063dSJacob Faibussowitsch   PetscCall(PetscFree(pids));
17393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1740d0c080abSJoseph Pusztay }
1741d0c080abSJoseph Pusztay 
1742d0c080abSJoseph Pusztay PETSC_INTERN PetscErrorCode DMClone_Swarm(DM, DM *);
1743d0c080abSJoseph Pusztay 
1744d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMInitialize_Swarm(DM sw)
1745d71ae5a4SJacob Faibussowitsch {
1746d0c080abSJoseph Pusztay   PetscFunctionBegin;
1747d0c080abSJoseph Pusztay   sw->dim                           = 0;
1748d0c080abSJoseph Pusztay   sw->ops->view                     = DMView_Swarm;
1749d0c080abSJoseph Pusztay   sw->ops->load                     = NULL;
1750d0c080abSJoseph Pusztay   sw->ops->setfromoptions           = NULL;
1751d0c080abSJoseph Pusztay   sw->ops->clone                    = DMClone_Swarm;
1752d0c080abSJoseph Pusztay   sw->ops->setup                    = DMSetup_Swarm;
1753d0c080abSJoseph Pusztay   sw->ops->createlocalsection       = NULL;
1754d0c080abSJoseph Pusztay   sw->ops->createdefaultconstraints = NULL;
1755d0c080abSJoseph Pusztay   sw->ops->createglobalvector       = DMCreateGlobalVector_Swarm;
1756d0c080abSJoseph Pusztay   sw->ops->createlocalvector        = DMCreateLocalVector_Swarm;
1757d0c080abSJoseph Pusztay   sw->ops->getlocaltoglobalmapping  = NULL;
1758d0c080abSJoseph Pusztay   sw->ops->createfieldis            = NULL;
1759d0c080abSJoseph Pusztay   sw->ops->createcoordinatedm       = NULL;
1760d0c080abSJoseph Pusztay   sw->ops->getcoloring              = NULL;
1761d0c080abSJoseph Pusztay   sw->ops->creatematrix             = DMCreateMatrix_Swarm;
1762d0c080abSJoseph Pusztay   sw->ops->createinterpolation      = NULL;
1763d0c080abSJoseph Pusztay   sw->ops->createinjection          = NULL;
1764d0c080abSJoseph Pusztay   sw->ops->createmassmatrix         = DMCreateMassMatrix_Swarm;
1765d0c080abSJoseph Pusztay   sw->ops->refine                   = NULL;
1766d0c080abSJoseph Pusztay   sw->ops->coarsen                  = NULL;
1767d0c080abSJoseph Pusztay   sw->ops->refinehierarchy          = NULL;
1768d0c080abSJoseph Pusztay   sw->ops->coarsenhierarchy         = NULL;
1769d0c080abSJoseph Pusztay   sw->ops->globaltolocalbegin       = NULL;
1770d0c080abSJoseph Pusztay   sw->ops->globaltolocalend         = NULL;
1771d0c080abSJoseph Pusztay   sw->ops->localtoglobalbegin       = NULL;
1772d0c080abSJoseph Pusztay   sw->ops->localtoglobalend         = NULL;
1773d0c080abSJoseph Pusztay   sw->ops->destroy                  = DMDestroy_Swarm;
1774d0c080abSJoseph Pusztay   sw->ops->createsubdm              = NULL;
1775d0c080abSJoseph Pusztay   sw->ops->getdimpoints             = NULL;
1776d0c080abSJoseph Pusztay   sw->ops->locatepoints             = NULL;
17773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1778d0c080abSJoseph Pusztay }
1779d0c080abSJoseph Pusztay 
1780d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMClone_Swarm(DM dm, DM *newdm)
1781d71ae5a4SJacob Faibussowitsch {
1782d0c080abSJoseph Pusztay   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1783d0c080abSJoseph Pusztay 
1784d0c080abSJoseph Pusztay   PetscFunctionBegin;
1785d0c080abSJoseph Pusztay   swarm->refct++;
1786d0c080abSJoseph Pusztay   (*newdm)->data = swarm;
17879566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMSWARM));
17889566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(*newdm));
17892e56dffeSJoe Pusztay   (*newdm)->dim = dm->dim;
17903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1791d0c080abSJoseph Pusztay }
1792d0c080abSJoseph Pusztay 
1793d3a51819SDave May /*MC
1794d3a51819SDave May 
1795*20f4b53cSBarry Smith  DMSWARM = "swarm" - A `DM` object used to represent arrays of data (fields) of arbitrary data type.
179662741f57SDave May  This implementation was designed for particle methods in which the underlying
1797d3a51819SDave May  data required to be represented is both (i) dynamic in length, (ii) and of arbitrary data type.
1798d3a51819SDave May 
1799*20f4b53cSBarry Smith  Level: intermediate
1800*20f4b53cSBarry Smith 
1801*20f4b53cSBarry Smith   Notes:
1802*20f4b53cSBarry Smith  User data can be represented by `DMSWARM` through a registering "fields".
180362741f57SDave May  To register a field, the user must provide;
180462741f57SDave May  (a) a unique name;
180562741f57SDave May  (b) the data type (or size in bytes);
180662741f57SDave May  (c) the block size of the data.
1807d3a51819SDave May 
1808d3a51819SDave May  For example, suppose the application requires a unique id, energy, momentum and density to be stored
1809c215a47eSMatthew Knepley  on a set of particles. Then the following code could be used
1810*20f4b53cSBarry Smith .vb
1811*20f4b53cSBarry Smith     DMSwarmInitializeFieldRegister(dm)
1812*20f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"uid",1,PETSC_LONG);
1813*20f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"energy",1,PETSC_REAL);
1814*20f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"momentum",3,PETSC_REAL);
1815*20f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"density",1,PETSC_FLOAT);
1816*20f4b53cSBarry Smith     DMSwarmFinalizeFieldRegister(dm)
1817*20f4b53cSBarry Smith .ve
1818d3a51819SDave May 
1819*20f4b53cSBarry Smith  The fields represented by `DMSWARM` are dynamic and can be re-sized at any time.
1820*20f4b53cSBarry Smith  The only restriction imposed by `DMSWARM` is that all fields contain the same number of points.
1821d3a51819SDave May 
1822d3a51819SDave May  To support particle methods, "migration" techniques are provided. These methods migrate data
18235627991aSBarry Smith  between ranks.
1824d3a51819SDave May 
1825*20f4b53cSBarry Smith  `DMSWARM` supports the methods `DMCreateGlobalVector()` and `DMCreateLocalVector()`.
1826*20f4b53cSBarry Smith  As a `DMSWARM` may internally define and store values of different data types,
1827*20f4b53cSBarry Smith  before calling `DMCreateGlobalVector()` or `DMCreateLocalVector()`, the user must inform `DMSWARM` which
1828*20f4b53cSBarry Smith  fields should be used to define a `Vec` object via
1829*20f4b53cSBarry Smith    `DMSwarmVectorDefineField()`
1830c215a47eSMatthew Knepley  The specified field can be changed at any time - thereby permitting vectors
1831c215a47eSMatthew Knepley  compatible with different fields to be created.
1832d3a51819SDave May 
1833*20f4b53cSBarry Smith  A dual representation of fields in the `DMSWARM` and a Vec object is permitted via
1834*20f4b53cSBarry Smith    `DMSwarmCreateGlobalVectorFromField()`
1835*20f4b53cSBarry Smith  Here the data defining the field in the `DMSWARM` is shared with a Vec.
1836d3a51819SDave May  This is inherently unsafe if you alter the size of the field at any time between
1837*20f4b53cSBarry Smith  calls to `DMSwarmCreateGlobalVectorFromField()` and `DMSwarmDestroyGlobalVectorFromField()`.
1838*20f4b53cSBarry Smith  If the local size of the `DMSWARM` does not match the local size of the global vector
1839*20f4b53cSBarry Smith  when `DMSwarmDestroyGlobalVectorFromField()` is called, an error is thrown.
1840d3a51819SDave May 
184162741f57SDave May  Additional high-level support is provided for Particle-In-Cell methods.
1842*20f4b53cSBarry Smith  Please refer to `DMSwarmSetType()`.
184362741f57SDave May 
1844*20f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMType`, `DMCreate()`, `DMSetType()`
1845d3a51819SDave May M*/
1846d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMCreate_Swarm(DM dm)
1847d71ae5a4SJacob Faibussowitsch {
184857795646SDave May   DM_Swarm *swarm;
184957795646SDave May 
185057795646SDave May   PetscFunctionBegin;
185157795646SDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
18524dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&swarm));
1853f0cdbbbaSDave May   dm->data = swarm;
18549566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreate(&swarm->db));
18559566063dSJacob Faibussowitsch   PetscCall(DMSwarmInitializeFieldRegister(dm));
1856d0c080abSJoseph Pusztay   swarm->refct                          = 1;
1857b5bcf523SDave May   swarm->vec_field_set                  = PETSC_FALSE;
18583454631fSDave May   swarm->issetup                        = PETSC_FALSE;
1859480eef7bSDave May   swarm->swarm_type                     = DMSWARM_BASIC;
1860480eef7bSDave May   swarm->migrate_type                   = DMSWARM_MIGRATE_BASIC;
1861480eef7bSDave May   swarm->collect_type                   = DMSWARM_COLLECT_BASIC;
186240c453e9SDave May   swarm->migrate_error_on_missing_point = PETSC_FALSE;
1863f0cdbbbaSDave May   swarm->dmcell                         = NULL;
1864f0cdbbbaSDave May   swarm->collect_view_active            = PETSC_FALSE;
1865f0cdbbbaSDave May   swarm->collect_view_reset_nlocal      = -1;
18669566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(dm));
18672e956fe4SStefano Zampini   if (SwarmDataFieldId == -1) PetscCall(PetscObjectComposedDataRegister(&SwarmDataFieldId));
18683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
186957795646SDave May }
1870