xref: /petsc/src/dm/impls/swarm/swarm.c (revision 0764c050596daa831a94d744a95074c51cdb668c)
157795646SDave May #define PETSCDM_DLL
257795646SDave May #include <petsc/private/dmswarmimpl.h> /*I   "petscdmswarm.h"   I*/
3e8f14785SLisandro Dalcin #include <petsc/private/hashsetij.h>
40643ed39SMatthew G. Knepley #include <petsc/private/petscfeimpl.h>
55917a6f0SStefano Zampini #include <petscviewer.h>
65917a6f0SStefano Zampini #include <petscdraw.h>
783c47955SMatthew G. Knepley #include <petscdmplex.h>
84cc7f7b2SMatthew G. Knepley #include <petscblaslapack.h>
9279f676cSBarry Smith #include "../src/dm/impls/swarm/data_bucket.h"
10d0c080abSJoseph Pusztay #include <petscdmlabel.h>
11d0c080abSJoseph Pusztay #include <petscsection.h>
1257795646SDave May 
13f2b2bee7SDave May PetscLogEvent DMSWARM_Migrate, DMSWARM_SetSizes, DMSWARM_AddPoints, DMSWARM_RemovePoints, DMSWARM_Sort;
14ed923d71SDave May PetscLogEvent DMSWARM_DataExchangerTopologySetup, DMSWARM_DataExchangerBegin, DMSWARM_DataExchangerEnd;
15ed923d71SDave May PetscLogEvent DMSWARM_DataExchangerSendCount, DMSWARM_DataExchangerPack;
16ed923d71SDave May 
17ea78f98cSLisandro Dalcin const char *DMSwarmTypeNames[]          = {"basic", "pic", NULL};
18ea78f98cSLisandro Dalcin const char *DMSwarmMigrateTypeNames[]   = {"basic", "dmcellnscatter", "dmcellexact", "user", NULL};
19ea78f98cSLisandro Dalcin const char *DMSwarmCollectTypeNames[]   = {"basic", "boundingbox", "general", "user", NULL};
20ea78f98cSLisandro Dalcin const char *DMSwarmPICLayoutTypeNames[] = {"regular", "gauss", "subdivision", NULL};
21f0cdbbbaSDave May 
22f0cdbbbaSDave May const char DMSwarmField_pid[]       = "DMSwarm_pid";
23f0cdbbbaSDave May const char DMSwarmField_rank[]      = "DMSwarm_rank";
24f0cdbbbaSDave May const char DMSwarmPICField_coor[]   = "DMSwarmPIC_coor";
25e2d107dbSDave May const char DMSwarmPICField_cellid[] = "DMSwarm_cellid";
26f0cdbbbaSDave May 
272e956fe4SStefano Zampini PetscInt SwarmDataFieldId = -1;
282e956fe4SStefano Zampini 
2974d0cae8SMatthew G. Knepley #if defined(PETSC_HAVE_HDF5)
3074d0cae8SMatthew G. Knepley   #include <petscviewerhdf5.h>
3174d0cae8SMatthew G. Knepley 
3266976f2fSJacob Faibussowitsch static PetscErrorCode VecView_Swarm_HDF5_Internal(Vec v, PetscViewer viewer)
33d71ae5a4SJacob Faibussowitsch {
3474d0cae8SMatthew G. Knepley   DM        dm;
3574d0cae8SMatthew G. Knepley   PetscReal seqval;
3674d0cae8SMatthew G. Knepley   PetscInt  seqnum, bs;
37eb0c6899SMatthew G. Knepley   PetscBool isseq, ists;
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));
45eb0c6899SMatthew G. Knepley   PetscCall(PetscViewerHDF5IsTimestepping(viewer, &ists));
46eb0c6899SMatthew G. Knepley   if (ists) PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum));
479566063dSJacob Faibussowitsch   /* PetscCall(DMSequenceView_HDF5(dm, "time", seqnum, (PetscScalar) seqval, viewer)); */
489566063dSJacob Faibussowitsch   PetscCall(VecViewNative(v, viewer));
499566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)v, "Nc", PETSC_INT, (void *)&bs));
509566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PopGroup(viewer));
513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5274d0cae8SMatthew G. Knepley }
5374d0cae8SMatthew G. Knepley 
5466976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmView_HDF5(DM dm, PetscViewer viewer)
55d71ae5a4SJacob Faibussowitsch {
5674d0cae8SMatthew G. Knepley   Vec       coordinates;
5774d0cae8SMatthew G. Knepley   PetscInt  Np;
5874d0cae8SMatthew G. Knepley   PetscBool isseq;
5974d0cae8SMatthew G. Knepley 
6074d0cae8SMatthew G. Knepley   PetscFunctionBegin;
619566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetSize(dm, &Np));
629566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateGlobalVectorFromField(dm, DMSwarmPICField_coor, &coordinates));
639566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
649566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PushGroup(viewer, "/particles"));
659566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)coordinates, VECSEQ, &isseq));
669566063dSJacob Faibussowitsch   PetscCall(VecViewNative(coordinates, viewer));
679566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)coordinates, "Np", PETSC_INT, (void *)&Np));
689566063dSJacob Faibussowitsch   PetscCall(PetscViewerHDF5PopGroup(viewer));
699566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyGlobalVectorFromField(dm, DMSwarmPICField_coor, &coordinates));
703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7174d0cae8SMatthew G. Knepley }
7274d0cae8SMatthew G. Knepley #endif
7374d0cae8SMatthew G. Knepley 
7466976f2fSJacob Faibussowitsch static PetscErrorCode VecView_Swarm(Vec v, PetscViewer viewer)
75d71ae5a4SJacob Faibussowitsch {
7674d0cae8SMatthew G. Knepley   DM dm;
77f9558f5cSBarry Smith #if defined(PETSC_HAVE_HDF5)
7874d0cae8SMatthew G. Knepley   PetscBool ishdf5;
79f9558f5cSBarry Smith #endif
8074d0cae8SMatthew G. Knepley 
8174d0cae8SMatthew G. Knepley   PetscFunctionBegin;
829566063dSJacob Faibussowitsch   PetscCall(VecGetDM(v, &dm));
8328b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
84f9558f5cSBarry Smith #if defined(PETSC_HAVE_HDF5)
859566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
8674d0cae8SMatthew G. Knepley   if (ishdf5) {
879566063dSJacob Faibussowitsch     PetscCall(VecView_Swarm_HDF5_Internal(v, viewer));
883ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
8974d0cae8SMatthew G. Knepley   }
90f9558f5cSBarry Smith #endif
919566063dSJacob Faibussowitsch   PetscCall(VecViewNative(v, viewer));
923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9374d0cae8SMatthew G. Knepley }
9474d0cae8SMatthew G. Knepley 
95cc4c1da9SBarry Smith /*@
960bf7c1c5SMatthew G. Knepley   DMSwarmVectorGetField - Gets the field from which to define a `Vec` object
970bf7c1c5SMatthew G. Knepley   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
980bf7c1c5SMatthew G. Knepley 
990bf7c1c5SMatthew G. Knepley   Not collective
1000bf7c1c5SMatthew G. Knepley 
1010bf7c1c5SMatthew G. Knepley   Input Parameter:
1020bf7c1c5SMatthew G. Knepley . dm - a `DMSWARM`
1030bf7c1c5SMatthew G. Knepley 
1040bf7c1c5SMatthew G. Knepley   Output Parameter:
1050bf7c1c5SMatthew G. Knepley . fieldname - the textual name given to a registered field, or the empty string if it has not been set
1060bf7c1c5SMatthew G. Knepley 
1070bf7c1c5SMatthew G. Knepley   Level: beginner
1080bf7c1c5SMatthew G. Knepley 
1090bf7c1c5SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmVectorDefineField()` `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
1100bf7c1c5SMatthew G. Knepley @*/
1110bf7c1c5SMatthew G. Knepley PetscErrorCode DMSwarmVectorGetField(DM dm, const char *fieldname[])
1120bf7c1c5SMatthew G. Knepley {
1130bf7c1c5SMatthew G. Knepley   PetscFunctionBegin;
1140bf7c1c5SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
1150bf7c1c5SMatthew G. Knepley   PetscAssertPointer(fieldname, 2);
1160bf7c1c5SMatthew G. Knepley   *fieldname = ((DM_Swarm *)dm->data)->vec_field_name;
1170bf7c1c5SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1180bf7c1c5SMatthew G. Knepley }
1190bf7c1c5SMatthew G. Knepley 
120cc4c1da9SBarry Smith /*@
12120f4b53cSBarry Smith   DMSwarmVectorDefineField - Sets the field from which to define a `Vec` object
12220f4b53cSBarry Smith   when `DMCreateLocalVector()`, or `DMCreateGlobalVector()` is called
12357795646SDave May 
12420f4b53cSBarry Smith   Collective
12557795646SDave May 
12660225df5SJacob Faibussowitsch   Input Parameters:
12720f4b53cSBarry Smith + dm        - a `DMSWARM`
12862741f57SDave May - fieldname - the textual name given to a registered field
12957795646SDave May 
130d3a51819SDave May   Level: beginner
13157795646SDave May 
132d3a51819SDave May   Notes:
13320f4b53cSBarry Smith   The field with name `fieldname` must be defined as having a data type of `PetscScalar`.
134e7af74c8SDave May 
13520f4b53cSBarry Smith   This function must be called prior to calling `DMCreateLocalVector()`, `DMCreateGlobalVector()`.
13620f4b53cSBarry Smith   Multiple calls to `DMSwarmVectorDefineField()` are permitted.
137e7af74c8SDave May 
1380bf7c1c5SMatthew G. Knepley .seealso: `DM`, `DMSWARM`, `DMSwarmVectorGetField()`, `DMSwarmRegisterPetscDatatypeField()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
139d3a51819SDave May @*/
140d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmVectorDefineField(DM dm, const char fieldname[])
141d71ae5a4SJacob Faibussowitsch {
142b5bcf523SDave May   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
143b5bcf523SDave May   PetscInt      bs, n;
144b5bcf523SDave May   PetscScalar  *array;
145b5bcf523SDave May   PetscDataType type;
146b5bcf523SDave May 
147a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
1480bf7c1c5SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
1490bf7c1c5SMatthew G. Knepley   if (fieldname) PetscAssertPointer(fieldname, 2);
1509566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
1519566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
1529566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array));
153b5bcf523SDave May 
154b5bcf523SDave May   /* Check all fields are of type PETSC_REAL or PETSC_SCALAR */
15508401ef6SPierre Jolivet   PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
1569566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(swarm->vec_field_name, PETSC_MAX_PATH_LEN - 1, "%s", fieldname));
157b5bcf523SDave May   swarm->vec_field_set    = PETSC_TRUE;
1581b1ea282SDave May   swarm->vec_field_bs     = bs;
159b5bcf523SDave May   swarm->vec_field_nlocal = n;
1609566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, fieldname, &bs, &type, (void **)&array));
1613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
162b5bcf523SDave May }
163b5bcf523SDave May 
164cc651181SDave May /* requires DMSwarmDefineFieldVector has been called */
16566976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateGlobalVector_Swarm(DM dm, Vec *vec)
166d71ae5a4SJacob Faibussowitsch {
167b5bcf523SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
168b5bcf523SDave May   Vec       x;
169b5bcf523SDave May   char      name[PETSC_MAX_PATH_LEN];
170b5bcf523SDave May 
171a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
1729566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
17328b400f6SJacob Faibussowitsch   PetscCheck(swarm->vec_field_set, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmVectorDefineField first");
17408401ef6SPierre 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 */
175cc651181SDave May 
1769566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmField_%s", swarm->vec_field_name));
1779566063dSJacob Faibussowitsch   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &x));
1789566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)x, name));
1799566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(x, swarm->db->L * swarm->vec_field_bs, PETSC_DETERMINE));
1809566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(x, swarm->vec_field_bs));
1819566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
1829566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(x));
1839566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
1849566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(x, VECOP_VIEW, (void (*)(void))VecView_Swarm));
185b5bcf523SDave May   *vec = x;
1863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
187b5bcf523SDave May }
188b5bcf523SDave May 
189b5bcf523SDave May /* requires DMSwarmDefineFieldVector has been called */
19066976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateLocalVector_Swarm(DM dm, Vec *vec)
191d71ae5a4SJacob Faibussowitsch {
192b5bcf523SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
193b5bcf523SDave May   Vec       x;
194b5bcf523SDave May   char      name[PETSC_MAX_PATH_LEN];
195b5bcf523SDave May 
196a9cbaee5SMatthew G. Knepley   PetscFunctionBegin;
1979566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
19828b400f6SJacob Faibussowitsch   PetscCheck(swarm->vec_field_set, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmVectorDefineField first");
19908401ef6SPierre 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");
200cc651181SDave May 
2019566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmField_%s", swarm->vec_field_name));
2029566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &x));
2039566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)x, name));
2049566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(x, swarm->db->L * swarm->vec_field_bs, PETSC_DETERMINE));
2059566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(x, swarm->vec_field_bs));
2069566063dSJacob Faibussowitsch   PetscCall(VecSetDM(x, dm));
2079566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(x));
208b5bcf523SDave May   *vec = x;
2093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
210b5bcf523SDave May }
211b5bcf523SDave May 
212d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmDestroyVectorFromField_Private(DM dm, const char fieldname[], Vec *vec)
213d71ae5a4SJacob Faibussowitsch {
214fb1bcc12SMatthew G. Knepley   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
21577048351SPatrick Sanan   DMSwarmDataField gfield;
2162e956fe4SStefano Zampini   PetscInt         bs, nlocal, fid = -1, cfid = -2;
2172e956fe4SStefano Zampini   PetscBool        flg;
218d3a51819SDave May 
219fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
2202e956fe4SStefano Zampini   /* check vector is an inplace array */
2212e956fe4SStefano Zampini   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
2222e956fe4SStefano Zampini   PetscCall(PetscObjectComposedDataGetInt((PetscObject)*vec, SwarmDataFieldId, cfid, flg));
223e978a55eSPierre Jolivet   PetscCheck(cfid == fid, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Vector being destroyed was not created from DMSwarm field(%s)! %" PetscInt_FMT " != %" PetscInt_FMT, fieldname, cfid, fid);
2249566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(*vec, &nlocal));
2259566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(*vec, &bs));
22608401ef6SPierre 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");
2279566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
2289566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
2298df78e51SMark Adams   PetscCall(VecResetArray(*vec));
2309566063dSJacob Faibussowitsch   PetscCall(VecDestroy(vec));
2313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
232fb1bcc12SMatthew G. Knepley }
233fb1bcc12SMatthew G. Knepley 
234d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmCreateVectorFromField_Private(DM dm, const char fieldname[], MPI_Comm comm, Vec *vec)
235d71ae5a4SJacob Faibussowitsch {
236fb1bcc12SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)dm->data;
237fb1bcc12SMatthew G. Knepley   PetscDataType type;
238fb1bcc12SMatthew G. Knepley   PetscScalar  *array;
2392e956fe4SStefano Zampini   PetscInt      bs, n, fid;
240fb1bcc12SMatthew G. Knepley   char          name[PETSC_MAX_PATH_LEN];
241e4fbd051SBarry Smith   PetscMPIInt   size;
2428df78e51SMark Adams   PetscBool     iscuda, iskokkos;
243fb1bcc12SMatthew G. Knepley 
244fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
2459566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
2469566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &n, NULL, NULL));
2479566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, fieldname, &bs, &type, (void **)&array));
24808401ef6SPierre Jolivet   PetscCheck(type == PETSC_REAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only valid for PETSC_REAL");
249fb1bcc12SMatthew G. Knepley 
2509566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
2518df78e51SMark Adams   PetscCall(PetscStrcmp(dm->vectype, VECKOKKOS, &iskokkos));
2528df78e51SMark Adams   PetscCall(PetscStrcmp(dm->vectype, VECCUDA, &iscuda));
2538df78e51SMark Adams   PetscCall(VecCreate(comm, vec));
2548df78e51SMark Adams   PetscCall(VecSetSizes(*vec, n * bs, PETSC_DETERMINE));
2558df78e51SMark Adams   PetscCall(VecSetBlockSize(*vec, bs));
2568df78e51SMark Adams   if (iskokkos) PetscCall(VecSetType(*vec, VECKOKKOS));
2578df78e51SMark Adams   else if (iscuda) PetscCall(VecSetType(*vec, VECCUDA));
2588df78e51SMark Adams   else PetscCall(VecSetType(*vec, VECSTANDARD));
2598df78e51SMark Adams   PetscCall(VecPlaceArray(*vec, array));
2608df78e51SMark Adams 
2619566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "DMSwarmSharedField_%s", fieldname));
2629566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*vec, name));
263fb1bcc12SMatthew G. Knepley 
264fb1bcc12SMatthew G. Knepley   /* Set guard */
2652e956fe4SStefano Zampini   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldIdByName(swarm->db, fieldname, &fid));
2662e956fe4SStefano Zampini   PetscCall(PetscObjectComposedDataSetInt((PetscObject)*vec, SwarmDataFieldId, fid));
26774d0cae8SMatthew G. Knepley 
2689566063dSJacob Faibussowitsch   PetscCall(VecSetDM(*vec, dm));
2699566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Swarm));
2703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
271fb1bcc12SMatthew G. Knepley }
272fb1bcc12SMatthew G. Knepley 
2730643ed39SMatthew G. Knepley /* This creates a "mass matrix" between a finite element and particle space. If a finite element interpolant is given by
2740643ed39SMatthew G. Knepley 
2750643ed39SMatthew G. Knepley      \hat f = \sum_i f_i \phi_i
2760643ed39SMatthew G. Knepley 
2770643ed39SMatthew G. Knepley    and a particle function is given by
2780643ed39SMatthew G. Knepley 
2790643ed39SMatthew G. Knepley      f = \sum_i w_i \delta(x - x_i)
2800643ed39SMatthew G. Knepley 
2810643ed39SMatthew G. Knepley    then we want to require that
2820643ed39SMatthew G. Knepley 
2830643ed39SMatthew G. Knepley      M \hat f = M_p f
2840643ed39SMatthew G. Knepley 
2850643ed39SMatthew G. Knepley    where the particle mass matrix is given by
2860643ed39SMatthew G. Knepley 
2870643ed39SMatthew G. Knepley      (M_p)_{ij} = \int \phi_i \delta(x - x_j)
2880643ed39SMatthew G. Knepley 
2890643ed39SMatthew G. Knepley    The way Dave May does particles, they amount to quadratue weights rather than delta functions, so he has |J| is in
2900643ed39SMatthew G. Knepley    his integral. We allow this with the boolean flag.
2910643ed39SMatthew G. Knepley */
292d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmComputeMassMatrix_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
293d71ae5a4SJacob Faibussowitsch {
29483c47955SMatthew G. Knepley   const char  *name = "Mass Matrix";
2950643ed39SMatthew G. Knepley   MPI_Comm     comm;
29683c47955SMatthew G. Knepley   PetscDS      prob;
29783c47955SMatthew G. Knepley   PetscSection fsection, globalFSection;
298e8f14785SLisandro Dalcin   PetscHSetIJ  ht;
2990643ed39SMatthew G. Knepley   PetscLayout  rLayout, colLayout;
30083c47955SMatthew G. Knepley   PetscInt    *dnz, *onz;
301adb2528bSMark Adams   PetscInt     locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
3020643ed39SMatthew G. Knepley   PetscReal   *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
30383c47955SMatthew G. Knepley   PetscScalar *elemMat;
3040bf7c1c5SMatthew G. Knepley   PetscInt     dim, Nf, field, cStart, cEnd, cell, totDim, maxC = 0, totNc = 0;
30583c47955SMatthew G. Knepley 
30683c47955SMatthew G. Knepley   PetscFunctionBegin;
3079566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
3089566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmf, &dim));
3099566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmf, &prob));
3109566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
3119566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
3129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
3139566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
3149566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
3159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
3169566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
31783c47955SMatthew G. Knepley 
3189566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &colLayout));
3199566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
3209566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
3219566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colLayout));
3229566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
3239566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&colLayout));
3240643ed39SMatthew G. Knepley 
3259566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &rLayout));
3269566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
3279566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
3289566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
3299566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
3309566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
3310643ed39SMatthew G. Knepley 
3329566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
3339566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
33453e60ab4SJoseph Pusztay 
3359566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(comm, NULL));
3360bf7c1c5SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
3370bf7c1c5SMatthew G. Knepley     PetscObject  obj;
3380bf7c1c5SMatthew G. Knepley     PetscClassId id;
3390bf7c1c5SMatthew G. Knepley     PetscInt     Nc;
3400bf7c1c5SMatthew G. Knepley 
3410bf7c1c5SMatthew G. Knepley     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
3420bf7c1c5SMatthew G. Knepley     PetscCall(PetscObjectGetClassId(obj, &id));
3430bf7c1c5SMatthew G. Knepley     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
3440bf7c1c5SMatthew G. Knepley     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
3450bf7c1c5SMatthew G. Knepley     totNc += Nc;
3460bf7c1c5SMatthew G. Knepley   }
3470643ed39SMatthew G. Knepley   /* count non-zeros */
3489566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(dmc));
34983c47955SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
3500bf7c1c5SMatthew G. Knepley     PetscObject  obj;
3510bf7c1c5SMatthew G. Knepley     PetscClassId id;
3520bf7c1c5SMatthew G. Knepley     PetscInt     Nc;
3530bf7c1c5SMatthew G. Knepley 
3540bf7c1c5SMatthew G. Knepley     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
3550bf7c1c5SMatthew G. Knepley     PetscCall(PetscObjectGetClassId(obj, &id));
3560bf7c1c5SMatthew G. Knepley     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
3570bf7c1c5SMatthew G. Knepley     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
3580bf7c1c5SMatthew G. Knepley 
35983c47955SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
3600643ed39SMatthew G. Knepley       PetscInt *findices, *cindices; /* fine is vertices, coarse is particles */
36183c47955SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
36283c47955SMatthew G. Knepley 
3639566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3649566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
365fc7c92abSMatthew G. Knepley       maxC = PetscMax(maxC, numCIndices);
36683c47955SMatthew G. Knepley       {
367e8f14785SLisandro Dalcin         PetscHashIJKey key;
368e8f14785SLisandro Dalcin         PetscBool      missing;
3690bf7c1c5SMatthew G. Knepley         for (PetscInt i = 0; i < numFIndices; ++i) {
370adb2528bSMark Adams           key.j = findices[i]; /* global column (from Plex) */
371adb2528bSMark Adams           if (key.j >= 0) {
37283c47955SMatthew G. Knepley             /* Get indices for coarse elements */
3730bf7c1c5SMatthew G. Knepley             for (PetscInt j = 0; j < numCIndices; ++j) {
3740bf7c1c5SMatthew G. Knepley               for (PetscInt c = 0; c < Nc; ++c) {
3750bf7c1c5SMatthew G. Knepley                 // TODO Need field offset on particle here
3760bf7c1c5SMatthew G. Knepley                 key.i = cindices[j] * totNc + c + rStart; /* global cols (from Swarm) */
377adb2528bSMark Adams                 if (key.i < 0) continue;
3789566063dSJacob Faibussowitsch                 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
37983c47955SMatthew G. Knepley                 if (missing) {
3800643ed39SMatthew G. Knepley                   if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
381e8f14785SLisandro Dalcin                   else ++onz[key.i - rStart];
38263a3b9bcSJacob Faibussowitsch                 } else SETERRQ(PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Set new value at %" PetscInt_FMT ",%" PetscInt_FMT, key.i, key.j);
38383c47955SMatthew G. Knepley               }
384fc7c92abSMatthew G. Knepley             }
385fc7c92abSMatthew G. Knepley           }
3860bf7c1c5SMatthew G. Knepley         }
3879566063dSJacob Faibussowitsch         PetscCall(PetscFree(cindices));
38883c47955SMatthew G. Knepley       }
3899566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
39083c47955SMatthew G. Knepley     }
39183c47955SMatthew G. Knepley   }
3929566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
3939566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
3949566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
3959566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
3960bf7c1c5SMatthew G. Knepley   PetscCall(PetscMalloc3(maxC * totNc * totDim, &elemMat, maxC * totNc, &rowIDXs, maxC * dim, &xi));
39783c47955SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
398ef0bb6c7SMatthew G. Knepley     PetscTabulation Tcoarse;
39983c47955SMatthew G. Knepley     PetscObject     obj;
400ad9634fcSMatthew G. Knepley     PetscClassId    id;
401ea7032a0SMatthew G. Knepley     PetscReal      *fieldVals;
4020bf7c1c5SMatthew G. Knepley     PetscInt        Nc;
40383c47955SMatthew G. Knepley 
4049566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
405ad9634fcSMatthew G. Knepley     PetscCall(PetscObjectGetClassId(obj, &id));
406ad9634fcSMatthew G. Knepley     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
407ad9634fcSMatthew G. Knepley     else PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
408ea7032a0SMatthew G. Knepley 
409ea7032a0SMatthew G. Knepley     PetscCall(DMSwarmGetField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&fieldVals));
41083c47955SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
41183c47955SMatthew G. Knepley       PetscInt *findices, *cindices;
41283c47955SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
41383c47955SMatthew G. Knepley 
4140643ed39SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
4159566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
4169566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
4179566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
4180bf7c1c5SMatthew G. Knepley       for (PetscInt j = 0; j < numCIndices; ++j) CoordinatesRealToRef(dim, dim, v0ref, v0, invJ, &fieldVals[cindices[j] * dim], &xi[j * dim]);
419ad9634fcSMatthew G. Knepley       if (id == PETSCFE_CLASSID) PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
420ad9634fcSMatthew G. Knepley       else PetscCall(PetscFVCreateTabulation((PetscFV)obj, 1, numCIndices, xi, 0, &Tcoarse));
42183c47955SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
4220bf7c1c5SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMat, numCIndices * Nc * totDim));
4230bf7c1c5SMatthew G. Knepley       for (PetscInt i = 0; i < numFIndices / Nc; ++i) {
4240bf7c1c5SMatthew G. Knepley         for (PetscInt j = 0; j < numCIndices; ++j) {
4250bf7c1c5SMatthew G. Knepley           for (PetscInt c = 0; c < Nc; ++c) {
4260bf7c1c5SMatthew G. Knepley             // TODO Need field offset on particle and field here
4270643ed39SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
4280bf7c1c5SMatthew G. Knepley             elemMat[(j * totNc + c) * numFIndices + i * Nc + c] += Tcoarse->T[0][(j * numFIndices + i * Nc + c) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
42983c47955SMatthew G. Knepley           }
4300643ed39SMatthew G. Knepley         }
4310643ed39SMatthew G. Knepley       }
4320bf7c1c5SMatthew G. Knepley       for (PetscInt j = 0; j < numCIndices; ++j)
4330bf7c1c5SMatthew G. Knepley         // TODO Need field offset on particle here
4340bf7c1c5SMatthew G. Knepley         for (PetscInt c = 0; c < Nc; ++c) rowIDXs[j * Nc + c] = cindices[j] * totNc + c + rStart;
4350bf7c1c5SMatthew G. Knepley       if (0) PetscCall(DMPrintCellMatrix(cell, name, numCIndices * Nc, numFIndices, elemMat));
4360bf7c1c5SMatthew G. Knepley       PetscCall(MatSetValues(mass, numCIndices * Nc, rowIDXs, numFIndices, findices, elemMat, ADD_VALUES));
4379566063dSJacob Faibussowitsch       PetscCall(PetscFree(cindices));
4389566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
4399566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
44083c47955SMatthew G. Knepley     }
441ea7032a0SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&fieldVals));
44283c47955SMatthew G. Knepley   }
4439566063dSJacob Faibussowitsch   PetscCall(PetscFree3(elemMat, rowIDXs, xi));
4449566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
4459566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
4469566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
4479566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
4483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44983c47955SMatthew G. Knepley }
45083c47955SMatthew G. Knepley 
451d0c080abSJoseph Pusztay /* Returns empty matrix for use with SNES FD */
452d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMatrix_Swarm(DM sw, Mat *m)
453d71ae5a4SJacob Faibussowitsch {
454d0c080abSJoseph Pusztay   Vec      field;
455d0c080abSJoseph Pusztay   PetscInt size;
456d0c080abSJoseph Pusztay 
457d0c080abSJoseph Pusztay   PetscFunctionBegin;
4589566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(sw, &field));
4599566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(field, &size));
4609566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(sw, &field));
4619566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD, m));
4629566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(*m));
4639566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*m, PETSC_DECIDE, PETSC_DECIDE, size, size));
4649566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*m, 1, NULL));
4659566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(*m));
4669566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*m, MAT_FINAL_ASSEMBLY));
4679566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*m, MAT_FINAL_ASSEMBLY));
4689566063dSJacob Faibussowitsch   PetscCall(MatShift(*m, 1.0));
4699566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*m, sw));
4703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
471d0c080abSJoseph Pusztay }
472d0c080abSJoseph Pusztay 
473adb2528bSMark Adams /* FEM cols, Particle rows */
474d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMassMatrix_Swarm(DM dmCoarse, DM dmFine, Mat *mass)
475d71ae5a4SJacob Faibussowitsch {
476895a1698SMatthew G. Knepley   PetscSection gsf;
4770bf7c1c5SMatthew G. Knepley   PetscInt     m, n, Np, bs = 1;
47883c47955SMatthew G. Knepley   void        *ctx;
4790bf7c1c5SMatthew G. Knepley   PetscBool    set  = ((DM_Swarm *)dmCoarse->data)->vec_field_set;
4800bf7c1c5SMatthew G. Knepley   char        *name = ((DM_Swarm *)dmCoarse->data)->vec_field_name;
48183c47955SMatthew G. Knepley 
48283c47955SMatthew G. Knepley   PetscFunctionBegin;
4839566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
4849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
4850bf7c1c5SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(dmCoarse, &Np));
4860bf7c1c5SMatthew G. Knepley   // TODO Include all fields
4870bf7c1c5SMatthew G. Knepley   if (set) PetscCall(DMSwarmGetFieldInfo(dmCoarse, name, &bs, NULL));
4880bf7c1c5SMatthew G. Knepley   n = Np * bs;
4899566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
4909566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, m, PETSC_DETERMINE, PETSC_DETERMINE));
4919566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
4929566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
49383c47955SMatthew G. Knepley 
4949566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrix_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
4959566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view"));
4963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49783c47955SMatthew G. Knepley }
49883c47955SMatthew G. Knepley 
499d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSwarmComputeMassMatrixSquare_Private(DM dmc, DM dmf, Mat mass, PetscBool useDeltaFunction, void *ctx)
500d71ae5a4SJacob Faibussowitsch {
5014cc7f7b2SMatthew G. Knepley   const char  *name = "Mass Matrix Square";
5024cc7f7b2SMatthew G. Knepley   MPI_Comm     comm;
5034cc7f7b2SMatthew G. Knepley   PetscDS      prob;
5044cc7f7b2SMatthew G. Knepley   PetscSection fsection, globalFSection;
5054cc7f7b2SMatthew G. Knepley   PetscHSetIJ  ht;
5064cc7f7b2SMatthew G. Knepley   PetscLayout  rLayout, colLayout;
5074cc7f7b2SMatthew G. Knepley   PetscInt    *dnz, *onz, *adj, depth, maxConeSize, maxSupportSize, maxAdjSize;
5084cc7f7b2SMatthew G. Knepley   PetscInt     locRows, locCols, rStart, colStart, colEnd, *rowIDXs;
5094cc7f7b2SMatthew G. Knepley   PetscReal   *xi, *v0, *J, *invJ, detJ = 1.0, v0ref[3] = {-1.0, -1.0, -1.0};
5104cc7f7b2SMatthew G. Knepley   PetscScalar *elemMat, *elemMatSq;
5114cc7f7b2SMatthew G. Knepley   PetscInt     cdim, Nf, field, cStart, cEnd, cell, totDim, maxC = 0;
5124cc7f7b2SMatthew G. Knepley 
5134cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
5149566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)mass, &comm));
5159566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmf, &cdim));
5169566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmf, &prob));
5179566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
5189566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
5199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(cdim, &v0, cdim * cdim, &J, cdim * cdim, &invJ));
5209566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
5219566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
5229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
5239566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, &locCols));
5244cc7f7b2SMatthew G. Knepley 
5259566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &colLayout));
5269566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(colLayout, locCols));
5279566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(colLayout, 1));
5289566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colLayout));
5299566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colLayout, &colStart, &colEnd));
5309566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&colLayout));
5314cc7f7b2SMatthew G. Knepley 
5329566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &rLayout));
5339566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
5349566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
5359566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
5369566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, NULL));
5379566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
5384cc7f7b2SMatthew G. Knepley 
5399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dmf, &depth));
5409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dmf, &maxConeSize, &maxSupportSize));
5414cc7f7b2SMatthew G. Knepley   maxAdjSize = PetscPowInt(maxConeSize * maxSupportSize, depth);
5429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxAdjSize, &adj));
5434cc7f7b2SMatthew G. Knepley 
5449566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
5459566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
5464cc7f7b2SMatthew G. Knepley   /* Count nonzeros
5474cc7f7b2SMatthew G. Knepley        This is just FVM++, but we cannot use the Plex P0 allocation since unknowns in a cell will not be contiguous
5484cc7f7b2SMatthew G. Knepley   */
5499566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(dmc));
5504cc7f7b2SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
5514cc7f7b2SMatthew G. Knepley     PetscInt  i;
5524cc7f7b2SMatthew G. Knepley     PetscInt *cindices;
5534cc7f7b2SMatthew G. Knepley     PetscInt  numCIndices;
5544cc7f7b2SMatthew G. Knepley #if 0
5554cc7f7b2SMatthew G. Knepley     PetscInt  adjSize = maxAdjSize, a, j;
5564cc7f7b2SMatthew G. Knepley #endif
5574cc7f7b2SMatthew G. Knepley 
5589566063dSJacob Faibussowitsch     PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
5594cc7f7b2SMatthew G. Knepley     maxC = PetscMax(maxC, numCIndices);
5604cc7f7b2SMatthew G. Knepley     /* Diagonal block */
561ad540459SPierre Jolivet     for (i = 0; i < numCIndices; ++i) dnz[cindices[i]] += numCIndices;
5624cc7f7b2SMatthew G. Knepley #if 0
5634cc7f7b2SMatthew G. Knepley     /* Off-diagonal blocks */
5649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(dmf, cell, &adjSize, &adj));
5654cc7f7b2SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
5664cc7f7b2SMatthew G. Knepley       if (adj[a] >= cStart && adj[a] < cEnd && adj[a] != cell) {
5674cc7f7b2SMatthew G. Knepley         const PetscInt ncell = adj[a];
5684cc7f7b2SMatthew G. Knepley         PetscInt      *ncindices;
5694cc7f7b2SMatthew G. Knepley         PetscInt       numNCIndices;
5704cc7f7b2SMatthew G. Knepley 
5719566063dSJacob Faibussowitsch         PetscCall(DMSwarmSortGetPointsPerCell(dmc, ncell, &numNCIndices, &ncindices));
5724cc7f7b2SMatthew G. Knepley         {
5734cc7f7b2SMatthew G. Knepley           PetscHashIJKey key;
5744cc7f7b2SMatthew G. Knepley           PetscBool      missing;
5754cc7f7b2SMatthew G. Knepley 
5764cc7f7b2SMatthew G. Knepley           for (i = 0; i < numCIndices; ++i) {
5774cc7f7b2SMatthew G. Knepley             key.i = cindices[i] + rStart; /* global rows (from Swarm) */
5784cc7f7b2SMatthew G. Knepley             if (key.i < 0) continue;
5794cc7f7b2SMatthew G. Knepley             for (j = 0; j < numNCIndices; ++j) {
5804cc7f7b2SMatthew G. Knepley               key.j = ncindices[j] + rStart; /* global column (from Swarm) */
5814cc7f7b2SMatthew G. Knepley               if (key.j < 0) continue;
5829566063dSJacob Faibussowitsch               PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
5834cc7f7b2SMatthew G. Knepley               if (missing) {
5844cc7f7b2SMatthew G. Knepley                 if ((key.j >= colStart) && (key.j < colEnd)) ++dnz[key.i - rStart];
5854cc7f7b2SMatthew G. Knepley                 else                                         ++onz[key.i - rStart];
5864cc7f7b2SMatthew G. Knepley               }
5874cc7f7b2SMatthew G. Knepley             }
5884cc7f7b2SMatthew G. Knepley           }
5894cc7f7b2SMatthew G. Knepley         }
5909566063dSJacob Faibussowitsch         PetscCall(PetscFree(ncindices));
5914cc7f7b2SMatthew G. Knepley       }
5924cc7f7b2SMatthew G. Knepley     }
5934cc7f7b2SMatthew G. Knepley #endif
5949566063dSJacob Faibussowitsch     PetscCall(PetscFree(cindices));
5954cc7f7b2SMatthew G. Knepley   }
5969566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
5979566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
5989566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
5999566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
6009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(maxC * totDim, &elemMat, maxC * maxC, &elemMatSq, maxC, &rowIDXs, maxC * cdim, &xi));
6014cc7f7b2SMatthew G. Knepley   /* Fill in values
6024cc7f7b2SMatthew G. Knepley        Each entry is a sum of terms \phi_i(x_p) \phi_i(x_q)
6034cc7f7b2SMatthew G. Knepley        Start just by producing block diagonal
6044cc7f7b2SMatthew G. Knepley        Could loop over adjacent cells
6054cc7f7b2SMatthew G. Knepley          Produce neighboring element matrix
6064cc7f7b2SMatthew G. Knepley          TODO Determine which columns and rows correspond to shared dual vector
6074cc7f7b2SMatthew G. Knepley          Do MatMatMult with rectangular matrices
6084cc7f7b2SMatthew G. Knepley          Insert block
6094cc7f7b2SMatthew G. Knepley   */
6104cc7f7b2SMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
6114cc7f7b2SMatthew G. Knepley     PetscTabulation Tcoarse;
6124cc7f7b2SMatthew G. Knepley     PetscObject     obj;
6134cc7f7b2SMatthew G. Knepley     PetscReal      *coords;
6144cc7f7b2SMatthew G. Knepley     PetscInt        Nc, i;
6154cc7f7b2SMatthew G. Knepley 
6169566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
6179566063dSJacob Faibussowitsch     PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
61863a3b9bcSJacob Faibussowitsch     PetscCheck(Nc == 1, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "Can only interpolate a scalar field from particles, Nc = %" PetscInt_FMT, Nc);
6199566063dSJacob Faibussowitsch     PetscCall(DMSwarmGetField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
6204cc7f7b2SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
6214cc7f7b2SMatthew G. Knepley       PetscInt *findices, *cindices;
6224cc7f7b2SMatthew G. Knepley       PetscInt  numFIndices, numCIndices;
6234cc7f7b2SMatthew G. Knepley       PetscInt  p, c;
6244cc7f7b2SMatthew G. Knepley 
6254cc7f7b2SMatthew G. Knepley       /* TODO: Use DMField instead of assuming affine */
6269566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
6279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
6289566063dSJacob Faibussowitsch       PetscCall(DMSwarmSortGetPointsPerCell(dmc, cell, &numCIndices, &cindices));
629ad540459SPierre Jolivet       for (p = 0; p < numCIndices; ++p) CoordinatesRealToRef(cdim, cdim, v0ref, v0, invJ, &coords[cindices[p] * cdim], &xi[p * cdim]);
6309566063dSJacob Faibussowitsch       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, numCIndices, xi, 0, &Tcoarse));
6314cc7f7b2SMatthew G. Knepley       /* Get elemMat entries by multiplying by weight */
6329566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemMat, numCIndices * totDim));
6334cc7f7b2SMatthew G. Knepley       for (i = 0; i < numFIndices; ++i) {
6344cc7f7b2SMatthew G. Knepley         for (p = 0; p < numCIndices; ++p) {
6354cc7f7b2SMatthew G. Knepley           for (c = 0; c < Nc; ++c) {
6364cc7f7b2SMatthew G. Knepley             /* B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c */
6374cc7f7b2SMatthew G. Knepley             elemMat[p * numFIndices + i] += Tcoarse->T[0][(p * numFIndices + i) * Nc + c] * (useDeltaFunction ? 1.0 : detJ);
6384cc7f7b2SMatthew G. Knepley           }
6394cc7f7b2SMatthew G. Knepley         }
6404cc7f7b2SMatthew G. Knepley       }
6419566063dSJacob Faibussowitsch       PetscCall(PetscTabulationDestroy(&Tcoarse));
6424cc7f7b2SMatthew G. Knepley       for (p = 0; p < numCIndices; ++p) rowIDXs[p] = cindices[p] + rStart;
6439566063dSJacob Faibussowitsch       if (0) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
6444cc7f7b2SMatthew G. Knepley       /* Block diagonal */
64578884ca7SMatthew G. Knepley       if (numCIndices) {
6464cc7f7b2SMatthew G. Knepley         PetscBLASInt blasn, blask;
6474cc7f7b2SMatthew G. Knepley         PetscScalar  one = 1.0, zero = 0.0;
6484cc7f7b2SMatthew G. Knepley 
6499566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numCIndices, &blasn));
6509566063dSJacob Faibussowitsch         PetscCall(PetscBLASIntCast(numFIndices, &blask));
651792fecdfSBarry Smith         PetscCallBLAS("BLASgemm", BLASgemm_("T", "N", &blasn, &blasn, &blask, &one, elemMat, &blask, elemMat, &blask, &zero, elemMatSq, &blasn));
6524cc7f7b2SMatthew G. Knepley       }
6539566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mass, numCIndices, rowIDXs, numCIndices, rowIDXs, elemMatSq, ADD_VALUES));
6544cf0e950SBarry Smith       /* TODO off-diagonal */
6559566063dSJacob Faibussowitsch       PetscCall(PetscFree(cindices));
6569566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
6574cc7f7b2SMatthew G. Knepley     }
6589566063dSJacob Faibussowitsch     PetscCall(DMSwarmRestoreField(dmc, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
6594cc7f7b2SMatthew G. Knepley   }
6609566063dSJacob Faibussowitsch   PetscCall(PetscFree4(elemMat, elemMatSq, rowIDXs, xi));
6619566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
6629566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(dmc));
6639566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
6649566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
6659566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
6663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6674cc7f7b2SMatthew G. Knepley }
6684cc7f7b2SMatthew G. Knepley 
669cc4c1da9SBarry Smith /*@
6704cc7f7b2SMatthew G. Knepley   DMSwarmCreateMassMatrixSquare - Creates the block-diagonal of the square, M^T_p M_p, of the particle mass matrix M_p
6714cc7f7b2SMatthew G. Knepley 
67220f4b53cSBarry Smith   Collective
6734cc7f7b2SMatthew G. Knepley 
67460225df5SJacob Faibussowitsch   Input Parameters:
67520f4b53cSBarry Smith + dmCoarse - a `DMSWARM`
67620f4b53cSBarry Smith - dmFine   - a `DMPLEX`
6774cc7f7b2SMatthew G. Knepley 
67860225df5SJacob Faibussowitsch   Output Parameter:
6794cc7f7b2SMatthew G. Knepley . mass - the square of the particle mass matrix
6804cc7f7b2SMatthew G. Knepley 
6814cc7f7b2SMatthew G. Knepley   Level: advanced
6824cc7f7b2SMatthew G. Knepley 
68320f4b53cSBarry Smith   Note:
6844cc7f7b2SMatthew G. Knepley   We only compute the block diagonal since this provides a good preconditioner and is completely local. It would be possible in the
6854cc7f7b2SMatthew G. Knepley   future to compute the full normal equations.
6864cc7f7b2SMatthew G. Knepley 
68720f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMCreateMassMatrix()`
6884cc7f7b2SMatthew G. Knepley @*/
689d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateMassMatrixSquare(DM dmCoarse, DM dmFine, Mat *mass)
690d71ae5a4SJacob Faibussowitsch {
6914cc7f7b2SMatthew G. Knepley   PetscInt n;
6924cc7f7b2SMatthew G. Knepley   void    *ctx;
6934cc7f7b2SMatthew G. Knepley 
6944cc7f7b2SMatthew G. Knepley   PetscFunctionBegin;
6959566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dmCoarse, &n));
6969566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass));
6979566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mass, n, n, PETSC_DETERMINE, PETSC_DETERMINE));
6989566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mass, dmCoarse->mattype));
6999566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmFine, &ctx));
7004cc7f7b2SMatthew G. Knepley 
7019566063dSJacob Faibussowitsch   PetscCall(DMSwarmComputeMassMatrixSquare_Private(dmCoarse, dmFine, *mass, PETSC_TRUE, ctx));
7029566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*mass, NULL, "-mass_sq_mat_view"));
7033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7044cc7f7b2SMatthew G. Knepley }
7054cc7f7b2SMatthew G. Knepley 
706cc4c1da9SBarry Smith /*@
70720f4b53cSBarry Smith   DMSwarmCreateGlobalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
708d3a51819SDave May 
70920f4b53cSBarry Smith   Collective
710d3a51819SDave May 
71160225df5SJacob Faibussowitsch   Input Parameters:
71220f4b53cSBarry Smith + dm        - a `DMSWARM`
71362741f57SDave May - fieldname - the textual name given to a registered field
714d3a51819SDave May 
71560225df5SJacob Faibussowitsch   Output Parameter:
716d3a51819SDave May . vec - the vector
717d3a51819SDave May 
718d3a51819SDave May   Level: beginner
719d3a51819SDave May 
720cc4c1da9SBarry Smith   Note:
72120f4b53cSBarry Smith   The vector must be returned using a matching call to `DMSwarmDestroyGlobalVectorFromField()`.
7228b8a3813SDave May 
72320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyGlobalVectorFromField()`
724d3a51819SDave May @*/
725d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
726d71ae5a4SJacob Faibussowitsch {
727fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PetscObjectComm((PetscObject)dm);
728b5bcf523SDave May 
729fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
730ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
7319566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
7323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
733b5bcf523SDave May }
734b5bcf523SDave May 
735cc4c1da9SBarry Smith /*@
73620f4b53cSBarry Smith   DMSwarmDestroyGlobalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
737d3a51819SDave May 
73820f4b53cSBarry Smith   Collective
739d3a51819SDave May 
74060225df5SJacob Faibussowitsch   Input Parameters:
74120f4b53cSBarry Smith + dm        - a `DMSWARM`
74262741f57SDave May - fieldname - the textual name given to a registered field
743d3a51819SDave May 
74460225df5SJacob Faibussowitsch   Output Parameter:
745d3a51819SDave May . vec - the vector
746d3a51819SDave May 
747d3a51819SDave May   Level: beginner
748d3a51819SDave May 
74920f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateGlobalVectorFromField()`
750d3a51819SDave May @*/
751d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyGlobalVectorFromField(DM dm, const char fieldname[], Vec *vec)
752d71ae5a4SJacob Faibussowitsch {
753fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
754ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
7559566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
7563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
757b5bcf523SDave May }
758b5bcf523SDave May 
759cc4c1da9SBarry Smith /*@
76020f4b53cSBarry Smith   DMSwarmCreateLocalVectorFromField - Creates a `Vec` object sharing the array associated with a given field
761fb1bcc12SMatthew G. Knepley 
76220f4b53cSBarry Smith   Collective
763fb1bcc12SMatthew G. Knepley 
76460225df5SJacob Faibussowitsch   Input Parameters:
76520f4b53cSBarry Smith + dm        - a `DMSWARM`
76662741f57SDave May - fieldname - the textual name given to a registered field
767fb1bcc12SMatthew G. Knepley 
76860225df5SJacob Faibussowitsch   Output Parameter:
769fb1bcc12SMatthew G. Knepley . vec - the vector
770fb1bcc12SMatthew G. Knepley 
771fb1bcc12SMatthew G. Knepley   Level: beginner
772fb1bcc12SMatthew G. Knepley 
77320f4b53cSBarry Smith   Note:
7748b8a3813SDave May   The vector must be returned using a matching call to DMSwarmDestroyLocalVectorFromField().
7758b8a3813SDave May 
77620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmDestroyLocalVectorFromField()`
777fb1bcc12SMatthew G. Knepley @*/
778d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCreateLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
779d71ae5a4SJacob Faibussowitsch {
780fb1bcc12SMatthew G. Knepley   MPI_Comm comm = PETSC_COMM_SELF;
781bbe8250bSMatthew G. Knepley 
782fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
7839566063dSJacob Faibussowitsch   PetscCall(DMSwarmCreateVectorFromField_Private(dm, fieldname, comm, vec));
7843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
785bbe8250bSMatthew G. Knepley }
786fb1bcc12SMatthew G. Knepley 
787cc4c1da9SBarry Smith /*@
78820f4b53cSBarry Smith   DMSwarmDestroyLocalVectorFromField - Destroys the `Vec` object which share the array associated with a given field
789fb1bcc12SMatthew G. Knepley 
79020f4b53cSBarry Smith   Collective
791fb1bcc12SMatthew G. Knepley 
79260225df5SJacob Faibussowitsch   Input Parameters:
79320f4b53cSBarry Smith + dm        - a `DMSWARM`
79462741f57SDave May - fieldname - the textual name given to a registered field
795fb1bcc12SMatthew G. Knepley 
79660225df5SJacob Faibussowitsch   Output Parameter:
797fb1bcc12SMatthew G. Knepley . vec - the vector
798fb1bcc12SMatthew G. Knepley 
799fb1bcc12SMatthew G. Knepley   Level: beginner
800fb1bcc12SMatthew G. Knepley 
80120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmCreateLocalVectorFromField()`
802fb1bcc12SMatthew G. Knepley @*/
803d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmDestroyLocalVectorFromField(DM dm, const char fieldname[], Vec *vec)
804d71ae5a4SJacob Faibussowitsch {
805fb1bcc12SMatthew G. Knepley   PetscFunctionBegin;
806ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
8079566063dSJacob Faibussowitsch   PetscCall(DMSwarmDestroyVectorFromField_Private(dm, fieldname, vec));
8083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
809bbe8250bSMatthew G. Knepley }
810bbe8250bSMatthew G. Knepley 
811cc4c1da9SBarry Smith /*@
81220f4b53cSBarry Smith   DMSwarmInitializeFieldRegister - Initiates the registration of fields to a `DMSWARM`
813d3a51819SDave May 
81420f4b53cSBarry Smith   Collective
815d3a51819SDave May 
81660225df5SJacob Faibussowitsch   Input Parameter:
81720f4b53cSBarry Smith . dm - a `DMSWARM`
818d3a51819SDave May 
819d3a51819SDave May   Level: beginner
820d3a51819SDave May 
82120f4b53cSBarry Smith   Note:
82220f4b53cSBarry Smith   After all fields have been registered, you must call `DMSwarmFinalizeFieldRegister()`.
823d3a51819SDave May 
82420f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmFinalizeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
825db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
826d3a51819SDave May @*/
827d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmInitializeFieldRegister(DM dm)
828d71ae5a4SJacob Faibussowitsch {
8295f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
8303454631fSDave May 
831521f74f9SMatthew G. Knepley   PetscFunctionBegin;
832cc651181SDave May   if (!swarm->field_registration_initialized) {
8335f50eb2eSDave May     swarm->field_registration_initialized = PETSC_TRUE;
834da81f932SPierre Jolivet     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_pid, 1, PETSC_INT64)); /* unique identifier */
8359566063dSJacob Faibussowitsch     PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmField_rank, 1, PETSC_INT));  /* used for communication */
836cc651181SDave May   }
8373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8385f50eb2eSDave May }
8395f50eb2eSDave May 
84074d0cae8SMatthew G. Knepley /*@
84120f4b53cSBarry Smith   DMSwarmFinalizeFieldRegister - Finalizes the registration of fields to a `DMSWARM`
842d3a51819SDave May 
84320f4b53cSBarry Smith   Collective
844d3a51819SDave May 
84560225df5SJacob Faibussowitsch   Input Parameter:
84620f4b53cSBarry Smith . dm - a `DMSWARM`
847d3a51819SDave May 
848d3a51819SDave May   Level: beginner
849d3a51819SDave May 
85020f4b53cSBarry Smith   Note:
85120f4b53cSBarry Smith   After `DMSwarmFinalizeFieldRegister()` has been called, no new fields can be defined on the `DMSWARM`.
852d3a51819SDave May 
85320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmInitializeFieldRegister()`, `DMSwarmRegisterPetscDatatypeField()`,
854db781477SPatrick Sanan           `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
855d3a51819SDave May @*/
856d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmFinalizeFieldRegister(DM dm)
857d71ae5a4SJacob Faibussowitsch {
8585f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
8596845f8f5SDave May 
860521f74f9SMatthew G. Knepley   PetscFunctionBegin;
86148a46eb9SPierre Jolivet   if (!swarm->field_registration_finalized) PetscCall(DMSwarmDataBucketFinalize(swarm->db));
862f0cdbbbaSDave May   swarm->field_registration_finalized = PETSC_TRUE;
8633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8645f50eb2eSDave May }
8655f50eb2eSDave May 
86674d0cae8SMatthew G. Knepley /*@
86720f4b53cSBarry Smith   DMSwarmSetLocalSizes - Sets the length of all registered fields on the `DMSWARM`
868d3a51819SDave May 
86920f4b53cSBarry Smith   Not Collective
870d3a51819SDave May 
87160225df5SJacob Faibussowitsch   Input Parameters:
87220f4b53cSBarry Smith + dm     - a `DMSWARM`
873d3a51819SDave May . nlocal - the length of each registered field
87462741f57SDave May - buffer - the length of the buffer used to efficient dynamic re-sizing
875d3a51819SDave May 
876d3a51819SDave May   Level: beginner
877d3a51819SDave May 
87820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`
879d3a51819SDave May @*/
880d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetLocalSizes(DM dm, PetscInt nlocal, PetscInt buffer)
881d71ae5a4SJacob Faibussowitsch {
8825f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
8835f50eb2eSDave May 
884521f74f9SMatthew G. Knepley   PetscFunctionBegin;
8859566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_SetSizes, 0, 0, 0, 0));
8869566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, buffer));
8879566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_SetSizes, 0, 0, 0, 0));
8883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8895f50eb2eSDave May }
8905f50eb2eSDave May 
89174d0cae8SMatthew G. Knepley /*@
89220f4b53cSBarry Smith   DMSwarmSetCellDM - Attaches a `DM` to a `DMSWARM`
893d3a51819SDave May 
89420f4b53cSBarry Smith   Collective
895d3a51819SDave May 
89660225df5SJacob Faibussowitsch   Input Parameters:
89720f4b53cSBarry Smith + dm     - a `DMSWARM`
89820f4b53cSBarry Smith - dmcell - the `DM` to attach to the `DMSWARM`
899d3a51819SDave May 
900d3a51819SDave May   Level: beginner
901d3a51819SDave May 
90220f4b53cSBarry Smith   Note:
90320f4b53cSBarry Smith   The attached `DM` (dmcell) will be queried for point location and
90420f4b53cSBarry Smith   neighbor MPI-rank information if `DMSwarmMigrate()` is called.
905d3a51819SDave May 
90620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetType()`, `DMSwarmGetCellDM()`, `DMSwarmMigrate()`
907d3a51819SDave May @*/
908d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetCellDM(DM dm, DM dmcell)
909d71ae5a4SJacob Faibussowitsch {
910b16650c8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
911521f74f9SMatthew G. Knepley 
912521f74f9SMatthew G. Knepley   PetscFunctionBegin;
913b16650c8SDave May   swarm->dmcell = dmcell;
9143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
915b16650c8SDave May }
916b16650c8SDave May 
91774d0cae8SMatthew G. Knepley /*@
91820f4b53cSBarry Smith   DMSwarmGetCellDM - Fetches the attached cell `DM`
919d3a51819SDave May 
92020f4b53cSBarry Smith   Collective
921d3a51819SDave May 
92260225df5SJacob Faibussowitsch   Input Parameter:
92320f4b53cSBarry Smith . dm - a `DMSWARM`
924d3a51819SDave May 
92560225df5SJacob Faibussowitsch   Output Parameter:
92620f4b53cSBarry Smith . dmcell - the `DM` which was attached to the `DMSWARM`
927d3a51819SDave May 
928d3a51819SDave May   Level: beginner
929d3a51819SDave May 
93020f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
931d3a51819SDave May @*/
932d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetCellDM(DM dm, DM *dmcell)
933d71ae5a4SJacob Faibussowitsch {
934fe39f135SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
935521f74f9SMatthew G. Knepley 
936521f74f9SMatthew G. Knepley   PetscFunctionBegin;
937fe39f135SDave May   *dmcell = swarm->dmcell;
9383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
939fe39f135SDave May }
940fe39f135SDave May 
94174d0cae8SMatthew G. Knepley /*@
942d5b43468SJose E. Roman   DMSwarmGetLocalSize - Retrieves the local length of fields registered
943d3a51819SDave May 
94420f4b53cSBarry Smith   Not Collective
945d3a51819SDave May 
94660225df5SJacob Faibussowitsch   Input Parameter:
94720f4b53cSBarry Smith . dm - a `DMSWARM`
948d3a51819SDave May 
94960225df5SJacob Faibussowitsch   Output Parameter:
950d3a51819SDave May . nlocal - the length of each registered field
951d3a51819SDave May 
952d3a51819SDave May   Level: beginner
953d3a51819SDave May 
95420f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetSize()`, `DMSwarmSetLocalSizes()`
955d3a51819SDave May @*/
956d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetLocalSize(DM dm, PetscInt *nlocal)
957d71ae5a4SJacob Faibussowitsch {
958dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
959dcf43ee8SDave May 
960521f74f9SMatthew G. Knepley   PetscFunctionBegin;
9619566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, nlocal, NULL, NULL));
9623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
963dcf43ee8SDave May }
964dcf43ee8SDave May 
96574d0cae8SMatthew G. Knepley /*@
966d5b43468SJose E. Roman   DMSwarmGetSize - Retrieves the total length of fields registered
967d3a51819SDave May 
96820f4b53cSBarry Smith   Collective
969d3a51819SDave May 
97060225df5SJacob Faibussowitsch   Input Parameter:
97120f4b53cSBarry Smith . dm - a `DMSWARM`
972d3a51819SDave May 
97360225df5SJacob Faibussowitsch   Output Parameter:
974d3a51819SDave May . n - the total length of each registered field
975d3a51819SDave May 
976d3a51819SDave May   Level: beginner
977d3a51819SDave May 
978d3a51819SDave May   Note:
97920f4b53cSBarry Smith   This calls `MPI_Allreduce()` upon each call (inefficient but safe)
980d3a51819SDave May 
98120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetLocalSize()`, `DMSwarmSetLocalSizes()`
982d3a51819SDave May @*/
983d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetSize(DM dm, PetscInt *n)
984d71ae5a4SJacob Faibussowitsch {
985dcf43ee8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
9865627991aSBarry Smith   PetscInt  nlocal;
987dcf43ee8SDave May 
988521f74f9SMatthew G. Knepley   PetscFunctionBegin;
9899566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
990712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&nlocal, n, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
9913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
992dcf43ee8SDave May }
993dcf43ee8SDave May 
994cc4c1da9SBarry Smith /*@
99520f4b53cSBarry Smith   DMSwarmRegisterPetscDatatypeField - Register a field to a `DMSWARM` with a native PETSc data type
996d3a51819SDave May 
99720f4b53cSBarry Smith   Collective
998d3a51819SDave May 
99960225df5SJacob Faibussowitsch   Input Parameters:
100020f4b53cSBarry Smith + dm        - a `DMSWARM`
1001d3a51819SDave May . fieldname - the textual name to identify this field
1002d3a51819SDave May . blocksize - the number of each data type
100320f4b53cSBarry Smith - type      - a valid PETSc data type (`PETSC_CHAR`, `PETSC_SHORT`, `PETSC_INT`, `PETSC_FLOAT`, `PETSC_REAL`, `PETSC_LONG`)
1004d3a51819SDave May 
1005d3a51819SDave May   Level: beginner
1006d3a51819SDave May 
1007d3a51819SDave May   Notes:
10088b8a3813SDave May   The textual name for each registered field must be unique.
1009d3a51819SDave May 
101020f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterUserStructField()`, `DMSwarmRegisterUserDatatypeField()`
1011d3a51819SDave May @*/
1012d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterPetscDatatypeField(DM dm, const char fieldname[], PetscInt blocksize, PetscDataType type)
1013d71ae5a4SJacob Faibussowitsch {
1014b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1015b62e03f8SDave May   size_t    size;
1016b62e03f8SDave May 
1017521f74f9SMatthew G. Knepley   PetscFunctionBegin;
101828b400f6SJacob Faibussowitsch   PetscCheck(swarm->field_registration_initialized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMSwarmInitializeFieldRegister() first");
101928b400f6SJacob Faibussowitsch   PetscCheck(!swarm->field_registration_finalized, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Cannot register additional fields after calling DMSwarmFinalizeFieldRegister() first");
10205f50eb2eSDave May 
102108401ef6SPierre Jolivet   PetscCheck(type != PETSC_OBJECT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
102208401ef6SPierre Jolivet   PetscCheck(type != PETSC_FUNCTION, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
102308401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRING, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
102408401ef6SPierre Jolivet   PetscCheck(type != PETSC_STRUCT, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
102508401ef6SPierre Jolivet   PetscCheck(type != PETSC_DATATYPE_UNKNOWN, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Valid for {char,short,int,long,float,double}");
1026b62e03f8SDave May 
10279566063dSJacob Faibussowitsch   PetscCall(PetscDataTypeGetSize(type, &size));
1028b62e03f8SDave May   /* Load a specific data type into data bucket, specifying textual name and its size in bytes */
10299566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterPetscDatatypeField", fieldname, blocksize * size, NULL));
103052c3ed93SDave May   {
103177048351SPatrick Sanan     DMSwarmDataField gfield;
103252c3ed93SDave May 
10339566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
10349566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
103552c3ed93SDave May   }
1036b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = type;
10373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1038b62e03f8SDave May }
1039b62e03f8SDave May 
1040d3a51819SDave May /*@C
104120f4b53cSBarry Smith   DMSwarmRegisterUserStructField - Register a user defined struct to a `DMSWARM`
1042d3a51819SDave May 
104320f4b53cSBarry Smith   Collective
1044d3a51819SDave May 
104560225df5SJacob Faibussowitsch   Input Parameters:
104620f4b53cSBarry Smith + dm        - a `DMSWARM`
1047d3a51819SDave May . fieldname - the textual name to identify this field
104862741f57SDave May - size      - the size in bytes of the user struct of each data type
1049d3a51819SDave May 
1050d3a51819SDave May   Level: beginner
1051d3a51819SDave May 
105220f4b53cSBarry Smith   Note:
10538b8a3813SDave May   The textual name for each registered field must be unique.
1054d3a51819SDave May 
105520f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserDatatypeField()`
1056d3a51819SDave May @*/
1057d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserStructField(DM dm, const char fieldname[], size_t size)
1058d71ae5a4SJacob Faibussowitsch {
1059b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1060b62e03f8SDave May 
1061521f74f9SMatthew G. Knepley   PetscFunctionBegin;
10629566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserStructField", fieldname, size, NULL));
1063b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_STRUCT;
10643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1065b62e03f8SDave May }
1066b62e03f8SDave May 
1067d3a51819SDave May /*@C
106820f4b53cSBarry Smith   DMSwarmRegisterUserDatatypeField - Register a user defined data type to a `DMSWARM`
1069d3a51819SDave May 
107020f4b53cSBarry Smith   Collective
1071d3a51819SDave May 
107260225df5SJacob Faibussowitsch   Input Parameters:
107320f4b53cSBarry Smith + dm        - a `DMSWARM`
1074d3a51819SDave May . fieldname - the textual name to identify this field
1075d3a51819SDave May . size      - the size in bytes of the user data type
107662741f57SDave May - blocksize - the number of each data type
1077d3a51819SDave May 
1078d3a51819SDave May   Level: beginner
1079d3a51819SDave May 
108020f4b53cSBarry Smith   Note:
10818b8a3813SDave May   The textual name for each registered field must be unique.
1082d3a51819SDave May 
108342747ad1SJacob Faibussowitsch .seealso: `DM`, `DMSWARM`, `DMSwarmRegisterPetscDatatypeField()`, `DMSwarmRegisterUserStructField()`
1084d3a51819SDave May @*/
1085d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRegisterUserDatatypeField(DM dm, const char fieldname[], size_t size, PetscInt blocksize)
1086d71ae5a4SJacob Faibussowitsch {
1087b62e03f8SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1088b62e03f8SDave May 
1089521f74f9SMatthew G. Knepley   PetscFunctionBegin;
10909566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRegisterField(swarm->db, "DMSwarmRegisterUserDatatypeField", fieldname, blocksize * size, NULL));
1091320740a0SDave May   {
109277048351SPatrick Sanan     DMSwarmDataField gfield;
1093320740a0SDave May 
10949566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
10959566063dSJacob Faibussowitsch     PetscCall(DMSwarmDataFieldSetBlockSize(gfield, blocksize));
1096320740a0SDave May   }
1097b62e03f8SDave May   swarm->db->field[swarm->db->nfields - 1]->petsc_type = PETSC_DATATYPE_UNKNOWN;
10983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1099b62e03f8SDave May }
1100b62e03f8SDave May 
1101d3a51819SDave May /*@C
1102d3a51819SDave May   DMSwarmGetField - Get access to the underlying array storing all entries associated with a registered field
1103d3a51819SDave May 
1104cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1105d3a51819SDave May 
110660225df5SJacob Faibussowitsch   Input Parameters:
110720f4b53cSBarry Smith + dm        - a `DMSWARM`
110862741f57SDave May - fieldname - the textual name to identify this field
1109d3a51819SDave May 
111060225df5SJacob Faibussowitsch   Output Parameters:
111162741f57SDave May + blocksize - the number of each data type
1112d3a51819SDave May . type      - the data type
111362741f57SDave May - data      - pointer to raw array
1114d3a51819SDave May 
1115d3a51819SDave May   Level: beginner
1116d3a51819SDave May 
1117d3a51819SDave May   Notes:
111820f4b53cSBarry Smith   The array must be returned using a matching call to `DMSwarmRestoreField()`.
1119d3a51819SDave May 
112020f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreField()`
1121d3a51819SDave May @*/
1122d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmGetField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1123d71ae5a4SJacob Faibussowitsch {
1124b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
112577048351SPatrick Sanan   DMSwarmDataField gfield;
1126b62e03f8SDave May 
1127521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1128ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
11299566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
11309566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
11319566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetAccess(gfield));
11329566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldGetEntries(gfield, data));
1133ad540459SPierre Jolivet   if (blocksize) *blocksize = gfield->bs;
1134ad540459SPierre Jolivet   if (type) *type = gfield->petsc_type;
11353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1136b62e03f8SDave May }
1137b62e03f8SDave May 
1138d3a51819SDave May /*@C
1139d3a51819SDave May   DMSwarmRestoreField - Restore access to the underlying array storing all entries associated with a registered field
1140d3a51819SDave May 
1141cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1142d3a51819SDave May 
114360225df5SJacob Faibussowitsch   Input Parameters:
114420f4b53cSBarry Smith + dm        - a `DMSWARM`
114562741f57SDave May - fieldname - the textual name to identify this field
1146d3a51819SDave May 
114760225df5SJacob Faibussowitsch   Output Parameters:
114862741f57SDave May + blocksize - the number of each data type
1149d3a51819SDave May . type      - the data type
115062741f57SDave May - data      - pointer to raw array
1151d3a51819SDave May 
1152d3a51819SDave May   Level: beginner
1153d3a51819SDave May 
1154d3a51819SDave May   Notes:
115520f4b53cSBarry Smith   The user must call `DMSwarmGetField()` prior to calling `DMSwarmRestoreField()`.
1156d3a51819SDave May 
115720f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetField()`
1158d3a51819SDave May @*/
1159d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRestoreField(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type, void **data)
1160d71ae5a4SJacob Faibussowitsch {
1161b62e03f8SDave May   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
116277048351SPatrick Sanan   DMSwarmDataField gfield;
1163b62e03f8SDave May 
1164521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1165ea7032a0SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
11669566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
11679566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataFieldRestoreAccess(gfield));
1168b62e03f8SDave May   if (data) *data = NULL;
11693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1170b62e03f8SDave May }
1171b62e03f8SDave May 
11720bf7c1c5SMatthew G. Knepley PetscErrorCode DMSwarmGetFieldInfo(DM dm, const char fieldname[], PetscInt *blocksize, PetscDataType *type)
11730bf7c1c5SMatthew G. Knepley {
11740bf7c1c5SMatthew G. Knepley   DM_Swarm        *swarm = (DM_Swarm *)dm->data;
11750bf7c1c5SMatthew G. Knepley   DMSwarmDataField gfield;
11760bf7c1c5SMatthew G. Knepley 
11770bf7c1c5SMatthew G. Knepley   PetscFunctionBegin;
11780bf7c1c5SMatthew G. Knepley   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMSWARM);
11790bf7c1c5SMatthew G. Knepley   PetscCall(DMSwarmDataBucketGetDMSwarmDataFieldByName(swarm->db, fieldname, &gfield));
11800bf7c1c5SMatthew G. Knepley   if (blocksize) *blocksize = gfield->bs;
11810bf7c1c5SMatthew G. Knepley   if (type) *type = gfield->petsc_type;
11820bf7c1c5SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
11830bf7c1c5SMatthew G. Knepley }
11840bf7c1c5SMatthew G. Knepley 
118574d0cae8SMatthew G. Knepley /*@
118620f4b53cSBarry Smith   DMSwarmAddPoint - Add space for one new point in the `DMSWARM`
1187d3a51819SDave May 
118820f4b53cSBarry Smith   Not Collective
1189d3a51819SDave May 
119060225df5SJacob Faibussowitsch   Input Parameter:
119120f4b53cSBarry Smith . dm - a `DMSWARM`
1192d3a51819SDave May 
1193d3a51819SDave May   Level: beginner
1194d3a51819SDave May 
1195d3a51819SDave May   Notes:
11968b8a3813SDave May   The new point will have all fields initialized to zero.
1197d3a51819SDave May 
119820f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmAddNPoints()`
1199d3a51819SDave May @*/
1200d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddPoint(DM dm)
1201d71ae5a4SJacob Faibussowitsch {
1202cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1203cb1d1399SDave May 
1204521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12059566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
12069566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
12079566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketAddPoint(swarm->db));
12089566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
12093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1210cb1d1399SDave May }
1211cb1d1399SDave May 
121274d0cae8SMatthew G. Knepley /*@
121320f4b53cSBarry Smith   DMSwarmAddNPoints - Add space for a number of new points in the `DMSWARM`
1214d3a51819SDave May 
121520f4b53cSBarry Smith   Not Collective
1216d3a51819SDave May 
121760225df5SJacob Faibussowitsch   Input Parameters:
121820f4b53cSBarry Smith + dm      - a `DMSWARM`
121962741f57SDave May - npoints - the number of new points to add
1220d3a51819SDave May 
1221d3a51819SDave May   Level: beginner
1222d3a51819SDave May 
1223d3a51819SDave May   Notes:
12248b8a3813SDave May   The new point will have all fields initialized to zero.
1225d3a51819SDave May 
122620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmAddPoint()`
1227d3a51819SDave May @*/
1228d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmAddNPoints(DM dm, PetscInt npoints)
1229d71ae5a4SJacob Faibussowitsch {
1230cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1231cb1d1399SDave May   PetscInt  nlocal;
1232cb1d1399SDave May 
1233521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12349566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_AddPoints, 0, 0, 0, 0));
12359566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &nlocal, NULL, NULL));
1236cb1d1399SDave May   nlocal = nlocal + npoints;
12379566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketSetSizes(swarm->db, nlocal, DMSWARM_DATA_BUCKET_BUFFER_DEFAULT));
12389566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_AddPoints, 0, 0, 0, 0));
12393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1240cb1d1399SDave May }
1241cb1d1399SDave May 
124274d0cae8SMatthew G. Knepley /*@
124320f4b53cSBarry Smith   DMSwarmRemovePoint - Remove the last point from the `DMSWARM`
1244d3a51819SDave May 
124520f4b53cSBarry Smith   Not Collective
1246d3a51819SDave May 
124760225df5SJacob Faibussowitsch   Input Parameter:
124820f4b53cSBarry Smith . dm - a `DMSWARM`
1249d3a51819SDave May 
1250d3a51819SDave May   Level: beginner
1251d3a51819SDave May 
125220f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePointAtIndex()`
1253d3a51819SDave May @*/
1254d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePoint(DM dm)
1255d71ae5a4SJacob Faibussowitsch {
1256cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1257cb1d1399SDave May 
1258521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12599566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
12609566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePoint(swarm->db));
12619566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
12623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1263cb1d1399SDave May }
1264cb1d1399SDave May 
126574d0cae8SMatthew G. Knepley /*@
126620f4b53cSBarry Smith   DMSwarmRemovePointAtIndex - Removes a specific point from the `DMSWARM`
1267d3a51819SDave May 
126820f4b53cSBarry Smith   Not Collective
1269d3a51819SDave May 
127060225df5SJacob Faibussowitsch   Input Parameters:
127120f4b53cSBarry Smith + dm  - a `DMSWARM`
127262741f57SDave May - idx - index of point to remove
1273d3a51819SDave May 
1274d3a51819SDave May   Level: beginner
1275d3a51819SDave May 
127620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
1277d3a51819SDave May @*/
1278d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmRemovePointAtIndex(DM dm, PetscInt idx)
1279d71ae5a4SJacob Faibussowitsch {
1280cb1d1399SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1281cb1d1399SDave May 
1282521f74f9SMatthew G. Knepley   PetscFunctionBegin;
12839566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_RemovePoints, 0, 0, 0, 0));
12849566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketRemovePointAtIndex(swarm->db, idx));
12859566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_RemovePoints, 0, 0, 0, 0));
12863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1287cb1d1399SDave May }
1288b62e03f8SDave May 
128974d0cae8SMatthew G. Knepley /*@
129020f4b53cSBarry Smith   DMSwarmCopyPoint - Copy point pj to point pi in the `DMSWARM`
1291ba4fc9c6SDave May 
129220f4b53cSBarry Smith   Not Collective
1293ba4fc9c6SDave May 
129460225df5SJacob Faibussowitsch   Input Parameters:
129520f4b53cSBarry Smith + dm - a `DMSWARM`
1296ba4fc9c6SDave May . pi - the index of the point to copy
1297ba4fc9c6SDave May - pj - the point index where the copy should be located
1298ba4fc9c6SDave May 
1299ba4fc9c6SDave May   Level: beginner
1300ba4fc9c6SDave May 
130120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRemovePoint()`
1302ba4fc9c6SDave May @*/
1303d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCopyPoint(DM dm, PetscInt pi, PetscInt pj)
1304d71ae5a4SJacob Faibussowitsch {
1305ba4fc9c6SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1306ba4fc9c6SDave May 
1307ba4fc9c6SDave May   PetscFunctionBegin;
13089566063dSJacob Faibussowitsch   if (!swarm->issetup) PetscCall(DMSetUp(dm));
13099566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCopyPoint(swarm->db, pi, swarm->db, pj));
13103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1311ba4fc9c6SDave May }
1312ba4fc9c6SDave May 
131366976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmMigrate_Basic(DM dm, PetscBool remove_sent_points)
1314d71ae5a4SJacob Faibussowitsch {
1315521f74f9SMatthew G. Knepley   PetscFunctionBegin;
13169566063dSJacob Faibussowitsch   PetscCall(DMSwarmMigrate_Push_Basic(dm, remove_sent_points));
13173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13183454631fSDave May }
13193454631fSDave May 
132074d0cae8SMatthew G. Knepley /*@
132120f4b53cSBarry Smith   DMSwarmMigrate - Relocates points defined in the `DMSWARM` to other MPI-ranks
1322d3a51819SDave May 
132320f4b53cSBarry Smith   Collective
1324d3a51819SDave May 
132560225df5SJacob Faibussowitsch   Input Parameters:
132620f4b53cSBarry Smith + dm                 - the `DMSWARM`
132762741f57SDave May - remove_sent_points - flag indicating if sent points should be removed from the current MPI-rank
1328d3a51819SDave May 
1329d3a51819SDave May   Level: advanced
1330d3a51819SDave May 
133120f4b53cSBarry Smith   Notes:
133220f4b53cSBarry Smith   The `DM` will be modified to accommodate received points.
133320f4b53cSBarry Smith   If `remove_sent_points` is `PETSC_TRUE`, any points that were sent will be removed from the `DM`.
133420f4b53cSBarry Smith   Different styles of migration are supported. See `DMSwarmSetMigrateType()`.
133520f4b53cSBarry Smith 
133620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`
1337d3a51819SDave May @*/
1338d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmMigrate(DM dm, PetscBool remove_sent_points)
1339d71ae5a4SJacob Faibussowitsch {
1340f0cdbbbaSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1341f0cdbbbaSDave May 
1342521f74f9SMatthew G. Knepley   PetscFunctionBegin;
13439566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMSWARM_Migrate, 0, 0, 0, 0));
1344f0cdbbbaSDave May   switch (swarm->migrate_type) {
1345d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_BASIC:
1346d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_Basic(dm, remove_sent_points));
1347d71ae5a4SJacob Faibussowitsch     break;
1348d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLNSCATTER:
1349d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_CellDMScatter(dm, remove_sent_points));
1350d71ae5a4SJacob Faibussowitsch     break;
1351d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_DMCELLEXACT:
1352d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_DMCELLEXACT not implemented");
1353d71ae5a4SJacob Faibussowitsch   case DMSWARM_MIGRATE_USER:
1354d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE_USER not implemented");
1355d71ae5a4SJacob Faibussowitsch   default:
1356d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_MIGRATE type unknown");
1357f0cdbbbaSDave May   }
13589566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMSWARM_Migrate, 0, 0, 0, 0));
13599566063dSJacob Faibussowitsch   PetscCall(DMClearGlobalVectors(dm));
13603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13613454631fSDave May }
13623454631fSDave May 
1363f0cdbbbaSDave May PetscErrorCode DMSwarmMigrate_GlobalToLocal_Basic(DM dm, PetscInt *globalsize);
1364f0cdbbbaSDave May 
1365d3a51819SDave May /*
1366d3a51819SDave May  DMSwarmCollectViewCreate
1367d3a51819SDave May 
1368d3a51819SDave May  * Applies a collection method and gathers point neighbour points into dm
1369d3a51819SDave May 
1370d3a51819SDave May  Notes:
13718b8a3813SDave May  Users should call DMSwarmCollectViewDestroy() after
1372d3a51819SDave May  they have finished computations associated with the collected points
1373d3a51819SDave May */
1374d3a51819SDave May 
137574d0cae8SMatthew G. Knepley /*@
1376d3a51819SDave May   DMSwarmCollectViewCreate - Applies a collection method and gathers points
137720f4b53cSBarry Smith   in neighbour ranks into the `DMSWARM`
1378d3a51819SDave May 
137920f4b53cSBarry Smith   Collective
1380d3a51819SDave May 
138160225df5SJacob Faibussowitsch   Input Parameter:
138220f4b53cSBarry Smith . dm - the `DMSWARM`
1383d3a51819SDave May 
1384d3a51819SDave May   Level: advanced
1385d3a51819SDave May 
138620f4b53cSBarry Smith   Notes:
138720f4b53cSBarry Smith   Users should call `DMSwarmCollectViewDestroy()` after
138820f4b53cSBarry Smith   they have finished computations associated with the collected points
1389*0764c050SBarry Smith 
139020f4b53cSBarry Smith   Different collect methods are supported. See `DMSwarmSetCollectType()`.
139120f4b53cSBarry Smith 
1392*0764c050SBarry Smith   Developer Note:
1393*0764c050SBarry Smith   Create and Destroy routines create new objects that can get destroyed, they do not change the state
1394*0764c050SBarry Smith   of the current object.
1395*0764c050SBarry Smith 
139620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewDestroy()`, `DMSwarmSetCollectType()`
1397d3a51819SDave May @*/
1398d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewCreate(DM dm)
1399d71ae5a4SJacob Faibussowitsch {
14002712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
14012712d1f2SDave May   PetscInt  ng;
14022712d1f2SDave May 
1403521f74f9SMatthew G. Knepley   PetscFunctionBegin;
140428b400f6SJacob Faibussowitsch   PetscCheck(!swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView currently active");
14059566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &ng));
1406480eef7bSDave May   switch (swarm->collect_type) {
1407d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_BASIC:
1408d71ae5a4SJacob Faibussowitsch     PetscCall(DMSwarmMigrate_GlobalToLocal_Basic(dm, &ng));
1409d71ae5a4SJacob Faibussowitsch     break;
1410d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_DMDABOUNDINGBOX:
1411d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_DMDABOUNDINGBOX not implemented");
1412d71ae5a4SJacob Faibussowitsch   case DMSWARM_COLLECT_GENERAL:
1413d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT_GENERAL not implemented");
1414d71ae5a4SJacob Faibussowitsch   default:
1415d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "DMSWARM_COLLECT type unknown");
1416480eef7bSDave May   }
1417480eef7bSDave May   swarm->collect_view_active       = PETSC_TRUE;
1418480eef7bSDave May   swarm->collect_view_reset_nlocal = ng;
14193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14202712d1f2SDave May }
14212712d1f2SDave May 
142274d0cae8SMatthew G. Knepley /*@
142320f4b53cSBarry Smith   DMSwarmCollectViewDestroy - Resets the `DMSWARM` to the size prior to calling `DMSwarmCollectViewCreate()`
1424d3a51819SDave May 
142520f4b53cSBarry Smith   Collective
1426d3a51819SDave May 
142760225df5SJacob Faibussowitsch   Input Parameters:
142820f4b53cSBarry Smith . dm - the `DMSWARM`
1429d3a51819SDave May 
1430d3a51819SDave May   Notes:
143120f4b53cSBarry Smith   Users should call `DMSwarmCollectViewCreate()` before this function is called.
1432d3a51819SDave May 
1433d3a51819SDave May   Level: advanced
1434d3a51819SDave May 
1435*0764c050SBarry Smith   Developer Note:
1436*0764c050SBarry Smith   Create and Destroy routines create new objects that can get destroyed, they do not change the state
1437*0764c050SBarry Smith   of the current object.
1438*0764c050SBarry Smith 
143920f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmCollectViewCreate()`, `DMSwarmSetCollectType()`
1440d3a51819SDave May @*/
1441d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmCollectViewDestroy(DM dm)
1442d71ae5a4SJacob Faibussowitsch {
14432712d1f2SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
14442712d1f2SDave May 
1445521f74f9SMatthew G. Knepley   PetscFunctionBegin;
144628b400f6SJacob Faibussowitsch   PetscCheck(swarm->collect_view_active, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "CollectView is currently not active");
14479566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetLocalSizes(dm, swarm->collect_view_reset_nlocal, -1));
1448480eef7bSDave May   swarm->collect_view_active = PETSC_FALSE;
14493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14502712d1f2SDave May }
14513454631fSDave May 
145266976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmSetUpPIC(DM dm)
1453d71ae5a4SJacob Faibussowitsch {
1454f0cdbbbaSDave May   PetscInt dim;
1455f0cdbbbaSDave May 
1456521f74f9SMatthew G. Knepley   PetscFunctionBegin;
14579566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetNumSpecies(dm, 1));
14589566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
145963a3b9bcSJacob Faibussowitsch   PetscCheck(dim >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
146063a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Dimension must be 1,2,3 - found %" PetscInt_FMT, dim);
14619566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_coor, dim, PETSC_DOUBLE));
14629566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(dm, DMSwarmPICField_cellid, 1, PETSC_INT));
14633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1464f0cdbbbaSDave May }
1465f0cdbbbaSDave May 
146674d0cae8SMatthew G. Knepley /*@
146731403186SMatthew G. Knepley   DMSwarmSetPointCoordinatesRandom - Sets initial coordinates for particles in each cell
146831403186SMatthew G. Knepley 
146920f4b53cSBarry Smith   Collective
147031403186SMatthew G. Knepley 
147160225df5SJacob Faibussowitsch   Input Parameters:
147220f4b53cSBarry Smith + dm  - the `DMSWARM`
147320f4b53cSBarry Smith - Npc - The number of particles per cell in the cell `DM`
147431403186SMatthew G. Knepley 
147531403186SMatthew G. Knepley   Level: intermediate
147631403186SMatthew G. Knepley 
147720f4b53cSBarry Smith   Notes:
147820f4b53cSBarry Smith   The user must use `DMSwarmSetCellDM()` to set the cell `DM` first. The particles are placed randomly inside each cell. If only
147920f4b53cSBarry Smith   one particle is in each cell, it is placed at the centroid.
148020f4b53cSBarry Smith 
148120f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetCellDM()`
148231403186SMatthew G. Knepley @*/
1483d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetPointCoordinatesRandom(DM dm, PetscInt Npc)
1484d71ae5a4SJacob Faibussowitsch {
148531403186SMatthew G. Knepley   DM             cdm;
148631403186SMatthew G. Knepley   PetscRandom    rnd;
148731403186SMatthew G. Knepley   DMPolytopeType ct;
148831403186SMatthew G. Knepley   PetscBool      simplex;
148931403186SMatthew G. Knepley   PetscReal     *centroid, *coords, *xi0, *v0, *J, *invJ, detJ;
149031403186SMatthew G. Knepley   PetscInt       dim, d, cStart, cEnd, c, p;
149131403186SMatthew G. Knepley 
149231403186SMatthew G. Knepley   PetscFunctionBeginUser;
14939566063dSJacob Faibussowitsch   PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm), &rnd));
14949566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0));
14959566063dSJacob Faibussowitsch   PetscCall(PetscRandomSetType(rnd, PETSCRAND48));
149631403186SMatthew G. Knepley 
14979566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
14989566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(cdm, &dim));
14999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd));
15009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(cdm, cStart, &ct));
150131403186SMatthew G. Knepley   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
150231403186SMatthew G. Knepley 
15039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc5(dim, &centroid, dim, &xi0, dim, &v0, dim * dim, &J, dim * dim, &invJ));
150431403186SMatthew G. Knepley   for (d = 0; d < dim; ++d) xi0[d] = -1.0;
15059566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
150631403186SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
150731403186SMatthew G. Knepley     if (Npc == 1) {
15089566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFVM(cdm, c, NULL, centroid, NULL));
150931403186SMatthew G. Knepley       for (d = 0; d < dim; ++d) coords[c * dim + d] = centroid[d];
151031403186SMatthew G. Knepley     } else {
15119566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(cdm, c, NULL, v0, J, invJ, &detJ)); /* affine */
151231403186SMatthew G. Knepley       for (p = 0; p < Npc; ++p) {
151331403186SMatthew G. Knepley         const PetscInt n   = c * Npc + p;
151431403186SMatthew G. Knepley         PetscReal      sum = 0.0, refcoords[3];
151531403186SMatthew G. Knepley 
151631403186SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
15179566063dSJacob Faibussowitsch           PetscCall(PetscRandomGetValueReal(rnd, &refcoords[d]));
151831403186SMatthew G. Knepley           sum += refcoords[d];
151931403186SMatthew G. Knepley         }
15209371c9d4SSatish Balay         if (simplex && sum > 0.0)
15219371c9d4SSatish Balay           for (d = 0; d < dim; ++d) refcoords[d] -= PetscSqrtReal(dim) * sum;
152231403186SMatthew G. Knepley         CoordinatesRefToReal(dim, dim, xi0, v0, J, refcoords, &coords[n * dim]);
152331403186SMatthew G. Knepley       }
152431403186SMatthew G. Knepley     }
152531403186SMatthew G. Knepley   }
15269566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
15279566063dSJacob Faibussowitsch   PetscCall(PetscFree5(centroid, xi0, v0, J, invJ));
15289566063dSJacob Faibussowitsch   PetscCall(PetscRandomDestroy(&rnd));
15293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153031403186SMatthew G. Knepley }
153131403186SMatthew G. Knepley 
153231403186SMatthew G. Knepley /*@
153320f4b53cSBarry Smith   DMSwarmSetType - Set particular flavor of `DMSWARM`
1534d3a51819SDave May 
153520f4b53cSBarry Smith   Collective
1536d3a51819SDave May 
153760225df5SJacob Faibussowitsch   Input Parameters:
153820f4b53cSBarry Smith + dm    - the `DMSWARM`
153920f4b53cSBarry Smith - stype - the `DMSWARM` type (e.g. `DMSWARM_PIC`)
1540d3a51819SDave May 
1541d3a51819SDave May   Level: advanced
1542d3a51819SDave May 
154320f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmSetMigrateType()`, `DMSwarmSetCollectType()`, `DMSwarmType`, `DMSWARM_PIC`, `DMSWARM_BASIC`
1544d3a51819SDave May @*/
1545d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSwarmSetType(DM dm, DMSwarmType stype)
1546d71ae5a4SJacob Faibussowitsch {
1547f0cdbbbaSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1548f0cdbbbaSDave May 
1549521f74f9SMatthew G. Knepley   PetscFunctionBegin;
1550f0cdbbbaSDave May   swarm->swarm_type = stype;
155148a46eb9SPierre Jolivet   if (swarm->swarm_type == DMSWARM_PIC) PetscCall(DMSwarmSetUpPIC(dm));
15523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1553f0cdbbbaSDave May }
1554f0cdbbbaSDave May 
155566976f2fSJacob Faibussowitsch static PetscErrorCode DMSetup_Swarm(DM dm)
1556d71ae5a4SJacob Faibussowitsch {
15573454631fSDave May   DM_Swarm   *swarm = (DM_Swarm *)dm->data;
15583454631fSDave May   PetscMPIInt rank;
15593454631fSDave May   PetscInt    p, npoints, *rankval;
15603454631fSDave May 
1561521f74f9SMatthew G. Knepley   PetscFunctionBegin;
15623ba16761SJacob Faibussowitsch   if (swarm->issetup) PetscFunctionReturn(PETSC_SUCCESS);
15633454631fSDave May   swarm->issetup = PETSC_TRUE;
15643454631fSDave May 
1565f0cdbbbaSDave May   if (swarm->swarm_type == DMSWARM_PIC) {
1566f0cdbbbaSDave May     /* check dmcell exists */
156728b400f6SJacob Faibussowitsch     PetscCheck(swarm->dmcell, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires you call DMSwarmSetCellDM");
1568f0cdbbbaSDave May 
1569f0cdbbbaSDave May     if (swarm->dmcell->ops->locatepointssubdomain) {
1570f0cdbbbaSDave May       /* check methods exists for exact ownership identificiation */
15719566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->ops->LocatePointsSubdomain\n"));
1572f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLEXACT;
1573f0cdbbbaSDave May     } else {
1574f0cdbbbaSDave May       /* check methods exist for point location AND rank neighbor identification */
1575f0cdbbbaSDave May       if (swarm->dmcell->ops->locatepoints) {
15769566063dSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->LocatePoints\n"));
1577f0cdbbbaSDave May       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->locatepoints be defined");
1578f0cdbbbaSDave May 
1579f0cdbbbaSDave May       if (swarm->dmcell->ops->getneighbors) {
15809566063dSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "DMSWARM_PIC: Using method CellDM->GetNeigbors\n"));
1581f0cdbbbaSDave May       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "DMSWARM_PIC requires the method CellDM->ops->getneighbors be defined");
1582f0cdbbbaSDave May 
1583f0cdbbbaSDave May       swarm->migrate_type = DMSWARM_MIGRATE_DMCELLNSCATTER;
1584f0cdbbbaSDave May     }
1585f0cdbbbaSDave May   }
1586f0cdbbbaSDave May 
15879566063dSJacob Faibussowitsch   PetscCall(DMSwarmFinalizeFieldRegister(dm));
1588f0cdbbbaSDave May 
15893454631fSDave May   /* check some fields were registered */
159008401ef6SPierre Jolivet   PetscCheck(swarm->db->nfields > 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "At least one field user must be registered via DMSwarmRegisterXXX()");
15913454631fSDave May 
15923454631fSDave May   /* check local sizes were set */
159308401ef6SPierre Jolivet   PetscCheck(swarm->db->L != -1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Local sizes must be set via DMSwarmSetLocalSizes()");
15943454631fSDave May 
15953454631fSDave May   /* initialize values in pid and rank placeholders */
15963454631fSDave May   /* TODO: [pid - use MPI_Scan] */
15979566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
15989566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketGetSizes(swarm->db, &npoints, NULL, NULL));
15999566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
1600ad540459SPierre Jolivet   for (p = 0; p < npoints; p++) rankval[p] = (PetscInt)rank;
16019566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmField_rank, NULL, NULL, (void **)&rankval));
16023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16033454631fSDave May }
16043454631fSDave May 
1605dc5f5ce9SDave May extern PetscErrorCode DMSwarmSortDestroy(DMSwarmSort *_ctx);
1606dc5f5ce9SDave May 
160766976f2fSJacob Faibussowitsch static PetscErrorCode DMDestroy_Swarm(DM dm)
1608d71ae5a4SJacob Faibussowitsch {
160957795646SDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
161057795646SDave May 
161157795646SDave May   PetscFunctionBegin;
16123ba16761SJacob Faibussowitsch   if (--swarm->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
16139566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&swarm->db));
161448a46eb9SPierre Jolivet   if (swarm->sort_context) PetscCall(DMSwarmSortDestroy(&swarm->sort_context));
16159566063dSJacob Faibussowitsch   PetscCall(PetscFree(swarm));
16163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
161757795646SDave May }
161857795646SDave May 
161966976f2fSJacob Faibussowitsch static PetscErrorCode DMSwarmView_Draw(DM dm, PetscViewer viewer)
1620d71ae5a4SJacob Faibussowitsch {
1621a9ee3421SMatthew G. Knepley   DM         cdm;
1622a9ee3421SMatthew G. Knepley   PetscDraw  draw;
162331403186SMatthew G. Knepley   PetscReal *coords, oldPause, radius = 0.01;
1624a9ee3421SMatthew G. Knepley   PetscInt   Np, p, bs;
1625a9ee3421SMatthew G. Knepley 
1626a9ee3421SMatthew G. Knepley   PetscFunctionBegin;
16279566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetReal(NULL, ((PetscObject)dm)->prefix, "-dm_view_swarm_radius", &radius, NULL));
16289566063dSJacob Faibussowitsch   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
16299566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(dm, &cdm));
16309566063dSJacob Faibussowitsch   PetscCall(PetscDrawGetPause(draw, &oldPause));
16319566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, 0.0));
16329566063dSJacob Faibussowitsch   PetscCall(DMView(cdm, viewer));
16339566063dSJacob Faibussowitsch   PetscCall(PetscDrawSetPause(draw, oldPause));
1634a9ee3421SMatthew G. Knepley 
16359566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetLocalSize(dm, &Np));
16369566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&coords));
1637a9ee3421SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
1638a9ee3421SMatthew G. Knepley     const PetscInt i = p * bs;
1639a9ee3421SMatthew G. Knepley 
16409566063dSJacob Faibussowitsch     PetscCall(PetscDrawEllipse(draw, coords[i], coords[i + 1], radius, radius, PETSC_DRAW_BLUE));
1641a9ee3421SMatthew G. Knepley   }
16429566063dSJacob Faibussowitsch   PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_coor, &bs, NULL, (void **)&coords));
16439566063dSJacob Faibussowitsch   PetscCall(PetscDrawFlush(draw));
16449566063dSJacob Faibussowitsch   PetscCall(PetscDrawPause(draw));
16459566063dSJacob Faibussowitsch   PetscCall(PetscDrawSave(draw));
16463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1647a9ee3421SMatthew G. Knepley }
1648a9ee3421SMatthew G. Knepley 
1649d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_Swarm_Ascii(DM dm, PetscViewer viewer)
1650d71ae5a4SJacob Faibussowitsch {
16516a5217c0SMatthew G. Knepley   PetscViewerFormat format;
16526a5217c0SMatthew G. Knepley   PetscInt         *sizes;
16536a5217c0SMatthew G. Knepley   PetscInt          dim, Np, maxSize = 17;
16546a5217c0SMatthew G. Knepley   MPI_Comm          comm;
16556a5217c0SMatthew G. Knepley   PetscMPIInt       rank, size, p;
16566a5217c0SMatthew G. Knepley   const char       *name;
16576a5217c0SMatthew G. Knepley 
16586a5217c0SMatthew G. Knepley   PetscFunctionBegin;
16596a5217c0SMatthew G. Knepley   PetscCall(PetscViewerGetFormat(viewer, &format));
16606a5217c0SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
16616a5217c0SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(dm, &Np));
16626a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
16636a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
16646a5217c0SMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(comm, &size));
16656a5217c0SMatthew G. Knepley   PetscCall(PetscObjectGetName((PetscObject)dm, &name));
166663a3b9bcSJacob Faibussowitsch   if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
166763a3b9bcSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(viewer, "Swarm in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
16686a5217c0SMatthew G. Knepley   if (size < maxSize) PetscCall(PetscCalloc1(size, &sizes));
16696a5217c0SMatthew G. Knepley   else PetscCall(PetscCalloc1(3, &sizes));
16706a5217c0SMatthew G. Knepley   if (size < maxSize) {
16716a5217c0SMatthew G. Knepley     PetscCallMPI(MPI_Gather(&Np, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
16726a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of particles per rank:"));
16736a5217c0SMatthew G. Knepley     for (p = 0; p < size; ++p) {
16746a5217c0SMatthew G. Knepley       if (rank == 0) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]));
16756a5217c0SMatthew G. Knepley     }
16766a5217c0SMatthew G. Knepley   } else {
16776a5217c0SMatthew G. Knepley     PetscInt locMinMax[2] = {Np, Np};
16786a5217c0SMatthew G. Knepley 
16796a5217c0SMatthew G. Knepley     PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
16806a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of particles per rank: %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
16816a5217c0SMatthew G. Knepley   }
16826a5217c0SMatthew G. Knepley   PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
16836a5217c0SMatthew G. Knepley   PetscCall(PetscFree(sizes));
16846a5217c0SMatthew G. Knepley   if (format == PETSC_VIEWER_ASCII_INFO) {
16856a5217c0SMatthew G. Knepley     PetscInt *cell;
16866a5217c0SMatthew G. Knepley 
16876a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells containing each particle:\n"));
16886a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
16896a5217c0SMatthew G. Knepley     PetscCall(DMSwarmGetField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell));
169063a3b9bcSJacob Faibussowitsch     for (p = 0; p < Np; ++p) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  p%d: %" PetscInt_FMT "\n", p, cell[p]));
16916a5217c0SMatthew G. Knepley     PetscCall(PetscViewerFlush(viewer));
16926a5217c0SMatthew G. Knepley     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
16936a5217c0SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(dm, DMSwarmPICField_cellid, NULL, NULL, (void **)&cell));
16946a5217c0SMatthew G. Knepley   }
16953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16966a5217c0SMatthew G. Knepley }
16976a5217c0SMatthew G. Knepley 
169866976f2fSJacob Faibussowitsch static PetscErrorCode DMView_Swarm(DM dm, PetscViewer viewer)
1699d71ae5a4SJacob Faibussowitsch {
17005f50eb2eSDave May   DM_Swarm *swarm = (DM_Swarm *)dm->data;
17015627991aSBarry Smith   PetscBool iascii, ibinary, isvtk, isdraw;
17025627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
17035627991aSBarry Smith   PetscBool ishdf5;
17045627991aSBarry Smith #endif
17055f50eb2eSDave May 
17065f50eb2eSDave May   PetscFunctionBegin;
17075f50eb2eSDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
17085f50eb2eSDave May   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
17099566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
17109566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary));
17119566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
17125627991aSBarry Smith #if defined(PETSC_HAVE_HDF5)
17139566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
17145627991aSBarry Smith #endif
17159566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
17165f50eb2eSDave May   if (iascii) {
17176a5217c0SMatthew G. Knepley     PetscViewerFormat format;
17186a5217c0SMatthew G. Knepley 
17196a5217c0SMatthew G. Knepley     PetscCall(PetscViewerGetFormat(viewer, &format));
17206a5217c0SMatthew G. Knepley     switch (format) {
1721d71ae5a4SJacob Faibussowitsch     case PETSC_VIEWER_ASCII_INFO_DETAIL:
1722d71ae5a4SJacob Faibussowitsch       PetscCall(DMSwarmDataBucketView(PetscObjectComm((PetscObject)dm), swarm->db, NULL, DATABUCKET_VIEW_STDOUT));
1723d71ae5a4SJacob Faibussowitsch       break;
1724d71ae5a4SJacob Faibussowitsch     default:
1725d71ae5a4SJacob Faibussowitsch       PetscCall(DMView_Swarm_Ascii(dm, viewer));
17266a5217c0SMatthew G. Knepley     }
1727f7d195e4SLawrence Mitchell   } else {
17285f50eb2eSDave May #if defined(PETSC_HAVE_HDF5)
172948a46eb9SPierre Jolivet     if (ishdf5) PetscCall(DMSwarmView_HDF5(dm, viewer));
17305f50eb2eSDave May #endif
173148a46eb9SPierre Jolivet     if (isdraw) PetscCall(DMSwarmView_Draw(dm, viewer));
1732f7d195e4SLawrence Mitchell   }
17333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17345f50eb2eSDave May }
17355f50eb2eSDave May 
1736cc4c1da9SBarry Smith /*@
173720f4b53cSBarry Smith   DMSwarmGetCellSwarm - Extracts a single cell from the `DMSWARM` object, returns it as a single cell `DMSWARM`.
173820f4b53cSBarry Smith   The cell `DM` is filtered for fields of that cell, and the filtered `DM` is used as the cell `DM` of the new swarm object.
1739d0c080abSJoseph Pusztay 
1740d0c080abSJoseph Pusztay   Noncollective
1741d0c080abSJoseph Pusztay 
174260225df5SJacob Faibussowitsch   Input Parameters:
174320f4b53cSBarry Smith + sw        - the `DMSWARM`
17445627991aSBarry Smith . cellID    - the integer id of the cell to be extracted and filtered
174520f4b53cSBarry Smith - cellswarm - The `DMSWARM` to receive the cell
1746d0c080abSJoseph Pusztay 
1747d0c080abSJoseph Pusztay   Level: beginner
1748d0c080abSJoseph Pusztay 
17495627991aSBarry Smith   Notes:
175020f4b53cSBarry Smith   This presently only supports `DMSWARM_PIC` type
17515627991aSBarry Smith 
175220f4b53cSBarry Smith   Should be restored with `DMSwarmRestoreCellSwarm()`
1753d0c080abSJoseph Pusztay 
175420f4b53cSBarry Smith   Changes to this cell of the swarm will be lost if they are made prior to restoring this cell.
175520f4b53cSBarry Smith 
175620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmRestoreCellSwarm()`
1757d0c080abSJoseph Pusztay @*/
1758cc4c1da9SBarry Smith PetscErrorCode DMSwarmGetCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
1759d71ae5a4SJacob Faibussowitsch {
1760d0c080abSJoseph Pusztay   DM_Swarm *original = (DM_Swarm *)sw->data;
1761d0c080abSJoseph Pusztay   DMLabel   label;
1762d0c080abSJoseph Pusztay   DM        dmc, subdmc;
1763d0c080abSJoseph Pusztay   PetscInt *pids, particles, dim;
1764d0c080abSJoseph Pusztay 
1765d0c080abSJoseph Pusztay   PetscFunctionBegin;
1766d0c080abSJoseph Pusztay   /* Configure new swarm */
17679566063dSJacob Faibussowitsch   PetscCall(DMSetType(cellswarm, DMSWARM));
17689566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(sw, &dim));
17699566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(cellswarm, dim));
17709566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(cellswarm, DMSWARM_PIC));
1771d0c080abSJoseph Pusztay   /* Destroy the unused, unconfigured data bucket to prevent stragglers in memory */
17729566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketDestroy(&((DM_Swarm *)cellswarm->data)->db));
17739566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
17749566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, cellID, &particles));
17759566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
17769566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreateFromSubset(original->db, particles, pids, &((DM_Swarm *)cellswarm->data)->db));
17779566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
17789566063dSJacob Faibussowitsch   PetscCall(PetscFree(pids));
17799566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(sw, &dmc));
17809566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)sw), "singlecell", &label));
17819566063dSJacob Faibussowitsch   PetscCall(DMAddLabel(dmc, label));
17829566063dSJacob Faibussowitsch   PetscCall(DMLabelSetValue(label, cellID, 1));
178330cbcd5dSksagiyam   PetscCall(DMPlexFilter(dmc, label, 1, PETSC_FALSE, PETSC_FALSE, NULL, &subdmc));
17849566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetCellDM(cellswarm, subdmc));
17859566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&label));
17863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1787d0c080abSJoseph Pusztay }
1788d0c080abSJoseph Pusztay 
1789cc4c1da9SBarry Smith /*@
179020f4b53cSBarry Smith   DMSwarmRestoreCellSwarm - Restores a `DMSWARM` object obtained with `DMSwarmGetCellSwarm()`. All fields are copied back into the parent swarm.
1791d0c080abSJoseph Pusztay 
1792d0c080abSJoseph Pusztay   Noncollective
1793d0c080abSJoseph Pusztay 
179460225df5SJacob Faibussowitsch   Input Parameters:
179520f4b53cSBarry Smith + sw        - the parent `DMSWARM`
1796d0c080abSJoseph Pusztay . cellID    - the integer id of the cell to be copied back into the parent swarm
1797d0c080abSJoseph Pusztay - cellswarm - the cell swarm object
1798d0c080abSJoseph Pusztay 
1799d0c080abSJoseph Pusztay   Level: beginner
1800d0c080abSJoseph Pusztay 
18015627991aSBarry Smith   Note:
180220f4b53cSBarry Smith   This only supports `DMSWARM_PIC` types of `DMSWARM`s
1803d0c080abSJoseph Pusztay 
180420f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMSwarmGetCellSwarm()`
1805d0c080abSJoseph Pusztay @*/
1806cc4c1da9SBarry Smith PetscErrorCode DMSwarmRestoreCellSwarm(DM sw, PetscInt cellID, DM cellswarm)
1807d71ae5a4SJacob Faibussowitsch {
1808d0c080abSJoseph Pusztay   DM        dmc;
1809d0c080abSJoseph Pusztay   PetscInt *pids, particles, p;
1810d0c080abSJoseph Pusztay 
1811d0c080abSJoseph Pusztay   PetscFunctionBegin;
18129566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetAccess(sw));
18139566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortGetPointsPerCell(sw, cellID, &particles, &pids));
18149566063dSJacob Faibussowitsch   PetscCall(DMSwarmSortRestoreAccess(sw));
1815d0c080abSJoseph Pusztay   /* Pointwise copy of each particle based on pid. The parent swarm may not be altered during this process. */
181648a46eb9SPierre Jolivet   for (p = 0; p < particles; ++p) PetscCall(DMSwarmDataBucketCopyPoint(((DM_Swarm *)cellswarm->data)->db, pids[p], ((DM_Swarm *)sw->data)->db, pids[p]));
1817d0c080abSJoseph Pusztay   /* Free memory, destroy cell dm */
18189566063dSJacob Faibussowitsch   PetscCall(DMSwarmGetCellDM(cellswarm, &dmc));
18199566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmc));
18209566063dSJacob Faibussowitsch   PetscCall(PetscFree(pids));
18213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1822d0c080abSJoseph Pusztay }
1823d0c080abSJoseph Pusztay 
1824d0c080abSJoseph Pusztay PETSC_INTERN PetscErrorCode DMClone_Swarm(DM, DM *);
1825d0c080abSJoseph Pusztay 
1826d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMInitialize_Swarm(DM sw)
1827d71ae5a4SJacob Faibussowitsch {
1828d0c080abSJoseph Pusztay   PetscFunctionBegin;
1829d0c080abSJoseph Pusztay   sw->dim                           = 0;
1830d0c080abSJoseph Pusztay   sw->ops->view                     = DMView_Swarm;
1831d0c080abSJoseph Pusztay   sw->ops->load                     = NULL;
1832d0c080abSJoseph Pusztay   sw->ops->setfromoptions           = NULL;
1833d0c080abSJoseph Pusztay   sw->ops->clone                    = DMClone_Swarm;
1834d0c080abSJoseph Pusztay   sw->ops->setup                    = DMSetup_Swarm;
1835d0c080abSJoseph Pusztay   sw->ops->createlocalsection       = NULL;
1836adc21957SMatthew G. Knepley   sw->ops->createsectionpermutation = NULL;
1837d0c080abSJoseph Pusztay   sw->ops->createdefaultconstraints = NULL;
1838d0c080abSJoseph Pusztay   sw->ops->createglobalvector       = DMCreateGlobalVector_Swarm;
1839d0c080abSJoseph Pusztay   sw->ops->createlocalvector        = DMCreateLocalVector_Swarm;
1840d0c080abSJoseph Pusztay   sw->ops->getlocaltoglobalmapping  = NULL;
1841d0c080abSJoseph Pusztay   sw->ops->createfieldis            = NULL;
1842d0c080abSJoseph Pusztay   sw->ops->createcoordinatedm       = NULL;
1843d0c080abSJoseph Pusztay   sw->ops->getcoloring              = NULL;
1844d0c080abSJoseph Pusztay   sw->ops->creatematrix             = DMCreateMatrix_Swarm;
1845d0c080abSJoseph Pusztay   sw->ops->createinterpolation      = NULL;
1846d0c080abSJoseph Pusztay   sw->ops->createinjection          = NULL;
1847d0c080abSJoseph Pusztay   sw->ops->createmassmatrix         = DMCreateMassMatrix_Swarm;
1848d0c080abSJoseph Pusztay   sw->ops->refine                   = NULL;
1849d0c080abSJoseph Pusztay   sw->ops->coarsen                  = NULL;
1850d0c080abSJoseph Pusztay   sw->ops->refinehierarchy          = NULL;
1851d0c080abSJoseph Pusztay   sw->ops->coarsenhierarchy         = NULL;
1852d0c080abSJoseph Pusztay   sw->ops->globaltolocalbegin       = NULL;
1853d0c080abSJoseph Pusztay   sw->ops->globaltolocalend         = NULL;
1854d0c080abSJoseph Pusztay   sw->ops->localtoglobalbegin       = NULL;
1855d0c080abSJoseph Pusztay   sw->ops->localtoglobalend         = NULL;
1856d0c080abSJoseph Pusztay   sw->ops->destroy                  = DMDestroy_Swarm;
1857d0c080abSJoseph Pusztay   sw->ops->createsubdm              = NULL;
1858d0c080abSJoseph Pusztay   sw->ops->getdimpoints             = NULL;
1859d0c080abSJoseph Pusztay   sw->ops->locatepoints             = NULL;
18603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1861d0c080abSJoseph Pusztay }
1862d0c080abSJoseph Pusztay 
1863d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMClone_Swarm(DM dm, DM *newdm)
1864d71ae5a4SJacob Faibussowitsch {
1865d0c080abSJoseph Pusztay   DM_Swarm *swarm = (DM_Swarm *)dm->data;
1866d0c080abSJoseph Pusztay 
1867d0c080abSJoseph Pusztay   PetscFunctionBegin;
1868d0c080abSJoseph Pusztay   swarm->refct++;
1869d0c080abSJoseph Pusztay   (*newdm)->data = swarm;
18709566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMSWARM));
18719566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(*newdm));
18722e56dffeSJoe Pusztay   (*newdm)->dim = dm->dim;
18733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1874d0c080abSJoseph Pusztay }
1875d0c080abSJoseph Pusztay 
1876d3a51819SDave May /*MC
187720f4b53cSBarry Smith  DMSWARM = "swarm" - A `DM` object used to represent arrays of data (fields) of arbitrary data type.
187862741f57SDave May  This implementation was designed for particle methods in which the underlying
1879d3a51819SDave May  data required to be represented is both (i) dynamic in length, (ii) and of arbitrary data type.
1880d3a51819SDave May 
188120f4b53cSBarry Smith  Level: intermediate
188220f4b53cSBarry Smith 
188320f4b53cSBarry Smith   Notes:
188420f4b53cSBarry Smith  User data can be represented by `DMSWARM` through a registering "fields".
188562741f57SDave May  To register a field, the user must provide;
188662741f57SDave May  (a) a unique name;
188762741f57SDave May  (b) the data type (or size in bytes);
188862741f57SDave May  (c) the block size of the data.
1889d3a51819SDave May 
1890d3a51819SDave May  For example, suppose the application requires a unique id, energy, momentum and density to be stored
1891c215a47eSMatthew Knepley  on a set of particles. Then the following code could be used
189220f4b53cSBarry Smith .vb
189320f4b53cSBarry Smith     DMSwarmInitializeFieldRegister(dm)
189420f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"uid",1,PETSC_LONG);
189520f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"energy",1,PETSC_REAL);
189620f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"momentum",3,PETSC_REAL);
189720f4b53cSBarry Smith     DMSwarmRegisterPetscDatatypeField(dm,"density",1,PETSC_FLOAT);
189820f4b53cSBarry Smith     DMSwarmFinalizeFieldRegister(dm)
189920f4b53cSBarry Smith .ve
1900d3a51819SDave May 
190120f4b53cSBarry Smith  The fields represented by `DMSWARM` are dynamic and can be re-sized at any time.
190220f4b53cSBarry Smith  The only restriction imposed by `DMSWARM` is that all fields contain the same number of points.
1903d3a51819SDave May 
1904d3a51819SDave May  To support particle methods, "migration" techniques are provided. These methods migrate data
19055627991aSBarry Smith  between ranks.
1906d3a51819SDave May 
190720f4b53cSBarry Smith  `DMSWARM` supports the methods `DMCreateGlobalVector()` and `DMCreateLocalVector()`.
190820f4b53cSBarry Smith  As a `DMSWARM` may internally define and store values of different data types,
190920f4b53cSBarry Smith  before calling `DMCreateGlobalVector()` or `DMCreateLocalVector()`, the user must inform `DMSWARM` which
191020f4b53cSBarry Smith  fields should be used to define a `Vec` object via
191120f4b53cSBarry Smith    `DMSwarmVectorDefineField()`
1912c215a47eSMatthew Knepley  The specified field can be changed at any time - thereby permitting vectors
1913c215a47eSMatthew Knepley  compatible with different fields to be created.
1914d3a51819SDave May 
191520f4b53cSBarry Smith  A dual representation of fields in the `DMSWARM` and a Vec object is permitted via
191620f4b53cSBarry Smith    `DMSwarmCreateGlobalVectorFromField()`
191720f4b53cSBarry Smith  Here the data defining the field in the `DMSWARM` is shared with a Vec.
1918d3a51819SDave May  This is inherently unsafe if you alter the size of the field at any time between
191920f4b53cSBarry Smith  calls to `DMSwarmCreateGlobalVectorFromField()` and `DMSwarmDestroyGlobalVectorFromField()`.
192020f4b53cSBarry Smith  If the local size of the `DMSWARM` does not match the local size of the global vector
192120f4b53cSBarry Smith  when `DMSwarmDestroyGlobalVectorFromField()` is called, an error is thrown.
1922d3a51819SDave May 
192362741f57SDave May  Additional high-level support is provided for Particle-In-Cell methods.
192420f4b53cSBarry Smith  Please refer to `DMSwarmSetType()`.
192562741f57SDave May 
192620f4b53cSBarry Smith .seealso: `DM`, `DMSWARM`, `DMType`, `DMCreate()`, `DMSetType()`
1927d3a51819SDave May M*/
1928cc4c1da9SBarry Smith 
1929d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMCreate_Swarm(DM dm)
1930d71ae5a4SJacob Faibussowitsch {
193157795646SDave May   DM_Swarm *swarm;
193257795646SDave May 
193357795646SDave May   PetscFunctionBegin;
193457795646SDave May   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
19354dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&swarm));
1936f0cdbbbaSDave May   dm->data = swarm;
19379566063dSJacob Faibussowitsch   PetscCall(DMSwarmDataBucketCreate(&swarm->db));
19389566063dSJacob Faibussowitsch   PetscCall(DMSwarmInitializeFieldRegister(dm));
1939d0c080abSJoseph Pusztay   swarm->refct                          = 1;
1940b5bcf523SDave May   swarm->vec_field_set                  = PETSC_FALSE;
19413454631fSDave May   swarm->issetup                        = PETSC_FALSE;
1942480eef7bSDave May   swarm->swarm_type                     = DMSWARM_BASIC;
1943480eef7bSDave May   swarm->migrate_type                   = DMSWARM_MIGRATE_BASIC;
1944480eef7bSDave May   swarm->collect_type                   = DMSWARM_COLLECT_BASIC;
194540c453e9SDave May   swarm->migrate_error_on_missing_point = PETSC_FALSE;
1946f0cdbbbaSDave May   swarm->dmcell                         = NULL;
1947f0cdbbbaSDave May   swarm->collect_view_active            = PETSC_FALSE;
1948f0cdbbbaSDave May   swarm->collect_view_reset_nlocal      = -1;
19499566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Swarm(dm));
19502e956fe4SStefano Zampini   if (SwarmDataFieldId == -1) PetscCall(PetscObjectComposedDataRegister(&SwarmDataFieldId));
19513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
195257795646SDave May }
1953