xref: /petsc/src/dm/impls/swarm/swarm.c (revision ea7032a09bb1bdbf7994ebc1e6c6f7182819ef65)
157795646SDave May #define PETSCDM_DLL
257795646SDave May #include <petsc/private/dmswarmimpl.h> /*I   "petscdmswarm.h"   I*/
3e8f14785SLisandro Dalcin #include <petsc/private/hashsetij.h>
40643ed39SMatthew G. Knepley #include <petsc/private/petscfeimpl.h>
55917a6f0SStefano Zampini #include <petscviewer.h>
65917a6f0SStefano Zampini #include <petscdraw.h>
783c47955SMatthew G. Knepley #include <petscdmplex.h>
84cc7f7b2SMatthew G. Knepley #include <petscblaslapack.h>
9279f676cSBarry Smith #include "../src/dm/impls/swarm/data_bucket.h"
10d0c080abSJoseph Pusztay #include <petscdmlabel.h>
11d0c080abSJoseph Pusztay #include <petscsection.h>
1257795646SDave May 
13f2b2bee7SDave May PetscLogEvent DMSWARM_Migrate, DMSWARM_SetSizes, DMSWARM_AddPoints, DMSWARM_RemovePoints, DMSWARM_Sort;
14ed923d71SDave May PetscLogEvent DMSWARM_DataExchangerTopologySetup, DMSWARM_DataExchangerBegin, DMSWARM_DataExchangerEnd;
15ed923d71SDave May PetscLogEvent DMSWARM_DataExchangerSendCount, DMSWARM_DataExchangerPack;
16ed923d71SDave May 
17ea78f98cSLisandro Dalcin const char *DMSwarmTypeNames[]          = {"basic", "pic", NULL};
18ea78f98cSLisandro Dalcin const char *DMSwarmMigrateTypeNames[]   = {"basic", "dmcellnscatter", "dmcellexact", "user", NULL};
19ea78f98cSLisandro Dalcin const char *DMSwarmCollectTypeNames[]   = {"basic", "boundingbox", "general", "user", NULL};
20ea78f98cSLisandro Dalcin const char *DMSwarmPICLayoutTypeNames[] = {"regular", "gauss", "subdivision", NULL};
21f0cdbbbaSDave May 
22f0cdbbbaSDave May const char DMSwarmField_pid[]       = "DMSwarm_pid";
23f0cdbbbaSDave May const char DMSwarmField_rank[]      = "DMSwarm_rank";
24f0cdbbbaSDave May const char DMSwarmPICField_coor[]   = "DMSwarmPIC_coor";
25e2d107dbSDave May const char DMSwarmPICField_cellid[] = "DMSwarm_cellid";
26f0cdbbbaSDave May 
272e956fe4SStefano Zampini PetscInt SwarmDataFieldId = -1;
282e956fe4SStefano Zampini 
2974d0cae8SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
3074d0cae8SMatthew G. Knepley   #include <petscviewerhdf5.h>
3174d0cae8SMatthew G. Knepley 
32d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Swarm_HDF5_Internal(Vec v, PetscViewer viewer)
33d71ae5a4SJacob Faibussowitsch {
3474d0cae8SMatthew G. Knepley   DM        dm;
3574d0cae8SMatthew G. Knepley   PetscReal seqval;
3674d0cae8SMatthew G. Knepley   PetscInt  seqnum, bs;
3774d0cae8SMatthew G. Knepley   PetscBool isseq;
3874d0cae8SMatthew G. Knepley 
3974d0cae8SMatthew G. Knepley   PetscFunctionBegin;
409566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
419566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v, &bs));
429566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PushGroup(viewer, "/particle_fields"));
439566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
449566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, &seqval));
459566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum));
469566063dSJacob Faibussowitsch   /* PetscCall(DMSequenceView_HDF5(dm, "time", seqnum, (PetscScalar) seqval, viewer)); */
479566063dSJacob Faibussowitsch   PetscCall(VecViewNative(v, viewer));
489566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)v, "Nc", PETSC_INT, (void *)&bs));
499566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PopGroup(viewer));
503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5174d0cae8SMatthew G. Knepley }
5274d0cae8SMatthew G. Knepley 
53d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmView_HDF5(DM dm, PetscViewer viewer)
54d71ae5a4SJacob Faibussowitsch {
5574d0cae8SMatthew G. Knepley   Vec       coordinates;
5674d0cae8SMatthew G. Knepley   PetscInt  Np;
5774d0cae8SMatthew G. Knepley   PetscBool isseq;
5874d0cae8SMatthew G. Knepley 
5974d0cae8SMatthew G. Knepley   PetscFunctionBegin;
609566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetSize(dm, &Np));
619566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateGlobalVectorFromField(dm, DMSwarmPICField_coor, &coordinates));
629566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
639566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PushGroup(viewer, "/particles"));
649566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)coordinates, VECSEQ, &isseq));
659566063dSJacob Faibussowitsch   PetscCall(VecViewNative(coordinates, viewer));
669566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)coordinates, "Np", PETSC_INT, (void *)&Np));
679566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PopGroup(viewer));
689566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyGlobalVectorFromField(dm, DMSwarmPICField_coor, &coordinates));
693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7074d0cae8SMatthew G. Knepley }
7174d0cae8SMatthew G. Knepley #endif
7274d0cae8SMatthew G. Knepley 
73d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Swarm(Vec v, PetscViewer viewer)
74d71ae5a4SJacob Faibussowitsch {
7574d0cae8SMatthew G. Knepley   DM dm;
76f9558f5cSBarry Smith #if defined(PETSC_HAVE_HDF5)
7774d0cae8SMatthew G. Knepley   PetscBool ishdf5;
78f9558f5cSBarry Smith #endif
7974d0cae8SMatthew G. Knepley 
8074d0cae8SMatthew G. Knepley   PetscFunctionBegin;
819566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
8228b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
83f9558f5cSBarry Smith #if defined(PETSC_HAVE_HDF5)
849566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
8574d0cae8SMatthew G. Knepley   if (ishdf5) {
869566063dSJacob Faibussowitsch     PetscCall(VecView_Swarm_HDF5_Internal(v, viewer));
873ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
8874d0cae8SMatthew G. Knepley   }
89f9558f5cSBarry Smith #endif
909566063dSJacob Faibussowitsch   PetscCall(VecViewNative(v, viewer));
913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9274d0cae8SMatthew G. Knepley }
9374d0cae8SMatthew G. Knepley 
94d3a51819SDave May /*@C
9562741f57SDave May    DMSwarmVectorDefineField - Sets the field from which to define a Vec object
9662741f57SDave May                              when DMCreateLocalVector(), or DMCreateGlobalVector() is called
9757795646SDave May 
98d083f849SBarry Smith    Collective on dm
9957795646SDave May 
100d3a51819SDave May    Input parameters:
10162741f57SDave May +  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:
107e7af74c8SDave May 
10862741f57SDave May    The field with name fieldname must be defined as having a data type of PetscScalar.
109e7af74c8SDave May 
110d3a51819SDave May    This function must be called prior to calling DMCreateLocalVector(), DMCreateGlobalVector().
111d5b43468SJose E. Roman    Multiple calls to DMSwarmVectorDefineField() are permitted.
11257795646SDave May 
113db781477SPatrick Sanan .seealso: `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
114d3a51819SDave May @*/
115d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmVectorDefineField(DM dm, const char fieldname[])
116d71ae5a4SJacob Faibussowitsch {
117b5bcf523SDave May   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
118b5bcf523SDave May   PetscInt      bs, n;
119b5bcf523SDave May   PetscScalar  *array;
120b5bcf523SDave May   PetscDataType type;
121b5bcf523SDave May 
122a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
1239566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
1249566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
1259566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array));
126b5bcf523SDave May 
127b5bcf523SDave May   /* Check all fields are of type PETSC_REAL or PETSC_SCALAR */
12808401ef6SPierre Jolivet   PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
1299566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(swarm->vec_field_name, PETSC_MAX_PATH_LEN - 1, "%s", fieldname));
130b5bcf523SDave May   swarm->vec_field_set    = PETSC_TRUE;
1311b1ea282SDave May   swarm->vec_field_bs     = bs;
132b5bcf523SDave May   swarm->vec_field_nlocal = n;
1339566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, fieldname, &bs, &type, (void **)&array));
1343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
135b5bcf523SDave May }
136b5bcf523SDave May 
137cc651181SDave May /* requires DMSwarmDefineFieldVector has been called */
138d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateGlobalVector_Swarm(DM dm, Vec *vec)
139d71ae5a4SJacob Faibussowitsch {
140b5bcf523SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
141b5bcf523SDave May   Vec       x;
142b5bcf523SDave May   char      name[PETSC_MAX_PATH_LEN];
143b5bcf523SDave May 
144a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
1459566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
14628b400f6SJacob Faibussowitsch   PetscCheck(swarm->vec_field_set, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmVectorDefineField first");
14708401ef6SPierre 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 */
148cc651181SDave May 
1499566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmField_%s", swarm->vec_field_name));
1509566063dSJacob Faibussowitsch   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &x));
1519566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)x, name));
1529566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(x, swarm->db->L * swarm->vec_field_bs, PETSC_DETERMINE));
1539566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(x, swarm->vec_field_bs));
1549566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
1559566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(x));
1569566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
1579566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(x, VECOP_VIEW, (void (*)(void))VecView_Swarm));
158b5bcf523SDave May   *vec = x;
1593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
160b5bcf523SDave May }
161b5bcf523SDave May 
162b5bcf523SDave May /* requires DMSwarmDefineFieldVector has been called */
163d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateLocalVector_Swarm(DM dm, Vec *vec)
164d71ae5a4SJacob Faibussowitsch {
165b5bcf523SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
166b5bcf523SDave May   Vec       x;
167b5bcf523SDave May   char      name[PETSC_MAX_PATH_LEN];
168b5bcf523SDave May 
169a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
1709566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
17128b400f6SJacob Faibussowitsch   PetscCheck(swarm->vec_field_set, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmVectorDefineField first");
17208401ef6SPierre 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");
173cc651181SDave May 
1749566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmField_%s", swarm->vec_field_name));
1759566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &x));
1769566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)x, name));
1779566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(x, swarm->db->L * swarm->vec_field_bs, PETSC_DETERMINE));
1789566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(x, swarm->vec_field_bs));
1799566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
1809566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(x));
181b5bcf523SDave May   *vec = x;
1823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
183b5bcf523SDave May }
184b5bcf523SDave May 
185d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmDestroyVectorFromField_Private(DM dm, const char fieldname[], Vec *vec)
186d71ae5a4SJacob Faibussowitsch {
187fb1bcc12SMatthew G. Knepley   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
18877048351SPatrick Sanan   DMSwarmDataField gfield;
1892e956fe4SStefano Zampini   PetscInt         bs, nlocal, fid = -1, cfid = -2;
1902e956fe4SStefano Zampini   PetscBool        flg;
191d3a51819SDave May 
192fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
1932e956fe4SStefano Zampini   /* check vector is an inplace array */
1942e956fe4SStefano Zampini   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
1952e956fe4SStefano Zampini   PetscCall(PetscObjectComposedDataGetInt((PetscObject)*vec, SwarmDataFieldId, cfid, flg));
1962e956fe4SStefano 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);
1979566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(*vec, &nlocal));
1989566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(*vec, &bs));
19908401ef6SPierre 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");
2009566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
2019566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
2028df78e51SMark Adams   PetscCall(VecResetArray(*vec));
2039566063dSJacob Faibussowitsch   PetscCall(VecDestroy(vec));
2043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
205fb1bcc12SMatthew G. Knepley }
206fb1bcc12SMatthew G. Knepley 
207d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmCreateVectorFromField_Private(DM dm, const char fieldname[], MPI_Comm comm, Vec *vec)
208d71ae5a4SJacob Faibussowitsch {
209fb1bcc12SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
210fb1bcc12SMatthew G. Knepley   PetscDataType type;
211fb1bcc12SMatthew G. Knepley   PetscScalar  *array;
2122e956fe4SStefano Zampini   PetscInt      bs, n, fid;
213fb1bcc12SMatthew G. Knepley   char          name[PETSC_MAX_PATH_LEN];
214e4fbd051SBarry Smith   PetscMPIInt   size;
2158df78e51SMark Adams   PetscBool     iscuda, iskokkos;
216fb1bcc12SMatthew G. Knepley 
217fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
2189566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
2199566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
2209566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array));
22108401ef6SPierre Jolivet   PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
222fb1bcc12SMatthew G. Knepley 
2239566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
2248df78e51SMark Adams   PetscCall(PetscStrcmp(dm->vectype, VECKOKKOS, &iskokkos));
2258df78e51SMark Adams   PetscCall(PetscStrcmp(dm->vectype, VECCUDA, &iscuda));
2268df78e51SMark Adams   PetscCall(VecCreate(comm, vec));
2278df78e51SMark Adams   PetscCall(VecSetSizes(*vec, n * bs, PETSC_DETERMINE));
2288df78e51SMark Adams   PetscCall(VecSetBlockSize(*vec, bs));
2298df78e51SMark Adams   if (iskokkos) PetscCall(VecSetType(*vec, VECKOKKOS));
2308df78e51SMark Adams   else if (iscuda) PetscCall(VecSetType(*vec, VECCUDA));
2318df78e51SMark Adams   else PetscCall(VecSetType(*vec, VECSTANDARD));
2328df78e51SMark Adams   PetscCall(VecPlaceArray(*vec, array));
2338df78e51SMark Adams 
2349566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmSharedField_%s", fieldname));
2359566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*vec, name));
236fb1bcc12SMatthew G. Knepley 
237fb1bcc12SMatthew G. Knepley   /* Set guard */
2382e956fe4SStefano Zampini   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
2392e956fe4SStefano Zampini   PetscCall(PetscObjectComposedDataSetInt((PetscObject)*vec, SwarmDataFieldId, fid));
24074d0cae8SMatthew G. Knepley 
2419566063dSJacob Faibussowitsch   PetscCall(VecSetDM(*vec, dm));
2429566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Swarm));
2433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
244fb1bcc12SMatthew G. Knepley }
245fb1bcc12SMatthew G. Knepley 
2460643ed39SMatthew G. Knepley /* This creates a "mass matrix" between a finite element and particle space. If a finite element interpolant is given by
2470643ed39SMatthew G. Knepley 
2480643ed39SMatthew G. Knepley      \hat f = \sum_i f_i \phi_i
2490643ed39SMatthew G. Knepley 
2500643ed39SMatthew G. Knepley    and a particle function is given by
2510643ed39SMatthew G. Knepley 
2520643ed39SMatthew G. Knepley      f = \sum_i w_i \delta(x - x_i)
2530643ed39SMatthew G. Knepley 
2540643ed39SMatthew G. Knepley    then we want to require that
2550643ed39SMatthew G. Knepley 
2560643ed39SMatthew G. Knepley      M \hat f = M_p f
2570643ed39SMatthew G. Knepley 
2580643ed39SMatthew G. Knepley    where the particle mass matrix is given by
2590643ed39SMatthew G. Knepley 
2600643ed39SMatthew G. Knepley      (M_p)_{ij} = \int \phi_i \delta(x - x_j)
2610643ed39SMatthew G. Knepley 
2620643ed39SMatthew G. Knepley    The way Dave May does particles, they amount to quadratue weights rather than delta functions, so he has |J| is in
2630643ed39SMatthew G. Knepley    his integral. We allow this with the boolean flag.
2640643ed39SMatthew G. Knepley */
265d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmComputeMassMatrix_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
266d71ae5a4SJacob Faibussowitsch {
26783c47955SMatthew G. Knepley   const char  *name = "Mass Matrix";
2680643ed39SMatthew G. Knepley   MPI_Comm     comm;
26983c47955SMatthew G. Knepley   PetscDS      prob;
27083c47955SMatthew G. Knepley   PetscSection fsection, globalFSection;
271e8f14785SLisandro Dalcin   PetscHSetIJ  ht;
2720643ed39SMatthew G. Knepley   PetscLayout  rLayout, colLayout;
27383c47955SMatthew G. Knepley   PetscInt    *dnz, *onz;
274adb2528bSMark Adams   PetscInt     locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
2750643ed39SMatthew G. Knepley   PetscReal   *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
27683c47955SMatthew G. Knepley   PetscScalar *elemMat;
2770643ed39SMatthew G. Knepley   PetscInt     dim, Nf, field, cStart, cEnd, cell, totDim, maxC = 0;
27883c47955SMatthew G. Knepley 
27983c47955SMatthew G. Knepley   PetscFunctionBegin;
2809566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
2819566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmf, &dim));
2829566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmf, &prob));
2839566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
2849566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
2859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
2869566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
2879566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
2889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
2899566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
29083c47955SMatthew G. Knepley 
2919566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &colLayout));
2929566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
2939566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
2949566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colLayout));
2959566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
2969566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&colLayout));
2970643ed39SMatthew G. Knepley 
2989566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &rLayout));
2999566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
3009566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
3019566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
3029566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
3039566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
3040643ed39SMatthew G. Knepley 
3059566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
3069566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
30753e60ab4SJoseph Pusztay 
3089566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(comm, NULL));
3090643ed39SMatthew G. Knepley   /* count non-zeros */
3109566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(dmc));
31183c47955SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
31283c47955SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
3130643ed39SMatthew G. Knepley       PetscInt  c, i;
3140643ed39SMatthew G. Knepley       PetscInt *findices, *cindices; /* fine is vertices, coarse is particles */
31583c47955SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
31683c47955SMatthew G. Knepley 
3179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3189566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
319fc7c92abSMatthew G. Knepley       maxC = PetscMax(maxC, numCIndices);
32083c47955SMatthew G. Knepley       {
321e8f14785SLisandro Dalcin         PetscHashIJKey key;
322e8f14785SLisandro Dalcin         PetscBool      missing;
32383c47955SMatthew G. Knepley         for (i = 0; i < numFIndices; ++i) {
324adb2528bSMark Adams           key.j = findices[i]; /* global column (from Plex) */
325adb2528bSMark Adams           if (key.j >= 0) {
32683c47955SMatthew G. Knepley             /* Get indices for coarse elements */
32783c47955SMatthew G. Knepley             for (c = 0; c < numCIndices; ++c) {
328adb2528bSMark Adams               key.i = cindices[c] + rStart; /* global cols (from Swarm) */
329adb2528bSMark Adams               if (key.i < 0) continue;
3309566063dSJacob Faibussowitsch               PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
33183c47955SMatthew G. Knepley               if (missing) {
3320643ed39SMatthew G. Knepley                 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
333e8f14785SLisandro Dalcin                 else ++onz[key.i - rStart];
33463a3b9bcSJacob Faibussowitsch               } else SETERRQ(PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Set new value at %" PetscInt_FMT ",%" PetscInt_FMT, key.i, key.j);
33583c47955SMatthew G. Knepley             }
336fc7c92abSMatthew G. Knepley           }
337fc7c92abSMatthew G. Knepley         }
3389566063dSJacob Faibussowitsch         PetscCall(PetscFree(cindices));
33983c47955SMatthew G. Knepley       }
3409566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
34183c47955SMatthew G. Knepley     }
34283c47955SMatthew G. Knepley   }
3439566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
3449566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
3459566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
3469566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
3479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(maxC * totDim, &elemMat, maxC, &rowIDXs, maxC * dim, &xi));
34883c47955SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
349ef0bb6c7SMatthew G. Knepley     PetscTabulation Tcoarse;
35083c47955SMatthew G. Knepley     PetscObject     obj;
351*ea7032a0SMatthew G. Knepley     PetscReal      *fieldVals;
3520643ed39SMatthew G. Knepley     PetscInt        Nc, i;
35383c47955SMatthew G. Knepley 
3549566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
3559566063dSJacob Faibussowitsch     PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
35663a3b9bcSJacob Faibussowitsch     PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc);
357*ea7032a0SMatthew G. Knepley 
358*ea7032a0SMatthew G. Knepley     PetscCall(DMSwarmGetField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&fieldVals));
35983c47955SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
36083c47955SMatthew G. Knepley       PetscInt *findices, *cindices;
36183c47955SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
3620643ed39SMatthew G. Knepley       PetscInt  p, c;
36383c47955SMatthew G. Knepley 
3640643ed39SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
3659566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
3669566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3679566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
368*ea7032a0SMatthew G. Knepley       for (p = 0; p < numCIndices; ++p) CoordinatesRealToRef(dim, dim, v0ref, v0, invJ, &fieldVals[cindices[p] * dim], &xi[p * dim]);
3699566063dSJacob Faibussowitsch       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
37083c47955SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
3719566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemMat, numCIndices * totDim));
37283c47955SMatthew G. Knepley       for (i = 0; i < numFIndices; ++i) {
3730643ed39SMatthew G. Knepley         for (p = 0; p < numCIndices; ++p) {
3740643ed39SMatthew G. Knepley           for (c = 0; c < Nc; ++c) {
3750643ed39SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
376ef0bb6c7SMatthew G. Knepley             elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
37783c47955SMatthew G. Knepley           }
3780643ed39SMatthew G. Knepley         }
3790643ed39SMatthew G. Knepley       }
380adb2528bSMark Adams       for (p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart;
3819566063dSJacob Faibussowitsch       if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
3829566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numFIndices, findices, elemMat, ADD_VALUES));
3839566063dSJacob Faibussowitsch       PetscCall(PetscFree(cindices));
3849566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3859566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
38683c47955SMatthew G. Knepley     }
387*ea7032a0SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&fieldVals));
38883c47955SMatthew G. Knepley   }
3899566063dSJacob Faibussowitsch   PetscCall(PetscFree3(elemMat, rowIDXs, xi));
3909566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
3919566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
3929566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
3939566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
3943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39583c47955SMatthew G. Knepley }
39683c47955SMatthew G. Knepley 
397d0c080abSJoseph Pusztay /* Returns empty matrix for use with SNES FD */
398d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMatrix_Swarm(DM sw, Mat *m)
399d71ae5a4SJacob Faibussowitsch {
400d0c080abSJoseph Pusztay   Vec      field;
401d0c080abSJoseph Pusztay   PetscInt size;
402d0c080abSJoseph Pusztay 
403d0c080abSJoseph Pusztay   PetscFunctionBegin;
4049566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(sw, &field));
4059566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(field, &size));
4069566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(sw, &field));
4079566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD, m));
4089566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*m));
4099566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*m, PETSC_DECIDE, PETSC_DECIDE, size, size));
4109566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*m, 1, NULL));
4119566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(*m));
4129566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*m, MAT_FINAL_ASSEMBLY));
4139566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*m, MAT_FINAL_ASSEMBLY));
4149566063dSJacob Faibussowitsch   PetscCall(MatShift(*m, 1.0));
4159566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*m, sw));
4163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
417d0c080abSJoseph Pusztay }
418d0c080abSJoseph Pusztay 
419adb2528bSMark Adams /* FEM cols, Particle rows */
420d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMassMatrix_Swarm(DM dmCoarse, DM dmFine, Mat *mass)
421d71ae5a4SJacob Faibussowitsch {
422895a1698SMatthew G. Knepley   PetscSection gsf;
42383c47955SMatthew G. Knepley   PetscInt     m, n;
42483c47955SMatthew G. Knepley   void        *ctx;
42583c47955SMatthew G. Knepley 
42683c47955SMatthew G. Knepley   PetscFunctionBegin;
4279566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
4289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
4299566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dmCoarse, &n));
4309566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
4319566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, m, PETSC_DETERMINE, PETSC_DETERMINE));
4329566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
4339566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
43483c47955SMatthew G. Knepley 
4359566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrix_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
4369566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
4373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43883c47955SMatthew G. Knepley }
43983c47955SMatthew G. Knepley 
440d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmComputeMassMatrixSquare_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
441d71ae5a4SJacob Faibussowitsch {
4424cc7f7b2SMatthew G. Knepley   const char  *name = "Mass Matrix Square";
4434cc7f7b2SMatthew G. Knepley   MPI_Comm     comm;
4444cc7f7b2SMatthew G. Knepley   PetscDS      prob;
4454cc7f7b2SMatthew G. Knepley   PetscSection fsection, globalFSection;
4464cc7f7b2SMatthew G. Knepley   PetscHSetIJ  ht;
4474cc7f7b2SMatthew G. Knepley   PetscLayout  rLayout, colLayout;
4484cc7f7b2SMatthew G. Knepley   PetscInt    *dnz, *onz, *adj, depth, maxConeSize, maxSupportSize, maxAdjSize;
4494cc7f7b2SMatthew G. Knepley   PetscInt     locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
4504cc7f7b2SMatthew G. Knepley   PetscReal   *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
4514cc7f7b2SMatthew G. Knepley   PetscScalar *elemMat, *elemMatSq;
4524cc7f7b2SMatthew G. Knepley   PetscInt     cdim, Nf, field, cStart, cEnd, cell, totDim, maxC = 0;
4534cc7f7b2SMatthew G. Knepley 
4544cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
4559566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
4569566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmf, &cdim));
4579566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmf, &prob));
4589566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
4599566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
4609566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(cdim, &v0, cdim * cdim, &J, cdim * cdim, &invJ));
4619566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
4629566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
4639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
4649566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
4654cc7f7b2SMatthew G. Knepley 
4669566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &colLayout));
4679566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
4689566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
4699566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colLayout));
4709566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
4719566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&colLayout));
4724cc7f7b2SMatthew G. Knepley 
4739566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &rLayout));
4749566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
4759566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
4769566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
4779566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
4789566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
4794cc7f7b2SMatthew G. Knepley 
4809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmf, &depth));
4819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dmf, &maxConeSize, &maxSupportSize));
4824cc7f7b2SMatthew G. Knepley   maxAdjSize = PetscPowInt(maxConeSize * maxSupportSize, depth);
4839566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxAdjSize, &adj));
4844cc7f7b2SMatthew G. Knepley 
4859566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
4869566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
4874cc7f7b2SMatthew G. Knepley   /* Count nonzeros
4884cc7f7b2SMatthew G. Knepley        This is just FVM++, but we cannot use the Plex P0 allocation since unknowns in a cell will not be contiguous
4894cc7f7b2SMatthew G. Knepley   */
4909566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(dmc));
4914cc7f7b2SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
4924cc7f7b2SMatthew G. Knepley     PetscInt  i;
4934cc7f7b2SMatthew G. Knepley     PetscInt *cindices;
4944cc7f7b2SMatthew G. Knepley     PetscInt  numCIndices;
4954cc7f7b2SMatthew G. Knepley #if 0
4964cc7f7b2SMatthew G. Knepley     PetscInt  adjSize = maxAdjSize, a, j;
4974cc7f7b2SMatthew G. Knepley #endif
4984cc7f7b2SMatthew G. Knepley 
4999566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
5004cc7f7b2SMatthew G. Knepley     maxC = PetscMax(maxC, numCIndices);
5014cc7f7b2SMatthew G. Knepley     /* Diagonal block */
502ad540459SPierre Jolivet     for (i = 0; i < numCIndices; ++i) dnz[cindices[i]] += numCIndices;
5034cc7f7b2SMatthew G. Knepley #if 0
5044cc7f7b2SMatthew G. Knepley     /* Off-diagonal blocks */
5059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(dmf, cell, &adjSize, &adj));
5064cc7f7b2SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
5074cc7f7b2SMatthew G. Knepley       if (adj[a] >= cStart && adj[a] < cEnd && adj[a] != cell) {
5084cc7f7b2SMatthew G. Knepley         const PetscInt ncell = adj[a];
5094cc7f7b2SMatthew G. Knepley         PetscInt      *ncindices;
5104cc7f7b2SMatthew G. Knepley         PetscInt       numNCIndices;
5114cc7f7b2SMatthew G. Knepley 
5129566063dSJacob Faibussowitsch         PetscCall(DMSwarmSortGetPointsPerCell(dmc, ncell, &numNCIndices, &ncindices));
5134cc7f7b2SMatthew G. Knepley         {
5144cc7f7b2SMatthew G. Knepley           PetscHashIJKey key;
5154cc7f7b2SMatthew G. Knepley           PetscBool      missing;
5164cc7f7b2SMatthew G. Knepley 
5174cc7f7b2SMatthew G. Knepley           for (i = 0; i < numCIndices; ++i) {
5184cc7f7b2SMatthew G. Knepley             key.i = cindices[i] + rStart; /* global rows (from Swarm) */
5194cc7f7b2SMatthew G. Knepley             if (key.i < 0) continue;
5204cc7f7b2SMatthew G. Knepley             for (j = 0; j < numNCIndices; ++j) {
5214cc7f7b2SMatthew G. Knepley               key.j = ncindices[j] + rStart; /* global column (from Swarm) */
5224cc7f7b2SMatthew G. Knepley               if (key.j < 0) continue;
5239566063dSJacob Faibussowitsch               PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
5244cc7f7b2SMatthew G. Knepley               if (missing) {
5254cc7f7b2SMatthew G. Knepley                 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
5264cc7f7b2SMatthew G. Knepley                 else                                         ++onz[key.i - rStart];
5274cc7f7b2SMatthew G. Knepley               }
5284cc7f7b2SMatthew G. Knepley             }
5294cc7f7b2SMatthew G. Knepley           }
5304cc7f7b2SMatthew G. Knepley         }
5319566063dSJacob Faibussowitsch         PetscCall(PetscFree(ncindices));
5324cc7f7b2SMatthew G. Knepley       }
5334cc7f7b2SMatthew G. Knepley     }
5344cc7f7b2SMatthew G. Knepley #endif
5359566063dSJacob Faibussowitsch     PetscCall(PetscFree(cindices));
5364cc7f7b2SMatthew G. Knepley   }
5379566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
5389566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
5399566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
5409566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
5419566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(maxC * totDim, &elemMat, maxC * maxC, &elemMatSq, maxC, &rowIDXs, maxC * cdim, &xi));
5424cc7f7b2SMatthew G. Knepley   /* Fill in values
5434cc7f7b2SMatthew G. Knepley        Each entry is a sum of terms \phi_i(x_p) \phi_i(x_q)
5444cc7f7b2SMatthew G. Knepley        Start just by producing block diagonal
5454cc7f7b2SMatthew G. Knepley        Could loop over adjacent cells
5464cc7f7b2SMatthew G. Knepley          Produce neighboring element matrix
5474cc7f7b2SMatthew G. Knepley          TODO Determine which columns and rows correspond to shared dual vector
5484cc7f7b2SMatthew G. Knepley          Do MatMatMult with rectangular matrices
5494cc7f7b2SMatthew G. Knepley          Insert block
5504cc7f7b2SMatthew G. Knepley   */
5514cc7f7b2SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
5524cc7f7b2SMatthew G. Knepley     PetscTabulation Tcoarse;
5534cc7f7b2SMatthew G. Knepley     PetscObject     obj;
5544cc7f7b2SMatthew G. Knepley     PetscReal      *coords;
5554cc7f7b2SMatthew G. Knepley     PetscInt        Nc, i;
5564cc7f7b2SMatthew G. Knepley 
5579566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
5589566063dSJacob Faibussowitsch     PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
55963a3b9bcSJacob Faibussowitsch     PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc);
5609566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
5614cc7f7b2SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
5624cc7f7b2SMatthew G. Knepley       PetscInt *findices, *cindices;
5634cc7f7b2SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
5644cc7f7b2SMatthew G. Knepley       PetscInt  p, c;
5654cc7f7b2SMatthew G. Knepley 
5664cc7f7b2SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
5679566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
5689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
5699566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
570ad540459SPierre Jolivet       for (p = 0; p < numCIndices; ++p) CoordinatesRealToRef(cdim, cdim, v0ref, v0, invJ, &coords[cindices[p] * cdim], &xi[p * cdim]);
5719566063dSJacob Faibussowitsch       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
5724cc7f7b2SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
5739566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemMat, numCIndices * totDim));
5744cc7f7b2SMatthew G. Knepley       for (i = 0; i < numFIndices; ++i) {
5754cc7f7b2SMatthew G. Knepley         for (p = 0; p < numCIndices; ++p) {
5764cc7f7b2SMatthew G. Knepley           for (c = 0; c < Nc; ++c) {
5774cc7f7b2SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
5784cc7f7b2SMatthew G. Knepley             elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
5794cc7f7b2SMatthew G. Knepley           }
5804cc7f7b2SMatthew G. Knepley         }
5814cc7f7b2SMatthew G. Knepley       }
5829566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
5834cc7f7b2SMatthew G. Knepley       for (p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart;
5849566063dSJacob Faibussowitsch       if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
5854cc7f7b2SMatthew G. Knepley       /* Block diagonal */
58678884ca7SMatthew G. Knepley       if (numCIndices) {
5874cc7f7b2SMatthew G. Knepley         PetscBLASInt blasn, blask;
5884cc7f7b2SMatthew G. Knepley         PetscScalar  one = 1.0, zero = 0.0;
5894cc7f7b2SMatthew G. Knepley 
5909566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numCIndices, &blasn));
5919566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numFIndices, &blask));
592792fecdfSBarry Smith         PetscCallBLAS("BLASgemm", BLASgemm_("T", "N", &blasn, &blasn, &blask, &one, elemMat, &blask, elemMat, &blask, &zero, elemMatSq, &blasn));
5934cc7f7b2SMatthew G. Knepley       }
5949566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numCIndices, rowIDXs, elemMatSq, ADD_VALUES));
5954cc7f7b2SMatthew G. Knepley       /* TODO Off-diagonal */
5969566063dSJacob Faibussowitsch       PetscCall(PetscFree(cindices));
5979566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
5984cc7f7b2SMatthew G. Knepley     }
5999566063dSJacob Faibussowitsch     PetscCall(DMSwarmRestoreField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
6004cc7f7b2SMatthew G. Knepley   }
6019566063dSJacob Faibussowitsch   PetscCall(PetscFree4(elemMat, elemMatSq, rowIDXs, xi));
6029566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
6039566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
6049566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
6059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
6069566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
6073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6084cc7f7b2SMatthew G. Knepley }
6094cc7f7b2SMatthew G. Knepley 
6104cc7f7b2SMatthew G. Knepley /*@C
6114cc7f7b2SMatthew G. Knepley   DMSwarmCreateMassMatrixSquare - Creates the block-diagonal of the square, M^T_p M_p, of the particle mass matrix M_p
6124cc7f7b2SMatthew G. Knepley 
6134cc7f7b2SMatthew G. Knepley   Collective on dmCoarse
6144cc7f7b2SMatthew G. Knepley 
6154cc7f7b2SMatthew G. Knepley   Input parameters:
6164cc7f7b2SMatthew G. Knepley + dmCoarse - a DMSwarm
6174cc7f7b2SMatthew G. Knepley - dmFine   - a DMPlex
6184cc7f7b2SMatthew G. Knepley 
6194cc7f7b2SMatthew G. Knepley   Output parameter:
6204cc7f7b2SMatthew G. Knepley . mass     - the square of the particle mass matrix
6214cc7f7b2SMatthew G. Knepley 
6224cc7f7b2SMatthew G. Knepley   Level: advanced
6234cc7f7b2SMatthew G. Knepley 
6244cc7f7b2SMatthew G. Knepley   Notes:
6254cc7f7b2SMatthew G. Knepley   We only compute the block diagonal since this provides a good preconditioner and is completely local. It would be possible in the
6264cc7f7b2SMatthew G. Knepley   future to compute the full normal equations.
6274cc7f7b2SMatthew G. Knepley 
628db781477SPatrick Sanan .seealso: `DMCreateMassMatrix()`
6294cc7f7b2SMatthew G. Knepley @*/
630d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateMassMatrixSquare(DM dmCoarse, DM dmFine, Mat *mass)
631d71ae5a4SJacob Faibussowitsch {
6324cc7f7b2SMatthew G. Knepley   PetscInt n;
6334cc7f7b2SMatthew G. Knepley   void    *ctx;
6344cc7f7b2SMatthew G. Knepley 
6354cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
6369566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dmCoarse, &n));
6379566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
6389566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, n, PETSC_DETERMINE, PETSC_DETERMINE));
6399566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
6409566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
6414cc7f7b2SMatthew G. Knepley 
6429566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrixSquare_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
6439566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_sq_mat_view"));
6443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6454cc7f7b2SMatthew G. Knepley }
6464cc7f7b2SMatthew G. Knepley 
647fb1bcc12SMatthew G. Knepley /*@C
648d3a51819SDave May    DMSwarmCreateGlobalVectorFromField - Creates a Vec object sharing the array associated with a given field
649d3a51819SDave May 
650d083f849SBarry Smith    Collective on dm
651d3a51819SDave May 
652d3a51819SDave May    Input parameters:
65362741f57SDave May +  dm - a DMSwarm
65462741f57SDave May -  fieldname - the textual name given to a registered field
655d3a51819SDave May 
6568b8a3813SDave May    Output parameter:
657d3a51819SDave May .  vec - the vector
658d3a51819SDave May 
659d3a51819SDave May    Level: beginner
660d3a51819SDave May 
6618b8a3813SDave May    Notes:
6628b8a3813SDave May    The vector must be returned using a matching call to DMSwarmDestroyGlobalVectorFromField().
6638b8a3813SDave May 
664db781477SPatrick Sanan .seealso: `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromField()`
665d3a51819SDave May @*/
666d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
667d71ae5a4SJacob Faibussowitsch {
668fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PetscObjectComm((PetscObject)dm);
669b5bcf523SDave May 
670fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
671*ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
6729566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
6733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
674b5bcf523SDave May }
675b5bcf523SDave May 
676d3a51819SDave May /*@C
677d3a51819SDave May    DMSwarmDestroyGlobalVectorFromField - Destroys the Vec object which share the array associated with a given field
678d3a51819SDave May 
679d083f849SBarry Smith    Collective on dm
680d3a51819SDave May 
681d3a51819SDave May    Input parameters:
68262741f57SDave May +  dm - a DMSwarm
68362741f57SDave May -  fieldname - the textual name given to a registered field
684d3a51819SDave May 
6858b8a3813SDave May    Output parameter:
686d3a51819SDave May .  vec - the vector
687d3a51819SDave May 
688d3a51819SDave May    Level: beginner
689d3a51819SDave May 
690db781477SPatrick Sanan .seealso: `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()`
691d3a51819SDave May @*/
692d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
693d71ae5a4SJacob Faibussowitsch {
694fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
695*ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
6969566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
6973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
698b5bcf523SDave May }
699b5bcf523SDave May 
700fb1bcc12SMatthew G. Knepley /*@C
701fb1bcc12SMatthew G. Knepley    DMSwarmCreateLocalVectorFromField - Creates a Vec object sharing the array associated with a given field
702fb1bcc12SMatthew G. Knepley 
703d083f849SBarry Smith    Collective on dm
704fb1bcc12SMatthew G. Knepley 
705fb1bcc12SMatthew G. Knepley    Input parameters:
70662741f57SDave May +  dm - a DMSwarm
70762741f57SDave May -  fieldname - the textual name given to a registered field
708fb1bcc12SMatthew G. Knepley 
7098b8a3813SDave May    Output parameter:
710fb1bcc12SMatthew G. Knepley .  vec - the vector
711fb1bcc12SMatthew G. Knepley 
712fb1bcc12SMatthew G. Knepley    Level: beginner
713fb1bcc12SMatthew G. Knepley 
7148b8a3813SDave May    Notes:
7158b8a3813SDave May    The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField().
7168b8a3813SDave May 
717db781477SPatrick Sanan .seealso: `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()`
718fb1bcc12SMatthew G. Knepley @*/
719d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
720d71ae5a4SJacob Faibussowitsch {
721fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PETSC_COMM_SELF;
722bbe8250bSMatthew G. Knepley 
723fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
7249566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
7253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
726bbe8250bSMatthew G. Knepley }
727fb1bcc12SMatthew G. Knepley 
728fb1bcc12SMatthew G. Knepley /*@C
729fb1bcc12SMatthew G. Knepley    DMSwarmDestroyLocalVectorFromField - Destroys the Vec object which share the array associated with a given field
730fb1bcc12SMatthew G. Knepley 
731d083f849SBarry Smith    Collective on dm
732fb1bcc12SMatthew G. Knepley 
733fb1bcc12SMatthew G. Knepley    Input parameters:
73462741f57SDave May +  dm - a DMSwarm
73562741f57SDave May -  fieldname - the textual name given to a registered field
736fb1bcc12SMatthew G. Knepley 
7378b8a3813SDave May    Output parameter:
738fb1bcc12SMatthew G. Knepley .  vec - the vector
739fb1bcc12SMatthew G. Knepley 
740fb1bcc12SMatthew G. Knepley    Level: beginner
741fb1bcc12SMatthew G. Knepley 
742db781477SPatrick Sanan .seealso: `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromField()`
743fb1bcc12SMatthew G. Knepley @*/
744d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
745d71ae5a4SJacob Faibussowitsch {
746fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
747*ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
7489566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
7493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
750bbe8250bSMatthew G. Knepley }
751bbe8250bSMatthew G. Knepley 
752d3a51819SDave May /*@C
753d3a51819SDave May    DMSwarmInitializeFieldRegister - Initiates the registration of fields to a DMSwarm
754d3a51819SDave May 
755d083f849SBarry Smith    Collective on dm
756d3a51819SDave May 
757d3a51819SDave May    Input parameter:
758d3a51819SDave May .  dm - a DMSwarm
759d3a51819SDave May 
760d3a51819SDave May    Level: beginner
761d3a51819SDave May 
762d3a51819SDave May    Notes:
7638b8a3813SDave May    After all fields have been registered, you must call DMSwarmFinalizeFieldRegister().
764d3a51819SDave May 
765db781477SPatrick Sanan .seealso: `DMSwarmFinalizeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
766db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
767d3a51819SDave May @*/
768d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmInitializeFieldRegister(DM dm)
769d71ae5a4SJacob Faibussowitsch {
7705f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
7713454631fSDave May 
772521f74f9SMatthew G. Knepley   PetscFunctionBegin;
773cc651181SDave May   if (!swarm->field_registration_initialized) {
7745f50eb2eSDave May     swarm->field_registration_initialized = PETSC_TRUE;
775da81f932SPierre Jolivet     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_pid, 1, PETSC_INT64)); /* unique identifier */
7769566063dSJacob Faibussowitsch     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_rank, 1, PETSC_INT));  /* used for communication */
777cc651181SDave May   }
7783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7795f50eb2eSDave May }
7805f50eb2eSDave May 
78174d0cae8SMatthew G. Knepley /*@
782d3a51819SDave May    DMSwarmFinalizeFieldRegister - Finalizes the registration of fields to a DMSwarm
783d3a51819SDave May 
784d083f849SBarry Smith    Collective on dm
785d3a51819SDave May 
786d3a51819SDave May    Input parameter:
787d3a51819SDave May .  dm - a DMSwarm
788d3a51819SDave May 
789d3a51819SDave May    Level: beginner
790d3a51819SDave May 
791d3a51819SDave May    Notes:
79262741f57SDave May    After DMSwarmFinalizeFieldRegister() has been called, no new fields can be defined on the DMSwarm.
793d3a51819SDave May 
794db781477SPatrick Sanan .seealso: `DMSwarmInitializeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
795db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
796d3a51819SDave May @*/
797d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmFinalizeFieldRegister(DM dm)
798d71ae5a4SJacob Faibussowitsch {
7995f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
8006845f8f5SDave May 
801521f74f9SMatthew G. Knepley   PetscFunctionBegin;
80248a46eb9SPierre Jolivet   if (!swarm->field_registration_finalized) PetscCall(DMSwarmDataBucketFinalize(swarm->db));
803f0cdbbbaSDave May   swarm->field_registration_finalized = PETSC_TRUE;
8043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8055f50eb2eSDave May }
8065f50eb2eSDave May 
80774d0cae8SMatthew G. Knepley /*@
808d3a51819SDave May    DMSwarmSetLocalSizes - Sets the length of all registered fields on the DMSwarm
809d3a51819SDave May 
810d3a51819SDave May    Not collective
811d3a51819SDave May 
812d3a51819SDave May    Input parameters:
81362741f57SDave May +  dm - a DMSwarm
814d3a51819SDave May .  nlocal - the length of each registered field
81562741f57SDave May -  buffer - the length of the buffer used to efficient dynamic re-sizing
816d3a51819SDave May 
817d3a51819SDave May    Level: beginner
818d3a51819SDave May 
819db781477SPatrick Sanan .seealso: `DMSwarmGetLocalSize()`
820d3a51819SDave May @*/
821d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetLocalSizes(DM dm, PetscInt nlocal, PetscInt buffer)
822d71ae5a4SJacob Faibussowitsch {
8235f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
8245f50eb2eSDave May 
825521f74f9SMatthew G. Knepley   PetscFunctionBegin;
8269566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_SetSizes, 0, 0, 0, 0));
8279566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, buffer));
8289566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_SetSizes, 0, 0, 0, 0));
8293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8305f50eb2eSDave May }
8315f50eb2eSDave May 
83274d0cae8SMatthew G. Knepley /*@
833d5b43468SJose E. Roman    DMSwarmSetCellDM - Attaches a DM to a DMSwarm
834d3a51819SDave May 
835d083f849SBarry Smith    Collective on dm
836d3a51819SDave May 
837d3a51819SDave May    Input parameters:
83862741f57SDave May +  dm - a DMSwarm
83962741f57SDave May -  dmcell - the DM to attach to the DMSwarm
840d3a51819SDave May 
841d3a51819SDave May    Level: beginner
842d3a51819SDave May 
843d3a51819SDave May    Notes:
844d3a51819SDave May    The attached DM (dmcell) will be queried for point location and
8458b8a3813SDave May    neighbor MPI-rank information if DMSwarmMigrate() is called.
846d3a51819SDave May 
847db781477SPatrick Sanan .seealso: `DMSwarmSetType()`, `DMSwarmGetCellDM()`, `DMSwarmMigrate()`
848d3a51819SDave May @*/
849d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetCellDM(DM dm, DM dmcell)
850d71ae5a4SJacob Faibussowitsch {
851b16650c8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
852521f74f9SMatthew G. Knepley 
853521f74f9SMatthew G. Knepley   PetscFunctionBegin;
854b16650c8SDave May   swarm->dmcell = dmcell;
8553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
856b16650c8SDave May }
857b16650c8SDave May 
85874d0cae8SMatthew G. Knepley /*@
859d3a51819SDave May    DMSwarmGetCellDM - Fetches the attached cell DM
860d3a51819SDave May 
861d083f849SBarry Smith    Collective on dm
862d3a51819SDave May 
863d3a51819SDave May    Input parameter:
864d3a51819SDave May .  dm - a DMSwarm
865d3a51819SDave May 
866d3a51819SDave May    Output parameter:
867d3a51819SDave May .  dmcell - the DM which was attached to the DMSwarm
868d3a51819SDave May 
869d3a51819SDave May    Level: beginner
870d3a51819SDave May 
871db781477SPatrick Sanan .seealso: `DMSwarmSetCellDM()`
872d3a51819SDave May @*/
873d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetCellDM(DM dm, DM *dmcell)
874d71ae5a4SJacob Faibussowitsch {
875fe39f135SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
876521f74f9SMatthew G. Knepley 
877521f74f9SMatthew G. Knepley   PetscFunctionBegin;
878fe39f135SDave May   *dmcell = swarm->dmcell;
8793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
880fe39f135SDave May }
881fe39f135SDave May 
88274d0cae8SMatthew G. Knepley /*@
883d5b43468SJose E. Roman    DMSwarmGetLocalSize - Retrieves the local length of fields registered
884d3a51819SDave May 
885d3a51819SDave May    Not collective
886d3a51819SDave May 
887d3a51819SDave May    Input parameter:
888d3a51819SDave May .  dm - a DMSwarm
889d3a51819SDave May 
890d3a51819SDave May    Output parameter:
891d3a51819SDave May .  nlocal - the length of each registered field
892d3a51819SDave May 
893d3a51819SDave May    Level: beginner
894d3a51819SDave May 
895db781477SPatrick Sanan .seealso: `DMSwarmGetSize()`, `DMSwarmSetLocalSizes()`
896d3a51819SDave May @*/
897d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetLocalSize(DM dm, PetscInt *nlocal)
898d71ae5a4SJacob Faibussowitsch {
899dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
900dcf43ee8SDave May 
901521f74f9SMatthew G. Knepley   PetscFunctionBegin;
9029566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, nlocal, NULL, NULL));
9033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
904dcf43ee8SDave May }
905dcf43ee8SDave May 
90674d0cae8SMatthew G. Knepley /*@
907d5b43468SJose E. Roman    DMSwarmGetSize - Retrieves the total length of fields registered
908d3a51819SDave May 
909d083f849SBarry Smith    Collective on dm
910d3a51819SDave May 
911d3a51819SDave May    Input parameter:
912d3a51819SDave May .  dm - a DMSwarm
913d3a51819SDave May 
914d3a51819SDave May    Output parameter:
915d3a51819SDave May .  n - the total length of each registered field
916d3a51819SDave May 
917d3a51819SDave May    Level: beginner
918d3a51819SDave May 
919d3a51819SDave May    Note:
920d3a51819SDave May    This calls MPI_Allreduce upon each call (inefficient but safe)
921d3a51819SDave May 
922db781477SPatrick Sanan .seealso: `DMSwarmGetLocalSize()`, `DMSwarmSetLocalSizes()`
923d3a51819SDave May @*/
924d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetSize(DM dm, PetscInt *n)
925d71ae5a4SJacob Faibussowitsch {
926dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
9275627991aSBarry Smith   PetscInt  nlocal;
928dcf43ee8SDave May 
929521f74f9SMatthew G. Knepley   PetscFunctionBegin;
9309566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
9319566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&nlocal, n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
9323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
933dcf43ee8SDave May }
934dcf43ee8SDave May 
935d3a51819SDave May /*@C
9368b8a3813SDave May    DMSwarmRegisterPetscDatatypeField - Register a field to a DMSwarm with a native PETSc data type
937d3a51819SDave May 
938d083f849SBarry Smith    Collective on dm
939d3a51819SDave May 
940d3a51819SDave May    Input parameters:
94162741f57SDave May +  dm - a DMSwarm
942d3a51819SDave May .  fieldname - the textual name to identify this field
943d3a51819SDave May .  blocksize - the number of each data type
94462741f57SDave May -  type - a valid PETSc data type (PETSC_CHAR, PETSC_SHORT, PETSC_INT, PETSC_FLOAT, PETSC_REAL, PETSC_LONG)
945d3a51819SDave May 
946d3a51819SDave May    Level: beginner
947d3a51819SDave May 
948d3a51819SDave May    Notes:
9498b8a3813SDave May    The textual name for each registered field must be unique.
950d3a51819SDave May 
951db781477SPatrick Sanan .seealso: `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
952d3a51819SDave May @*/
953d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterPetscDatatypeField(DM dm, const char fieldname[], PetscInt blocksize, PetscDataType type)
954d71ae5a4SJacob Faibussowitsch {
955b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
956b62e03f8SDave May   size_t    size;
957b62e03f8SDave May 
958521f74f9SMatthew G. Knepley   PetscFunctionBegin;
95928b400f6SJacob Faibussowitsch   PetscCheck(swarm->field_registration_initialized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmInitializeFieldRegister() first");
96028b400f6SJacob Faibussowitsch   PetscCheck(!swarm->field_registration_finalized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Cannot register additional fields after calling DMSwarmFinalizeFieldRegister() first");
9615f50eb2eSDave May 
96208401ef6SPierre Jolivet   PetscCheck(type != PETSC_OBJECT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96308401ef6SPierre Jolivet   PetscCheck(type != PETSC_FUNCTION, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96408401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRING, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96508401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRUCT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
96608401ef6SPierre Jolivet   PetscCheck(type != PETSC_DATATYPE_UNKNOWN, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
967b62e03f8SDave May 
9689566063dSJacob Faibussowitsch   PetscCall(PetscDataTypeGetSize(type, &size));
969b62e03f8SDave May   /* Load a specific data type into data bucket, specifying textual name and its size in bytes */
9709566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterPetscDatatypeField", fieldname, blocksize * size, NULL));
97152c3ed93SDave May   {
97277048351SPatrick Sanan     DMSwarmDataField gfield;
97352c3ed93SDave May 
9749566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
9759566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
97652c3ed93SDave May   }
977b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = type;
9783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
979b62e03f8SDave May }
980b62e03f8SDave May 
981d3a51819SDave May /*@C
982d3a51819SDave May    DMSwarmRegisterUserStructField - Register a user defined struct to a DMSwarm
983d3a51819SDave May 
984d083f849SBarry Smith    Collective on dm
985d3a51819SDave May 
986d3a51819SDave May    Input parameters:
98762741f57SDave May +  dm - a DMSwarm
988d3a51819SDave May .  fieldname - the textual name to identify this field
98962741f57SDave May -  size - the size in bytes of the user struct of each data type
990d3a51819SDave May 
991d3a51819SDave May    Level: beginner
992d3a51819SDave May 
993d3a51819SDave May    Notes:
9948b8a3813SDave May    The textual name for each registered field must be unique.
995d3a51819SDave May 
996db781477SPatrick Sanan .seealso: `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserDatatypeField()`
997d3a51819SDave May @*/
998d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserStructField(DM dm, const char fieldname[], size_t size)
999d71ae5a4SJacob Faibussowitsch {
1000b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1001b62e03f8SDave May 
1002521f74f9SMatthew G. Knepley   PetscFunctionBegin;
10039566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserStructField", fieldname, size, NULL));
1004b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_STRUCT;
10053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1006b62e03f8SDave May }
1007b62e03f8SDave May 
1008d3a51819SDave May /*@C
1009d3a51819SDave May    DMSwarmRegisterUserDatatypeField - Register a user defined data type to a DMSwarm
1010d3a51819SDave May 
1011d083f849SBarry Smith    Collective on dm
1012d3a51819SDave May 
1013d3a51819SDave May    Input parameters:
101462741f57SDave May +  dm - a DMSwarm
1015d3a51819SDave May .  fieldname - the textual name to identify this field
1016d3a51819SDave May .  size - the size in bytes of the user data type
101762741f57SDave May -  blocksize - the number of each data type
1018d3a51819SDave May 
1019d3a51819SDave May    Level: beginner
1020d3a51819SDave May 
1021d3a51819SDave May    Notes:
10228b8a3813SDave May    The textual name for each registered field must be unique.
1023d3a51819SDave May 
1024db781477SPatrick Sanan .seealso: `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
1025d3a51819SDave May @*/
1026d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserDatatypeField(DM dm, const char fieldname[], size_t size, PetscInt blocksize)
1027d71ae5a4SJacob Faibussowitsch {
1028b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1029b62e03f8SDave May 
1030521f74f9SMatthew G. Knepley   PetscFunctionBegin;
10319566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserDatatypeField", fieldname, blocksize * size, NULL));
1032320740a0SDave May   {
103377048351SPatrick Sanan     DMSwarmDataField gfield;
1034320740a0SDave May 
10359566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
10369566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
1037320740a0SDave May   }
1038b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_DATATYPE_UNKNOWN;
10393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1040b62e03f8SDave May }
1041b62e03f8SDave May 
1042d3a51819SDave May /*@C
1043d3a51819SDave May    DMSwarmGetField - Get access to the underlying array storing all entries associated with a registered field
1044d3a51819SDave May 
1045d3a51819SDave May    Not collective
1046d3a51819SDave May 
1047d3a51819SDave May    Input parameters:
104862741f57SDave May +  dm - a DMSwarm
104962741f57SDave May -  fieldname - the textual name to identify this field
1050d3a51819SDave May 
1051d3a51819SDave May    Output parameters:
105262741f57SDave May +  blocksize - the number of each data type
1053d3a51819SDave May .  type - the data type
105462741f57SDave May -  data - pointer to raw array
1055d3a51819SDave May 
1056d3a51819SDave May    Level: beginner
1057d3a51819SDave May 
1058d3a51819SDave May    Notes:
10598b8a3813SDave May    The array must be returned using a matching call to DMSwarmRestoreField().
1060d3a51819SDave May 
1061db781477SPatrick Sanan .seealso: `DMSwarmRestoreField()`
1062d3a51819SDave May @*/
1063d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1064d71ae5a4SJacob Faibussowitsch {
1065b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
106677048351SPatrick Sanan   DMSwarmDataField gfield;
1067b62e03f8SDave May 
1068521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1069*ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
10709566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
10719566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
10729566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetAccess(gfield));
10739566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetEntries(gfield, data));
1074ad540459SPierre Jolivet   if (blocksize) *blocksize = gfield->bs;
1075ad540459SPierre Jolivet   if (type) *type = gfield->petsc_type;
10763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1077b62e03f8SDave May }
1078b62e03f8SDave May 
1079d3a51819SDave May /*@C
1080d3a51819SDave May    DMSwarmRestoreField - Restore access to the underlying array storing all entries associated with a registered field
1081d3a51819SDave May 
1082d3a51819SDave May    Not collective
1083d3a51819SDave May 
1084d3a51819SDave May    Input parameters:
108562741f57SDave May +  dm - a DMSwarm
108662741f57SDave May -  fieldname - the textual name to identify this field
1087d3a51819SDave May 
1088d3a51819SDave May    Output parameters:
108962741f57SDave May +  blocksize - the number of each data type
1090d3a51819SDave May .  type - the data type
109162741f57SDave May -  data - pointer to raw array
1092d3a51819SDave May 
1093d3a51819SDave May    Level: beginner
1094d3a51819SDave May 
1095d3a51819SDave May    Notes:
10968b8a3813SDave May    The user must call DMSwarmGetField() prior to calling DMSwarmRestoreField().
1097d3a51819SDave May 
1098db781477SPatrick Sanan .seealso: `DMSwarmGetField()`
1099d3a51819SDave May @*/
1100d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRestoreField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1101d71ae5a4SJacob Faibussowitsch {
1102b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
110377048351SPatrick Sanan   DMSwarmDataField gfield;
1104b62e03f8SDave May 
1105521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1106*ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
11079566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
11089566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
1109b62e03f8SDave May   if (data) *data = NULL;
11103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1111b62e03f8SDave May }
1112b62e03f8SDave May 
111374d0cae8SMatthew G. Knepley /*@
1114d3a51819SDave May    DMSwarmAddPoint - Add space for one new point in the DMSwarm
1115d3a51819SDave May 
1116d3a51819SDave May    Not collective
1117d3a51819SDave May 
1118d3a51819SDave May    Input parameter:
1119d3a51819SDave May .  dm - a DMSwarm
1120d3a51819SDave May 
1121d3a51819SDave May    Level: beginner
1122d3a51819SDave May 
1123d3a51819SDave May    Notes:
11248b8a3813SDave May    The new point will have all fields initialized to zero.
1125d3a51819SDave May 
1126db781477SPatrick Sanan .seealso: `DMSwarmAddNPoints()`
1127d3a51819SDave May @*/
1128d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddPoint(DM dm)
1129d71ae5a4SJacob Faibussowitsch {
1130cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1131cb1d1399SDave May 
1132521f74f9SMatthew G. Knepley   PetscFunctionBegin;
11339566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
11349566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
11359566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketAddPoint(swarm->db));
11369566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
11373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1138cb1d1399SDave May }
1139cb1d1399SDave May 
114074d0cae8SMatthew G. Knepley /*@
1141d3a51819SDave May    DMSwarmAddNPoints - Add space for a number of new points in the DMSwarm
1142d3a51819SDave May 
1143d3a51819SDave May    Not collective
1144d3a51819SDave May 
1145d3a51819SDave May    Input parameters:
114662741f57SDave May +  dm - a DMSwarm
114762741f57SDave May -  npoints - the number of new points to add
1148d3a51819SDave May 
1149d3a51819SDave May    Level: beginner
1150d3a51819SDave May 
1151d3a51819SDave May    Notes:
11528b8a3813SDave May    The new point will have all fields initialized to zero.
1153d3a51819SDave May 
1154db781477SPatrick Sanan .seealso: `DMSwarmAddPoint()`
1155d3a51819SDave May @*/
1156d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddNPoints(DM dm, PetscInt npoints)
1157d71ae5a4SJacob Faibussowitsch {
1158cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1159cb1d1399SDave May   PetscInt  nlocal;
1160cb1d1399SDave May 
1161521f74f9SMatthew G. Knepley   PetscFunctionBegin;
11629566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
11639566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
1164cb1d1399SDave May   nlocal = nlocal + npoints;
11659566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
11669566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
11673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1168cb1d1399SDave May }
1169cb1d1399SDave May 
117074d0cae8SMatthew G. Knepley /*@
1171d3a51819SDave May    DMSwarmRemovePoint - Remove the last point from the DMSwarm
1172d3a51819SDave May 
1173d3a51819SDave May    Not collective
1174d3a51819SDave May 
1175d3a51819SDave May    Input parameter:
1176d3a51819SDave May .  dm - a DMSwarm
1177d3a51819SDave May 
1178d3a51819SDave May    Level: beginner
1179d3a51819SDave May 
1180db781477SPatrick Sanan .seealso: `DMSwarmRemovePointAtIndex()`
1181d3a51819SDave May @*/
1182d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePoint(DM dm)
1183d71ae5a4SJacob Faibussowitsch {
1184cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1185cb1d1399SDave May 
1186521f74f9SMatthew G. Knepley   PetscFunctionBegin;
11879566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
11889566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePoint(swarm->db));
11899566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
11903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1191cb1d1399SDave May }
1192cb1d1399SDave May 
119374d0cae8SMatthew G. Knepley /*@
1194d3a51819SDave May    DMSwarmRemovePointAtIndex - Removes a specific point from the DMSwarm
1195d3a51819SDave May 
1196d3a51819SDave May    Not collective
1197d3a51819SDave May 
1198d3a51819SDave May    Input parameters:
119962741f57SDave May +  dm - a DMSwarm
120062741f57SDave May -  idx - index of point to remove
1201d3a51819SDave May 
1202d3a51819SDave May    Level: beginner
1203d3a51819SDave May 
1204db781477SPatrick Sanan .seealso: `DMSwarmRemovePoint()`
1205d3a51819SDave May @*/
1206d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePointAtIndex(DM dm, PetscInt idx)
1207d71ae5a4SJacob Faibussowitsch {
1208cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1209cb1d1399SDave May 
1210521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12119566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
12129566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, idx));
12139566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
12143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1215cb1d1399SDave May }
1216b62e03f8SDave May 
121774d0cae8SMatthew G. Knepley /*@
1218ba4fc9c6SDave May    DMSwarmCopyPoint - Copy point pj to point pi in the DMSwarm
1219ba4fc9c6SDave May 
1220ba4fc9c6SDave May    Not collective
1221ba4fc9c6SDave May 
1222ba4fc9c6SDave May    Input parameters:
1223ba4fc9c6SDave May +  dm - a DMSwarm
1224ba4fc9c6SDave May .  pi - the index of the point to copy
1225ba4fc9c6SDave May -  pj - the point index where the copy should be located
1226ba4fc9c6SDave May 
1227ba4fc9c6SDave May  Level: beginner
1228ba4fc9c6SDave May 
1229db781477SPatrick Sanan .seealso: `DMSwarmRemovePoint()`
1230ba4fc9c6SDave May @*/
1231d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCopyPoint(DM dm, PetscInt pi, PetscInt pj)
1232d71ae5a4SJacob Faibussowitsch {
1233ba4fc9c6SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1234ba4fc9c6SDave May 
1235ba4fc9c6SDave May   PetscFunctionBegin;
12369566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
12379566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCopyPoint(swarm->db, pi, swarm->db, pj));
12383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1239ba4fc9c6SDave May }
1240ba4fc9c6SDave May 
1241d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmMigrate_Basic(DM dm, PetscBool remove_sent_points)
1242d71ae5a4SJacob Faibussowitsch {
1243521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12449566063dSJacob Faibussowitsch   PetscCall(DMSwarmMigrate_Push_Basic(dm, remove_sent_points));
12453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12463454631fSDave May }
12473454631fSDave May 
124874d0cae8SMatthew G. Knepley /*@
1249d3a51819SDave May    DMSwarmMigrate - Relocates points defined in the DMSwarm to other MPI-ranks
1250d3a51819SDave May 
1251d083f849SBarry Smith    Collective on dm
1252d3a51819SDave May 
1253d3a51819SDave May    Input parameters:
125462741f57SDave May +  dm - the DMSwarm
125562741f57SDave May -  remove_sent_points - flag indicating if sent points should be removed from the current MPI-rank
1256d3a51819SDave May 
1257d3a51819SDave May    Notes:
1258a5b23f4aSJose E. Roman    The DM will be modified to accommodate received points.
12598b8a3813SDave May    If remove_sent_points = PETSC_TRUE, any points that were sent will be removed from the DM.
12608b8a3813SDave May    Different styles of migration are supported. See DMSwarmSetMigrateType().
1261d3a51819SDave May 
1262d3a51819SDave May    Level: advanced
1263d3a51819SDave May 
1264db781477SPatrick Sanan .seealso: `DMSwarmSetMigrateType()`
1265d3a51819SDave May @*/
1266d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmMigrate(DM dm, PetscBool remove_sent_points)
1267d71ae5a4SJacob Faibussowitsch {
1268f0cdbbbaSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1269f0cdbbbaSDave May 
1270521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12719566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_Migrate, 0, 0, 0, 0));
1272f0cdbbbaSDave May   switch (swarm->migrate_type) {
1273d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_BASIC:
1274d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_Basic(dm, remove_sent_points));
1275d71ae5a4SJacob Faibussowitsch     break;
1276d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLNSCATTER:
1277d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_CellDMScatter(dm, remove_sent_points));
1278d71ae5a4SJacob Faibussowitsch     break;
1279d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLEXACT:
1280d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_DMCELLEXACT not implemented");
1281d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_USER:
1282d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_USER not implemented");
1283d71ae5a4SJacob Faibussowitsch   default:
1284d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE type unknown");
1285f0cdbbbaSDave May   }
12869566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_Migrate, 0, 0, 0, 0));
12879566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm));
12883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12893454631fSDave May }
12903454631fSDave May 
1291f0cdbbbaSDave May PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm, PetscInt *globalsize);
1292f0cdbbbaSDave May 
1293d3a51819SDave May /*
1294d3a51819SDave May  DMSwarmCollectViewCreate
1295d3a51819SDave May 
1296d3a51819SDave May  * Applies a collection method and gathers point neighbour points into dm
1297d3a51819SDave May 
1298d3a51819SDave May  Notes:
12998b8a3813SDave May  Users should call DMSwarmCollectViewDestroy() after
1300d3a51819SDave May  they have finished computations associated with the collected points
1301d3a51819SDave May */
1302d3a51819SDave May 
130374d0cae8SMatthew G. Knepley /*@
1304d3a51819SDave May    DMSwarmCollectViewCreate - Applies a collection method and gathers points
13055627991aSBarry Smith                               in neighbour ranks into the DMSwarm
1306d3a51819SDave May 
1307d083f849SBarry Smith    Collective on dm
1308d3a51819SDave May 
1309d3a51819SDave May    Input parameter:
1310d3a51819SDave May .  dm - the DMSwarm
1311d3a51819SDave May 
1312d3a51819SDave May    Notes:
1313d3a51819SDave May    Users should call DMSwarmCollectViewDestroy() after
1314d3a51819SDave May    they have finished computations associated with the collected points
13158b8a3813SDave May    Different collect methods are supported. See DMSwarmSetCollectType().
1316d3a51819SDave May 
1317d3a51819SDave May    Level: advanced
1318d3a51819SDave May 
1319db781477SPatrick Sanan .seealso: `DMSwarmCollectViewDestroy()`, `DMSwarmSetCollectType()`
1320d3a51819SDave May @*/
1321d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewCreate(DM dm)
1322d71ae5a4SJacob Faibussowitsch {
13232712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
13242712d1f2SDave May   PetscInt  ng;
13252712d1f2SDave May 
1326521f74f9SMatthew G. Knepley   PetscFunctionBegin;
132728b400f6SJacob Faibussowitsch   PetscCheck(!swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView currently active");
13289566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &ng));
1329480eef7bSDave May   switch (swarm->collect_type) {
1330d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_BASIC:
1331d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_GlobalToLocal_Basic(dm, &ng));
1332d71ae5a4SJacob Faibussowitsch     break;
1333d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_DMDABOUNDINGBOX:
1334d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_DMDABOUNDINGBOX not implemented");
1335d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_GENERAL:
1336d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_GENERAL not implemented");
1337d71ae5a4SJacob Faibussowitsch   default:
1338d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT type unknown");
1339480eef7bSDave May   }
1340480eef7bSDave May   swarm->collect_view_active       = PETSC_TRUE;
1341480eef7bSDave May   swarm->collect_view_reset_nlocal = ng;
13423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13432712d1f2SDave May }
13442712d1f2SDave May 
134574d0cae8SMatthew G. Knepley /*@
1346d3a51819SDave May    DMSwarmCollectViewDestroy - Resets the DMSwarm to the size prior to calling DMSwarmCollectViewCreate()
1347d3a51819SDave May 
1348d083f849SBarry Smith    Collective on dm
1349d3a51819SDave May 
1350d3a51819SDave May    Input parameters:
1351d3a51819SDave May .  dm - the DMSwarm
1352d3a51819SDave May 
1353d3a51819SDave May    Notes:
1354d3a51819SDave May    Users should call DMSwarmCollectViewCreate() before this function is called.
1355d3a51819SDave May 
1356d3a51819SDave May    Level: advanced
1357d3a51819SDave May 
1358db781477SPatrick Sanan .seealso: `DMSwarmCollectViewCreate()`, `DMSwarmSetCollectType()`
1359d3a51819SDave May @*/
1360d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewDestroy(DM dm)
1361d71ae5a4SJacob Faibussowitsch {
13622712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
13632712d1f2SDave May 
1364521f74f9SMatthew G. Knepley   PetscFunctionBegin;
136528b400f6SJacob Faibussowitsch   PetscCheck(swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView is currently not active");
13669566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetLocalSizes(dm, swarm->collect_view_reset_nlocal, -1));
1367480eef7bSDave May   swarm->collect_view_active = PETSC_FALSE;
13683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13692712d1f2SDave May }
13703454631fSDave May 
1371d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetUpPIC(DM dm)
1372d71ae5a4SJacob Faibussowitsch {
1373f0cdbbbaSDave May   PetscInt dim;
1374f0cdbbbaSDave May 
1375521f74f9SMatthew G. Knepley   PetscFunctionBegin;
13769566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetNumSpecies(dm, 1));
13779566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
137863a3b9bcSJacob Faibussowitsch   PetscCheck(dim >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
137963a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
13809566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_coor, dim, PETSC_DOUBLE));
13819566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_cellid, 1, PETSC_INT));
13823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1383f0cdbbbaSDave May }
1384f0cdbbbaSDave May 
138574d0cae8SMatthew G. Knepley /*@
138631403186SMatthew G. Knepley   DMSwarmSetPointCoordinatesRandom - Sets initial coordinates for particles in each cell
138731403186SMatthew G. Knepley 
138831403186SMatthew G. Knepley   Collective on dm
138931403186SMatthew G. Knepley 
139031403186SMatthew G. Knepley   Input parameters:
139131403186SMatthew G. Knepley + dm  - the DMSwarm
139231403186SMatthew G. Knepley - Npc - The number of particles per cell in the cell DM
139331403186SMatthew G. Knepley 
139431403186SMatthew G. Knepley   Notes:
139531403186SMatthew G. Knepley   The user must use DMSwarmSetCellDM() to set the cell DM first. The particles are placed randomly inside each cell. If only
139631403186SMatthew G. Knepley   one particle is in each cell, it is placed at the centroid.
139731403186SMatthew G. Knepley 
139831403186SMatthew G. Knepley   Level: intermediate
139931403186SMatthew G. Knepley 
1400db781477SPatrick Sanan .seealso: `DMSwarmSetCellDM()`
140131403186SMatthew G. Knepley @*/
1402d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetPointCoordinatesRandom(DM dm, PetscInt Npc)
1403d71ae5a4SJacob Faibussowitsch {
140431403186SMatthew G. Knepley   DM             cdm;
140531403186SMatthew G. Knepley   PetscRandom    rnd;
140631403186SMatthew G. Knepley   DMPolytopeType ct;
140731403186SMatthew G. Knepley   PetscBool      simplex;
140831403186SMatthew G. Knepley   PetscReal     *centroid, *coords, *xi0, *v0, *J, *invJ, detJ;
140931403186SMatthew G. Knepley   PetscInt       dim, d, cStart, cEnd, c, p;
141031403186SMatthew G. Knepley 
141131403186SMatthew G. Knepley   PetscFunctionBeginUser;
14129566063dSJacob Faibussowitsch   PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm), &rnd));
14139566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0));
14149566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetType(rnd, PETSCRAND48));
141531403186SMatthew G. Knepley 
14169566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
14179566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(cdm, &dim));
14189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd));
14199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(cdm, cStart, &ct));
142031403186SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
142131403186SMatthew G. Knepley 
14229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(dim, &centroid, dim, &xi0, dim, &v0, dim * dim, &J, dim * dim, &invJ));
142331403186SMatthew G. Knepley   for (d = 0; d < dim; ++d) xi0[d] = -1.0;
14249566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
142531403186SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
142631403186SMatthew G. Knepley     if (Npc == 1) {
14279566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(cdm, c, NULL, centroid, NULL));
142831403186SMatthew G. Knepley       for (d = 0; d < dim; ++d) coords[c * dim + d] = centroid[d];
142931403186SMatthew G. Knepley     } else {
14309566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(cdm, c, NULL, v0, J, invJ, &detJ)); /* affine */
143131403186SMatthew G. Knepley       for (p = 0; p < Npc; ++p) {
143231403186SMatthew G. Knepley         const PetscInt n   = c * Npc + p;
143331403186SMatthew G. Knepley         PetscReal      sum = 0.0, refcoords[3];
143431403186SMatthew G. Knepley 
143531403186SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
14369566063dSJacob Faibussowitsch           PetscCall(PetscRandomGetValueReal(rnd, &refcoords[d]));
143731403186SMatthew G. Knepley           sum += refcoords[d];
143831403186SMatthew G. Knepley         }
14399371c9d4SSatish Balay         if (simplex && sum > 0.0)
14409371c9d4SSatish Balay           for (d = 0; d < dim; ++d) refcoords[d] -= PetscSqrtReal(dim) * sum;
144131403186SMatthew G. Knepley         CoordinatesRefToReal(dim, dim, xi0, v0, J, refcoords, &coords[n * dim]);
144231403186SMatthew G. Knepley       }
144331403186SMatthew G. Knepley     }
144431403186SMatthew G. Knepley   }
14459566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
14469566063dSJacob Faibussowitsch   PetscCall(PetscFree5(centroid, xi0, v0, J, invJ));
14479566063dSJacob Faibussowitsch   PetscCall(PetscRandomDestroy(&rnd));
14483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
144931403186SMatthew G. Knepley }
145031403186SMatthew G. Knepley 
145131403186SMatthew G. Knepley /*@
1452d3a51819SDave May    DMSwarmSetType - Set particular flavor of DMSwarm
1453d3a51819SDave May 
1454d083f849SBarry Smith    Collective on dm
1455d3a51819SDave May 
1456d3a51819SDave May    Input parameters:
145762741f57SDave May +  dm - the DMSwarm
145862741f57SDave May -  stype - the DMSwarm type (e.g. DMSWARM_PIC)
1459d3a51819SDave May 
1460d3a51819SDave May    Level: advanced
1461d3a51819SDave May 
1462db781477SPatrick Sanan .seealso: `DMSwarmSetMigrateType()`, `DMSwarmSetCollectType()`, `DMSwarmType`, `DMSWARM_PIC`, `DMSWARM_BASIC`
1463d3a51819SDave May @*/
1464d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetType(DM dm, DMSwarmType stype)
1465d71ae5a4SJacob Faibussowitsch {
1466f0cdbbbaSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1467f0cdbbbaSDave May 
1468521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1469f0cdbbbaSDave May   swarm->swarm_type = stype;
147048a46eb9SPierre Jolivet   if (swarm->swarm_type == DMSWARM_PIC) PetscCall(DMSwarmSetUpPIC(dm));
14713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1472f0cdbbbaSDave May }
1473f0cdbbbaSDave May 
1474d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSetup_Swarm(DM dm)
1475d71ae5a4SJacob Faibussowitsch {
14763454631fSDave May   DM_Swarm   *swarm = (DM_Swarm *)dm->data;
14773454631fSDave May   PetscMPIInt rank;
14783454631fSDave May   PetscInt    p, npoints, *rankval;
14793454631fSDave May 
1480521f74f9SMatthew G. Knepley   PetscFunctionBegin;
14813ba16761SJacob Faibussowitsch   if (swarm->issetup) PetscFunctionReturn(PETSC_SUCCESS);
14823454631fSDave May   swarm->issetup = PETSC_TRUE;
14833454631fSDave May 
1484f0cdbbbaSDave May   if (swarm->swarm_type == DMSWARM_PIC) {
1485f0cdbbbaSDave May     /* check dmcell exists */
148628b400f6SJacob Faibussowitsch     PetscCheck(swarm->dmcell, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires you call DMSwarmSetCellDM");
1487f0cdbbbaSDave May 
1488f0cdbbbaSDave May     if (swarm->dmcell->ops->locatepointssubdomain) {
1489f0cdbbbaSDave May       /* check methods exists for exact ownership identificiation */
14909566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->ops->LocatePointsSubdomain\n"));
1491f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLEXACT;
1492f0cdbbbaSDave May     } else {
1493f0cdbbbaSDave May       /* check methods exist for point location AND rank neighbor identification */
1494f0cdbbbaSDave May       if (swarm->dmcell->ops->locatepoints) {
14959566063dSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->LocatePoints\n"));
1496f0cdbbbaSDave May       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->locatepoints be defined");
1497f0cdbbbaSDave May 
1498f0cdbbbaSDave May       if (swarm->dmcell->ops->getneighbors) {
14999566063dSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->GetNeigbors\n"));
1500f0cdbbbaSDave May       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->getneighbors be defined");
1501f0cdbbbaSDave May 
1502f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLNSCATTER;
1503f0cdbbbaSDave May     }
1504f0cdbbbaSDave May   }
1505f0cdbbbaSDave May 
15069566063dSJacob Faibussowitsch   PetscCall(DMSwarmFinalizeFieldRegister(dm));
1507f0cdbbbaSDave May 
15083454631fSDave May   /* check some fields were registered */
150908401ef6SPierre Jolivet   PetscCheck(swarm->db->nfields > 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "At least one field user must be registered via DMSwarmRegisterXXX()");
15103454631fSDave May 
15113454631fSDave May   /* check local sizes were set */
151208401ef6SPierre Jolivet   PetscCheck(swarm->db->L != -1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Local sizes must be set via DMSwarmSetLocalSizes()");
15133454631fSDave May 
15143454631fSDave May   /* initialize values in pid and rank placeholders */
15153454631fSDave May   /* TODO: [pid - use MPI_Scan] */
15169566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
15179566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
15189566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
1519ad540459SPierre Jolivet   for (p = 0; p < npoints; p++) rankval[p] = (PetscInt)rank;
15209566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
15213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15223454631fSDave May }
15233454631fSDave May 
1524dc5f5ce9SDave May extern PetscErrorCode DMSwarmSortDestroy(DMSwarmSort *_ctx);
1525dc5f5ce9SDave May 
1526d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDestroy_Swarm(DM dm)
1527d71ae5a4SJacob Faibussowitsch {
152857795646SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
152957795646SDave May 
153057795646SDave May   PetscFunctionBegin;
15313ba16761SJacob Faibussowitsch   if (--swarm->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
15329566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&swarm->db));
153348a46eb9SPierre Jolivet   if (swarm->sort_context) PetscCall(DMSwarmSortDestroy(&swarm->sort_context));
15349566063dSJacob Faibussowitsch   PetscCall(PetscFree(swarm));
15353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153657795646SDave May }
153757795646SDave May 
1538d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmView_Draw(DM dm, PetscViewer viewer)
1539d71ae5a4SJacob Faibussowitsch {
1540a9ee3421SMatthew G. Knepley   DM         cdm;
1541a9ee3421SMatthew G. Knepley   PetscDraw  draw;
154231403186SMatthew G. Knepley   PetscReal *coords, oldPause, radius = 0.01;
1543a9ee3421SMatthew G. Knepley   PetscInt   Np, p, bs;
1544a9ee3421SMatthew G. Knepley 
1545a9ee3421SMatthew G. Knepley   PetscFunctionBegin;
15469566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetReal(NULL, ((PetscObject)dm)->prefix, "-dm_view_swarm_radius", &radius, NULL));
15479566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
15489566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
15499566063dSJacob Faibussowitsch   PetscCall(PetscDrawGetPause(draw, &oldPause));
15509566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, 0.0));
15519566063dSJacob Faibussowitsch   PetscCall(DMView(cdm, viewer));
15529566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, oldPause));
1553a9ee3421SMatthew G. Knepley 
15549566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &Np));
15559566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&coords));
1556a9ee3421SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
1557a9ee3421SMatthew G. Knepley     const PetscInt i = p * bs;
1558a9ee3421SMatthew G. Knepley 
15599566063dSJacob Faibussowitsch     PetscCall(PetscDrawEllipse(draw, coords[i], coords[i + 1], radius, radius, PETSC_DRAW_BLUE));
1560a9ee3421SMatthew G. Knepley   }
15619566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&coords));
15629566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
15639566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
15649566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
15653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1566a9ee3421SMatthew G. Knepley }
1567a9ee3421SMatthew G. Knepley 
1568d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_Swarm_Ascii(DM dm, PetscViewer viewer)
1569d71ae5a4SJacob Faibussowitsch {
15706a5217c0SMatthew G. Knepley   PetscViewerFormat format;
15716a5217c0SMatthew G. Knepley   PetscInt         *sizes;
15726a5217c0SMatthew G. Knepley   PetscInt          dim, Np, maxSize = 17;
15736a5217c0SMatthew G. Knepley   MPI_Comm          comm;
15746a5217c0SMatthew G. Knepley   PetscMPIInt       rank, size, p;
15756a5217c0SMatthew G. Knepley   const char       *name;
15766a5217c0SMatthew G. Knepley 
15776a5217c0SMatthew G. Knepley   PetscFunctionBegin;
15786a5217c0SMatthew G. Knepley   PetscCall(PetscViewerGetFormat(viewer, &format));
15796a5217c0SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
15806a5217c0SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(dm, &Np));
15816a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
15826a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
15836a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(comm, &size));
15846a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetName((PetscObject)dm, &name));
158563a3b9bcSJacob Faibussowitsch   if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
158663a3b9bcSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(viewer, "Swarm in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
15876a5217c0SMatthew G. Knepley   if (size < maxSize) PetscCall(PetscCalloc1(size, &sizes));
15886a5217c0SMatthew G. Knepley   else PetscCall(PetscCalloc1(3, &sizes));
15896a5217c0SMatthew G. Knepley   if (size < maxSize) {
15906a5217c0SMatthew G. Knepley     PetscCallMPI(MPI_Gather(&Np, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
15916a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of particles per rank:"));
15926a5217c0SMatthew G. Knepley     for (p = 0; p < size; ++p) {
15936a5217c0SMatthew G. Knepley       if (rank == 0) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]));
15946a5217c0SMatthew G. Knepley     }
15956a5217c0SMatthew G. Knepley   } else {
15966a5217c0SMatthew G. Knepley     PetscInt locMinMax[2] = {Np, Np};
15976a5217c0SMatthew G. Knepley 
15986a5217c0SMatthew G. Knepley     PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
15996a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of particles per rank: %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
16006a5217c0SMatthew G. Knepley   }
16016a5217c0SMatthew G. Knepley   PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
16026a5217c0SMatthew G. Knepley   PetscCall(PetscFree(sizes));
16036a5217c0SMatthew G. Knepley   if (format == PETSC_VIEWER_ASCII_INFO) {
16046a5217c0SMatthew G. Knepley     PetscInt *cell;
16056a5217c0SMatthew G. Knepley 
16066a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells containing each particle:\n"));
16076a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
16086a5217c0SMatthew G. Knepley     PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell));
160963a3b9bcSJacob Faibussowitsch     for (p = 0; p < Np; ++p) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  p%d: %" PetscInt_FMT "\n", p, cell[p]));
16106a5217c0SMatthew G. Knepley     PetscCall(PetscViewerFlush(viewer));
16116a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
16126a5217c0SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell));
16136a5217c0SMatthew G. Knepley   }
16143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16156a5217c0SMatthew G. Knepley }
16166a5217c0SMatthew G. Knepley 
1617d71ae5a4SJacob Faibussowitsch PetscErrorCode DMView_Swarm(DM dm, PetscViewer viewer)
1618d71ae5a4SJacob Faibussowitsch {
16195f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
16205627991aSBarry Smith   PetscBool iascii, ibinary, isvtk, isdraw;
16215627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
16225627991aSBarry Smith   PetscBool ishdf5;
16235627991aSBarry Smith #endif
16245f50eb2eSDave May 
16255f50eb2eSDave May   PetscFunctionBegin;
16265f50eb2eSDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
16275f50eb2eSDave May   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
16289566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
16299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary));
16309566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
16315627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
16329566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
16335627991aSBarry Smith #endif
16349566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
16355f50eb2eSDave May   if (iascii) {
16366a5217c0SMatthew G. Knepley     PetscViewerFormat format;
16376a5217c0SMatthew G. Knepley 
16386a5217c0SMatthew G. Knepley     PetscCall(PetscViewerGetFormat(viewer, &format));
16396a5217c0SMatthew G. Knepley     switch (format) {
1640d71ae5a4SJacob Faibussowitsch     case PETSC_VIEWER_ASCII_INFO_DETAIL:
1641d71ae5a4SJacob Faibussowitsch       PetscCall(DMSwarmDataBucketView(PetscObjectComm((PetscObject)dm), swarm->db, NULL, DATABUCKET_VIEW_STDOUT));
1642d71ae5a4SJacob Faibussowitsch       break;
1643d71ae5a4SJacob Faibussowitsch     default:
1644d71ae5a4SJacob Faibussowitsch       PetscCall(DMView_Swarm_Ascii(dm, viewer));
16456a5217c0SMatthew G. Knepley     }
1646f7d195e4SLawrence Mitchell   } else {
16475f50eb2eSDave May #if defined(PETSC_HAVE_HDF5)
164848a46eb9SPierre Jolivet     if (ishdf5) PetscCall(DMSwarmView_HDF5(dm, viewer));
16495f50eb2eSDave May #endif
165048a46eb9SPierre Jolivet     if (isdraw) PetscCall(DMSwarmView_Draw(dm, viewer));
1651f7d195e4SLawrence Mitchell   }
16523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16535f50eb2eSDave May }
16545f50eb2eSDave May 
1655d0c080abSJoseph Pusztay /*@C
1656d0c080abSJoseph Pusztay    DMSwarmGetCellSwarm - Extracts a single cell from the DMSwarm object, returns it as a single cell DMSwarm.
1657d0c080abSJoseph Pusztay    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.
1658d0c080abSJoseph Pusztay 
1659d0c080abSJoseph Pusztay    Important: Changes to this cell of the swarm will be lost if they are made prior to restoring this cell.
1660d0c080abSJoseph Pusztay 
1661d0c080abSJoseph Pusztay    Noncollective
1662d0c080abSJoseph Pusztay 
1663d0c080abSJoseph Pusztay    Input parameters:
1664d0c080abSJoseph Pusztay +  sw - the DMSwarm
16655627991aSBarry Smith .  cellID - the integer id of the cell to be extracted and filtered
16665627991aSBarry Smith -  cellswarm - The DMSwarm to receive the cell
1667d0c080abSJoseph Pusztay 
1668d0c080abSJoseph Pusztay    Level: beginner
1669d0c080abSJoseph Pusztay 
16705627991aSBarry Smith    Notes:
16715627991aSBarry Smith       This presently only supports DMSWARM_PIC type
16725627991aSBarry Smith 
16735627991aSBarry Smith       Should be restored with DMSwarmRestoreCellSwarm()
1674d0c080abSJoseph Pusztay 
1675db781477SPatrick Sanan .seealso: `DMSwarmRestoreCellSwarm()`
1676d0c080abSJoseph Pusztay @*/
1677d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMSwarmGetCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
1678d71ae5a4SJacob Faibussowitsch {
1679d0c080abSJoseph Pusztay   DM_Swarm *original = (DM_Swarm *)sw->data;
1680d0c080abSJoseph Pusztay   DMLabel   label;
1681d0c080abSJoseph Pusztay   DM        dmc, subdmc;
1682d0c080abSJoseph Pusztay   PetscInt *pids, particles, dim;
1683d0c080abSJoseph Pusztay 
1684d0c080abSJoseph Pusztay   PetscFunctionBegin;
1685d0c080abSJoseph Pusztay   /* Configure new swarm */
16869566063dSJacob Faibussowitsch   PetscCall(DMSetType(cellswarm, DMSWARM));
16879566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(sw, &dim));
16889566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(cellswarm, dim));
16899566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(cellswarm, DMSWARM_PIC));
1690d0c080abSJoseph Pusztay   /* Destroy the unused, unconfigured data bucket to prevent stragglers in memory */
16919566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&((DM_Swarm *)cellswarm->data)->db));
16929566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
16939566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, cellID, &particles));
16949566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
16959566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreateFromSubset(original->db, particles, pids, &((DM_Swarm *)cellswarm->data)->db));
16969566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
16979566063dSJacob Faibussowitsch   PetscCall(PetscFree(pids));
16989566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(sw, &dmc));
16999566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)sw), "singlecell", &label));
17009566063dSJacob Faibussowitsch   PetscCall(DMAddLabel(dmc, label));
17019566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cellID, 1));
17029566063dSJacob Faibussowitsch   PetscCall(DMPlexFilter(dmc, label, 1, &subdmc));
17039566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetCellDM(cellswarm, subdmc));
17049566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&label));
17053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1706d0c080abSJoseph Pusztay }
1707d0c080abSJoseph Pusztay 
1708d0c080abSJoseph Pusztay /*@C
17095627991aSBarry Smith    DMSwarmRestoreCellSwarm - Restores a DMSwarm object obtained with DMSwarmGetCellSwarm(). All fields are copied back into the parent swarm.
1710d0c080abSJoseph Pusztay 
1711d0c080abSJoseph Pusztay    Noncollective
1712d0c080abSJoseph Pusztay 
1713d0c080abSJoseph Pusztay    Input parameters:
1714d0c080abSJoseph Pusztay +  sw - the parent DMSwarm
1715d0c080abSJoseph Pusztay .  cellID - the integer id of the cell to be copied back into the parent swarm
1716d0c080abSJoseph Pusztay -  cellswarm - the cell swarm object
1717d0c080abSJoseph Pusztay 
1718d0c080abSJoseph Pusztay    Level: beginner
1719d0c080abSJoseph Pusztay 
17205627991aSBarry Smith    Note:
17215627991aSBarry Smith     This only supports DMSWARM_PIC types of DMSwarms
1722d0c080abSJoseph Pusztay 
1723db781477SPatrick Sanan .seealso: `DMSwarmGetCellSwarm()`
1724d0c080abSJoseph Pusztay @*/
1725d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMSwarmRestoreCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
1726d71ae5a4SJacob Faibussowitsch {
1727d0c080abSJoseph Pusztay   DM        dmc;
1728d0c080abSJoseph Pusztay   PetscInt *pids, particles, p;
1729d0c080abSJoseph Pusztay 
1730d0c080abSJoseph Pusztay   PetscFunctionBegin;
17319566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
17329566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
17339566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
1734d0c080abSJoseph Pusztay   /* Pointwise copy of each particle based on pid. The parent swarm may not be altered during this process. */
173548a46eb9SPierre Jolivet   for (p = 0; p < particles; ++p) PetscCall(DMSwarmDataBucketCopyPoint(((DM_Swarm *)cellswarm->data)->db, pids[p], ((DM_Swarm *)sw->data)->db, pids[p]));
1736d0c080abSJoseph Pusztay   /* Free memory, destroy cell dm */
17379566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(cellswarm, &dmc));
17389566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
17399566063dSJacob Faibussowitsch   PetscCall(PetscFree(pids));
17403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1741d0c080abSJoseph Pusztay }
1742d0c080abSJoseph Pusztay 
1743d0c080abSJoseph Pusztay PETSC_INTERN PetscErrorCode DMClone_Swarm(DM, DM *);
1744d0c080abSJoseph Pusztay 
1745d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMInitialize_Swarm(DM sw)
1746d71ae5a4SJacob Faibussowitsch {
1747d0c080abSJoseph Pusztay   PetscFunctionBegin;
1748d0c080abSJoseph Pusztay   sw->dim                           = 0;
1749d0c080abSJoseph Pusztay   sw->ops->view                     = DMView_Swarm;
1750d0c080abSJoseph Pusztay   sw->ops->load                     = NULL;
1751d0c080abSJoseph Pusztay   sw->ops->setfromoptions           = NULL;
1752d0c080abSJoseph Pusztay   sw->ops->clone                    = DMClone_Swarm;
1753d0c080abSJoseph Pusztay   sw->ops->setup                    = DMSetup_Swarm;
1754d0c080abSJoseph Pusztay   sw->ops->createlocalsection       = NULL;
1755d0c080abSJoseph Pusztay   sw->ops->createdefaultconstraints = NULL;
1756d0c080abSJoseph Pusztay   sw->ops->createglobalvector       = DMCreateGlobalVector_Swarm;
1757d0c080abSJoseph Pusztay   sw->ops->createlocalvector        = DMCreateLocalVector_Swarm;
1758d0c080abSJoseph Pusztay   sw->ops->getlocaltoglobalmapping  = NULL;
1759d0c080abSJoseph Pusztay   sw->ops->createfieldis            = NULL;
1760d0c080abSJoseph Pusztay   sw->ops->createcoordinatedm       = NULL;
1761d0c080abSJoseph Pusztay   sw->ops->getcoloring              = NULL;
1762d0c080abSJoseph Pusztay   sw->ops->creatematrix             = DMCreateMatrix_Swarm;
1763d0c080abSJoseph Pusztay   sw->ops->createinterpolation      = NULL;
1764d0c080abSJoseph Pusztay   sw->ops->createinjection          = NULL;
1765d0c080abSJoseph Pusztay   sw->ops->createmassmatrix         = DMCreateMassMatrix_Swarm;
1766d0c080abSJoseph Pusztay   sw->ops->refine                   = NULL;
1767d0c080abSJoseph Pusztay   sw->ops->coarsen                  = NULL;
1768d0c080abSJoseph Pusztay   sw->ops->refinehierarchy          = NULL;
1769d0c080abSJoseph Pusztay   sw->ops->coarsenhierarchy         = NULL;
1770d0c080abSJoseph Pusztay   sw->ops->globaltolocalbegin       = NULL;
1771d0c080abSJoseph Pusztay   sw->ops->globaltolocalend         = NULL;
1772d0c080abSJoseph Pusztay   sw->ops->localtoglobalbegin       = NULL;
1773d0c080abSJoseph Pusztay   sw->ops->localtoglobalend         = NULL;
1774d0c080abSJoseph Pusztay   sw->ops->destroy                  = DMDestroy_Swarm;
1775d0c080abSJoseph Pusztay   sw->ops->createsubdm              = NULL;
1776d0c080abSJoseph Pusztay   sw->ops->getdimpoints             = NULL;
1777d0c080abSJoseph Pusztay   sw->ops->locatepoints             = NULL;
17783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1779d0c080abSJoseph Pusztay }
1780d0c080abSJoseph Pusztay 
1781d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMClone_Swarm(DM dm, DM *newdm)
1782d71ae5a4SJacob Faibussowitsch {
1783d0c080abSJoseph Pusztay   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1784d0c080abSJoseph Pusztay 
1785d0c080abSJoseph Pusztay   PetscFunctionBegin;
1786d0c080abSJoseph Pusztay   swarm->refct++;
1787d0c080abSJoseph Pusztay   (*newdm)->data = swarm;
17889566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMSWARM));
17899566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(*newdm));
17902e56dffeSJoe Pusztay   (*newdm)->dim = dm->dim;
17913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1792d0c080abSJoseph Pusztay }
1793d0c080abSJoseph Pusztay 
1794d3a51819SDave May /*MC
1795d3a51819SDave May 
1796d3a51819SDave May  DMSWARM = "swarm" - A DM object used to represent arrays of data (fields) of arbitrary data type.
179762741f57SDave May  This implementation was designed for particle methods in which the underlying
1798d3a51819SDave May  data required to be represented is both (i) dynamic in length, (ii) and of arbitrary data type.
1799d3a51819SDave May 
180062741f57SDave May  User data can be represented by DMSwarm through a registering "fields".
180162741f57SDave May  To register a field, the user must provide;
180262741f57SDave May  (a) a unique name;
180362741f57SDave May  (b) the data type (or size in bytes);
180462741f57SDave May  (c) the block size of the data.
1805d3a51819SDave May 
1806d3a51819SDave May  For example, suppose the application requires a unique id, energy, momentum and density to be stored
1807c215a47eSMatthew Knepley  on a set of particles. Then the following code could be used
1808d3a51819SDave May 
180962741f57SDave May $    DMSwarmInitializeFieldRegister(dm)
181062741f57SDave May $    DMSwarmRegisterPetscDatatypeField(dm,"uid",1,PETSC_LONG);
181162741f57SDave May $    DMSwarmRegisterPetscDatatypeField(dm,"energy",1,PETSC_REAL);
181262741f57SDave May $    DMSwarmRegisterPetscDatatypeField(dm,"momentum",3,PETSC_REAL);
181362741f57SDave May $    DMSwarmRegisterPetscDatatypeField(dm,"density",1,PETSC_FLOAT);
181462741f57SDave May $    DMSwarmFinalizeFieldRegister(dm)
1815d3a51819SDave May 
1816d3a51819SDave May  The fields represented by DMSwarm are dynamic and can be re-sized at any time.
181762741f57SDave May  The only restriction imposed by DMSwarm is that all fields contain the same number of points.
1818d3a51819SDave May 
1819d3a51819SDave May  To support particle methods, "migration" techniques are provided. These methods migrate data
18205627991aSBarry Smith  between ranks.
1821d3a51819SDave May 
1822d3a51819SDave May  DMSwarm supports the methods DMCreateGlobalVector() and DMCreateLocalVector().
1823d3a51819SDave May  As a DMSwarm may internally define and store values of different data types,
182462741f57SDave May  before calling DMCreateGlobalVector() or DMCreateLocalVector(), the user must inform DMSwarm which
1825d3a51819SDave May  fields should be used to define a Vec object via
1826d3a51819SDave May    DMSwarmVectorDefineField()
1827c215a47eSMatthew Knepley  The specified field can be changed at any time - thereby permitting vectors
1828c215a47eSMatthew Knepley  compatible with different fields to be created.
1829d3a51819SDave May 
183062741f57SDave May  A dual representation of fields in the DMSwarm and a Vec object is permitted via
1831d3a51819SDave May    DMSwarmCreateGlobalVectorFromField()
1832d3a51819SDave May  Here the data defining the field in the DMSwarm is shared with a Vec.
1833d3a51819SDave May  This is inherently unsafe if you alter the size of the field at any time between
1834d3a51819SDave May  calls to DMSwarmCreateGlobalVectorFromField() and DMSwarmDestroyGlobalVectorFromField().
1835cc651181SDave May  If the local size of the DMSwarm does not match the local size of the global vector
1836cc651181SDave May  when DMSwarmDestroyGlobalVectorFromField() is called, an error is thrown.
1837d3a51819SDave May 
183862741f57SDave May  Additional high-level support is provided for Particle-In-Cell methods.
183962741f57SDave May  Please refer to the man page for DMSwarmSetType().
184062741f57SDave May 
1841d3a51819SDave May  Level: beginner
1842d3a51819SDave May 
1843db781477SPatrick Sanan .seealso: `DMType`, `DMCreate()`, `DMSetType()`
1844d3a51819SDave May M*/
1845d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMCreate_Swarm(DM dm)
1846d71ae5a4SJacob Faibussowitsch {
184757795646SDave May   DM_Swarm *swarm;
184857795646SDave May 
184957795646SDave May   PetscFunctionBegin;
185057795646SDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
18514dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&swarm));
1852f0cdbbbaSDave May   dm->data = swarm;
18539566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreate(&swarm->db));
18549566063dSJacob Faibussowitsch   PetscCall(DMSwarmInitializeFieldRegister(dm));
1855d0c080abSJoseph Pusztay   swarm->refct                          = 1;
1856b5bcf523SDave May   swarm->vec_field_set                  = PETSC_FALSE;
18573454631fSDave May   swarm->issetup                        = PETSC_FALSE;
1858480eef7bSDave May   swarm->swarm_type                     = DMSWARM_BASIC;
1859480eef7bSDave May   swarm->migrate_type                   = DMSWARM_MIGRATE_BASIC;
1860480eef7bSDave May   swarm->collect_type                   = DMSWARM_COLLECT_BASIC;
186140c453e9SDave May   swarm->migrate_error_on_missing_point = PETSC_FALSE;
1862f0cdbbbaSDave May   swarm->dmcell                         = NULL;
1863f0cdbbbaSDave May   swarm->collect_view_active            = PETSC_FALSE;
1864f0cdbbbaSDave May   swarm->collect_view_reset_nlocal      = -1;
18659566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(dm));
18662e956fe4SStefano Zampini   if (SwarmDataFieldId == -1) PetscCall(PetscObjectComposedDataRegister(&SwarmDataFieldId));
18673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
186857795646SDave May }
1869