1d0c080abSJoseph Pusztay static char help[] = "Example application of the Bhatnagar-Gross-Krook (BGK) collision operator.\n\
2d0c080abSJoseph Pusztay This example is a 0D-1V setting for the kinetic equation\n\
3d0c080abSJoseph Pusztay https://en.wikipedia.org/wiki/Bhatnagar%E2%80%93Gross%E2%80%93Krook_operator\n";
4d0c080abSJoseph Pusztay
5d0c080abSJoseph Pusztay #include <petscdmplex.h>
6d0c080abSJoseph Pusztay #include <petscdmswarm.h>
7d0c080abSJoseph Pusztay #include <petscts.h>
8d0c080abSJoseph Pusztay #include <petscdraw.h>
9d0c080abSJoseph Pusztay #include <petscviewer.h>
10d0c080abSJoseph Pusztay
11d0c080abSJoseph Pusztay typedef struct {
12d0c080abSJoseph Pusztay PetscInt particlesPerCell; /* The number of partices per cell */
13d0c080abSJoseph Pusztay PetscReal momentTol; /* Tolerance for checking moment conservation */
14d0c080abSJoseph Pusztay PetscBool monitorhg; /* Flag for using the TS histogram monitor */
15d0c080abSJoseph Pusztay PetscBool monitorsp; /* Flag for using the TS scatter monitor */
16d0c080abSJoseph Pusztay PetscBool monitorks; /* Monitor to perform KS test to the maxwellian */
17d0c080abSJoseph Pusztay PetscBool error; /* Flag for printing the error */
18d0c080abSJoseph Pusztay PetscInt ostep; /* print the energy at each ostep time steps */
19d0c080abSJoseph Pusztay PetscDraw draw; /* The draw object for histogram monitoring */
20d0c080abSJoseph Pusztay PetscDrawHG drawhg; /* The histogram draw context for monitoring */
21d0c080abSJoseph Pusztay PetscDrawSP drawsp; /* The scatter plot draw context for the monitor */
22d0c080abSJoseph Pusztay PetscDrawSP drawks; /* Scatterplot draw context for KS test */
23d0c080abSJoseph Pusztay } AppCtx;
24d0c080abSJoseph Pusztay
ProcessOptions(MPI_Comm comm,AppCtx * options)25d71ae5a4SJacob Faibussowitsch static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
26d71ae5a4SJacob Faibussowitsch {
27d0c080abSJoseph Pusztay PetscFunctionBeginUser;
28d0c080abSJoseph Pusztay options->monitorhg = PETSC_FALSE;
29d0c080abSJoseph Pusztay options->monitorsp = PETSC_FALSE;
30d0c080abSJoseph Pusztay options->monitorks = PETSC_FALSE;
31d0c080abSJoseph Pusztay options->particlesPerCell = 1;
32d0c080abSJoseph Pusztay options->momentTol = 100.0 * PETSC_MACHINE_EPSILON;
33d0c080abSJoseph Pusztay options->ostep = 100;
34d0c080abSJoseph Pusztay
35d0609cedSBarry Smith PetscOptionsBegin(comm, "", "Collision Options", "DMPLEX");
369566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-monitorhg", "Flag to use the TS histogram monitor", "ex28.c", options->monitorhg, &options->monitorhg, NULL));
379566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-monitorsp", "Flag to use the TS scatter plot monitor", "ex28.c", options->monitorsp, &options->monitorsp, NULL));
389566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-monitorks", "Flag to plot KS test results", "ex28.c", options->monitorks, &options->monitorks, NULL));
399566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-particles_per_cell", "Number of particles per cell", "ex28.c", options->particlesPerCell, &options->particlesPerCell, NULL));
40f3fa974cSJacob Faibussowitsch PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", "ex28.c", options->ostep, &options->ostep, NULL));
41d0609cedSBarry Smith PetscOptionsEnd();
423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
43d0c080abSJoseph Pusztay }
44d0c080abSJoseph Pusztay
45d0c080abSJoseph Pusztay /* Create the mesh for velocity space */
CreateMesh(MPI_Comm comm,DM * dm,AppCtx * user)46d71ae5a4SJacob Faibussowitsch static PetscErrorCode CreateMesh(MPI_Comm comm, DM *dm, AppCtx *user)
47d71ae5a4SJacob Faibussowitsch {
48d0c080abSJoseph Pusztay PetscFunctionBeginUser;
499566063dSJacob Faibussowitsch PetscCall(DMCreate(comm, dm));
509566063dSJacob Faibussowitsch PetscCall(DMSetType(*dm, DMPLEX));
519566063dSJacob Faibussowitsch PetscCall(DMSetFromOptions(*dm));
529566063dSJacob Faibussowitsch PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
54d0c080abSJoseph Pusztay }
55d0c080abSJoseph Pusztay
56d0c080abSJoseph Pusztay /* Since we are putting the same number of particles in each cell, this amounts to a uniform distribution of v */
SetInitialCoordinates(DM sw)57d71ae5a4SJacob Faibussowitsch static PetscErrorCode SetInitialCoordinates(DM sw)
58d71ae5a4SJacob Faibussowitsch {
59d0c080abSJoseph Pusztay AppCtx *user;
60d0c080abSJoseph Pusztay PetscRandom rnd;
61d0c080abSJoseph Pusztay DM dm;
62d0c080abSJoseph Pusztay DMPolytopeType ct;
63d0c080abSJoseph Pusztay PetscBool simplex;
64d0c080abSJoseph Pusztay PetscReal *centroid, *coords, *xi0, *v0, *J, *invJ, detJ, *vals;
65d0c080abSJoseph Pusztay PetscInt dim, d, cStart, cEnd, c, Np, p;
66d0c080abSJoseph Pusztay
67d0c080abSJoseph Pusztay PetscFunctionBeginUser;
689566063dSJacob Faibussowitsch PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)sw), &rnd));
699566063dSJacob Faibussowitsch PetscCall(PetscRandomSetInterval(rnd, -1.0, 1.0));
709566063dSJacob Faibussowitsch PetscCall(PetscRandomSetFromOptions(rnd));
71d0c080abSJoseph Pusztay
729566063dSJacob Faibussowitsch PetscCall(DMGetApplicationContext(sw, &user));
73d0c080abSJoseph Pusztay Np = user->particlesPerCell;
749566063dSJacob Faibussowitsch PetscCall(DMGetDimension(sw, &dim));
759566063dSJacob Faibussowitsch PetscCall(DMSwarmGetCellDM(sw, &dm));
769f4ada15SMatthew G. Knepley PetscCall(DMGetCoordinatesLocalSetUp(dm));
779566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
789566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellType(dm, cStart, &ct));
79d0c080abSJoseph Pusztay simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
809566063dSJacob Faibussowitsch PetscCall(PetscMalloc5(dim, ¢roid, dim, &xi0, dim, &v0, dim * dim, &J, dim * dim, &invJ));
81d0c080abSJoseph Pusztay for (d = 0; d < dim; ++d) xi0[d] = -1.0;
829566063dSJacob Faibussowitsch PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
839566063dSJacob Faibussowitsch PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&vals));
84d0c080abSJoseph Pusztay for (c = cStart; c < cEnd; ++c) {
85d0c080abSJoseph Pusztay if (Np == 1) {
869566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFVM(dm, c, NULL, centroid, NULL));
87d0c080abSJoseph Pusztay for (d = 0; d < dim; ++d) {
88d0c080abSJoseph Pusztay coords[c * dim + d] = centroid[d];
89d0c080abSJoseph Pusztay if ((coords[c * dim + d] >= -1) && (coords[c * dim + d] <= 1)) {
90d0c080abSJoseph Pusztay vals[c] = 1.0;
91d0c080abSJoseph Pusztay } else {
92d0c080abSJoseph Pusztay vals[c] = 0.;
93d0c080abSJoseph Pusztay }
94d0c080abSJoseph Pusztay }
95d0c080abSJoseph Pusztay } else {
969566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ)); /* affine */
97d0c080abSJoseph Pusztay for (p = 0; p < Np; ++p) {
98d0c080abSJoseph Pusztay const PetscInt n = c * Np + p;
99d0c080abSJoseph Pusztay PetscReal sum = 0.0, refcoords[3];
100d0c080abSJoseph Pusztay
101d0c080abSJoseph Pusztay for (d = 0; d < dim; ++d) {
1029566063dSJacob Faibussowitsch PetscCall(PetscRandomGetValueReal(rnd, &refcoords[d]));
103d0c080abSJoseph Pusztay sum += refcoords[d];
104d0c080abSJoseph Pusztay }
1059371c9d4SSatish Balay if (simplex && sum > 0.0)
1069371c9d4SSatish Balay for (d = 0; d < dim; ++d) refcoords[d] -= PetscSqrtReal(dim) * sum;
107d0c080abSJoseph Pusztay vals[n] = 1.0;
1089566063dSJacob Faibussowitsch PetscCall(DMPlexReferenceToCoordinates(dm, c, 1, refcoords, &coords[n * dim]));
109d0c080abSJoseph Pusztay }
110d0c080abSJoseph Pusztay }
111d0c080abSJoseph Pusztay }
1129566063dSJacob Faibussowitsch PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1139566063dSJacob Faibussowitsch PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&vals));
1149566063dSJacob Faibussowitsch PetscCall(PetscFree5(centroid, xi0, v0, J, invJ));
1159566063dSJacob Faibussowitsch PetscCall(PetscRandomDestroy(&rnd));
1163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
117d0c080abSJoseph Pusztay }
118d0c080abSJoseph Pusztay
119da81f932SPierre Jolivet /* The initial conditions are just the initial particle weights */
SetInitialConditions(DM dmSw,Vec u)120d71ae5a4SJacob Faibussowitsch static PetscErrorCode SetInitialConditions(DM dmSw, Vec u)
121d71ae5a4SJacob Faibussowitsch {
122d0c080abSJoseph Pusztay DM dm;
123d0c080abSJoseph Pusztay AppCtx *user;
124d0c080abSJoseph Pusztay PetscReal *vals;
125d0c080abSJoseph Pusztay PetscScalar *initialConditions;
126d0c080abSJoseph Pusztay PetscInt dim, d, cStart, cEnd, c, Np, p, n;
127d0c080abSJoseph Pusztay
128d0c080abSJoseph Pusztay PetscFunctionBeginUser;
1299566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(u, &n));
1309566063dSJacob Faibussowitsch PetscCall(DMGetApplicationContext(dmSw, &user));
131d0c080abSJoseph Pusztay Np = user->particlesPerCell;
1329566063dSJacob Faibussowitsch PetscCall(DMSwarmGetCellDM(dmSw, &dm));
1339566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim));
1349566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
13563a3b9bcSJacob Faibussowitsch PetscCheck(n == (cEnd - cStart) * Np, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "TS solution local size %" PetscInt_FMT " != %" PetscInt_FMT " nm particles", n, (cEnd - cStart) * Np);
1369566063dSJacob Faibussowitsch PetscCall(DMSwarmGetField(dmSw, "w_q", NULL, NULL, (void **)&vals));
1379566063dSJacob Faibussowitsch PetscCall(VecGetArray(u, &initialConditions));
138d0c080abSJoseph Pusztay for (c = cStart; c < cEnd; ++c) {
139d0c080abSJoseph Pusztay for (p = 0; p < Np; ++p) {
140d0c080abSJoseph Pusztay const PetscInt n = c * Np + p;
141ad540459SPierre Jolivet for (d = 0; d < dim; d++) initialConditions[n] = vals[n];
142d0c080abSJoseph Pusztay }
143d0c080abSJoseph Pusztay }
1449566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(u, &initialConditions));
1459566063dSJacob Faibussowitsch PetscCall(DMSwarmRestoreField(dmSw, "w_q", NULL, NULL, (void **)&vals));
1463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
147d0c080abSJoseph Pusztay }
148d0c080abSJoseph Pusztay
CreateParticles(DM dm,DM * sw,AppCtx * user)149d71ae5a4SJacob Faibussowitsch static PetscErrorCode CreateParticles(DM dm, DM *sw, AppCtx *user)
150d71ae5a4SJacob Faibussowitsch {
15119307e5cSMatthew G. Knepley DMSwarmCellDM celldm;
15219307e5cSMatthew G. Knepley PetscInt *swarm_cellid;
153d0c080abSJoseph Pusztay PetscInt dim, cStart, cEnd, c, Np = user->particlesPerCell, p;
15419307e5cSMatthew G. Knepley const char *cellid;
155d0c080abSJoseph Pusztay
156d0c080abSJoseph Pusztay PetscFunctionBeginUser;
1579566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim));
1589566063dSJacob Faibussowitsch PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw));
1599566063dSJacob Faibussowitsch PetscCall(DMSetType(*sw, DMSWARM));
1609566063dSJacob Faibussowitsch PetscCall(DMSetDimension(*sw, dim));
1619566063dSJacob Faibussowitsch PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC));
1629566063dSJacob Faibussowitsch PetscCall(DMSwarmSetCellDM(*sw, dm));
1639566063dSJacob Faibussowitsch PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "kinematics", dim, PETSC_REAL));
1649566063dSJacob Faibussowitsch PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR));
1659566063dSJacob Faibussowitsch PetscCall(DMSwarmFinalizeFieldRegister(*sw));
16619307e5cSMatthew G. Knepley PetscCall(DMSwarmGetCellDMActive(*sw, &celldm));
16719307e5cSMatthew G. Knepley PetscCall(DMSwarmCellDMGetCellID(celldm, &cellid));
1689566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1699566063dSJacob Faibussowitsch PetscCall(DMSwarmSetLocalSizes(*sw, (cEnd - cStart) * Np, 0));
1709566063dSJacob Faibussowitsch PetscCall(DMSetFromOptions(*sw));
17119307e5cSMatthew G. Knepley PetscCall(DMSwarmGetField(*sw, cellid, NULL, NULL, (void **)&swarm_cellid));
172d0c080abSJoseph Pusztay for (c = cStart; c < cEnd; ++c) {
173d0c080abSJoseph Pusztay for (p = 0; p < Np; ++p) {
174d0c080abSJoseph Pusztay const PetscInt n = c * Np + p;
17519307e5cSMatthew G. Knepley swarm_cellid[n] = c;
176d0c080abSJoseph Pusztay }
177d0c080abSJoseph Pusztay }
17819307e5cSMatthew G. Knepley PetscCall(DMSwarmRestoreField(*sw, cellid, NULL, NULL, (void **)&swarm_cellid));
1799566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles"));
1809566063dSJacob Faibussowitsch PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view"));
1813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
182d0c080abSJoseph Pusztay }
183d0c080abSJoseph Pusztay
184d0c080abSJoseph Pusztay /*
185d0c080abSJoseph Pusztay f_t = 1/\tau \left( f_eq - f \right)
186d0c080abSJoseph Pusztay n_t = 1/\tau \left( \int f_eq - \int f \right) = 1/\tau (n - n) = 0
187d0c080abSJoseph Pusztay v_t = 1/\tau \left( \int v f_eq - \int v f \right) = 1/\tau (v - v) = 0
188d0c080abSJoseph Pusztay E_t = 1/\tau \left( \int v^2 f_eq - \int v^2 f \right) = 1/\tau (T - T) = 0
189d0c080abSJoseph Pusztay
190d0c080abSJoseph Pusztay Let's look at a single cell:
191d0c080abSJoseph Pusztay
192d0c080abSJoseph Pusztay \int_C f_t = 1/\tau \left( \int_C f_eq - \int_C f \right)
193d0c080abSJoseph Pusztay \sum_{x_i \in C} w^i_t = 1/\tau \left( F_eq(C) - \sum_{x_i \in C} w_i \right)
194d0c080abSJoseph Pusztay */
195d0c080abSJoseph Pusztay
196d0c080abSJoseph Pusztay /* This computes the 1D Maxwellian distribution for given mass n, velocity v, and temperature T */
ComputePDF(PetscReal m,PetscReal n,PetscReal T,PetscReal v[])197d71ae5a4SJacob Faibussowitsch static PetscReal ComputePDF(PetscReal m, PetscReal n, PetscReal T, PetscReal v[])
198d71ae5a4SJacob Faibussowitsch {
199d0c080abSJoseph Pusztay return (n / PetscSqrtReal(2.0 * PETSC_PI * T / m)) * PetscExpReal(-0.5 * m * PetscSqr(v[0]) / T);
200d0c080abSJoseph Pusztay }
201d0c080abSJoseph Pusztay
202d0c080abSJoseph Pusztay /*
203d0c080abSJoseph Pusztay erf z = \frac{2}{\sqrt\pi} \int^z_0 dt e^{-t^2} and erf \infty = 1
204d0c080abSJoseph Pusztay
205d0c080abSJoseph Pusztay We begin with our distribution
206d0c080abSJoseph Pusztay
207d0c080abSJoseph Pusztay \sqrt{\frac{m}{2 \pi T}} e^{-m v^2/2T}
208d0c080abSJoseph Pusztay
209d0c080abSJoseph Pusztay Let t = \sqrt{m/2T} v, z = \sqrt{m/2T} w, so that we now have
210d0c080abSJoseph Pusztay
211d0c080abSJoseph Pusztay \sqrt{\frac{m}{2 \pi T}} \int^w_0 dv e^{-m v^2/2T}
212d0c080abSJoseph Pusztay = \sqrt{\frac{m}{2 \pi T}} \int^{\sqrt{m/2T} w}_0 \sqrt{2T/m} dt e^{-t^2}
213d0c080abSJoseph Pusztay = 1/\sqrt{\pi} \int^{\sqrt{m/2T} w}_0 dt e^{-t^2}
214d0c080abSJoseph Pusztay = 1/2 erf(\sqrt{m/2T} w)
215d0c080abSJoseph Pusztay */
ComputeCDF(PetscReal m,PetscReal n,PetscReal T,PetscReal va,PetscReal vb)216d71ae5a4SJacob Faibussowitsch static PetscReal ComputeCDF(PetscReal m, PetscReal n, PetscReal T, PetscReal va, PetscReal vb)
217d71ae5a4SJacob Faibussowitsch {
218d0c080abSJoseph Pusztay PetscReal alpha = PetscSqrtReal(0.5 * m / T);
219d0c080abSJoseph Pusztay PetscReal za = alpha * va;
220d0c080abSJoseph Pusztay PetscReal zb = alpha * vb;
221d0c080abSJoseph Pusztay PetscReal sum = 0.0;
222d0c080abSJoseph Pusztay
223d0c080abSJoseph Pusztay sum += zb >= 0 ? erf(zb) : -erf(-zb);
224d0c080abSJoseph Pusztay sum -= za >= 0 ? erf(za) : -erf(-za);
225d0c080abSJoseph Pusztay return 0.5 * n * sum;
226d0c080abSJoseph Pusztay }
227d0c080abSJoseph Pusztay
CheckDistribution(DM dm,PetscReal m,PetscReal n,PetscReal T,PetscReal v[])228d71ae5a4SJacob Faibussowitsch static PetscErrorCode CheckDistribution(DM dm, PetscReal m, PetscReal n, PetscReal T, PetscReal v[])
229d71ae5a4SJacob Faibussowitsch {
230d0c080abSJoseph Pusztay PetscSection coordSection;
231d0c080abSJoseph Pusztay Vec coordsLocal;
232d0c080abSJoseph Pusztay PetscReal *xq, *wq;
233d0c080abSJoseph Pusztay PetscReal vmin, vmax, neq, veq, Teq;
234d0c080abSJoseph Pusztay PetscInt Nq = 100, q, cStart, cEnd, c;
235d0c080abSJoseph Pusztay
2367510d9b0SBarry Smith PetscFunctionBeginUser;
2379566063dSJacob Faibussowitsch PetscCall(DMGetBoundingBox(dm, &vmin, &vmax));
238d0c080abSJoseph Pusztay /* Check analytic over entire line */
239d0c080abSJoseph Pusztay neq = ComputeCDF(m, n, T, vmin, vmax);
24063a3b9bcSJacob Faibussowitsch PetscCheck(PetscAbsReal(neq - n) <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Int f %g != %g mass (%g)", (double)neq, (double)n, (double)(neq - n));
241d0c080abSJoseph Pusztay /* Check analytic over cells */
2429566063dSJacob Faibussowitsch PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
2439566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateSection(dm, &coordSection));
2449566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
245d0c080abSJoseph Pusztay neq = 0.0;
246d0c080abSJoseph Pusztay for (c = cStart; c < cEnd; ++c) {
247d0c080abSJoseph Pusztay PetscScalar *vcoords = NULL;
248d0c080abSJoseph Pusztay
2499566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &vcoords));
250d0c080abSJoseph Pusztay neq += ComputeCDF(m, n, T, vcoords[0], vcoords[1]);
2519566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &vcoords));
252d0c080abSJoseph Pusztay }
25363a3b9bcSJacob Faibussowitsch PetscCheck(PetscAbsReal(neq - n) <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell Int f %g != %g mass (%g)", (double)neq, (double)n, (double)(neq - n));
254d0c080abSJoseph Pusztay /* Check quadrature over entire line */
2559566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(Nq, &xq, Nq, &wq));
2569566063dSJacob Faibussowitsch PetscCall(PetscDTGaussQuadrature(100, vmin, vmax, xq, wq));
257d0c080abSJoseph Pusztay neq = 0.0;
258ad540459SPierre Jolivet for (q = 0; q < Nq; ++q) neq += ComputePDF(m, n, T, &xq[q]) * wq[q];
25963a3b9bcSJacob Faibussowitsch PetscCheck(PetscAbsReal(neq - n) <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Int f %g != %g mass (%g)", (double)neq, (double)n, (double)(neq - n));
260d0c080abSJoseph Pusztay /* Check omemnts with quadrature */
261d0c080abSJoseph Pusztay veq = 0.0;
262ad540459SPierre Jolivet for (q = 0; q < Nq; ++q) veq += xq[q] * ComputePDF(m, n, T, &xq[q]) * wq[q];
263d0c080abSJoseph Pusztay veq /= neq;
26463a3b9bcSJacob Faibussowitsch PetscCheck(PetscAbsReal(veq - v[0]) <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Int v f %g != %g velocity (%g)", (double)veq, (double)v[0], (double)(veq - v[0]));
265d0c080abSJoseph Pusztay Teq = 0.0;
266ad540459SPierre Jolivet for (q = 0; q < Nq; ++q) Teq += PetscSqr(xq[q]) * ComputePDF(m, n, T, &xq[q]) * wq[q];
267d0c080abSJoseph Pusztay Teq = Teq * m / neq - PetscSqr(veq);
26863a3b9bcSJacob Faibussowitsch PetscCheck(PetscAbsReal(Teq - T) <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Int v^2 f %g != %g temperature (%g)", (double)Teq, (double)T, (double)(Teq - T));
2699566063dSJacob Faibussowitsch PetscCall(PetscFree2(xq, wq));
2703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
271d0c080abSJoseph Pusztay }
272d0c080abSJoseph Pusztay
RHSFunctionParticles(TS ts,PetscReal t,Vec U,Vec R,PetscCtx ctx)273*2a8381b2SBarry Smith static PetscErrorCode RHSFunctionParticles(TS ts, PetscReal t, Vec U, Vec R, PetscCtx ctx)
274d71ae5a4SJacob Faibussowitsch {
275d0c080abSJoseph Pusztay const PetscScalar *u;
276d0c080abSJoseph Pusztay PetscSection coordSection;
277d0c080abSJoseph Pusztay Vec coordsLocal;
278d0c080abSJoseph Pusztay PetscScalar *r, *coords;
279d0c080abSJoseph Pusztay PetscReal n = 0.0, v = 0.0, E = 0.0, T = 0.0, m = 1.0, cn = 0.0, cv = 0.0, cE = 0.0, pE = 0.0, eqE = 0.0;
280d0c080abSJoseph Pusztay PetscInt dim, d, Np, Ncp, p, cStart, cEnd, c;
281d0c080abSJoseph Pusztay DM dmSw, plex;
282d0c080abSJoseph Pusztay
283d0c080abSJoseph Pusztay PetscFunctionBeginUser;
2849566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(U, &Np));
2859566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(U, &u));
2869566063dSJacob Faibussowitsch PetscCall(VecGetArray(R, &r));
2879566063dSJacob Faibussowitsch PetscCall(TSGetDM(ts, &dmSw));
2889566063dSJacob Faibussowitsch PetscCall(DMSwarmGetCellDM(dmSw, &plex));
2899566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmSw, &dim));
2909566063dSJacob Faibussowitsch PetscCall(DMGetCoordinatesLocal(plex, &coordsLocal));
2919566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateSection(plex, &coordSection));
2929566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
293d0c080abSJoseph Pusztay Np /= dim;
294d0c080abSJoseph Pusztay Ncp = Np / (cEnd - cStart);
295d0c080abSJoseph Pusztay /* Calculate moments of particle distribution, note that velocity is in the coordinate */
2969566063dSJacob Faibussowitsch PetscCall(DMSwarmGetField(dmSw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
297d0c080abSJoseph Pusztay for (p = 0; p < Np; ++p) {
298d0c080abSJoseph Pusztay PetscReal m1 = 0.0, m2 = 0.0;
299d0c080abSJoseph Pusztay
3009371c9d4SSatish Balay for (d = 0; d < dim; ++d) {
3019371c9d4SSatish Balay m1 += PetscRealPart(coords[p * dim + d]);
3029371c9d4SSatish Balay m2 += PetscSqr(PetscRealPart(coords[p * dim + d]));
3039371c9d4SSatish Balay }
304d0c080abSJoseph Pusztay n += u[p];
305d0c080abSJoseph Pusztay v += u[p] * m1;
306d0c080abSJoseph Pusztay E += u[p] * m2;
307d0c080abSJoseph Pusztay }
308d0c080abSJoseph Pusztay v /= n;
309d0c080abSJoseph Pusztay T = E * m / n - v * v;
31063a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(ts, "Time %.2f: mass %.4f velocity: %+.4f temperature: %.4f\n", (double)t, (double)n, (double)v, (double)T));
3119566063dSJacob Faibussowitsch PetscCall(CheckDistribution(plex, m, n, T, &v));
312d0c080abSJoseph Pusztay /*
313d0c080abSJoseph Pusztay Begin cellwise evaluation of the collision operator. Essentially, penalize the weights of the particles
314d0c080abSJoseph Pusztay in that cell against the maxwellian for the number of particles expected to be in that cell
315d0c080abSJoseph Pusztay */
316d0c080abSJoseph Pusztay for (c = cStart; c < cEnd; ++c) {
317d0c080abSJoseph Pusztay PetscScalar *vcoords = NULL;
318d0c080abSJoseph Pusztay PetscReal relaxation = 1.0, neq;
319d0c080abSJoseph Pusztay PetscInt sp = c * Ncp, q;
320d0c080abSJoseph Pusztay
321d0c080abSJoseph Pusztay /* Calculate equilibrium occupation for this velocity cell */
3229566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, coordSection, coordsLocal, c, NULL, &vcoords));
323d0c080abSJoseph Pusztay neq = ComputeCDF(m, n, T, vcoords[0], vcoords[1]);
3249566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, coordSection, coordsLocal, c, NULL, &vcoords));
325d0c080abSJoseph Pusztay for (q = 0; q < Ncp; ++q) r[sp + q] = (1.0 / relaxation) * (neq - u[sp + q]);
326d0c080abSJoseph Pusztay }
327d0c080abSJoseph Pusztay /* Check update */
328d0c080abSJoseph Pusztay for (p = 0; p < Np; ++p) {
329d0c080abSJoseph Pusztay PetscReal m1 = 0.0, m2 = 0.0;
330d0c080abSJoseph Pusztay PetscScalar *vcoords = NULL;
331d0c080abSJoseph Pusztay
3329371c9d4SSatish Balay for (d = 0; d < dim; ++d) {
3339371c9d4SSatish Balay m1 += PetscRealPart(coords[p * dim + d]);
3349371c9d4SSatish Balay m2 += PetscSqr(PetscRealPart(coords[p * dim + d]));
3359371c9d4SSatish Balay }
336d0c080abSJoseph Pusztay cn += r[p];
337d0c080abSJoseph Pusztay cv += r[p] * m1;
338d0c080abSJoseph Pusztay cE += r[p] * m2;
339d0c080abSJoseph Pusztay pE += u[p] * m2;
3409566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, coordSection, coordsLocal, p, NULL, &vcoords));
341d0c080abSJoseph Pusztay eqE += ComputeCDF(m, n, T, vcoords[0], vcoords[1]) * m2;
3429566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, coordSection, coordsLocal, p, NULL, &vcoords));
343d0c080abSJoseph Pusztay }
34463a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(ts, "Time %.2f: mass update %.8f velocity update: %+.8f energy update: %.8f (%.8f, %.8f)\n", (double)t, (double)cn, (double)cv, (double)cE, (double)pE, (double)eqE));
3459566063dSJacob Faibussowitsch PetscCall(DMSwarmRestoreField(dmSw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
3469566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(U, &u));
3479566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(R, &r));
3483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
349d0c080abSJoseph Pusztay }
350d0c080abSJoseph Pusztay
HGMonitor(TS ts,PetscInt step,PetscReal t,Vec U,PetscCtx ctx)351*2a8381b2SBarry Smith static PetscErrorCode HGMonitor(TS ts, PetscInt step, PetscReal t, Vec U, PetscCtx ctx)
352d71ae5a4SJacob Faibussowitsch {
353d0c080abSJoseph Pusztay AppCtx *user = (AppCtx *)ctx;
354d0c080abSJoseph Pusztay const PetscScalar *u;
355d0c080abSJoseph Pusztay DM sw, dm;
356d0c080abSJoseph Pusztay PetscInt dim, Np, p;
357d0c080abSJoseph Pusztay
358d0c080abSJoseph Pusztay PetscFunctionBeginUser;
3593ba16761SJacob Faibussowitsch if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
360f4f49eeaSPierre Jolivet if ((user->ostep > 0) && (!(step % user->ostep))) {
361d0c080abSJoseph Pusztay PetscDrawAxis axis;
362d0c080abSJoseph Pusztay
3639566063dSJacob Faibussowitsch PetscCall(TSGetDM(ts, &sw));
3649566063dSJacob Faibussowitsch PetscCall(DMSwarmGetCellDM(sw, &dm));
3659566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim));
3669566063dSJacob Faibussowitsch PetscCall(PetscDrawHGReset(user->drawhg));
3679566063dSJacob Faibussowitsch PetscCall(PetscDrawHGGetAxis(user->drawhg, &axis));
3689566063dSJacob Faibussowitsch PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "V", "f(V)"));
3699566063dSJacob Faibussowitsch PetscCall(PetscDrawAxisSetLimits(axis, -3, 3, 0, 100));
3709566063dSJacob Faibussowitsch PetscCall(PetscDrawHGSetLimits(user->drawhg, -3.0, 3.0, 0, 10));
3719566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(U, &Np));
372d0c080abSJoseph Pusztay Np /= dim;
3739566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(U, &u));
374d0c080abSJoseph Pusztay /* get points from solution vector */
3759566063dSJacob Faibussowitsch for (p = 0; p < Np; ++p) PetscCall(PetscDrawHGAddValue(user->drawhg, u[p]));
3769566063dSJacob Faibussowitsch PetscCall(PetscDrawHGDraw(user->drawhg));
3779566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(U, &u));
378d0c080abSJoseph Pusztay }
3793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
380d0c080abSJoseph Pusztay }
381d0c080abSJoseph Pusztay
SPMonitor(TS ts,PetscInt step,PetscReal t,Vec U,PetscCtx ctx)382*2a8381b2SBarry Smith static PetscErrorCode SPMonitor(TS ts, PetscInt step, PetscReal t, Vec U, PetscCtx ctx)
383d71ae5a4SJacob Faibussowitsch {
384d0c080abSJoseph Pusztay AppCtx *user = (AppCtx *)ctx;
385d0c080abSJoseph Pusztay const PetscScalar *u;
386d0c080abSJoseph Pusztay PetscReal *v, *coords;
387d0c080abSJoseph Pusztay PetscInt Np, p;
388d0c080abSJoseph Pusztay DM dmSw;
389d0c080abSJoseph Pusztay
390d0c080abSJoseph Pusztay PetscFunctionBeginUser;
3913ba16761SJacob Faibussowitsch if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
392f4f49eeaSPierre Jolivet if ((user->ostep > 0) && (!(step % user->ostep))) {
393d0c080abSJoseph Pusztay PetscDrawAxis axis;
394d0c080abSJoseph Pusztay
3959566063dSJacob Faibussowitsch PetscCall(TSGetDM(ts, &dmSw));
3969566063dSJacob Faibussowitsch PetscCall(PetscDrawSPReset(user->drawsp));
3979566063dSJacob Faibussowitsch PetscCall(PetscDrawSPGetAxis(user->drawsp, &axis));
3989566063dSJacob Faibussowitsch PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "V", "w"));
3999566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(U, &Np));
4009566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(U, &u));
401d0c080abSJoseph Pusztay /* get points from solution vector */
4029566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Np, &v));
403d0c080abSJoseph Pusztay for (p = 0; p < Np; ++p) v[p] = PetscRealPart(u[p]);
4049566063dSJacob Faibussowitsch PetscCall(DMSwarmGetField(dmSw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
4059566063dSJacob Faibussowitsch for (p = 0; p < Np - 1; ++p) PetscCall(PetscDrawSPAddPoint(user->drawsp, &coords[p], &v[p]));
4069566063dSJacob Faibussowitsch PetscCall(PetscDrawSPDraw(user->drawsp, PETSC_TRUE));
4079566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(U, &u));
4089566063dSJacob Faibussowitsch PetscCall(DMSwarmRestoreField(dmSw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
4099566063dSJacob Faibussowitsch PetscCall(PetscFree(v));
410d0c080abSJoseph Pusztay }
4113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
412d0c080abSJoseph Pusztay }
413d0c080abSJoseph Pusztay
KSConv(TS ts,PetscInt step,PetscReal t,Vec U,PetscCtx ctx)414*2a8381b2SBarry Smith static PetscErrorCode KSConv(TS ts, PetscInt step, PetscReal t, Vec U, PetscCtx ctx)
415d71ae5a4SJacob Faibussowitsch {
416d0c080abSJoseph Pusztay AppCtx *user = (AppCtx *)ctx;
417d0c080abSJoseph Pusztay const PetscScalar *u;
418d0c080abSJoseph Pusztay PetscScalar sup;
419d0c080abSJoseph Pusztay PetscReal *v, *coords, T = 0., vel = 0., step_cast, w_sum;
420d0c080abSJoseph Pusztay PetscInt dim, Np, p, cStart, cEnd;
421d0c080abSJoseph Pusztay DM sw, plex;
422d0c080abSJoseph Pusztay
423d0c080abSJoseph Pusztay PetscFunctionBeginUser;
4243ba16761SJacob Faibussowitsch if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
425f4f49eeaSPierre Jolivet if ((user->ostep > 0) && (!(step % user->ostep))) {
426d0c080abSJoseph Pusztay PetscDrawAxis axis;
4279566063dSJacob Faibussowitsch PetscCall(PetscDrawSPGetAxis(user->drawks, &axis));
4289566063dSJacob Faibussowitsch PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "t", "D_n"));
4299566063dSJacob Faibussowitsch PetscCall(PetscDrawSPSetLimits(user->drawks, 0., 100, 0., 3.5));
4309566063dSJacob Faibussowitsch PetscCall(TSGetDM(ts, &sw));
4319566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(U, &Np));
4329566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(U, &u));
433d0c080abSJoseph Pusztay /* get points from solution vector */
4349566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Np, &v));
4359566063dSJacob Faibussowitsch PetscCall(DMSwarmGetCellDM(sw, &plex));
4369566063dSJacob Faibussowitsch PetscCall(DMGetDimension(sw, &dim));
4379566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
438d0c080abSJoseph Pusztay for (p = 0; p < Np; ++p) v[p] = PetscRealPart(u[p]);
4399566063dSJacob Faibussowitsch PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
440d0c080abSJoseph Pusztay w_sum = 0.;
441d0c080abSJoseph Pusztay for (p = 0; p < Np; ++p) {
442d0c080abSJoseph Pusztay w_sum += u[p];
443d0c080abSJoseph Pusztay T += u[p] * coords[p] * coords[p];
444d0c080abSJoseph Pusztay vel += u[p] * coords[p];
445d0c080abSJoseph Pusztay }
446d0c080abSJoseph Pusztay vel /= w_sum;
447d0c080abSJoseph Pusztay T = T / w_sum - vel * vel;
448d0c080abSJoseph Pusztay sup = 0.0;
449d0c080abSJoseph Pusztay for (p = 0; p < Np; ++p) {
450d0c080abSJoseph Pusztay PetscReal tmp = 0.;
451d0c080abSJoseph Pusztay tmp = PetscAbs(u[p] - ComputePDF(1.0, w_sum, T, &coords[p * dim]));
452d0c080abSJoseph Pusztay if (tmp > sup) sup = tmp;
453d0c080abSJoseph Pusztay }
454d0c080abSJoseph Pusztay step_cast = (PetscReal)step;
4559566063dSJacob Faibussowitsch PetscCall(PetscDrawSPAddPoint(user->drawks, &step_cast, &sup));
4569566063dSJacob Faibussowitsch PetscCall(PetscDrawSPDraw(user->drawks, PETSC_TRUE));
4579566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(U, &u));
4589566063dSJacob Faibussowitsch PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
4599566063dSJacob Faibussowitsch PetscCall(PetscFree(v));
460d0c080abSJoseph Pusztay }
4613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
462d0c080abSJoseph Pusztay }
463d0c080abSJoseph Pusztay
InitializeSolve(TS ts,Vec u)464d71ae5a4SJacob Faibussowitsch static PetscErrorCode InitializeSolve(TS ts, Vec u)
465d71ae5a4SJacob Faibussowitsch {
466d0c080abSJoseph Pusztay DM dm;
467d0c080abSJoseph Pusztay AppCtx *user;
468d0c080abSJoseph Pusztay
469d0c080abSJoseph Pusztay PetscFunctionBeginUser;
4709566063dSJacob Faibussowitsch PetscCall(TSGetDM(ts, &dm));
4719566063dSJacob Faibussowitsch PetscCall(DMGetApplicationContext(dm, &user));
4729566063dSJacob Faibussowitsch PetscCall(SetInitialCoordinates(dm));
4739566063dSJacob Faibussowitsch PetscCall(SetInitialConditions(dm, u));
4743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
475d0c080abSJoseph Pusztay }
476d0c080abSJoseph Pusztay /*
477d0c080abSJoseph Pusztay A single particle is generated for each velocity space cell using the dmswarmpicfield_coor and is used to evaluate collisions in that cell.
478d0c080abSJoseph Pusztay 0 weight ghost particles are initialized outside of a small velocity domain to ensure the tails of the amxwellian are resolved.
479d0c080abSJoseph Pusztay */
main(int argc,char ** argv)480d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
481d71ae5a4SJacob Faibussowitsch {
482d0c080abSJoseph Pusztay TS ts; /* nonlinear solver */
483d0c080abSJoseph Pusztay DM dm, sw; /* Velocity space mesh and Particle Swarm */
484d0c080abSJoseph Pusztay Vec u, w; /* swarm vector */
485d0c080abSJoseph Pusztay MPI_Comm comm;
486d0c080abSJoseph Pusztay AppCtx user;
487d0c080abSJoseph Pusztay
488327415f7SBarry Smith PetscFunctionBeginUser;
4899566063dSJacob Faibussowitsch PetscCall(PetscInitialize(&argc, &argv, NULL, help));
490d0c080abSJoseph Pusztay comm = PETSC_COMM_WORLD;
4919566063dSJacob Faibussowitsch PetscCall(ProcessOptions(comm, &user));
4929566063dSJacob Faibussowitsch PetscCall(CreateMesh(comm, &dm, &user));
4939566063dSJacob Faibussowitsch PetscCall(CreateParticles(dm, &sw, &user));
4949566063dSJacob Faibussowitsch PetscCall(DMSetApplicationContext(sw, &user));
4959566063dSJacob Faibussowitsch PetscCall(TSCreate(comm, &ts));
4969566063dSJacob Faibussowitsch PetscCall(TSSetDM(ts, sw));
4979566063dSJacob Faibussowitsch PetscCall(TSSetMaxTime(ts, 10.0));
4989566063dSJacob Faibussowitsch PetscCall(TSSetTimeStep(ts, 0.01));
4999566063dSJacob Faibussowitsch PetscCall(TSSetMaxSteps(ts, 100000));
5009566063dSJacob Faibussowitsch PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
501d0c080abSJoseph Pusztay if (user.monitorhg) {
5029566063dSJacob Faibussowitsch PetscCall(PetscDrawCreate(comm, NULL, "monitor", 0, 0, 400, 300, &user.draw));
5039566063dSJacob Faibussowitsch PetscCall(PetscDrawSetFromOptions(user.draw));
5049566063dSJacob Faibussowitsch PetscCall(PetscDrawHGCreate(user.draw, 20, &user.drawhg));
5059566063dSJacob Faibussowitsch PetscCall(PetscDrawHGSetColor(user.drawhg, 3));
5069566063dSJacob Faibussowitsch PetscCall(TSMonitorSet(ts, HGMonitor, &user, NULL));
5079371c9d4SSatish Balay } else if (user.monitorsp) {
5089566063dSJacob Faibussowitsch PetscCall(PetscDrawCreate(comm, NULL, "monitor", 0, 0, 400, 300, &user.draw));
5099566063dSJacob Faibussowitsch PetscCall(PetscDrawSetFromOptions(user.draw));
5109566063dSJacob Faibussowitsch PetscCall(PetscDrawSPCreate(user.draw, 1, &user.drawsp));
5119566063dSJacob Faibussowitsch PetscCall(TSMonitorSet(ts, SPMonitor, &user, NULL));
5129371c9d4SSatish Balay } else if (user.monitorks) {
5139566063dSJacob Faibussowitsch PetscCall(PetscDrawCreate(comm, NULL, "monitor", 0, 0, 400, 300, &user.draw));
5149566063dSJacob Faibussowitsch PetscCall(PetscDrawSetFromOptions(user.draw));
5159566063dSJacob Faibussowitsch PetscCall(PetscDrawSPCreate(user.draw, 1, &user.drawks));
5169566063dSJacob Faibussowitsch PetscCall(TSMonitorSet(ts, KSConv, &user, NULL));
517d0c080abSJoseph Pusztay }
5189566063dSJacob Faibussowitsch PetscCall(TSSetRHSFunction(ts, NULL, RHSFunctionParticles, &user));
5199566063dSJacob Faibussowitsch PetscCall(TSSetFromOptions(ts));
5209566063dSJacob Faibussowitsch PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve));
5219566063dSJacob Faibussowitsch PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &w));
5229566063dSJacob Faibussowitsch PetscCall(VecDuplicate(w, &u));
5239566063dSJacob Faibussowitsch PetscCall(VecCopy(w, u));
5249566063dSJacob Faibussowitsch PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &w));
5259566063dSJacob Faibussowitsch PetscCall(TSComputeInitialCondition(ts, u));
5269566063dSJacob Faibussowitsch PetscCall(TSSolve(ts, u));
527d0c080abSJoseph Pusztay if (user.monitorhg) {
5289566063dSJacob Faibussowitsch PetscCall(PetscDrawSave(user.draw));
5299566063dSJacob Faibussowitsch PetscCall(PetscDrawHGDestroy(&user.drawhg));
5309566063dSJacob Faibussowitsch PetscCall(PetscDrawDestroy(&user.draw));
531d0c080abSJoseph Pusztay }
532d0c080abSJoseph Pusztay if (user.monitorsp) {
5339566063dSJacob Faibussowitsch PetscCall(PetscDrawSave(user.draw));
5349566063dSJacob Faibussowitsch PetscCall(PetscDrawSPDestroy(&user.drawsp));
5359566063dSJacob Faibussowitsch PetscCall(PetscDrawDestroy(&user.draw));
536d0c080abSJoseph Pusztay }
537d0c080abSJoseph Pusztay if (user.monitorks) {
5389566063dSJacob Faibussowitsch PetscCall(PetscDrawSave(user.draw));
5399566063dSJacob Faibussowitsch PetscCall(PetscDrawSPDestroy(&user.drawks));
5409566063dSJacob Faibussowitsch PetscCall(PetscDrawDestroy(&user.draw));
541d0c080abSJoseph Pusztay }
5429566063dSJacob Faibussowitsch PetscCall(VecDestroy(&u));
5439566063dSJacob Faibussowitsch PetscCall(TSDestroy(&ts));
5449566063dSJacob Faibussowitsch PetscCall(DMDestroy(&sw));
5459566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dm));
5469566063dSJacob Faibussowitsch PetscCall(PetscFinalize());
547b122ec5aSJacob Faibussowitsch return 0;
548d0c080abSJoseph Pusztay }
549d0c080abSJoseph Pusztay
550d0c080abSJoseph Pusztay /*TEST
551d0c080abSJoseph Pusztay build:
55230602db0SMatthew G. Knepley requires: double !complex
553d0c080abSJoseph Pusztay test:
554d0c080abSJoseph Pusztay suffix: 1
55530602db0SMatthew G. Knepley args: -particles_per_cell 1 -output_step 10 -ts_type euler -dm_plex_dim 1 -dm_plex_box_faces 200 -dm_plex_box_lower -10 -dm_plex_box_upper 10 -dm_view -monitorsp
556d0c080abSJoseph Pusztay test:
557d0c080abSJoseph Pusztay suffix: 2
55830602db0SMatthew G. Knepley args: -particles_per_cell 1 -output_step 50 -ts_type euler -dm_plex_dim 1 -dm_plex_box_faces 200 -dm_plex_box_lower -10 -dm_plex_box_upper 10 -dm_view -monitorks
559d0c080abSJoseph Pusztay TEST*/
560