xref: /petsc/src/dm/impls/swarm/swarm.c (revision ad9634fc0b58de6ea4bcad5e2f557a96223669ff)
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 
3266976f2fSJacob Faibussowitsch static 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 
5366976f2fSJacob Faibussowitsch static 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 
7366976f2fSJacob Faibussowitsch static 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
9520f4b53cSBarry Smith   DMSwarmVectorDefineField - Sets the field from which to define a `Vec` object
9620f4b53cSBarry Smith   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
9757795646SDave May 
9820f4b53cSBarry Smith   Collective
9957795646SDave May 
10060225df5SJacob Faibussowitsch   Input Parameters:
10120f4b53cSBarry 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:
10720f4b53cSBarry Smith   The field with name `fieldname` must be defined as having a data type of `PetscScalar`.
108e7af74c8SDave May 
10920f4b53cSBarry Smith   This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`.
11020f4b53cSBarry Smith   Multiple calls to `DMSwarmVectorDefineField()` are permitted.
111e7af74c8SDave May 
11220f4b53cSBarry 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 */
13766976f2fSJacob Faibussowitsch static 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 */
16266976f2fSJacob Faibussowitsch static 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;
350*ad9634fcSMatthew G. Knepley     PetscClassId    id;
351ea7032a0SMatthew G. Knepley     PetscReal      *fieldVals;
3520643ed39SMatthew G. Knepley     PetscInt        Nc, i;
35383c47955SMatthew G. Knepley 
3549566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
355*ad9634fcSMatthew G. Knepley     PetscCall(PetscObjectGetClassId(obj, &id));
356*ad9634fcSMatthew G. Knepley     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
357*ad9634fcSMatthew G. Knepley     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
35863a3b9bcSJacob Faibussowitsch     PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc);
359ea7032a0SMatthew G. Knepley 
360ea7032a0SMatthew G. Knepley     PetscCall(DMSwarmGetField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&fieldVals));
36183c47955SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
36283c47955SMatthew G. Knepley       PetscInt *findices, *cindices;
36383c47955SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
3640643ed39SMatthew G. Knepley       PetscInt  p, c;
36583c47955SMatthew G. Knepley 
3660643ed39SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
3679566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
3689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3699566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
370ea7032a0SMatthew G. Knepley       for (p = 0; p < numCIndices; ++p) CoordinatesRealToRef(dim, dim, v0ref, v0, invJ, &fieldVals[cindices[p] * dim], &xi[p * dim]);
371*ad9634fcSMatthew G. Knepley       if (id == PETSCFE_CLASSID) PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
372*ad9634fcSMatthew G. Knepley       else PetscCall(PetscFVCreateTabulation((PetscFV)obj, 1, numCIndices, xi, 0, &Tcoarse));
37383c47955SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
3749566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemMat, numCIndices * totDim));
37583c47955SMatthew G. Knepley       for (i = 0; i < numFIndices; ++i) {
3760643ed39SMatthew G. Knepley         for (p = 0; p < numCIndices; ++p) {
3770643ed39SMatthew G. Knepley           for (c = 0; c < Nc; ++c) {
3780643ed39SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
379ef0bb6c7SMatthew G. Knepley             elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
38083c47955SMatthew G. Knepley           }
3810643ed39SMatthew G. Knepley         }
3820643ed39SMatthew G. Knepley       }
383adb2528bSMark Adams       for (p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart;
3849566063dSJacob Faibussowitsch       if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
3859566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numFIndices, findices, elemMat, ADD_VALUES));
3869566063dSJacob Faibussowitsch       PetscCall(PetscFree(cindices));
3879566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3889566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
38983c47955SMatthew G. Knepley     }
390ea7032a0SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&fieldVals));
39183c47955SMatthew G. Knepley   }
3929566063dSJacob Faibussowitsch   PetscCall(PetscFree3(elemMat, rowIDXs, xi));
3939566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
3949566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
3959566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
3969566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
3973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39883c47955SMatthew G. Knepley }
39983c47955SMatthew G. Knepley 
400d0c080abSJoseph Pusztay /* Returns empty matrix for use with SNES FD */
401d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMatrix_Swarm(DM sw, Mat *m)
402d71ae5a4SJacob Faibussowitsch {
403d0c080abSJoseph Pusztay   Vec      field;
404d0c080abSJoseph Pusztay   PetscInt size;
405d0c080abSJoseph Pusztay 
406d0c080abSJoseph Pusztay   PetscFunctionBegin;
4079566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(sw, &field));
4089566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(field, &size));
4099566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(sw, &field));
4109566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD, m));
4119566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*m));
4129566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*m, PETSC_DECIDE, PETSC_DECIDE, size, size));
4139566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*m, 1, NULL));
4149566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(*m));
4159566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*m, MAT_FINAL_ASSEMBLY));
4169566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*m, MAT_FINAL_ASSEMBLY));
4179566063dSJacob Faibussowitsch   PetscCall(MatShift(*m, 1.0));
4189566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*m, sw));
4193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
420d0c080abSJoseph Pusztay }
421d0c080abSJoseph Pusztay 
422adb2528bSMark Adams /* FEM cols, Particle rows */
423d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMassMatrix_Swarm(DM dmCoarse, DM dmFine, Mat *mass)
424d71ae5a4SJacob Faibussowitsch {
425895a1698SMatthew G. Knepley   PetscSection gsf;
42683c47955SMatthew G. Knepley   PetscInt     m, n;
42783c47955SMatthew G. Knepley   void        *ctx;
42883c47955SMatthew G. Knepley 
42983c47955SMatthew G. Knepley   PetscFunctionBegin;
4309566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
4319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
4329566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dmCoarse, &n));
4339566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
4349566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, m, PETSC_DETERMINE, PETSC_DETERMINE));
4359566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
4369566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
43783c47955SMatthew G. Knepley 
4389566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrix_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
4399566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
4403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44183c47955SMatthew G. Knepley }
44283c47955SMatthew G. Knepley 
443d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmComputeMassMatrixSquare_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
444d71ae5a4SJacob Faibussowitsch {
4454cc7f7b2SMatthew G. Knepley   const char  *name = "Mass Matrix Square";
4464cc7f7b2SMatthew G. Knepley   MPI_Comm     comm;
4474cc7f7b2SMatthew G. Knepley   PetscDS      prob;
4484cc7f7b2SMatthew G. Knepley   PetscSection fsection, globalFSection;
4494cc7f7b2SMatthew G. Knepley   PetscHSetIJ  ht;
4504cc7f7b2SMatthew G. Knepley   PetscLayout  rLayout, colLayout;
4514cc7f7b2SMatthew G. Knepley   PetscInt    *dnz, *onz, *adj, depth, maxConeSize, maxSupportSize, maxAdjSize;
4524cc7f7b2SMatthew G. Knepley   PetscInt     locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
4534cc7f7b2SMatthew G. Knepley   PetscReal   *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
4544cc7f7b2SMatthew G. Knepley   PetscScalar *elemMat, *elemMatSq;
4554cc7f7b2SMatthew G. Knepley   PetscInt     cdim, Nf, field, cStart, cEnd, cell, totDim, maxC = 0;
4564cc7f7b2SMatthew G. Knepley 
4574cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
4589566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
4599566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmf, &cdim));
4609566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmf, &prob));
4619566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
4629566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
4639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(cdim, &v0, cdim * cdim, &J, cdim * cdim, &invJ));
4649566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
4659566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
4669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
4679566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
4684cc7f7b2SMatthew G. Knepley 
4699566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &colLayout));
4709566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
4719566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
4729566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colLayout));
4739566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
4749566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&colLayout));
4754cc7f7b2SMatthew G. Knepley 
4769566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &rLayout));
4779566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
4789566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
4799566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
4809566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
4819566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
4824cc7f7b2SMatthew G. Knepley 
4839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmf, &depth));
4849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dmf, &maxConeSize, &maxSupportSize));
4854cc7f7b2SMatthew G. Knepley   maxAdjSize = PetscPowInt(maxConeSize * maxSupportSize, depth);
4869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxAdjSize, &adj));
4874cc7f7b2SMatthew G. Knepley 
4889566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
4899566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
4904cc7f7b2SMatthew G. Knepley   /* Count nonzeros
4914cc7f7b2SMatthew G. Knepley        This is just FVM++, but we cannot use the Plex P0 allocation since unknowns in a cell will not be contiguous
4924cc7f7b2SMatthew G. Knepley   */
4939566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(dmc));
4944cc7f7b2SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
4954cc7f7b2SMatthew G. Knepley     PetscInt  i;
4964cc7f7b2SMatthew G. Knepley     PetscInt *cindices;
4974cc7f7b2SMatthew G. Knepley     PetscInt  numCIndices;
4984cc7f7b2SMatthew G. Knepley #if 0
4994cc7f7b2SMatthew G. Knepley     PetscInt  adjSize = maxAdjSize, a, j;
5004cc7f7b2SMatthew G. Knepley #endif
5014cc7f7b2SMatthew G. Knepley 
5029566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
5034cc7f7b2SMatthew G. Knepley     maxC = PetscMax(maxC, numCIndices);
5044cc7f7b2SMatthew G. Knepley     /* Diagonal block */
505ad540459SPierre Jolivet     for (i = 0; i < numCIndices; ++i) dnz[cindices[i]] += numCIndices;
5064cc7f7b2SMatthew G. Knepley #if 0
5074cc7f7b2SMatthew G. Knepley     /* Off-diagonal blocks */
5089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(dmf, cell, &adjSize, &adj));
5094cc7f7b2SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
5104cc7f7b2SMatthew G. Knepley       if (adj[a] >= cStart && adj[a] < cEnd && adj[a] != cell) {
5114cc7f7b2SMatthew G. Knepley         const PetscInt ncell = adj[a];
5124cc7f7b2SMatthew G. Knepley         PetscInt      *ncindices;
5134cc7f7b2SMatthew G. Knepley         PetscInt       numNCIndices;
5144cc7f7b2SMatthew G. Knepley 
5159566063dSJacob Faibussowitsch         PetscCall(DMSwarmSortGetPointsPerCell(dmc, ncell, &numNCIndices, &ncindices));
5164cc7f7b2SMatthew G. Knepley         {
5174cc7f7b2SMatthew G. Knepley           PetscHashIJKey key;
5184cc7f7b2SMatthew G. Knepley           PetscBool      missing;
5194cc7f7b2SMatthew G. Knepley 
5204cc7f7b2SMatthew G. Knepley           for (i = 0; i < numCIndices; ++i) {
5214cc7f7b2SMatthew G. Knepley             key.i = cindices[i] + rStart; /* global rows (from Swarm) */
5224cc7f7b2SMatthew G. Knepley             if (key.i < 0) continue;
5234cc7f7b2SMatthew G. Knepley             for (j = 0; j < numNCIndices; ++j) {
5244cc7f7b2SMatthew G. Knepley               key.j = ncindices[j] + rStart; /* global column (from Swarm) */
5254cc7f7b2SMatthew G. Knepley               if (key.j < 0) continue;
5269566063dSJacob Faibussowitsch               PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
5274cc7f7b2SMatthew G. Knepley               if (missing) {
5284cc7f7b2SMatthew G. Knepley                 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
5294cc7f7b2SMatthew G. Knepley                 else                                         ++onz[key.i - rStart];
5304cc7f7b2SMatthew G. Knepley               }
5314cc7f7b2SMatthew G. Knepley             }
5324cc7f7b2SMatthew G. Knepley           }
5334cc7f7b2SMatthew G. Knepley         }
5349566063dSJacob Faibussowitsch         PetscCall(PetscFree(ncindices));
5354cc7f7b2SMatthew G. Knepley       }
5364cc7f7b2SMatthew G. Knepley     }
5374cc7f7b2SMatthew G. Knepley #endif
5389566063dSJacob Faibussowitsch     PetscCall(PetscFree(cindices));
5394cc7f7b2SMatthew G. Knepley   }
5409566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
5419566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
5429566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
5439566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
5449566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(maxC * totDim, &elemMat, maxC * maxC, &elemMatSq, maxC, &rowIDXs, maxC * cdim, &xi));
5454cc7f7b2SMatthew G. Knepley   /* Fill in values
5464cc7f7b2SMatthew G. Knepley        Each entry is a sum of terms \phi_i(x_p) \phi_i(x_q)
5474cc7f7b2SMatthew G. Knepley        Start just by producing block diagonal
5484cc7f7b2SMatthew G. Knepley        Could loop over adjacent cells
5494cc7f7b2SMatthew G. Knepley          Produce neighboring element matrix
5504cc7f7b2SMatthew G. Knepley          TODO Determine which columns and rows correspond to shared dual vector
5514cc7f7b2SMatthew G. Knepley          Do MatMatMult with rectangular matrices
5524cc7f7b2SMatthew G. Knepley          Insert block
5534cc7f7b2SMatthew G. Knepley   */
5544cc7f7b2SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
5554cc7f7b2SMatthew G. Knepley     PetscTabulation Tcoarse;
5564cc7f7b2SMatthew G. Knepley     PetscObject     obj;
5574cc7f7b2SMatthew G. Knepley     PetscReal      *coords;
5584cc7f7b2SMatthew G. Knepley     PetscInt        Nc, i;
5594cc7f7b2SMatthew G. Knepley 
5609566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
5619566063dSJacob Faibussowitsch     PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
56263a3b9bcSJacob Faibussowitsch     PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc);
5639566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
5644cc7f7b2SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
5654cc7f7b2SMatthew G. Knepley       PetscInt *findices, *cindices;
5664cc7f7b2SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
5674cc7f7b2SMatthew G. Knepley       PetscInt  p, c;
5684cc7f7b2SMatthew G. Knepley 
5694cc7f7b2SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
5709566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
5719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
5729566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
573ad540459SPierre Jolivet       for (p = 0; p < numCIndices; ++p) CoordinatesRealToRef(cdim, cdim, v0ref, v0, invJ, &coords[cindices[p] * cdim], &xi[p * cdim]);
5749566063dSJacob Faibussowitsch       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
5754cc7f7b2SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
5769566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemMat, numCIndices * totDim));
5774cc7f7b2SMatthew G. Knepley       for (i = 0; i < numFIndices; ++i) {
5784cc7f7b2SMatthew G. Knepley         for (p = 0; p < numCIndices; ++p) {
5794cc7f7b2SMatthew G. Knepley           for (c = 0; c < Nc; ++c) {
5804cc7f7b2SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
5814cc7f7b2SMatthew G. Knepley             elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
5824cc7f7b2SMatthew G. Knepley           }
5834cc7f7b2SMatthew G. Knepley         }
5844cc7f7b2SMatthew G. Knepley       }
5859566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
5864cc7f7b2SMatthew G. Knepley       for (p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart;
5879566063dSJacob Faibussowitsch       if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
5884cc7f7b2SMatthew G. Knepley       /* Block diagonal */
58978884ca7SMatthew G. Knepley       if (numCIndices) {
5904cc7f7b2SMatthew G. Knepley         PetscBLASInt blasn, blask;
5914cc7f7b2SMatthew G. Knepley         PetscScalar  one = 1.0, zero = 0.0;
5924cc7f7b2SMatthew G. Knepley 
5939566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numCIndices, &blasn));
5949566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numFIndices, &blask));
595792fecdfSBarry Smith         PetscCallBLAS("BLASgemm", BLASgemm_("T", "N", &blasn, &blasn, &blask, &one, elemMat, &blask, elemMat, &blask, &zero, elemMatSq, &blasn));
5964cc7f7b2SMatthew G. Knepley       }
5979566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numCIndices, rowIDXs, elemMatSq, ADD_VALUES));
5984cf0e950SBarry Smith       /* TODO off-diagonal */
5999566063dSJacob Faibussowitsch       PetscCall(PetscFree(cindices));
6009566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
6014cc7f7b2SMatthew G. Knepley     }
6029566063dSJacob Faibussowitsch     PetscCall(DMSwarmRestoreField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
6034cc7f7b2SMatthew G. Knepley   }
6049566063dSJacob Faibussowitsch   PetscCall(PetscFree4(elemMat, elemMatSq, rowIDXs, xi));
6059566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
6069566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
6079566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
6089566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
6099566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
6103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6114cc7f7b2SMatthew G. Knepley }
6124cc7f7b2SMatthew G. Knepley 
6134cc7f7b2SMatthew G. Knepley /*@C
6144cc7f7b2SMatthew G. Knepley   DMSwarmCreateMassMatrixSquare - Creates the block-diagonal of the square, M^T_p M_p, of the particle mass matrix M_p
6154cc7f7b2SMatthew G. Knepley 
61620f4b53cSBarry Smith   Collective
6174cc7f7b2SMatthew G. Knepley 
61860225df5SJacob Faibussowitsch   Input Parameters:
61920f4b53cSBarry Smith + dmCoarse - a `DMSWARM`
62020f4b53cSBarry Smith - dmFine   - a `DMPLEX`
6214cc7f7b2SMatthew G. Knepley 
62260225df5SJacob Faibussowitsch   Output Parameter:
6234cc7f7b2SMatthew G. Knepley . mass - the square of the particle mass matrix
6244cc7f7b2SMatthew G. Knepley 
6254cc7f7b2SMatthew G. Knepley   Level: advanced
6264cc7f7b2SMatthew G. Knepley 
62720f4b53cSBarry Smith   Note:
6284cc7f7b2SMatthew G. Knepley   We only compute the block diagonal since this provides a good preconditioner and is completely local. It would be possible in the
6294cc7f7b2SMatthew G. Knepley   future to compute the full normal equations.
6304cc7f7b2SMatthew G. Knepley 
63120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMCreateMassMatrix()`
6324cc7f7b2SMatthew G. Knepley @*/
633d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateMassMatrixSquare(DM dmCoarse, DM dmFine, Mat *mass)
634d71ae5a4SJacob Faibussowitsch {
6354cc7f7b2SMatthew G. Knepley   PetscInt n;
6364cc7f7b2SMatthew G. Knepley   void    *ctx;
6374cc7f7b2SMatthew G. Knepley 
6384cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
6399566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dmCoarse, &n));
6409566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
6419566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, n, PETSC_DETERMINE, PETSC_DETERMINE));
6429566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
6439566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
6444cc7f7b2SMatthew G. Knepley 
6459566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrixSquare_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
6469566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_sq_mat_view"));
6473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6484cc7f7b2SMatthew G. Knepley }
6494cc7f7b2SMatthew G. Knepley 
650fb1bcc12SMatthew G. Knepley /*@C
65120f4b53cSBarry Smith   DMSwarmCreateGlobalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
652d3a51819SDave May 
65320f4b53cSBarry Smith   Collective
654d3a51819SDave May 
65560225df5SJacob Faibussowitsch   Input Parameters:
65620f4b53cSBarry Smith + dm        - a `DMSWARM`
65762741f57SDave May - fieldname - the textual name given to a registered field
658d3a51819SDave May 
65960225df5SJacob Faibussowitsch   Output Parameter:
660d3a51819SDave May . vec - the vector
661d3a51819SDave May 
662d3a51819SDave May   Level: beginner
663d3a51819SDave May 
6648b8a3813SDave May   Notes:
66520f4b53cSBarry Smith   The vector must be returned using a matching call to `DMSwarmDestroyGlobalVectorFromField()`.
6668b8a3813SDave May 
66720f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromField()`
668d3a51819SDave May @*/
669d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
670d71ae5a4SJacob Faibussowitsch {
671fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PetscObjectComm((PetscObject)dm);
672b5bcf523SDave May 
673fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
674ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
6759566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
6763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
677b5bcf523SDave May }
678b5bcf523SDave May 
679d3a51819SDave May /*@C
68020f4b53cSBarry Smith   DMSwarmDestroyGlobalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
681d3a51819SDave May 
68220f4b53cSBarry Smith   Collective
683d3a51819SDave May 
68460225df5SJacob Faibussowitsch   Input Parameters:
68520f4b53cSBarry Smith + dm        - a `DMSWARM`
68662741f57SDave May - fieldname - the textual name given to a registered field
687d3a51819SDave May 
68860225df5SJacob Faibussowitsch   Output Parameter:
689d3a51819SDave May . vec - the vector
690d3a51819SDave May 
691d3a51819SDave May   Level: beginner
692d3a51819SDave May 
69320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()`
694d3a51819SDave May @*/
695d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
696d71ae5a4SJacob Faibussowitsch {
697fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
698ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
6999566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
7003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
701b5bcf523SDave May }
702b5bcf523SDave May 
703fb1bcc12SMatthew G. Knepley /*@C
70420f4b53cSBarry Smith   DMSwarmCreateLocalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
705fb1bcc12SMatthew G. Knepley 
70620f4b53cSBarry Smith   Collective
707fb1bcc12SMatthew G. Knepley 
70860225df5SJacob Faibussowitsch   Input Parameters:
70920f4b53cSBarry Smith + dm        - a `DMSWARM`
71062741f57SDave May - fieldname - the textual name given to a registered field
711fb1bcc12SMatthew G. Knepley 
71260225df5SJacob Faibussowitsch   Output Parameter:
713fb1bcc12SMatthew G. Knepley . vec - the vector
714fb1bcc12SMatthew G. Knepley 
715fb1bcc12SMatthew G. Knepley   Level: beginner
716fb1bcc12SMatthew G. Knepley 
71720f4b53cSBarry Smith   Note:
7188b8a3813SDave May   The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField().
7198b8a3813SDave May 
72020f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()`
721fb1bcc12SMatthew G. Knepley @*/
722d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
723d71ae5a4SJacob Faibussowitsch {
724fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PETSC_COMM_SELF;
725bbe8250bSMatthew G. Knepley 
726fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
7279566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
7283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
729bbe8250bSMatthew G. Knepley }
730fb1bcc12SMatthew G. Knepley 
731fb1bcc12SMatthew G. Knepley /*@C
73220f4b53cSBarry Smith   DMSwarmDestroyLocalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
733fb1bcc12SMatthew G. Knepley 
73420f4b53cSBarry Smith   Collective
735fb1bcc12SMatthew G. Knepley 
73660225df5SJacob Faibussowitsch   Input Parameters:
73720f4b53cSBarry Smith + dm        - a `DMSWARM`
73862741f57SDave May - fieldname - the textual name given to a registered field
739fb1bcc12SMatthew G. Knepley 
74060225df5SJacob Faibussowitsch   Output Parameter:
741fb1bcc12SMatthew G. Knepley . vec - the vector
742fb1bcc12SMatthew G. Knepley 
743fb1bcc12SMatthew G. Knepley   Level: beginner
744fb1bcc12SMatthew G. Knepley 
74520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromField()`
746fb1bcc12SMatthew G. Knepley @*/
747d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
748d71ae5a4SJacob Faibussowitsch {
749fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
750ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
7519566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
7523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
753bbe8250bSMatthew G. Knepley }
754bbe8250bSMatthew G. Knepley 
755d3a51819SDave May /*@C
75620f4b53cSBarry Smith   DMSwarmInitializeFieldRegister - Initiates the registration of fields to a `DMSWARM`
757d3a51819SDave May 
75820f4b53cSBarry Smith   Collective
759d3a51819SDave May 
76060225df5SJacob Faibussowitsch   Input Parameter:
76120f4b53cSBarry Smith . dm - a `DMSWARM`
762d3a51819SDave May 
763d3a51819SDave May   Level: beginner
764d3a51819SDave May 
76520f4b53cSBarry Smith   Note:
76620f4b53cSBarry Smith   After all fields have been registered, you must call `DMSwarmFinalizeFieldRegister()`.
767d3a51819SDave May 
76820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmFinalizeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
769db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
770d3a51819SDave May @*/
771d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmInitializeFieldRegister(DM dm)
772d71ae5a4SJacob Faibussowitsch {
7735f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
7743454631fSDave May 
775521f74f9SMatthew G. Knepley   PetscFunctionBegin;
776cc651181SDave May   if (!swarm->field_registration_initialized) {
7775f50eb2eSDave May     swarm->field_registration_initialized = PETSC_TRUE;
778da81f932SPierre Jolivet     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_pid, 1, PETSC_INT64)); /* unique identifier */
7799566063dSJacob Faibussowitsch     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_rank, 1, PETSC_INT));  /* used for communication */
780cc651181SDave May   }
7813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7825f50eb2eSDave May }
7835f50eb2eSDave May 
78474d0cae8SMatthew G. Knepley /*@
78520f4b53cSBarry Smith   DMSwarmFinalizeFieldRegister - Finalizes the registration of fields to a `DMSWARM`
786d3a51819SDave May 
78720f4b53cSBarry Smith   Collective
788d3a51819SDave May 
78960225df5SJacob Faibussowitsch   Input Parameter:
79020f4b53cSBarry Smith . dm - a `DMSWARM`
791d3a51819SDave May 
792d3a51819SDave May   Level: beginner
793d3a51819SDave May 
79420f4b53cSBarry Smith   Note:
79520f4b53cSBarry Smith   After `DMSwarmFinalizeFieldRegister()` has been called, no new fields can be defined on the `DMSWARM`.
796d3a51819SDave May 
79720f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmInitializeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
798db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
799d3a51819SDave May @*/
800d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmFinalizeFieldRegister(DM dm)
801d71ae5a4SJacob Faibussowitsch {
8025f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
8036845f8f5SDave May 
804521f74f9SMatthew G. Knepley   PetscFunctionBegin;
80548a46eb9SPierre Jolivet   if (!swarm->field_registration_finalized) PetscCall(DMSwarmDataBucketFinalize(swarm->db));
806f0cdbbbaSDave May   swarm->field_registration_finalized = PETSC_TRUE;
8073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8085f50eb2eSDave May }
8095f50eb2eSDave May 
81074d0cae8SMatthew G. Knepley /*@
81120f4b53cSBarry Smith   DMSwarmSetLocalSizes - Sets the length of all registered fields on the `DMSWARM`
812d3a51819SDave May 
81320f4b53cSBarry Smith   Not Collective
814d3a51819SDave May 
81560225df5SJacob Faibussowitsch   Input Parameters:
81620f4b53cSBarry Smith + dm     - a `DMSWARM`
817d3a51819SDave May . nlocal - the length of each registered field
81862741f57SDave May - buffer - the length of the buffer used to efficient dynamic re-sizing
819d3a51819SDave May 
820d3a51819SDave May   Level: beginner
821d3a51819SDave May 
82220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`
823d3a51819SDave May @*/
824d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetLocalSizes(DM dm, PetscInt nlocal, PetscInt buffer)
825d71ae5a4SJacob Faibussowitsch {
8265f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
8275f50eb2eSDave May 
828521f74f9SMatthew G. Knepley   PetscFunctionBegin;
8299566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_SetSizes, 0, 0, 0, 0));
8309566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, buffer));
8319566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_SetSizes, 0, 0, 0, 0));
8323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8335f50eb2eSDave May }
8345f50eb2eSDave May 
83574d0cae8SMatthew G. Knepley /*@
83620f4b53cSBarry Smith   DMSwarmSetCellDM - Attaches a `DM` to a `DMSWARM`
837d3a51819SDave May 
83820f4b53cSBarry Smith   Collective
839d3a51819SDave May 
84060225df5SJacob Faibussowitsch   Input Parameters:
84120f4b53cSBarry Smith + dm     - a `DMSWARM`
84220f4b53cSBarry Smith - dmcell - the `DM` to attach to the `DMSWARM`
843d3a51819SDave May 
844d3a51819SDave May   Level: beginner
845d3a51819SDave May 
84620f4b53cSBarry Smith   Note:
84720f4b53cSBarry Smith   The attached `DM` (dmcell) will be queried for point location and
84820f4b53cSBarry Smith   neighbor MPI-rank information if `DMSwarmMigrate()` is called.
849d3a51819SDave May 
85020f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmGetCellDM()`, `DMSwarmMigrate()`
851d3a51819SDave May @*/
852d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetCellDM(DM dm, DM dmcell)
853d71ae5a4SJacob Faibussowitsch {
854b16650c8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
855521f74f9SMatthew G. Knepley 
856521f74f9SMatthew G. Knepley   PetscFunctionBegin;
857b16650c8SDave May   swarm->dmcell = dmcell;
8583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
859b16650c8SDave May }
860b16650c8SDave May 
86174d0cae8SMatthew G. Knepley /*@
86220f4b53cSBarry Smith   DMSwarmGetCellDM - Fetches the attached cell `DM`
863d3a51819SDave May 
86420f4b53cSBarry Smith   Collective
865d3a51819SDave May 
86660225df5SJacob Faibussowitsch   Input Parameter:
86720f4b53cSBarry Smith . dm - a `DMSWARM`
868d3a51819SDave May 
86960225df5SJacob Faibussowitsch   Output Parameter:
87020f4b53cSBarry Smith . dmcell - the `DM` which was attached to the `DMSWARM`
871d3a51819SDave May 
872d3a51819SDave May   Level: beginner
873d3a51819SDave May 
87420f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
875d3a51819SDave May @*/
876d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetCellDM(DM dm, DM *dmcell)
877d71ae5a4SJacob Faibussowitsch {
878fe39f135SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
879521f74f9SMatthew G. Knepley 
880521f74f9SMatthew G. Knepley   PetscFunctionBegin;
881fe39f135SDave May   *dmcell = swarm->dmcell;
8823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
883fe39f135SDave May }
884fe39f135SDave May 
88574d0cae8SMatthew G. Knepley /*@
886d5b43468SJose E. Roman   DMSwarmGetLocalSize - Retrieves the local length of fields registered
887d3a51819SDave May 
88820f4b53cSBarry Smith   Not Collective
889d3a51819SDave May 
89060225df5SJacob Faibussowitsch   Input Parameter:
89120f4b53cSBarry Smith . dm - a `DMSWARM`
892d3a51819SDave May 
89360225df5SJacob Faibussowitsch   Output Parameter:
894d3a51819SDave May . nlocal - the length of each registered field
895d3a51819SDave May 
896d3a51819SDave May   Level: beginner
897d3a51819SDave May 
89820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetSize()`, `DMSwarmSetLocalSizes()`
899d3a51819SDave May @*/
900d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetLocalSize(DM dm, PetscInt *nlocal)
901d71ae5a4SJacob Faibussowitsch {
902dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
903dcf43ee8SDave May 
904521f74f9SMatthew G. Knepley   PetscFunctionBegin;
9059566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, nlocal, NULL, NULL));
9063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
907dcf43ee8SDave May }
908dcf43ee8SDave May 
90974d0cae8SMatthew G. Knepley /*@
910d5b43468SJose E. Roman   DMSwarmGetSize - Retrieves the total length of fields registered
911d3a51819SDave May 
91220f4b53cSBarry Smith   Collective
913d3a51819SDave May 
91460225df5SJacob Faibussowitsch   Input Parameter:
91520f4b53cSBarry Smith . dm - a `DMSWARM`
916d3a51819SDave May 
91760225df5SJacob Faibussowitsch   Output Parameter:
918d3a51819SDave May . n - the total length of each registered field
919d3a51819SDave May 
920d3a51819SDave May   Level: beginner
921d3a51819SDave May 
922d3a51819SDave May   Note:
92320f4b53cSBarry Smith   This calls `MPI_Allreduce()` upon each call (inefficient but safe)
924d3a51819SDave May 
92520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`, `DMSwarmSetLocalSizes()`
926d3a51819SDave May @*/
927d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetSize(DM dm, PetscInt *n)
928d71ae5a4SJacob Faibussowitsch {
929dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
9305627991aSBarry Smith   PetscInt  nlocal;
931dcf43ee8SDave May 
932521f74f9SMatthew G. Knepley   PetscFunctionBegin;
9339566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
934712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&nlocal, n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
9353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
936dcf43ee8SDave May }
937dcf43ee8SDave May 
938d3a51819SDave May /*@C
93920f4b53cSBarry Smith   DMSwarmRegisterPetscDatatypeField - Register a field to a `DMSWARM` with a native PETSc data type
940d3a51819SDave May 
94120f4b53cSBarry Smith   Collective
942d3a51819SDave May 
94360225df5SJacob Faibussowitsch   Input Parameters:
94420f4b53cSBarry Smith + dm        - a `DMSWARM`
945d3a51819SDave May . fieldname - the textual name to identify this field
946d3a51819SDave May . blocksize - the number of each data type
94720f4b53cSBarry Smith - type      - a valid PETSc data type (`PETSC_CHAR`, `PETSC_SHORT`, `PETSC_INT`, `PETSC_FLOAT`, `PETSC_REAL`, `PETSC_LONG`)
948d3a51819SDave May 
949d3a51819SDave May   Level: beginner
950d3a51819SDave May 
951d3a51819SDave May   Notes:
9528b8a3813SDave May   The textual name for each registered field must be unique.
953d3a51819SDave May 
95420f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
955d3a51819SDave May @*/
956d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterPetscDatatypeField(DM dm, const char fieldname[], PetscInt blocksize, PetscDataType type)
957d71ae5a4SJacob Faibussowitsch {
958b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
959b62e03f8SDave May   size_t    size;
960b62e03f8SDave May 
961521f74f9SMatthew G. Knepley   PetscFunctionBegin;
96228b400f6SJacob Faibussowitsch   PetscCheck(swarm->field_registration_initialized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmInitializeFieldRegister() first");
96328b400f6SJacob Faibussowitsch   PetscCheck(!swarm->field_registration_finalized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Cannot register additional fields after calling DMSwarmFinalizeFieldRegister() first");
9645f50eb2eSDave May 
96508401ef6SPierre Jolivet   PetscCheck(type != PETSC_OBJECT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96608401ef6SPierre Jolivet   PetscCheck(type != PETSC_FUNCTION, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96708401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRING, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96808401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRUCT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96908401ef6SPierre Jolivet   PetscCheck(type != PETSC_DATATYPE_UNKNOWN, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
970b62e03f8SDave May 
9719566063dSJacob Faibussowitsch   PetscCall(PetscDataTypeGetSize(type, &size));
972b62e03f8SDave May   /* Load a specific data type into data bucket, specifying textual name and its size in bytes */
9739566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterPetscDatatypeField", fieldname, blocksize * size, NULL));
97452c3ed93SDave May   {
97577048351SPatrick Sanan     DMSwarmDataField gfield;
97652c3ed93SDave May 
9779566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
9789566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
97952c3ed93SDave May   }
980b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = type;
9813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
982b62e03f8SDave May }
983b62e03f8SDave May 
984d3a51819SDave May /*@C
98520f4b53cSBarry Smith   DMSwarmRegisterUserStructField - Register a user defined struct to a `DMSWARM`
986d3a51819SDave May 
98720f4b53cSBarry Smith   Collective
988d3a51819SDave May 
98960225df5SJacob Faibussowitsch   Input Parameters:
99020f4b53cSBarry Smith + dm        - a `DMSWARM`
991d3a51819SDave May . fieldname - the textual name to identify this field
99262741f57SDave May - size      - the size in bytes of the user struct of each data type
993d3a51819SDave May 
994d3a51819SDave May   Level: beginner
995d3a51819SDave May 
99620f4b53cSBarry Smith   Note:
9978b8a3813SDave May   The textual name for each registered field must be unique.
998d3a51819SDave May 
99920f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserDatatypeField()`
1000d3a51819SDave May @*/
1001d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserStructField(DM dm, const char fieldname[], size_t size)
1002d71ae5a4SJacob Faibussowitsch {
1003b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1004b62e03f8SDave May 
1005521f74f9SMatthew G. Knepley   PetscFunctionBegin;
10069566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserStructField", fieldname, size, NULL));
1007b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_STRUCT;
10083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1009b62e03f8SDave May }
1010b62e03f8SDave May 
1011d3a51819SDave May /*@C
101220f4b53cSBarry Smith   DMSwarmRegisterUserDatatypeField - Register a user defined data type to a `DMSWARM`
1013d3a51819SDave May 
101420f4b53cSBarry Smith   Collective
1015d3a51819SDave May 
101660225df5SJacob Faibussowitsch   Input Parameters:
101720f4b53cSBarry Smith + dm        - a `DMSWARM`
1018d3a51819SDave May . fieldname - the textual name to identify this field
1019d3a51819SDave May . size      - the size in bytes of the user data type
102062741f57SDave May - blocksize - the number of each data type
1021d3a51819SDave May 
1022d3a51819SDave May   Level: beginner
1023d3a51819SDave May 
102420f4b53cSBarry Smith   Note:
10258b8a3813SDave May   The textual name for each registered field must be unique.
1026d3a51819SDave May 
102742747ad1SJacob Faibussowitsch .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserStructField()`
1028d3a51819SDave May @*/
1029d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserDatatypeField(DM dm, const char fieldname[], size_t size, PetscInt blocksize)
1030d71ae5a4SJacob Faibussowitsch {
1031b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1032b62e03f8SDave May 
1033521f74f9SMatthew G. Knepley   PetscFunctionBegin;
10349566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserDatatypeField", fieldname, blocksize * size, NULL));
1035320740a0SDave May   {
103677048351SPatrick Sanan     DMSwarmDataField gfield;
1037320740a0SDave May 
10389566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
10399566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
1040320740a0SDave May   }
1041b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_DATATYPE_UNKNOWN;
10423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1043b62e03f8SDave May }
1044b62e03f8SDave May 
1045d3a51819SDave May /*@C
1046d3a51819SDave May   DMSwarmGetField - Get access to the underlying array storing all entries associated with a registered field
1047d3a51819SDave May 
104820f4b53cSBarry Smith   Not Collective
1049d3a51819SDave May 
105060225df5SJacob Faibussowitsch   Input Parameters:
105120f4b53cSBarry Smith + dm        - a `DMSWARM`
105262741f57SDave May - fieldname - the textual name to identify this field
1053d3a51819SDave May 
105460225df5SJacob Faibussowitsch   Output Parameters:
105562741f57SDave May + blocksize - the number of each data type
1056d3a51819SDave May . type      - the data type
105762741f57SDave May - data      - pointer to raw array
1058d3a51819SDave May 
1059d3a51819SDave May   Level: beginner
1060d3a51819SDave May 
1061d3a51819SDave May   Notes:
106220f4b53cSBarry Smith   The array must be returned using a matching call to `DMSwarmRestoreField()`.
1063d3a51819SDave May 
106420f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreField()`
1065d3a51819SDave May @*/
1066d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1067d71ae5a4SJacob Faibussowitsch {
1068b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
106977048351SPatrick Sanan   DMSwarmDataField gfield;
1070b62e03f8SDave May 
1071521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1072ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
10739566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
10749566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
10759566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetAccess(gfield));
10769566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetEntries(gfield, data));
1077ad540459SPierre Jolivet   if (blocksize) *blocksize = gfield->bs;
1078ad540459SPierre Jolivet   if (type) *type = gfield->petsc_type;
10793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1080b62e03f8SDave May }
1081b62e03f8SDave May 
1082d3a51819SDave May /*@C
1083d3a51819SDave May   DMSwarmRestoreField - Restore access to the underlying array storing all entries associated with a registered field
1084d3a51819SDave May 
108520f4b53cSBarry Smith   Not Collective
1086d3a51819SDave May 
108760225df5SJacob Faibussowitsch   Input Parameters:
108820f4b53cSBarry Smith + dm        - a `DMSWARM`
108962741f57SDave May - fieldname - the textual name to identify this field
1090d3a51819SDave May 
109160225df5SJacob Faibussowitsch   Output Parameters:
109262741f57SDave May + blocksize - the number of each data type
1093d3a51819SDave May . type      - the data type
109462741f57SDave May - data      - pointer to raw array
1095d3a51819SDave May 
1096d3a51819SDave May   Level: beginner
1097d3a51819SDave May 
1098d3a51819SDave May   Notes:
109920f4b53cSBarry Smith   The user must call `DMSwarmGetField()` prior to calling `DMSwarmRestoreField()`.
1100d3a51819SDave May 
110120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetField()`
1102d3a51819SDave May @*/
1103d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRestoreField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1104d71ae5a4SJacob Faibussowitsch {
1105b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
110677048351SPatrick Sanan   DMSwarmDataField gfield;
1107b62e03f8SDave May 
1108521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1109ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
11109566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
11119566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
1112b62e03f8SDave May   if (data) *data = NULL;
11133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1114b62e03f8SDave May }
1115b62e03f8SDave May 
111674d0cae8SMatthew G. Knepley /*@
111720f4b53cSBarry Smith   DMSwarmAddPoint - Add space for one new point in the `DMSWARM`
1118d3a51819SDave May 
111920f4b53cSBarry Smith   Not Collective
1120d3a51819SDave May 
112160225df5SJacob Faibussowitsch   Input Parameter:
112220f4b53cSBarry Smith . dm - a `DMSWARM`
1123d3a51819SDave May 
1124d3a51819SDave May   Level: beginner
1125d3a51819SDave May 
1126d3a51819SDave May   Notes:
11278b8a3813SDave May   The new point will have all fields initialized to zero.
1128d3a51819SDave May 
112920f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmAddNPoints()`
1130d3a51819SDave May @*/
1131d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddPoint(DM dm)
1132d71ae5a4SJacob Faibussowitsch {
1133cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1134cb1d1399SDave May 
1135521f74f9SMatthew G. Knepley   PetscFunctionBegin;
11369566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
11379566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
11389566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketAddPoint(swarm->db));
11399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
11403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1141cb1d1399SDave May }
1142cb1d1399SDave May 
114374d0cae8SMatthew G. Knepley /*@
114420f4b53cSBarry Smith   DMSwarmAddNPoints - Add space for a number of new points in the `DMSWARM`
1145d3a51819SDave May 
114620f4b53cSBarry Smith   Not Collective
1147d3a51819SDave May 
114860225df5SJacob Faibussowitsch   Input Parameters:
114920f4b53cSBarry Smith + dm      - a `DMSWARM`
115062741f57SDave May - npoints - the number of new points to add
1151d3a51819SDave May 
1152d3a51819SDave May   Level: beginner
1153d3a51819SDave May 
1154d3a51819SDave May   Notes:
11558b8a3813SDave May   The new point will have all fields initialized to zero.
1156d3a51819SDave May 
115720f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmAddPoint()`
1158d3a51819SDave May @*/
1159d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddNPoints(DM dm, PetscInt npoints)
1160d71ae5a4SJacob Faibussowitsch {
1161cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1162cb1d1399SDave May   PetscInt  nlocal;
1163cb1d1399SDave May 
1164521f74f9SMatthew G. Knepley   PetscFunctionBegin;
11659566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
11669566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
1167cb1d1399SDave May   nlocal = nlocal + npoints;
11689566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
11699566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
11703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1171cb1d1399SDave May }
1172cb1d1399SDave May 
117374d0cae8SMatthew G. Knepley /*@
117420f4b53cSBarry Smith   DMSwarmRemovePoint - Remove the last point from the `DMSWARM`
1175d3a51819SDave May 
117620f4b53cSBarry Smith   Not Collective
1177d3a51819SDave May 
117860225df5SJacob Faibussowitsch   Input Parameter:
117920f4b53cSBarry Smith . dm - a `DMSWARM`
1180d3a51819SDave May 
1181d3a51819SDave May   Level: beginner
1182d3a51819SDave May 
118320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePointAtIndex()`
1184d3a51819SDave May @*/
1185d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePoint(DM dm)
1186d71ae5a4SJacob Faibussowitsch {
1187cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1188cb1d1399SDave May 
1189521f74f9SMatthew G. Knepley   PetscFunctionBegin;
11909566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
11919566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePoint(swarm->db));
11929566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
11933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1194cb1d1399SDave May }
1195cb1d1399SDave May 
119674d0cae8SMatthew G. Knepley /*@
119720f4b53cSBarry Smith   DMSwarmRemovePointAtIndex - Removes a specific point from the `DMSWARM`
1198d3a51819SDave May 
119920f4b53cSBarry Smith   Not Collective
1200d3a51819SDave May 
120160225df5SJacob Faibussowitsch   Input Parameters:
120220f4b53cSBarry Smith + dm  - a `DMSWARM`
120362741f57SDave May - idx - index of point to remove
1204d3a51819SDave May 
1205d3a51819SDave May   Level: beginner
1206d3a51819SDave May 
120720f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
1208d3a51819SDave May @*/
1209d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePointAtIndex(DM dm, PetscInt idx)
1210d71ae5a4SJacob Faibussowitsch {
1211cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1212cb1d1399SDave May 
1213521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12149566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
12159566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, idx));
12169566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
12173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1218cb1d1399SDave May }
1219b62e03f8SDave May 
122074d0cae8SMatthew G. Knepley /*@
122120f4b53cSBarry Smith   DMSwarmCopyPoint - Copy point pj to point pi in the `DMSWARM`
1222ba4fc9c6SDave May 
122320f4b53cSBarry Smith   Not Collective
1224ba4fc9c6SDave May 
122560225df5SJacob Faibussowitsch   Input Parameters:
122620f4b53cSBarry Smith + dm - a `DMSWARM`
1227ba4fc9c6SDave May . pi - the index of the point to copy
1228ba4fc9c6SDave May - pj - the point index where the copy should be located
1229ba4fc9c6SDave May 
1230ba4fc9c6SDave May   Level: beginner
1231ba4fc9c6SDave May 
123220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
1233ba4fc9c6SDave May @*/
1234d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCopyPoint(DM dm, PetscInt pi, PetscInt pj)
1235d71ae5a4SJacob Faibussowitsch {
1236ba4fc9c6SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1237ba4fc9c6SDave May 
1238ba4fc9c6SDave May   PetscFunctionBegin;
12399566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
12409566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCopyPoint(swarm->db, pi, swarm->db, pj));
12413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1242ba4fc9c6SDave May }
1243ba4fc9c6SDave May 
124466976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmMigrate_Basic(DM dm, PetscBool remove_sent_points)
1245d71ae5a4SJacob Faibussowitsch {
1246521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12479566063dSJacob Faibussowitsch   PetscCall(DMSwarmMigrate_Push_Basic(dm, remove_sent_points));
12483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12493454631fSDave May }
12503454631fSDave May 
125174d0cae8SMatthew G. Knepley /*@
125220f4b53cSBarry Smith   DMSwarmMigrate - Relocates points defined in the `DMSWARM` to other MPI-ranks
1253d3a51819SDave May 
125420f4b53cSBarry Smith   Collective
1255d3a51819SDave May 
125660225df5SJacob Faibussowitsch   Input Parameters:
125720f4b53cSBarry Smith + dm                 - the `DMSWARM`
125862741f57SDave May - remove_sent_points - flag indicating if sent points should be removed from the current MPI-rank
1259d3a51819SDave May 
1260d3a51819SDave May   Level: advanced
1261d3a51819SDave May 
126220f4b53cSBarry Smith   Notes:
126320f4b53cSBarry Smith   The `DM` will be modified to accommodate received points.
126420f4b53cSBarry Smith   If `remove_sent_points` is `PETSC_TRUE`, any points that were sent will be removed from the `DM`.
126520f4b53cSBarry Smith   Different styles of migration are supported. See `DMSwarmSetMigrateType()`.
126620f4b53cSBarry Smith 
126720f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`
1268d3a51819SDave May @*/
1269d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmMigrate(DM dm, PetscBool remove_sent_points)
1270d71ae5a4SJacob Faibussowitsch {
1271f0cdbbbaSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1272f0cdbbbaSDave May 
1273521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12749566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_Migrate, 0, 0, 0, 0));
1275f0cdbbbaSDave May   switch (swarm->migrate_type) {
1276d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_BASIC:
1277d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_Basic(dm, remove_sent_points));
1278d71ae5a4SJacob Faibussowitsch     break;
1279d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLNSCATTER:
1280d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_CellDMScatter(dm, remove_sent_points));
1281d71ae5a4SJacob Faibussowitsch     break;
1282d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLEXACT:
1283d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_DMCELLEXACT not implemented");
1284d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_USER:
1285d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_USER not implemented");
1286d71ae5a4SJacob Faibussowitsch   default:
1287d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE type unknown");
1288f0cdbbbaSDave May   }
12899566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_Migrate, 0, 0, 0, 0));
12909566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm));
12913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12923454631fSDave May }
12933454631fSDave May 
1294f0cdbbbaSDave May PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm, PetscInt *globalsize);
1295f0cdbbbaSDave May 
1296d3a51819SDave May /*
1297d3a51819SDave May  DMSwarmCollectViewCreate
1298d3a51819SDave May 
1299d3a51819SDave May  * Applies a collection method and gathers point neighbour points into dm
1300d3a51819SDave May 
1301d3a51819SDave May  Notes:
13028b8a3813SDave May  Users should call DMSwarmCollectViewDestroy() after
1303d3a51819SDave May  they have finished computations associated with the collected points
1304d3a51819SDave May */
1305d3a51819SDave May 
130674d0cae8SMatthew G. Knepley /*@
1307d3a51819SDave May   DMSwarmCollectViewCreate - Applies a collection method and gathers points
130820f4b53cSBarry Smith   in neighbour ranks into the `DMSWARM`
1309d3a51819SDave May 
131020f4b53cSBarry Smith   Collective
1311d3a51819SDave May 
131260225df5SJacob Faibussowitsch   Input Parameter:
131320f4b53cSBarry Smith . dm - the `DMSWARM`
1314d3a51819SDave May 
1315d3a51819SDave May   Level: advanced
1316d3a51819SDave May 
131720f4b53cSBarry Smith   Notes:
131820f4b53cSBarry Smith   Users should call `DMSwarmCollectViewDestroy()` after
131920f4b53cSBarry Smith   they have finished computations associated with the collected points
132020f4b53cSBarry Smith   Different collect methods are supported. See `DMSwarmSetCollectType()`.
132120f4b53cSBarry Smith 
132220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewDestroy()`, `DMSwarmSetCollectType()`
1323d3a51819SDave May @*/
1324d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewCreate(DM dm)
1325d71ae5a4SJacob Faibussowitsch {
13262712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
13272712d1f2SDave May   PetscInt  ng;
13282712d1f2SDave May 
1329521f74f9SMatthew G. Knepley   PetscFunctionBegin;
133028b400f6SJacob Faibussowitsch   PetscCheck(!swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView currently active");
13319566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &ng));
1332480eef7bSDave May   switch (swarm->collect_type) {
1333d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_BASIC:
1334d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_GlobalToLocal_Basic(dm, &ng));
1335d71ae5a4SJacob Faibussowitsch     break;
1336d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_DMDABOUNDINGBOX:
1337d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_DMDABOUNDINGBOX not implemented");
1338d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_GENERAL:
1339d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_GENERAL not implemented");
1340d71ae5a4SJacob Faibussowitsch   default:
1341d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT type unknown");
1342480eef7bSDave May   }
1343480eef7bSDave May   swarm->collect_view_active       = PETSC_TRUE;
1344480eef7bSDave May   swarm->collect_view_reset_nlocal = ng;
13453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13462712d1f2SDave May }
13472712d1f2SDave May 
134874d0cae8SMatthew G. Knepley /*@
134920f4b53cSBarry Smith   DMSwarmCollectViewDestroy - Resets the `DMSWARM` to the size prior to calling `DMSwarmCollectViewCreate()`
1350d3a51819SDave May 
135120f4b53cSBarry Smith   Collective
1352d3a51819SDave May 
135360225df5SJacob Faibussowitsch   Input Parameters:
135420f4b53cSBarry Smith . dm - the `DMSWARM`
1355d3a51819SDave May 
1356d3a51819SDave May   Notes:
135720f4b53cSBarry Smith   Users should call `DMSwarmCollectViewCreate()` before this function is called.
1358d3a51819SDave May 
1359d3a51819SDave May   Level: advanced
1360d3a51819SDave May 
136120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewCreate()`, `DMSwarmSetCollectType()`
1362d3a51819SDave May @*/
1363d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewDestroy(DM dm)
1364d71ae5a4SJacob Faibussowitsch {
13652712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
13662712d1f2SDave May 
1367521f74f9SMatthew G. Knepley   PetscFunctionBegin;
136828b400f6SJacob Faibussowitsch   PetscCheck(swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView is currently not active");
13699566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetLocalSizes(dm, swarm->collect_view_reset_nlocal, -1));
1370480eef7bSDave May   swarm->collect_view_active = PETSC_FALSE;
13713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13722712d1f2SDave May }
13733454631fSDave May 
137466976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmSetUpPIC(DM dm)
1375d71ae5a4SJacob Faibussowitsch {
1376f0cdbbbaSDave May   PetscInt dim;
1377f0cdbbbaSDave May 
1378521f74f9SMatthew G. Knepley   PetscFunctionBegin;
13799566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetNumSpecies(dm, 1));
13809566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
138163a3b9bcSJacob Faibussowitsch   PetscCheck(dim >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
138263a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
13839566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_coor, dim, PETSC_DOUBLE));
13849566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_cellid, 1, PETSC_INT));
13853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1386f0cdbbbaSDave May }
1387f0cdbbbaSDave May 
138874d0cae8SMatthew G. Knepley /*@
138931403186SMatthew G. Knepley   DMSwarmSetPointCoordinatesRandom - Sets initial coordinates for particles in each cell
139031403186SMatthew G. Knepley 
139120f4b53cSBarry Smith   Collective
139231403186SMatthew G. Knepley 
139360225df5SJacob Faibussowitsch   Input Parameters:
139420f4b53cSBarry Smith + dm  - the `DMSWARM`
139520f4b53cSBarry Smith - Npc - The number of particles per cell in the cell `DM`
139631403186SMatthew G. Knepley 
139731403186SMatthew G. Knepley   Level: intermediate
139831403186SMatthew G. Knepley 
139920f4b53cSBarry Smith   Notes:
140020f4b53cSBarry Smith   The user must use `DMSwarmSetCellDM()` to set the cell `DM` first. The particles are placed randomly inside each cell. If only
140120f4b53cSBarry Smith   one particle is in each cell, it is placed at the centroid.
140220f4b53cSBarry Smith 
140320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
140431403186SMatthew G. Knepley @*/
1405d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetPointCoordinatesRandom(DM dm, PetscInt Npc)
1406d71ae5a4SJacob Faibussowitsch {
140731403186SMatthew G. Knepley   DM             cdm;
140831403186SMatthew G. Knepley   PetscRandom    rnd;
140931403186SMatthew G. Knepley   DMPolytopeType ct;
141031403186SMatthew G. Knepley   PetscBool      simplex;
141131403186SMatthew G. Knepley   PetscReal     *centroid, *coords, *xi0, *v0, *J, *invJ, detJ;
141231403186SMatthew G. Knepley   PetscInt       dim, d, cStart, cEnd, c, p;
141331403186SMatthew G. Knepley 
141431403186SMatthew G. Knepley   PetscFunctionBeginUser;
14159566063dSJacob Faibussowitsch   PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm), &rnd));
14169566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0));
14179566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetType(rnd, PETSCRAND48));
141831403186SMatthew G. Knepley 
14199566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
14209566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(cdm, &dim));
14219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd));
14229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(cdm, cStart, &ct));
142331403186SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
142431403186SMatthew G. Knepley 
14259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(dim, &centroid, dim, &xi0, dim, &v0, dim * dim, &J, dim * dim, &invJ));
142631403186SMatthew G. Knepley   for (d = 0; d < dim; ++d) xi0[d] = -1.0;
14279566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
142831403186SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
142931403186SMatthew G. Knepley     if (Npc == 1) {
14309566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(cdm, c, NULL, centroid, NULL));
143131403186SMatthew G. Knepley       for (d = 0; d < dim; ++d) coords[c * dim + d] = centroid[d];
143231403186SMatthew G. Knepley     } else {
14339566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(cdm, c, NULL, v0, J, invJ, &detJ)); /* affine */
143431403186SMatthew G. Knepley       for (p = 0; p < Npc; ++p) {
143531403186SMatthew G. Knepley         const PetscInt n   = c * Npc + p;
143631403186SMatthew G. Knepley         PetscReal      sum = 0.0, refcoords[3];
143731403186SMatthew G. Knepley 
143831403186SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
14399566063dSJacob Faibussowitsch           PetscCall(PetscRandomGetValueReal(rnd, &refcoords[d]));
144031403186SMatthew G. Knepley           sum += refcoords[d];
144131403186SMatthew G. Knepley         }
14429371c9d4SSatish Balay         if (simplex && sum > 0.0)
14439371c9d4SSatish Balay           for (d = 0; d < dim; ++d) refcoords[d] -= PetscSqrtReal(dim) * sum;
144431403186SMatthew G. Knepley         CoordinatesRefToReal(dim, dim, xi0, v0, J, refcoords, &coords[n * dim]);
144531403186SMatthew G. Knepley       }
144631403186SMatthew G. Knepley     }
144731403186SMatthew G. Knepley   }
14489566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
14499566063dSJacob Faibussowitsch   PetscCall(PetscFree5(centroid, xi0, v0, J, invJ));
14509566063dSJacob Faibussowitsch   PetscCall(PetscRandomDestroy(&rnd));
14513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
145231403186SMatthew G. Knepley }
145331403186SMatthew G. Knepley 
145431403186SMatthew G. Knepley /*@
145520f4b53cSBarry Smith   DMSwarmSetType - Set particular flavor of `DMSWARM`
1456d3a51819SDave May 
145720f4b53cSBarry Smith   Collective
1458d3a51819SDave May 
145960225df5SJacob Faibussowitsch   Input Parameters:
146020f4b53cSBarry Smith + dm    - the `DMSWARM`
146120f4b53cSBarry Smith - stype - the `DMSWARM` type (e.g. `DMSWARM_PIC`)
1462d3a51819SDave May 
1463d3a51819SDave May   Level: advanced
1464d3a51819SDave May 
146520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`, `DMSwarmSetCollectType()`, `DMSwarmType`, `DMSWARM_PIC`, `DMSWARM_BASIC`
1466d3a51819SDave May @*/
1467d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetType(DM dm, DMSwarmType stype)
1468d71ae5a4SJacob Faibussowitsch {
1469f0cdbbbaSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1470f0cdbbbaSDave May 
1471521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1472f0cdbbbaSDave May   swarm->swarm_type = stype;
147348a46eb9SPierre Jolivet   if (swarm->swarm_type == DMSWARM_PIC) PetscCall(DMSwarmSetUpPIC(dm));
14743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1475f0cdbbbaSDave May }
1476f0cdbbbaSDave May 
147766976f2fSJacob Faibussowitsch static PetscErrorCode DMSetup_Swarm(DM dm)
1478d71ae5a4SJacob Faibussowitsch {
14793454631fSDave May   DM_Swarm   *swarm = (DM_Swarm *)dm->data;
14803454631fSDave May   PetscMPIInt rank;
14813454631fSDave May   PetscInt    p, npoints, *rankval;
14823454631fSDave May 
1483521f74f9SMatthew G. Knepley   PetscFunctionBegin;
14843ba16761SJacob Faibussowitsch   if (swarm->issetup) PetscFunctionReturn(PETSC_SUCCESS);
14853454631fSDave May   swarm->issetup = PETSC_TRUE;
14863454631fSDave May 
1487f0cdbbbaSDave May   if (swarm->swarm_type == DMSWARM_PIC) {
1488f0cdbbbaSDave May     /* check dmcell exists */
148928b400f6SJacob Faibussowitsch     PetscCheck(swarm->dmcell, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires you call DMSwarmSetCellDM");
1490f0cdbbbaSDave May 
1491f0cdbbbaSDave May     if (swarm->dmcell->ops->locatepointssubdomain) {
1492f0cdbbbaSDave May       /* check methods exists for exact ownership identificiation */
14939566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->ops->LocatePointsSubdomain\n"));
1494f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLEXACT;
1495f0cdbbbaSDave May     } else {
1496f0cdbbbaSDave May       /* check methods exist for point location AND rank neighbor identification */
1497f0cdbbbaSDave May       if (swarm->dmcell->ops->locatepoints) {
14989566063dSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->LocatePoints\n"));
1499f0cdbbbaSDave May       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->locatepoints be defined");
1500f0cdbbbaSDave May 
1501f0cdbbbaSDave May       if (swarm->dmcell->ops->getneighbors) {
15029566063dSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->GetNeigbors\n"));
1503f0cdbbbaSDave May       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->getneighbors be defined");
1504f0cdbbbaSDave May 
1505f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLNSCATTER;
1506f0cdbbbaSDave May     }
1507f0cdbbbaSDave May   }
1508f0cdbbbaSDave May 
15099566063dSJacob Faibussowitsch   PetscCall(DMSwarmFinalizeFieldRegister(dm));
1510f0cdbbbaSDave May 
15113454631fSDave May   /* check some fields were registered */
151208401ef6SPierre Jolivet   PetscCheck(swarm->db->nfields > 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "At least one field user must be registered via DMSwarmRegisterXXX()");
15133454631fSDave May 
15143454631fSDave May   /* check local sizes were set */
151508401ef6SPierre Jolivet   PetscCheck(swarm->db->L != -1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Local sizes must be set via DMSwarmSetLocalSizes()");
15163454631fSDave May 
15173454631fSDave May   /* initialize values in pid and rank placeholders */
15183454631fSDave May   /* TODO: [pid - use MPI_Scan] */
15199566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
15209566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
15219566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
1522ad540459SPierre Jolivet   for (p = 0; p < npoints; p++) rankval[p] = (PetscInt)rank;
15239566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
15243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15253454631fSDave May }
15263454631fSDave May 
1527dc5f5ce9SDave May extern PetscErrorCode DMSwarmSortDestroy(DMSwarmSort *_ctx);
1528dc5f5ce9SDave May 
152966976f2fSJacob Faibussowitsch static PetscErrorCode DMDestroy_Swarm(DM dm)
1530d71ae5a4SJacob Faibussowitsch {
153157795646SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
153257795646SDave May 
153357795646SDave May   PetscFunctionBegin;
15343ba16761SJacob Faibussowitsch   if (--swarm->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
15359566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&swarm->db));
153648a46eb9SPierre Jolivet   if (swarm->sort_context) PetscCall(DMSwarmSortDestroy(&swarm->sort_context));
15379566063dSJacob Faibussowitsch   PetscCall(PetscFree(swarm));
15383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153957795646SDave May }
154057795646SDave May 
154166976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmView_Draw(DM dm, PetscViewer viewer)
1542d71ae5a4SJacob Faibussowitsch {
1543a9ee3421SMatthew G. Knepley   DM         cdm;
1544a9ee3421SMatthew G. Knepley   PetscDraw  draw;
154531403186SMatthew G. Knepley   PetscReal *coords, oldPause, radius = 0.01;
1546a9ee3421SMatthew G. Knepley   PetscInt   Np, p, bs;
1547a9ee3421SMatthew G. Knepley 
1548a9ee3421SMatthew G. Knepley   PetscFunctionBegin;
15499566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetReal(NULL, ((PetscObject)dm)->prefix, "-dm_view_swarm_radius", &radius, NULL));
15509566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
15519566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
15529566063dSJacob Faibussowitsch   PetscCall(PetscDrawGetPause(draw, &oldPause));
15539566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, 0.0));
15549566063dSJacob Faibussowitsch   PetscCall(DMView(cdm, viewer));
15559566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, oldPause));
1556a9ee3421SMatthew G. Knepley 
15579566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &Np));
15589566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&coords));
1559a9ee3421SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
1560a9ee3421SMatthew G. Knepley     const PetscInt i = p * bs;
1561a9ee3421SMatthew G. Knepley 
15629566063dSJacob Faibussowitsch     PetscCall(PetscDrawEllipse(draw, coords[i], coords[i + 1], radius, radius, PETSC_DRAW_BLUE));
1563a9ee3421SMatthew G. Knepley   }
15649566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&coords));
15659566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
15669566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
15679566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
15683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1569a9ee3421SMatthew G. Knepley }
1570a9ee3421SMatthew G. Knepley 
1571d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_Swarm_Ascii(DM dm, PetscViewer viewer)
1572d71ae5a4SJacob Faibussowitsch {
15736a5217c0SMatthew G. Knepley   PetscViewerFormat format;
15746a5217c0SMatthew G. Knepley   PetscInt         *sizes;
15756a5217c0SMatthew G. Knepley   PetscInt          dim, Np, maxSize = 17;
15766a5217c0SMatthew G. Knepley   MPI_Comm          comm;
15776a5217c0SMatthew G. Knepley   PetscMPIInt       rank, size, p;
15786a5217c0SMatthew G. Knepley   const char       *name;
15796a5217c0SMatthew G. Knepley 
15806a5217c0SMatthew G. Knepley   PetscFunctionBegin;
15816a5217c0SMatthew G. Knepley   PetscCall(PetscViewerGetFormat(viewer, &format));
15826a5217c0SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
15836a5217c0SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(dm, &Np));
15846a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
15856a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
15866a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(comm, &size));
15876a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetName((PetscObject)dm, &name));
158863a3b9bcSJacob Faibussowitsch   if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
158963a3b9bcSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(viewer, "Swarm in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
15906a5217c0SMatthew G. Knepley   if (size < maxSize) PetscCall(PetscCalloc1(size, &sizes));
15916a5217c0SMatthew G. Knepley   else PetscCall(PetscCalloc1(3, &sizes));
15926a5217c0SMatthew G. Knepley   if (size < maxSize) {
15936a5217c0SMatthew G. Knepley     PetscCallMPI(MPI_Gather(&Np, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
15946a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of particles per rank:"));
15956a5217c0SMatthew G. Knepley     for (p = 0; p < size; ++p) {
15966a5217c0SMatthew G. Knepley       if (rank == 0) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]));
15976a5217c0SMatthew G. Knepley     }
15986a5217c0SMatthew G. Knepley   } else {
15996a5217c0SMatthew G. Knepley     PetscInt locMinMax[2] = {Np, Np};
16006a5217c0SMatthew G. Knepley 
16016a5217c0SMatthew G. Knepley     PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
16026a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of particles per rank: %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
16036a5217c0SMatthew G. Knepley   }
16046a5217c0SMatthew G. Knepley   PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
16056a5217c0SMatthew G. Knepley   PetscCall(PetscFree(sizes));
16066a5217c0SMatthew G. Knepley   if (format == PETSC_VIEWER_ASCII_INFO) {
16076a5217c0SMatthew G. Knepley     PetscInt *cell;
16086a5217c0SMatthew G. Knepley 
16096a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells containing each particle:\n"));
16106a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
16116a5217c0SMatthew G. Knepley     PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell));
161263a3b9bcSJacob Faibussowitsch     for (p = 0; p < Np; ++p) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  p%d: %" PetscInt_FMT "\n", p, cell[p]));
16136a5217c0SMatthew G. Knepley     PetscCall(PetscViewerFlush(viewer));
16146a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
16156a5217c0SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell));
16166a5217c0SMatthew G. Knepley   }
16173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16186a5217c0SMatthew G. Knepley }
16196a5217c0SMatthew G. Knepley 
162066976f2fSJacob Faibussowitsch static PetscErrorCode DMView_Swarm(DM dm, PetscViewer viewer)
1621d71ae5a4SJacob Faibussowitsch {
16225f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
16235627991aSBarry Smith   PetscBool iascii, ibinary, isvtk, isdraw;
16245627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
16255627991aSBarry Smith   PetscBool ishdf5;
16265627991aSBarry Smith #endif
16275f50eb2eSDave May 
16285f50eb2eSDave May   PetscFunctionBegin;
16295f50eb2eSDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
16305f50eb2eSDave May   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
16319566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
16329566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary));
16339566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
16345627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
16359566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
16365627991aSBarry Smith #endif
16379566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
16385f50eb2eSDave May   if (iascii) {
16396a5217c0SMatthew G. Knepley     PetscViewerFormat format;
16406a5217c0SMatthew G. Knepley 
16416a5217c0SMatthew G. Knepley     PetscCall(PetscViewerGetFormat(viewer, &format));
16426a5217c0SMatthew G. Knepley     switch (format) {
1643d71ae5a4SJacob Faibussowitsch     case PETSC_VIEWER_ASCII_INFO_DETAIL:
1644d71ae5a4SJacob Faibussowitsch       PetscCall(DMSwarmDataBucketView(PetscObjectComm((PetscObject)dm), swarm->db, NULL, DATABUCKET_VIEW_STDOUT));
1645d71ae5a4SJacob Faibussowitsch       break;
1646d71ae5a4SJacob Faibussowitsch     default:
1647d71ae5a4SJacob Faibussowitsch       PetscCall(DMView_Swarm_Ascii(dm, viewer));
16486a5217c0SMatthew G. Knepley     }
1649f7d195e4SLawrence Mitchell   } else {
16505f50eb2eSDave May #if defined(PETSC_HAVE_HDF5)
165148a46eb9SPierre Jolivet     if (ishdf5) PetscCall(DMSwarmView_HDF5(dm, viewer));
16525f50eb2eSDave May #endif
165348a46eb9SPierre Jolivet     if (isdraw) PetscCall(DMSwarmView_Draw(dm, viewer));
1654f7d195e4SLawrence Mitchell   }
16553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16565f50eb2eSDave May }
16575f50eb2eSDave May 
1658d0c080abSJoseph Pusztay /*@C
165920f4b53cSBarry Smith   DMSwarmGetCellSwarm - Extracts a single cell from the `DMSWARM` object, returns it as a single cell `DMSWARM`.
166020f4b53cSBarry 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.
1661d0c080abSJoseph Pusztay 
1662d0c080abSJoseph Pusztay   Noncollective
1663d0c080abSJoseph Pusztay 
166460225df5SJacob Faibussowitsch   Input Parameters:
166520f4b53cSBarry Smith + sw        - the `DMSWARM`
16665627991aSBarry Smith . cellID    - the integer id of the cell to be extracted and filtered
166720f4b53cSBarry Smith - cellswarm - The `DMSWARM` to receive the cell
1668d0c080abSJoseph Pusztay 
1669d0c080abSJoseph Pusztay   Level: beginner
1670d0c080abSJoseph Pusztay 
16715627991aSBarry Smith   Notes:
167220f4b53cSBarry Smith   This presently only supports `DMSWARM_PIC` type
16735627991aSBarry Smith 
167420f4b53cSBarry Smith   Should be restored with `DMSwarmRestoreCellSwarm()`
1675d0c080abSJoseph Pusztay 
167620f4b53cSBarry Smith   Changes to this cell of the swarm will be lost if they are made prior to restoring this cell.
167720f4b53cSBarry Smith 
167820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreCellSwarm()`
1679d0c080abSJoseph Pusztay @*/
1680d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMSwarmGetCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
1681d71ae5a4SJacob Faibussowitsch {
1682d0c080abSJoseph Pusztay   DM_Swarm *original = (DM_Swarm *)sw->data;
1683d0c080abSJoseph Pusztay   DMLabel   label;
1684d0c080abSJoseph Pusztay   DM        dmc, subdmc;
1685d0c080abSJoseph Pusztay   PetscInt *pids, particles, dim;
1686d0c080abSJoseph Pusztay 
1687d0c080abSJoseph Pusztay   PetscFunctionBegin;
1688d0c080abSJoseph Pusztay   /* Configure new swarm */
16899566063dSJacob Faibussowitsch   PetscCall(DMSetType(cellswarm, DMSWARM));
16909566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(sw, &dim));
16919566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(cellswarm, dim));
16929566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(cellswarm, DMSWARM_PIC));
1693d0c080abSJoseph Pusztay   /* Destroy the unused, unconfigured data bucket to prevent stragglers in memory */
16949566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&((DM_Swarm *)cellswarm->data)->db));
16959566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
16969566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, cellID, &particles));
16979566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
16989566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreateFromSubset(original->db, particles, pids, &((DM_Swarm *)cellswarm->data)->db));
16999566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
17009566063dSJacob Faibussowitsch   PetscCall(PetscFree(pids));
17019566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(sw, &dmc));
17029566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)sw), "singlecell", &label));
17039566063dSJacob Faibussowitsch   PetscCall(DMAddLabel(dmc, label));
17049566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cellID, 1));
17059566063dSJacob Faibussowitsch   PetscCall(DMPlexFilter(dmc, label, 1, &subdmc));
17069566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetCellDM(cellswarm, subdmc));
17079566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&label));
17083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1709d0c080abSJoseph Pusztay }
1710d0c080abSJoseph Pusztay 
1711d0c080abSJoseph Pusztay /*@C
171220f4b53cSBarry Smith   DMSwarmRestoreCellSwarm - Restores a `DMSWARM` object obtained with `DMSwarmGetCellSwarm()`. All fields are copied back into the parent swarm.
1713d0c080abSJoseph Pusztay 
1714d0c080abSJoseph Pusztay   Noncollective
1715d0c080abSJoseph Pusztay 
171660225df5SJacob Faibussowitsch   Input Parameters:
171720f4b53cSBarry Smith + sw        - the parent `DMSWARM`
1718d0c080abSJoseph Pusztay . cellID    - the integer id of the cell to be copied back into the parent swarm
1719d0c080abSJoseph Pusztay - cellswarm - the cell swarm object
1720d0c080abSJoseph Pusztay 
1721d0c080abSJoseph Pusztay   Level: beginner
1722d0c080abSJoseph Pusztay 
17235627991aSBarry Smith   Note:
172420f4b53cSBarry Smith   This only supports `DMSWARM_PIC` types of `DMSWARM`s
1725d0c080abSJoseph Pusztay 
172620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetCellSwarm()`
1727d0c080abSJoseph Pusztay @*/
1728d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMSwarmRestoreCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
1729d71ae5a4SJacob Faibussowitsch {
1730d0c080abSJoseph Pusztay   DM        dmc;
1731d0c080abSJoseph Pusztay   PetscInt *pids, particles, p;
1732d0c080abSJoseph Pusztay 
1733d0c080abSJoseph Pusztay   PetscFunctionBegin;
17349566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
17359566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
17369566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
1737d0c080abSJoseph Pusztay   /* Pointwise copy of each particle based on pid. The parent swarm may not be altered during this process. */
173848a46eb9SPierre Jolivet   for (p = 0; p < particles; ++p) PetscCall(DMSwarmDataBucketCopyPoint(((DM_Swarm *)cellswarm->data)->db, pids[p], ((DM_Swarm *)sw->data)->db, pids[p]));
1739d0c080abSJoseph Pusztay   /* Free memory, destroy cell dm */
17409566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(cellswarm, &dmc));
17419566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
17429566063dSJacob Faibussowitsch   PetscCall(PetscFree(pids));
17433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1744d0c080abSJoseph Pusztay }
1745d0c080abSJoseph Pusztay 
1746d0c080abSJoseph Pusztay PETSC_INTERN PetscErrorCode DMClone_Swarm(DM, DM *);
1747d0c080abSJoseph Pusztay 
1748d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMInitialize_Swarm(DM sw)
1749d71ae5a4SJacob Faibussowitsch {
1750d0c080abSJoseph Pusztay   PetscFunctionBegin;
1751d0c080abSJoseph Pusztay   sw->dim                           = 0;
1752d0c080abSJoseph Pusztay   sw->ops->view                     = DMView_Swarm;
1753d0c080abSJoseph Pusztay   sw->ops->load                     = NULL;
1754d0c080abSJoseph Pusztay   sw->ops->setfromoptions           = NULL;
1755d0c080abSJoseph Pusztay   sw->ops->clone                    = DMClone_Swarm;
1756d0c080abSJoseph Pusztay   sw->ops->setup                    = DMSetup_Swarm;
1757d0c080abSJoseph Pusztay   sw->ops->createlocalsection       = NULL;
1758d0c080abSJoseph Pusztay   sw->ops->createdefaultconstraints = NULL;
1759d0c080abSJoseph Pusztay   sw->ops->createglobalvector       = DMCreateGlobalVector_Swarm;
1760d0c080abSJoseph Pusztay   sw->ops->createlocalvector        = DMCreateLocalVector_Swarm;
1761d0c080abSJoseph Pusztay   sw->ops->getlocaltoglobalmapping  = NULL;
1762d0c080abSJoseph Pusztay   sw->ops->createfieldis            = NULL;
1763d0c080abSJoseph Pusztay   sw->ops->createcoordinatedm       = NULL;
1764d0c080abSJoseph Pusztay   sw->ops->getcoloring              = NULL;
1765d0c080abSJoseph Pusztay   sw->ops->creatematrix             = DMCreateMatrix_Swarm;
1766d0c080abSJoseph Pusztay   sw->ops->createinterpolation      = NULL;
1767d0c080abSJoseph Pusztay   sw->ops->createinjection          = NULL;
1768d0c080abSJoseph Pusztay   sw->ops->createmassmatrix         = DMCreateMassMatrix_Swarm;
1769d0c080abSJoseph Pusztay   sw->ops->refine                   = NULL;
1770d0c080abSJoseph Pusztay   sw->ops->coarsen                  = NULL;
1771d0c080abSJoseph Pusztay   sw->ops->refinehierarchy          = NULL;
1772d0c080abSJoseph Pusztay   sw->ops->coarsenhierarchy         = NULL;
1773d0c080abSJoseph Pusztay   sw->ops->globaltolocalbegin       = NULL;
1774d0c080abSJoseph Pusztay   sw->ops->globaltolocalend         = NULL;
1775d0c080abSJoseph Pusztay   sw->ops->localtoglobalbegin       = NULL;
1776d0c080abSJoseph Pusztay   sw->ops->localtoglobalend         = NULL;
1777d0c080abSJoseph Pusztay   sw->ops->destroy                  = DMDestroy_Swarm;
1778d0c080abSJoseph Pusztay   sw->ops->createsubdm              = NULL;
1779d0c080abSJoseph Pusztay   sw->ops->getdimpoints             = NULL;
1780d0c080abSJoseph Pusztay   sw->ops->locatepoints             = NULL;
17813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1782d0c080abSJoseph Pusztay }
1783d0c080abSJoseph Pusztay 
1784d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMClone_Swarm(DM dm, DM *newdm)
1785d71ae5a4SJacob Faibussowitsch {
1786d0c080abSJoseph Pusztay   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1787d0c080abSJoseph Pusztay 
1788d0c080abSJoseph Pusztay   PetscFunctionBegin;
1789d0c080abSJoseph Pusztay   swarm->refct++;
1790d0c080abSJoseph Pusztay   (*newdm)->data = swarm;
17919566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMSWARM));
17929566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(*newdm));
17932e56dffeSJoe Pusztay   (*newdm)->dim = dm->dim;
17943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1795d0c080abSJoseph Pusztay }
1796d0c080abSJoseph Pusztay 
1797d3a51819SDave May /*MC
1798d3a51819SDave May 
179920f4b53cSBarry Smith  DMSWARM = "swarm" - A `DM` object used to represent arrays of data (fields) of arbitrary data type.
180062741f57SDave May  This implementation was designed for particle methods in which the underlying
1801d3a51819SDave May  data required to be represented is both (i) dynamic in length, (ii) and of arbitrary data type.
1802d3a51819SDave May 
180320f4b53cSBarry Smith  Level: intermediate
180420f4b53cSBarry Smith 
180520f4b53cSBarry Smith   Notes:
180620f4b53cSBarry Smith  User data can be represented by `DMSWARM` through a registering "fields".
180762741f57SDave May  To register a field, the user must provide;
180862741f57SDave May  (a) a unique name;
180962741f57SDave May  (b) the data type (or size in bytes);
181062741f57SDave May  (c) the block size of the data.
1811d3a51819SDave May 
1812d3a51819SDave May  For example, suppose the application requires a unique id, energy, momentum and density to be stored
1813c215a47eSMatthew Knepley  on a set of particles. Then the following code could be used
181420f4b53cSBarry Smith .vb
181520f4b53cSBarry Smith     DMSwarmInitializeFieldRegister(dm)
181620f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"uid",1,PETSC_LONG);
181720f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"energy",1,PETSC_REAL);
181820f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"momentum",3,PETSC_REAL);
181920f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"density",1,PETSC_FLOAT);
182020f4b53cSBarry Smith     DMSwarmFinalizeFieldRegister(dm)
182120f4b53cSBarry Smith .ve
1822d3a51819SDave May 
182320f4b53cSBarry Smith  The fields represented by `DMSWARM` are dynamic and can be re-sized at any time.
182420f4b53cSBarry Smith  The only restriction imposed by `DMSWARM` is that all fields contain the same number of points.
1825d3a51819SDave May 
1826d3a51819SDave May  To support particle methods, "migration" techniques are provided. These methods migrate data
18275627991aSBarry Smith  between ranks.
1828d3a51819SDave May 
182920f4b53cSBarry Smith  `DMSWARM` supports the methods `DMCreateGlobalVector()` and `DMCreateLocalVector()`.
183020f4b53cSBarry Smith  As a `DMSWARM` may internally define and store values of different data types,
183120f4b53cSBarry Smith  before calling `DMCreateGlobalVector()` or `DMCreateLocalVector()`, the user must inform `DMSWARM` which
183220f4b53cSBarry Smith  fields should be used to define a `Vec` object via
183320f4b53cSBarry Smith    `DMSwarmVectorDefineField()`
1834c215a47eSMatthew Knepley  The specified field can be changed at any time - thereby permitting vectors
1835c215a47eSMatthew Knepley  compatible with different fields to be created.
1836d3a51819SDave May 
183720f4b53cSBarry Smith  A dual representation of fields in the `DMSWARM` and a Vec object is permitted via
183820f4b53cSBarry Smith    `DMSwarmCreateGlobalVectorFromField()`
183920f4b53cSBarry Smith  Here the data defining the field in the `DMSWARM` is shared with a Vec.
1840d3a51819SDave May  This is inherently unsafe if you alter the size of the field at any time between
184120f4b53cSBarry Smith  calls to `DMSwarmCreateGlobalVectorFromField()` and `DMSwarmDestroyGlobalVectorFromField()`.
184220f4b53cSBarry Smith  If the local size of the `DMSWARM` does not match the local size of the global vector
184320f4b53cSBarry Smith  when `DMSwarmDestroyGlobalVectorFromField()` is called, an error is thrown.
1844d3a51819SDave May 
184562741f57SDave May  Additional high-level support is provided for Particle-In-Cell methods.
184620f4b53cSBarry Smith  Please refer to `DMSwarmSetType()`.
184762741f57SDave May 
184820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMType`, `DMCreate()`, `DMSetType()`
1849d3a51819SDave May M*/
1850d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMCreate_Swarm(DM dm)
1851d71ae5a4SJacob Faibussowitsch {
185257795646SDave May   DM_Swarm *swarm;
185357795646SDave May 
185457795646SDave May   PetscFunctionBegin;
185557795646SDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
18564dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&swarm));
1857f0cdbbbaSDave May   dm->data = swarm;
18589566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreate(&swarm->db));
18599566063dSJacob Faibussowitsch   PetscCall(DMSwarmInitializeFieldRegister(dm));
1860d0c080abSJoseph Pusztay   swarm->refct                          = 1;
1861b5bcf523SDave May   swarm->vec_field_set                  = PETSC_FALSE;
18623454631fSDave May   swarm->issetup                        = PETSC_FALSE;
1863480eef7bSDave May   swarm->swarm_type                     = DMSWARM_BASIC;
1864480eef7bSDave May   swarm->migrate_type                   = DMSWARM_MIGRATE_BASIC;
1865480eef7bSDave May   swarm->collect_type                   = DMSWARM_COLLECT_BASIC;
186640c453e9SDave May   swarm->migrate_error_on_missing_point = PETSC_FALSE;
1867f0cdbbbaSDave May   swarm->dmcell                         = NULL;
1868f0cdbbbaSDave May   swarm->collect_view_active            = PETSC_FALSE;
1869f0cdbbbaSDave May   swarm->collect_view_reset_nlocal      = -1;
18709566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(dm));
18712e956fe4SStefano Zampini   if (SwarmDataFieldId == -1) PetscCall(PetscObjectComposedDataRegister(&SwarmDataFieldId));
18723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
187357795646SDave May }
1874