xref: /petsc/src/ts/tutorials/hamiltonian/ex4.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
1918dfc20SMatthew G. Knepley static char help[] = "Two-level system for Landau Damping using Vlasov-Poisson equations\n";
2918dfc20SMatthew G. Knepley 
3918dfc20SMatthew G. Knepley /*
4918dfc20SMatthew G. Knepley   Moment Equations:
5918dfc20SMatthew G. Knepley 
6918dfc20SMatthew G. Knepley     We will discretize the moment equations using finite elements, and we will project the moments into the finite element space We will use the PFAK method, which guarantees that our FE approximation is weakly equivalent to the true moment. The first moment, number density, is given by
7918dfc20SMatthew G. Knepley 
8918dfc20SMatthew G. Knepley       \int dx \phi_i n_f = \int dx \phi_i n_p
9918dfc20SMatthew G. Knepley       \int dx \phi_i n_f = \int dx \phi_i \int dv f
10918dfc20SMatthew G. Knepley       \int dx \phi_i n_f = \int dx \phi_i \int dv \sum_p w_p \delta(x - x_p) \delta(v - v_p)
11918dfc20SMatthew G. Knepley       \int dx \phi_i n_f = \int dx \phi_i \sum_p w_p \delta(x - x_p)
12918dfc20SMatthew G. Knepley                    M n_F = M_p w_p
13918dfc20SMatthew G. Knepley 
14918dfc20SMatthew G. Knepley     where
15918dfc20SMatthew G. Knepley 
16918dfc20SMatthew G. Knepley       (M_p){ip} = \phi_i(x_p)
17918dfc20SMatthew G. Knepley 
18918dfc20SMatthew G. Knepley     which is just a scaled version of the charge density. The second moment, momentum density, is given by
19918dfc20SMatthew G. Knepley 
20918dfc20SMatthew G. Knepley       \int dx \phi_i p_f = m \int dx \phi_i \int dv v f
21918dfc20SMatthew G. Knepley       \int dx \phi_i p_f = m \int dx \phi_i \sum_p w_p \delta(x - x_p) v_p
22918dfc20SMatthew G. Knepley                    M p_F = M_p v_p w_p
23918dfc20SMatthew G. Knepley 
24918dfc20SMatthew G. Knepley     And finally the third moment, pressure, is given by
25918dfc20SMatthew G. Knepley 
26918dfc20SMatthew G. Knepley       \int dx \phi_i pr_f = m \int dx \phi_i \int dv (v - u)^2 f
27918dfc20SMatthew G. Knepley       \int dx \phi_i pr_f = m \int dx \phi_i \sum_p w_p \delta(x - x_p) (v_p - u)^2
28918dfc20SMatthew G. Knepley                    M pr_F = M_p (v_p - u)^2 w_p
29918dfc20SMatthew G. Knepley                           = M_p (v_p - p_F(x_p) / m n_F(x_p))^2 w_p
30918dfc20SMatthew G. Knepley                           = M_p (v_p - (\sum_j p_F \phi_j(x_p)) / m (\sum_k n_F \phi_k(x_p)))^2 w_p
31918dfc20SMatthew G. Knepley 
32918dfc20SMatthew G. Knepley     Here we need all FEM basis functions \phi_i that see that particle p.
33918dfc20SMatthew G. Knepley 
34918dfc20SMatthew G. Knepley   To run the code with particles sinusoidally perturbed in x space use the test "pp_poisson_bsi_1d_4" or "pp_poisson_bsi_2d_4"
35918dfc20SMatthew G. Knepley   According to Lukas, good damping results come at ~16k particles per cell
36918dfc20SMatthew G. Knepley 
37918dfc20SMatthew G. Knepley   Swarm CellDMs
38918dfc20SMatthew G. Knepley   =============
39918dfc20SMatthew G. Knepley   Name: "space"
40918dfc20SMatthew G. Knepley   Fields: DMSwarmPICField_coor, "velocity"
41918dfc20SMatthew G. Knepley   Coordinates: DMSwarmPICField_coor
42918dfc20SMatthew G. Knepley 
43918dfc20SMatthew G. Knepley   Name: "velocity"
44918dfc20SMatthew G. Knepley   Fields: "w_q"
45918dfc20SMatthew G. Knepley   Coordinates: "velocity"
46918dfc20SMatthew G. Knepley 
47918dfc20SMatthew G. Knepley   Name: "moments"
48918dfc20SMatthew G. Knepley   Fields: "w_q"
49918dfc20SMatthew G. Knepley   Coordinates: DMSwarmPICField_coor
50918dfc20SMatthew G. Knepley 
51918dfc20SMatthew G. Knepley   Name: "moment fields"
52918dfc20SMatthew G. Knepley   Fields: "velocity"
53918dfc20SMatthew G. Knepley   Coordinates: DMSwarmPICField_coor
54918dfc20SMatthew G. Knepley 
55918dfc20SMatthew G. Knepley   To visualize the maximum electric field use
56918dfc20SMatthew G. Knepley 
57918dfc20SMatthew G. Knepley     -efield_monitor
58918dfc20SMatthew G. Knepley 
59918dfc20SMatthew G. Knepley   To monitor velocity moments of the distribution use
60918dfc20SMatthew G. Knepley 
61918dfc20SMatthew G. Knepley     -ptof_pc_type lu -moments_monitor
62918dfc20SMatthew G. Knepley 
63918dfc20SMatthew G. Knepley   To monitor the particle positions in phase space use
64918dfc20SMatthew G. Knepley 
65918dfc20SMatthew G. Knepley     -positions_monitor
66918dfc20SMatthew G. Knepley 
67918dfc20SMatthew G. Knepley   To monitor the charge density, E field, and potential use
68918dfc20SMatthew G. Knepley 
69918dfc20SMatthew G. Knepley     -poisson_monitor
70918dfc20SMatthew G. Knepley 
71918dfc20SMatthew G. Knepley   To monitor the remapping field use
72918dfc20SMatthew G. Knepley 
73918dfc20SMatthew G. Knepley     -remap_uf_view draw
74918dfc20SMatthew G. Knepley 
75918dfc20SMatthew G. Knepley   To visualize the swarm distribution use
76918dfc20SMatthew G. Knepley 
77918dfc20SMatthew G. Knepley     -ts_monitor_hg_swarm
78918dfc20SMatthew G. Knepley 
79918dfc20SMatthew G. Knepley   To visualize the particles, we can use
80918dfc20SMatthew G. Knepley 
81918dfc20SMatthew G. Knepley     -ts_monitor_sp_swarm -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500
82918dfc20SMatthew G. Knepley */
83918dfc20SMatthew G. Knepley #include <petsctao.h>
84918dfc20SMatthew G. Knepley #include <petscts.h>
85918dfc20SMatthew G. Knepley #include <petscdmplex.h>
86918dfc20SMatthew G. Knepley #include <petscdmswarm.h>
87918dfc20SMatthew G. Knepley #include <petscfe.h>
88918dfc20SMatthew G. Knepley #include <petscds.h>
89918dfc20SMatthew G. Knepley #include <petscbag.h>
90918dfc20SMatthew G. Knepley #include <petscdraw.h>
91918dfc20SMatthew G. Knepley #include <petsc/private/petscfeimpl.h> /* For interpolation */
92918dfc20SMatthew G. Knepley #include <petsc/private/dmswarmimpl.h> /* For swarm debugging */
93918dfc20SMatthew G. Knepley #include "petscdm.h"
94918dfc20SMatthew G. Knepley #include "petscdmlabel.h"
95918dfc20SMatthew G. Knepley 
96918dfc20SMatthew G. Knepley PETSC_EXTERN PetscErrorCode stream(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
97918dfc20SMatthew G. Knepley PETSC_EXTERN PetscErrorCode line(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
98918dfc20SMatthew G. Knepley 
99918dfc20SMatthew G. Knepley const char *EMTypes[] = {"primal", "mixed", "coulomb", "none", "EMType", "EM_", NULL};
100918dfc20SMatthew G. Knepley typedef enum {
101f14fce1bSMatthew G. Knepley   EM_PRIMAL,
102918dfc20SMatthew G. Knepley   EM_MIXED,
103918dfc20SMatthew G. Knepley   EM_COULOMB,
104f14fce1bSMatthew G. Knepley   EM_NONE
105918dfc20SMatthew G. Knepley } EMType;
106918dfc20SMatthew G. Knepley 
107918dfc20SMatthew G. Knepley typedef enum {
108918dfc20SMatthew G. Knepley   V0,
109918dfc20SMatthew G. Knepley   X0,
110918dfc20SMatthew G. Knepley   T0,
111918dfc20SMatthew G. Knepley   M0,
112918dfc20SMatthew G. Knepley   Q0,
113918dfc20SMatthew G. Knepley   PHI0,
114918dfc20SMatthew G. Knepley   POISSON,
115918dfc20SMatthew G. Knepley   VLASOV,
116918dfc20SMatthew G. Knepley   SIGMA,
117918dfc20SMatthew G. Knepley   NUM_CONSTANTS
118918dfc20SMatthew G. Knepley } ConstantType;
119918dfc20SMatthew G. Knepley 
120918dfc20SMatthew G. Knepley typedef enum {
121918dfc20SMatthew G. Knepley   E_MONITOR_NONE,
122918dfc20SMatthew G. Knepley   E_MONITOR_FULL,
123918dfc20SMatthew G. Knepley   E_MONITOR_QUIET
124918dfc20SMatthew G. Knepley } EMonitorType;
125918dfc20SMatthew G. Knepley const char *const EMonitorTypes[] = {"NONE", "FULL", "QUIET", "EMonitorType", "E_MONITOR_", NULL};
126918dfc20SMatthew G. Knepley 
127918dfc20SMatthew G. Knepley typedef struct {
128918dfc20SMatthew G. Knepley   PetscScalar v0; /* Velocity scale, often the thermal velocity */
129918dfc20SMatthew G. Knepley   PetscScalar t0; /* Time scale */
130918dfc20SMatthew G. Knepley   PetscScalar x0; /* Space scale */
131918dfc20SMatthew G. Knepley   PetscScalar m0; /* Mass scale */
132918dfc20SMatthew G. Knepley   PetscScalar q0; /* Charge scale */
133918dfc20SMatthew G. Knepley   PetscScalar kb;
134918dfc20SMatthew G. Knepley   PetscScalar epsi0;
135918dfc20SMatthew G. Knepley   PetscScalar phi0;          /* Potential scale */
136918dfc20SMatthew G. Knepley   PetscScalar poissonNumber; /* Non-Dimensional Poisson Number */
137918dfc20SMatthew G. Knepley   PetscScalar vlasovNumber;  /* Non-Dimensional Vlasov Number */
138918dfc20SMatthew G. Knepley   PetscReal   sigma;         /* Nondimensional charge per length in x */
139918dfc20SMatthew G. Knepley } Parameter;
140918dfc20SMatthew G. Knepley 
141918dfc20SMatthew G. Knepley typedef struct {
142f940b0e3Sdanofinn   PetscInt         s;    // Starting sample (we ignore some in the beginning)
143f940b0e3Sdanofinn   PetscInt         e;    // Ending sample
144f940b0e3Sdanofinn   PetscInt         per;  // Period of fitting
145f940b0e3Sdanofinn   const PetscReal *t;    // Time for each sample
146f940b0e3Sdanofinn   const PetscReal *Emax; // Emax for each sample
147f940b0e3Sdanofinn } EmaxCtx;
148f940b0e3Sdanofinn 
149f940b0e3Sdanofinn typedef struct {
150918dfc20SMatthew G. Knepley   PetscBag     bag;                  // Problem parameters
151918dfc20SMatthew G. Knepley   PetscBool    error;                // Flag for printing the error
152918dfc20SMatthew G. Knepley   PetscInt     remapFreq;            // Number of timesteps between remapping
153918dfc20SMatthew G. Knepley   EMonitorType efield_monitor;       // Flag to show electric field monitor
154918dfc20SMatthew G. Knepley   PetscBool    moment_monitor;       // Flag to show distribution moment monitor
155918dfc20SMatthew G. Knepley   PetscBool    moment_field_monitor; // Flag to show moment field monitor
156918dfc20SMatthew G. Knepley   PetscBool    positions_monitor;    // Flag to show particle positins at each time step
157918dfc20SMatthew G. Knepley   PetscBool    poisson_monitor;      // Flag to display charge, E field, and potential at each solve
158918dfc20SMatthew G. Knepley   PetscBool    initial_monitor;      // Flag to monitor the initial conditions
159918dfc20SMatthew G. Knepley   PetscInt     velocity_monitor;     // Cell to monitor the velocity distribution for
160918dfc20SMatthew G. Knepley   PetscBool    perturbed_weights;    // Uniformly sample x,v space with gaussian weights
161918dfc20SMatthew G. Knepley   PetscInt     ostep;                // Print the energy at each ostep time steps
162918dfc20SMatthew G. Knepley   PetscInt     numParticles;
163918dfc20SMatthew G. Knepley   PetscReal    timeScale;              /* Nondimensionalizing time scale */
164918dfc20SMatthew G. Knepley   PetscReal    charges[2];             /* The charges of each species */
165918dfc20SMatthew G. Knepley   PetscReal    masses[2];              /* The masses of each species */
166918dfc20SMatthew G. Knepley   PetscReal    thermal_energy[2];      /* Thermal Energy (used to get other constants)*/
167918dfc20SMatthew G. Knepley   PetscReal    cosine_coefficients[2]; /*(alpha, k)*/
168918dfc20SMatthew G. Knepley   PetscReal    totalWeight;
169918dfc20SMatthew G. Knepley   PetscReal    stepSize;
170918dfc20SMatthew G. Knepley   PetscInt     steps;
171918dfc20SMatthew G. Knepley   PetscReal    initVel;
172918dfc20SMatthew G. Knepley   EMType       em;           // Type of electrostatic model
173918dfc20SMatthew G. Knepley   SNES         snes;         // EM solver
174918dfc20SMatthew G. Knepley   DM           dmMom;        // The DM for moment fields
175918dfc20SMatthew G. Knepley   DM           dmN;          // The DM for number density fields
176918dfc20SMatthew G. Knepley   IS           isN;          // The IS mapping dmN into dmMom
177918dfc20SMatthew G. Knepley   Mat          MN;           // The finite element mass matrix for number density
178918dfc20SMatthew G. Knepley   DM           dmP;          // The DM for momentum density fields
179918dfc20SMatthew G. Knepley   IS           isP;          // The IS mapping dmP into dmMom
180918dfc20SMatthew G. Knepley   Mat          MP;           // The finite element mass matrix for momentum density
181918dfc20SMatthew G. Knepley   DM           dmE;          // The DM for energy density (pressure) fields
182918dfc20SMatthew G. Knepley   IS           isE;          // The IS mapping dmE into dmMom
183918dfc20SMatthew G. Knepley   Mat          ME;           // The finite element mass matrix for energy density (pressure)
184918dfc20SMatthew G. Knepley   DM           dmPot;        // The DM for potential
185918dfc20SMatthew G. Knepley   Mat          fftPot;       // Fourier Transform operator for the potential
186918dfc20SMatthew G. Knepley   Vec          fftX, fftY;   //   FFT vectors with phases added (complex parts)
187918dfc20SMatthew G. Knepley   IS           fftReal;      //   The indices for real parts
188918dfc20SMatthew G. Knepley   IS           isPot;        // The IS for potential, or NULL in primal
189918dfc20SMatthew G. Knepley   Mat          M;            // The finite element mass matrix for potential
190918dfc20SMatthew G. Knepley   PetscFEGeom *fegeom;       // Geometric information for the DM cells
191918dfc20SMatthew G. Knepley   PetscDrawHG  drawhgic_x;   // Histogram of the particle weight in each X cell
192918dfc20SMatthew G. Knepley   PetscDrawHG  drawhgic_v;   // Histogram of the particle weight in each X cell
193918dfc20SMatthew G. Knepley   PetscDrawHG  drawhgcell_v; // Histogram of the particle weight in a given cell
194918dfc20SMatthew G. Knepley   PetscBool    validE;       // Flag to indicate E-field in swarm is valid
195918dfc20SMatthew G. Knepley   PetscReal    drawlgEmin;   // The minimum lg(E) to plot
196918dfc20SMatthew G. Knepley   PetscDrawLG  drawlgE;      // Logarithm of maximum electric field
197918dfc20SMatthew G. Knepley   PetscDrawSP  drawspE;      // Electric field at particle positions
198918dfc20SMatthew G. Knepley   PetscDrawSP  drawspX;      // Particle positions
199918dfc20SMatthew G. Knepley   PetscViewer  viewerRho;    // Charge density viewer
200918dfc20SMatthew G. Knepley   PetscViewer  viewerRhoHat; // Charge density Fourier Transform viewer
201918dfc20SMatthew G. Knepley   PetscViewer  viewerPhi;    // Potential viewer
202918dfc20SMatthew G. Knepley   PetscViewer  viewerN;      // Number density viewer
203918dfc20SMatthew G. Knepley   PetscViewer  viewerP;      // Momentum density viewer
204918dfc20SMatthew G. Knepley   PetscViewer  viewerE;      // Energy density (pressure) viewer
205f14fce1bSMatthew G. Knepley   PetscViewer  viewerNRes;   // Number density residual viewer
206f14fce1bSMatthew G. Knepley   PetscViewer  viewerPRes;   // Momentum density residual viewer
207f14fce1bSMatthew G. Knepley   PetscViewer  viewerERes;   // Energy density (pressure) residual viewer
208f14fce1bSMatthew G. Knepley   PetscDrawLG  drawlgMomRes; // Residuals for the moment equations
209918dfc20SMatthew G. Knepley   DM           swarm;        // The particle swarm
210918dfc20SMatthew G. Knepley   PetscRandom  random;       // Used for particle perturbations
211918dfc20SMatthew G. Knepley   PetscBool    twostream;    // Flag for activating 2-stream setup
212918dfc20SMatthew G. Knepley   PetscBool    checkweights; // Check weight normalization
213918dfc20SMatthew G. Knepley   PetscInt     checkVRes;    // Flag to check/output velocity residuals for nightly tests
214918dfc20SMatthew G. Knepley   PetscBool    checkLandau;  // Check the Landau damping result
215f940b0e3Sdanofinn   EmaxCtx      emaxCtx;      // Information for fit to decay profile
216918dfc20SMatthew G. Knepley   PetscReal    gamma;        // The damping rate for Landau damping
217918dfc20SMatthew G. Knepley   PetscReal    omega;        // The perturbed oscillation frequency for Landau damping
218918dfc20SMatthew G. Knepley 
219918dfc20SMatthew G. Knepley   PetscLogEvent RhsXEvent, RhsVEvent, ESolveEvent, ETabEvent;
220918dfc20SMatthew G. Knepley } AppCtx;
221918dfc20SMatthew G. Knepley 
ProcessOptions(MPI_Comm comm,AppCtx * options)222918dfc20SMatthew G. Knepley static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
223918dfc20SMatthew G. Knepley {
224918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
225918dfc20SMatthew G. Knepley   PetscInt d                      = 2;
226918dfc20SMatthew G. Knepley   PetscInt maxSpecies             = 2;
227918dfc20SMatthew G. Knepley   options->error                  = PETSC_FALSE;
228918dfc20SMatthew G. Knepley   options->remapFreq              = 1;
229918dfc20SMatthew G. Knepley   options->efield_monitor         = E_MONITOR_NONE;
230918dfc20SMatthew G. Knepley   options->moment_monitor         = PETSC_FALSE;
231918dfc20SMatthew G. Knepley   options->moment_field_monitor   = PETSC_FALSE;
232918dfc20SMatthew G. Knepley   options->initial_monitor        = PETSC_FALSE;
233918dfc20SMatthew G. Knepley   options->perturbed_weights      = PETSC_FALSE;
234918dfc20SMatthew G. Knepley   options->poisson_monitor        = PETSC_FALSE;
235918dfc20SMatthew G. Knepley   options->positions_monitor      = PETSC_FALSE;
236918dfc20SMatthew G. Knepley   options->velocity_monitor       = -1;
237918dfc20SMatthew G. Knepley   options->ostep                  = 100;
238918dfc20SMatthew G. Knepley   options->timeScale              = 2.0e-14;
239918dfc20SMatthew G. Knepley   options->charges[0]             = -1.0;
240918dfc20SMatthew G. Knepley   options->charges[1]             = 1.0;
241918dfc20SMatthew G. Knepley   options->masses[0]              = 1.0;
242918dfc20SMatthew G. Knepley   options->masses[1]              = 1000.0;
243918dfc20SMatthew G. Knepley   options->thermal_energy[0]      = 1.0;
244918dfc20SMatthew G. Knepley   options->thermal_energy[1]      = 1.0;
245918dfc20SMatthew G. Knepley   options->cosine_coefficients[0] = 0.01;
246918dfc20SMatthew G. Knepley   options->cosine_coefficients[1] = 0.5;
247918dfc20SMatthew G. Knepley   options->initVel                = 1;
248918dfc20SMatthew G. Knepley   options->totalWeight            = 1.0;
249918dfc20SMatthew G. Knepley   options->drawhgic_x             = NULL;
250918dfc20SMatthew G. Knepley   options->drawhgic_v             = NULL;
251918dfc20SMatthew G. Knepley   options->drawhgcell_v           = NULL;
252f940b0e3Sdanofinn   options->validE                 = PETSC_FALSE;
253918dfc20SMatthew G. Knepley   options->drawlgEmin             = -6;
254918dfc20SMatthew G. Knepley   options->drawlgE                = NULL;
255918dfc20SMatthew G. Knepley   options->drawspE                = NULL;
256918dfc20SMatthew G. Knepley   options->drawspX                = NULL;
257918dfc20SMatthew G. Knepley   options->viewerRho              = NULL;
258918dfc20SMatthew G. Knepley   options->viewerRhoHat           = NULL;
259918dfc20SMatthew G. Knepley   options->viewerPhi              = NULL;
260918dfc20SMatthew G. Knepley   options->viewerN                = NULL;
261918dfc20SMatthew G. Knepley   options->viewerP                = NULL;
262918dfc20SMatthew G. Knepley   options->viewerE                = NULL;
263f14fce1bSMatthew G. Knepley   options->viewerNRes             = NULL;
264f14fce1bSMatthew G. Knepley   options->viewerPRes             = NULL;
265f14fce1bSMatthew G. Knepley   options->viewerERes             = NULL;
266f14fce1bSMatthew G. Knepley   options->drawlgMomRes           = NULL;
267918dfc20SMatthew G. Knepley   options->em                     = EM_COULOMB;
268918dfc20SMatthew G. Knepley   options->snes                   = NULL;
269918dfc20SMatthew G. Knepley   options->dmMom                  = NULL;
270918dfc20SMatthew G. Knepley   options->dmN                    = NULL;
271918dfc20SMatthew G. Knepley   options->MN                     = NULL;
272918dfc20SMatthew G. Knepley   options->dmP                    = NULL;
273918dfc20SMatthew G. Knepley   options->MP                     = NULL;
274918dfc20SMatthew G. Knepley   options->dmE                    = NULL;
275918dfc20SMatthew G. Knepley   options->ME                     = NULL;
276918dfc20SMatthew G. Knepley   options->dmPot                  = NULL;
277918dfc20SMatthew G. Knepley   options->fftPot                 = NULL;
278918dfc20SMatthew G. Knepley   options->fftX                   = NULL;
279918dfc20SMatthew G. Knepley   options->fftY                   = NULL;
280918dfc20SMatthew G. Knepley   options->fftReal                = NULL;
281918dfc20SMatthew G. Knepley   options->isPot                  = NULL;
282918dfc20SMatthew G. Knepley   options->M                      = NULL;
283918dfc20SMatthew G. Knepley   options->numParticles           = 32768;
284918dfc20SMatthew G. Knepley   options->twostream              = PETSC_FALSE;
285918dfc20SMatthew G. Knepley   options->checkweights           = PETSC_FALSE;
286918dfc20SMatthew G. Knepley   options->checkVRes              = 0;
287918dfc20SMatthew G. Knepley   options->checkLandau            = PETSC_FALSE;
288f940b0e3Sdanofinn   options->emaxCtx.s              = 50;
289f940b0e3Sdanofinn   options->emaxCtx.per            = 100;
290918dfc20SMatthew G. Knepley 
291918dfc20SMatthew G. Knepley   PetscOptionsBegin(comm, "", "Landau Damping and Two Stream options", "DMSWARM");
292918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-error", "Flag to print the error", __FILE__, options->error, &options->error, NULL));
293918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsInt("-remap_freq", "Number", __FILE__, options->remapFreq, &options->remapFreq, NULL));
294918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsEnum("-efield_monitor", "Flag to record and plot log(max E) over time", __FILE__, EMonitorTypes, (PetscEnum)options->efield_monitor, (PetscEnum *)&options->efield_monitor, NULL));
295918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsReal("-efield_min_monitor", "Minimum E field to plot", __FILE__, options->drawlgEmin, &options->drawlgEmin, NULL));
296918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-moments_monitor", "Flag to show moments table", __FILE__, options->moment_monitor, &options->moment_monitor, NULL));
297918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-moment_field_monitor", "Flag to show moment fields", __FILE__, options->moment_field_monitor, &options->moment_field_monitor, NULL));
298918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-ics_monitor", "Flag to show initial condition histograms", __FILE__, options->initial_monitor, &options->initial_monitor, NULL));
299918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-positions_monitor", "The flag to show particle positions", __FILE__, options->positions_monitor, &options->positions_monitor, NULL));
300918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-poisson_monitor", "The flag to show charges, Efield and potential solve", __FILE__, options->poisson_monitor, &options->poisson_monitor, NULL));
301918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsInt("-velocity_monitor", "Cell to show velocity histograms", __FILE__, options->velocity_monitor, &options->velocity_monitor, NULL));
302918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-twostream", "Run two stream instability", __FILE__, options->twostream, &options->twostream, NULL));
303918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-perturbed_weights", "Flag to run uniform sampling with perturbed weights", __FILE__, options->perturbed_weights, &options->perturbed_weights, NULL));
304918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-check_weights", "Ensure all particle weights are positive", __FILE__, options->checkweights, &options->checkweights, NULL));
305918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-check_landau", "Check the decay from Landau damping", __FILE__, options->checkLandau, &options->checkLandau, NULL));
306918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", __FILE__, options->ostep, &options->ostep, NULL));
307918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsReal("-timeScale", "Nondimensionalizing time scale", __FILE__, options->timeScale, &options->timeScale, NULL));
308918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsInt("-check_vel_res", "Check particle velocity residuals for nightly tests", __FILE__, options->checkVRes, &options->checkVRes, NULL));
309918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsReal("-initial_velocity", "Initial velocity of perturbed particle", __FILE__, options->initVel, &options->initVel, NULL));
310918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsReal("-total_weight", "Total weight of all particles", __FILE__, options->totalWeight, &options->totalWeight, NULL));
311918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsRealArray("-cosine_coefficients", "Amplitude and frequency of cosine equation used in initialization", __FILE__, options->cosine_coefficients, &d, NULL));
312918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsRealArray("-charges", "Species charges", __FILE__, options->charges, &maxSpecies, NULL));
313918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsEnum("-em_type", "Type of electrostatic solver", __FILE__, EMTypes, (PetscEnum)options->em, (PetscEnum *)&options->em, NULL));
314f940b0e3Sdanofinn   PetscCall(PetscOptionsInt("-emax_start_step", "First time step to use for Emax fits", __FILE__, options->emaxCtx.s, &options->emaxCtx.s, NULL));
315f940b0e3Sdanofinn   PetscCall(PetscOptionsInt("-emax_solve_step", "Number of time steps between Emax fits", __FILE__, options->emaxCtx.per, &options->emaxCtx.per, NULL));
316918dfc20SMatthew G. Knepley   PetscOptionsEnd();
317918dfc20SMatthew G. Knepley 
318918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsX", TS_CLASSID, &options->RhsXEvent));
319918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsV", TS_CLASSID, &options->RhsVEvent));
320918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ESolve", TS_CLASSID, &options->ESolveEvent));
321918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ETab", TS_CLASSID, &options->ETabEvent));
322918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
323918dfc20SMatthew G. Knepley }
324918dfc20SMatthew G. Knepley 
SetupContext(DM dm,DM sw,AppCtx * ctx)325*2a8381b2SBarry Smith static PetscErrorCode SetupContext(DM dm, DM sw, AppCtx *ctx)
326918dfc20SMatthew G. Knepley {
327918dfc20SMatthew G. Knepley   MPI_Comm comm;
328918dfc20SMatthew G. Knepley 
329918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
330918dfc20SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
331*2a8381b2SBarry Smith   if (ctx->efield_monitor) {
332918dfc20SMatthew G. Knepley     PetscDraw     draw;
333918dfc20SMatthew G. Knepley     PetscDrawAxis axis;
334918dfc20SMatthew G. Knepley 
335*2a8381b2SBarry Smith     if (ctx->efield_monitor == E_MONITOR_FULL) {
336f14fce1bSMatthew G. Knepley       PetscCall(PetscDrawCreate(comm, NULL, "Max Electric Field", 0, 0, 400, 300, &draw));
337918dfc20SMatthew G. Knepley       PetscCall(PetscDrawSetSave(draw, "ex2_Efield"));
338918dfc20SMatthew G. Knepley       PetscCall(PetscDrawSetFromOptions(draw));
339918dfc20SMatthew G. Knepley     } else {
340918dfc20SMatthew G. Knepley       PetscCall(PetscDrawOpenNull(comm, &draw));
341918dfc20SMatthew G. Knepley     }
342*2a8381b2SBarry Smith     PetscCall(PetscDrawLGCreate(draw, 1, &ctx->drawlgE));
343918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
344*2a8381b2SBarry Smith     PetscCall(PetscDrawLGGetAxis(ctx->drawlgE, &axis));
345918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Max Electric Field", "time", "E_max"));
346*2a8381b2SBarry Smith     PetscCall(PetscDrawLGSetLimits(ctx->drawlgE, 0., ctx->steps * ctx->stepSize, ctx->drawlgEmin, 0.));
347918dfc20SMatthew G. Knepley   }
348918dfc20SMatthew G. Knepley 
349*2a8381b2SBarry Smith   if (ctx->initial_monitor) {
350918dfc20SMatthew G. Knepley     PetscDraw     drawic_x, drawic_v;
351918dfc20SMatthew G. Knepley     PetscDrawAxis axis1, axis2;
352918dfc20SMatthew G. Knepley     PetscReal     dmboxlower[2], dmboxupper[2];
353918dfc20SMatthew G. Knepley     PetscInt      dim, cStart, cEnd;
354918dfc20SMatthew G. Knepley 
355918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(sw, &dim));
356918dfc20SMatthew G. Knepley     PetscCall(DMGetBoundingBox(dm, dmboxlower, dmboxupper));
357918dfc20SMatthew G. Knepley     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
358918dfc20SMatthew G. Knepley 
359918dfc20SMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_x", 0, 300, 400, 300, &drawic_x));
360918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawic_x, "ex2_ic_x"));
361918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawic_x));
362*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCreate(drawic_x, (int)dim, &ctx->drawhgic_x));
363*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCalcStats(ctx->drawhgic_x, PETSC_TRUE));
364*2a8381b2SBarry Smith     PetscCall(PetscDrawHGGetAxis(ctx->drawhgic_x, &axis1));
365*2a8381b2SBarry Smith     PetscCall(PetscDrawHGSetNumberBins(ctx->drawhgic_x, (int)(cEnd - cStart)));
366918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis1, "Initial X Distribution", "X", "weight"));
367918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis1, dmboxlower[0], dmboxupper[0], 0, 0));
368918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawic_x));
369918dfc20SMatthew G. Knepley 
370918dfc20SMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_v", 400, 300, 400, 300, &drawic_v));
371918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawic_v, "ex9_ic_v"));
372918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawic_v));
373*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCreate(drawic_v, (int)dim, &ctx->drawhgic_v));
374*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCalcStats(ctx->drawhgic_v, PETSC_TRUE));
375*2a8381b2SBarry Smith     PetscCall(PetscDrawHGGetAxis(ctx->drawhgic_v, &axis2));
376*2a8381b2SBarry Smith     PetscCall(PetscDrawHGSetNumberBins(ctx->drawhgic_v, 21));
377918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis2, "Initial V_x Distribution", "V", "weight"));
378918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis2, -6, 6, 0, 0));
379918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawic_v));
380918dfc20SMatthew G. Knepley   }
381918dfc20SMatthew G. Knepley 
382*2a8381b2SBarry Smith   if (ctx->velocity_monitor >= 0) {
383918dfc20SMatthew G. Knepley     DM            vdm;
384918dfc20SMatthew G. Knepley     DMSwarmCellDM celldm;
385918dfc20SMatthew G. Knepley     PetscDraw     drawcell_v;
386918dfc20SMatthew G. Knepley     PetscDrawAxis axis;
387918dfc20SMatthew G. Knepley     PetscReal     dmboxlower[2], dmboxupper[2];
388918dfc20SMatthew G. Knepley     PetscInt      dim;
389918dfc20SMatthew G. Knepley     char          title[PETSC_MAX_PATH_LEN];
390918dfc20SMatthew G. Knepley 
391918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
392918dfc20SMatthew G. Knepley     PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
393918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(vdm, &dim));
394918dfc20SMatthew G. Knepley     PetscCall(DMGetBoundingBox(vdm, dmboxlower, dmboxupper));
395918dfc20SMatthew G. Knepley 
396*2a8381b2SBarry Smith     PetscCall(PetscSNPrintf(title, PETSC_MAX_PATH_LEN, "Cell %" PetscInt_FMT ": Velocity Distribution", ctx->velocity_monitor));
397918dfc20SMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, title, 400, 300, 400, 300, &drawcell_v));
398918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawcell_v, "ex2_cell_v"));
399918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawcell_v));
400*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCreate(drawcell_v, (int)dim, &ctx->drawhgcell_v));
401*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCalcStats(ctx->drawhgcell_v, PETSC_TRUE));
402*2a8381b2SBarry Smith     PetscCall(PetscDrawHGGetAxis(ctx->drawhgcell_v, &axis));
403*2a8381b2SBarry Smith     PetscCall(PetscDrawHGSetNumberBins(ctx->drawhgcell_v, 21));
404918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "V_x Distribution", "V", "weight"));
405918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis, dmboxlower[0], dmboxupper[0], 0, 0));
406918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawcell_v));
407918dfc20SMatthew G. Knepley   }
408918dfc20SMatthew G. Knepley 
409*2a8381b2SBarry Smith   if (ctx->positions_monitor) {
410918dfc20SMatthew G. Knepley     PetscDraw     draw;
411918dfc20SMatthew G. Knepley     PetscDrawAxis axis;
412918dfc20SMatthew G. Knepley 
413918dfc20SMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Particle Position", 0, 0, 400, 300, &draw));
414918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_pos"));
415918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
416*2a8381b2SBarry Smith     PetscCall(PetscDrawSPCreate(draw, 10, &ctx->drawspX));
417918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
418*2a8381b2SBarry Smith     PetscCall(PetscDrawSPSetDimension(ctx->drawspX, 1));
419*2a8381b2SBarry Smith     PetscCall(PetscDrawSPGetAxis(ctx->drawspX, &axis));
420918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "v"));
421*2a8381b2SBarry Smith     PetscCall(PetscDrawSPReset(ctx->drawspX));
422918dfc20SMatthew G. Knepley   }
423*2a8381b2SBarry Smith   if (ctx->poisson_monitor) {
424918dfc20SMatthew G. Knepley     Vec           rho, rhohat, phi;
425918dfc20SMatthew G. Knepley     PetscDraw     draw;
426918dfc20SMatthew G. Knepley     PetscDrawAxis axis;
427918dfc20SMatthew G. Knepley 
428918dfc20SMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Electric_Field", 0, 0, 400, 300, &draw));
429918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
430918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_E_spatial"));
431*2a8381b2SBarry Smith     PetscCall(PetscDrawSPCreate(draw, 10, &ctx->drawspE));
432918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
433*2a8381b2SBarry Smith     PetscCall(PetscDrawSPSetDimension(ctx->drawspE, 1));
434*2a8381b2SBarry Smith     PetscCall(PetscDrawSPGetAxis(ctx->drawspE, &axis));
435918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "E"));
436*2a8381b2SBarry Smith     PetscCall(PetscDrawSPReset(ctx->drawspE));
437918dfc20SMatthew G. Knepley 
438*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "Charge Density", 0, 0, 400, 300, &ctx->viewerRho));
439*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerRho, "rho_"));
440*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerRho, 0, &draw));
441918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_spatial"));
442*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerRho));
443*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rho", &rho));
444918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rho, "charge_density"));
445*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rho", &rho));
446918dfc20SMatthew G. Knepley 
447918dfc20SMatthew G. Knepley     PetscInt dim, N;
448918dfc20SMatthew G. Knepley 
449*2a8381b2SBarry Smith     PetscCall(DMGetDimension(ctx->dmPot, &dim));
450918dfc20SMatthew G. Knepley     if (dim == 1) {
451*2a8381b2SBarry Smith       PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
452918dfc20SMatthew G. Knepley       PetscCall(VecGetSize(rhohat, &N));
453*2a8381b2SBarry Smith       PetscCall(MatCreateFFT(comm, dim, &N, MATFFTW, &ctx->fftPot));
454*2a8381b2SBarry Smith       PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
455*2a8381b2SBarry Smith       PetscCall(MatCreateVecs(ctx->fftPot, &ctx->fftX, &ctx->fftY));
456*2a8381b2SBarry Smith       PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &ctx->fftReal));
457918dfc20SMatthew G. Knepley     }
458918dfc20SMatthew G. Knepley 
459*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "rhohat: Charge Density FT", 0, 0, 400, 300, &ctx->viewerRhoHat));
460*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerRhoHat, "rhohat_"));
461*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerRhoHat, 0, &draw));
462918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_ft"));
463*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerRhoHat));
464*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
465918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rhohat, "charge_density_ft"));
466*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
467918dfc20SMatthew G. Knepley 
468*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "Potential", 400, 0, 400, 300, &ctx->viewerPhi));
469*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerPhi, "phi_"));
470*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerPhi, 0, &draw));
471918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_phi_spatial"));
472*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerPhi));
473*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
474918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)phi, "potential"));
475*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
476918dfc20SMatthew G. Knepley   }
477*2a8381b2SBarry Smith   if (ctx->moment_field_monitor) {
478918dfc20SMatthew G. Knepley     Vec       n, p, e;
479f14fce1bSMatthew G. Knepley     Vec       nres, pres, eres;
480918dfc20SMatthew G. Knepley     PetscDraw draw;
481918dfc20SMatthew G. Knepley 
482*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "Number Density", 400, 0, 400, 300, &ctx->viewerN));
483*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerN, "n_"));
484*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerN, 0, &draw));
485f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex4_n_spatial"));
486*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerN));
487*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmN, "n", &n));
488918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)n, "Number Density"));
489*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmN, "n", &n));
490918dfc20SMatthew G. Knepley 
491*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "Momentum Density", 800, 0, 400, 300, &ctx->viewerP));
492*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerP, "p_"));
493*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerP, 0, &draw));
494f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex4_p_spatial"));
495*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerP));
496*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmP, "p", &p));
497918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)p, "Momentum Density"));
498*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmP, "p", &p));
499918dfc20SMatthew G. Knepley 
500*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "Emergy Density (Pressure)", 1200, 0, 400, 300, &ctx->viewerE));
501*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerE, "e_"));
502*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerE, 0, &draw));
503f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex4_e_spatial"));
504*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerE));
505*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmE, "e", &e));
506918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)e, "Energy Density (Pressure)"));
507*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmE, "e", &e));
508f14fce1bSMatthew G. Knepley 
509f14fce1bSMatthew G. Knepley     PetscDrawAxis axis;
510f14fce1bSMatthew G. Knepley 
511f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Moment Residual", 0, 320, 400, 300, &draw));
512f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex4_moment_res"));
513f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
514*2a8381b2SBarry Smith     PetscCall(PetscDrawLGCreate(draw, 3, &ctx->drawlgMomRes));
515f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
516*2a8381b2SBarry Smith     PetscCall(PetscDrawLGGetAxis(ctx->drawlgMomRes, &axis));
517f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Moment Residial", "time", "Residual Norm"));
518*2a8381b2SBarry Smith     PetscCall(PetscDrawLGSetLimits(ctx->drawlgMomRes, 0., ctx->steps * ctx->stepSize, -8, 0));
519f14fce1bSMatthew G. Knepley 
520*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "Number Density Residual", 400, 300, 400, 300, &ctx->viewerNRes));
521*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerNRes, "nres_"));
522*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerNRes, 0, &draw));
523f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex4_nres_spatial"));
524*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerNRes));
525*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmN, "nres", &nres));
526f14fce1bSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)nres, "Number Density Residual"));
527*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmN, "nres", &nres));
528f14fce1bSMatthew G. Knepley 
529*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "Momentum Density Residual", 800, 300, 400, 300, &ctx->viewerPRes));
530*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerPRes, "pres_"));
531*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerPRes, 0, &draw));
532f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex4_pres_spatial"));
533*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerPRes));
534*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmP, "pres", &pres));
535f14fce1bSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)pres, "Momentum Density Residual"));
536*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmP, "pres", &pres));
537f14fce1bSMatthew G. Knepley 
538*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "Energy Density Residual", 1200, 300, 400, 300, &ctx->viewerERes));
539*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerERes, "eres_"));
540*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerERes, 0, &draw));
541f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex4_eres_spatial"));
542*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerERes));
543*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmE, "eres", &eres));
544f14fce1bSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)eres, "Energy Density Residual"));
545*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmE, "eres", &eres));
546918dfc20SMatthew G. Knepley   }
547918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
548918dfc20SMatthew G. Knepley }
549918dfc20SMatthew G. Knepley 
DestroyContext(AppCtx * ctx)550*2a8381b2SBarry Smith static PetscErrorCode DestroyContext(AppCtx *ctx)
551918dfc20SMatthew G. Knepley {
552918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
553*2a8381b2SBarry Smith   PetscCall(PetscDrawHGDestroy(&ctx->drawhgic_x));
554*2a8381b2SBarry Smith   PetscCall(PetscDrawHGDestroy(&ctx->drawhgic_v));
555*2a8381b2SBarry Smith   PetscCall(PetscDrawHGDestroy(&ctx->drawhgcell_v));
556918dfc20SMatthew G. Knepley 
557*2a8381b2SBarry Smith   PetscCall(PetscDrawLGDestroy(&ctx->drawlgE));
558*2a8381b2SBarry Smith   PetscCall(PetscDrawSPDestroy(&ctx->drawspE));
559*2a8381b2SBarry Smith   PetscCall(PetscDrawSPDestroy(&ctx->drawspX));
560*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerRho));
561*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerRhoHat));
562*2a8381b2SBarry Smith   PetscCall(MatDestroy(&ctx->fftPot));
563*2a8381b2SBarry Smith   PetscCall(VecDestroy(&ctx->fftX));
564*2a8381b2SBarry Smith   PetscCall(VecDestroy(&ctx->fftY));
565*2a8381b2SBarry Smith   PetscCall(ISDestroy(&ctx->fftReal));
566*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerPhi));
567*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerN));
568*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerP));
569*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerE));
570*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerNRes));
571*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerPRes));
572*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerERes));
573*2a8381b2SBarry Smith   PetscCall(PetscDrawLGDestroy(&ctx->drawlgMomRes));
574918dfc20SMatthew G. Knepley 
575*2a8381b2SBarry Smith   PetscCall(PetscBagDestroy(&ctx->bag));
576918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
577918dfc20SMatthew G. Knepley }
578918dfc20SMatthew G. Knepley 
CheckNonNegativeWeights(DM sw,AppCtx * ctx)579*2a8381b2SBarry Smith static PetscErrorCode CheckNonNegativeWeights(DM sw, AppCtx *ctx)
580918dfc20SMatthew G. Knepley {
581918dfc20SMatthew G. Knepley   const PetscScalar *w;
582918dfc20SMatthew G. Knepley   PetscInt           Np;
583918dfc20SMatthew G. Knepley 
584918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
585*2a8381b2SBarry Smith   if (!ctx->checkweights) PetscFunctionReturn(PETSC_SUCCESS);
586918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w));
587918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
588918dfc20SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) PetscCheck(w[p] >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Particle %" PetscInt_FMT " has negative weight %g", p, w[p]);
589918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w));
590918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
591918dfc20SMatthew G. Knepley }
592918dfc20SMatthew G. Knepley 
f0_Dirichlet(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])593f940b0e3Sdanofinn static void f0_Dirichlet(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
594f940b0e3Sdanofinn {
595f940b0e3Sdanofinn   for (PetscInt d = 0; d < dim; ++d) f0[0] += 0.5 * PetscSqr(u_x[d]);
596f940b0e3Sdanofinn }
597f940b0e3Sdanofinn 
computeFieldEnergy(DM dm,Vec u,PetscReal * En)598f940b0e3Sdanofinn static PetscErrorCode computeFieldEnergy(DM dm, Vec u, PetscReal *En)
599f940b0e3Sdanofinn {
600f940b0e3Sdanofinn   PetscDS        ds;
601f940b0e3Sdanofinn   const PetscInt field = 0;
602f940b0e3Sdanofinn   PetscInt       Nf;
603f940b0e3Sdanofinn   void          *ctx;
604f940b0e3Sdanofinn 
605f940b0e3Sdanofinn   PetscFunctionBegin;
606f940b0e3Sdanofinn   PetscCall(DMGetApplicationContext(dm, &ctx));
607f940b0e3Sdanofinn   PetscCall(DMGetDS(dm, &ds));
608f940b0e3Sdanofinn   PetscCall(PetscDSGetNumFields(ds, &Nf));
609f940b0e3Sdanofinn   PetscCheck(Nf == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "We currently only support 1 field, not %" PetscInt_FMT, Nf);
610f940b0e3Sdanofinn   PetscCall(PetscDSSetObjective(ds, field, &f0_Dirichlet));
611f940b0e3Sdanofinn   PetscCall(DMPlexComputeIntegralFEM(dm, u, En, ctx));
612f940b0e3Sdanofinn   PetscFunctionReturn(PETSC_SUCCESS);
613f940b0e3Sdanofinn }
614f940b0e3Sdanofinn 
computeVelocityFEMMoments(DM sw,PetscReal moments[],AppCtx * ctx)615*2a8381b2SBarry Smith static PetscErrorCode computeVelocityFEMMoments(DM sw, PetscReal moments[], AppCtx *ctx)
616918dfc20SMatthew G. Knepley {
617918dfc20SMatthew G. Knepley   DMSwarmCellDM celldm;
618918dfc20SMatthew G. Knepley   DM            vdm;
619918dfc20SMatthew G. Knepley   Vec           u[1];
620918dfc20SMatthew G. Knepley   const char   *fields[1] = {"w_q"};
621918dfc20SMatthew G. Knepley 
622918dfc20SMatthew G. Knepley   PetscFunctionBegin;
623918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "velocity"));
624918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
625918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
626918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(vdm, &u[0]));
627918dfc20SMatthew G. Knepley   PetscCall(DMSwarmProjectFields(sw, vdm, 1, fields, u, SCATTER_FORWARD));
628918dfc20SMatthew G. Knepley   PetscCall(DMPlexComputeMoments(vdm, u[0], moments));
629918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(vdm, &u[0]));
630918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
631918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
632918dfc20SMatthew G. Knepley }
633918dfc20SMatthew G. Knepley 
f0_grad_phi2(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])634918dfc20SMatthew G. Knepley static void f0_grad_phi2(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
635918dfc20SMatthew G. Knepley {
636918dfc20SMatthew G. Knepley   f0[0] = 0.;
637918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f0[0] += PetscSqr(u_x[uOff_x[0] + d * dim + d]);
638918dfc20SMatthew G. Knepley }
639918dfc20SMatthew G. Knepley 
640918dfc20SMatthew G. Knepley // Our model is E_max(t) = C e^{-gamma t} |cos(omega t - phi)|
ComputeEmaxResidual(Tao tao,Vec x,Vec res,void * Ctx)641*2a8381b2SBarry Smith static PetscErrorCode ComputeEmaxResidual(Tao tao, Vec x, Vec res, void *Ctx)
642918dfc20SMatthew G. Knepley {
643*2a8381b2SBarry Smith   EmaxCtx           *ctx = (EmaxCtx *)Ctx;
644918dfc20SMatthew G. Knepley   const PetscScalar *a;
645918dfc20SMatthew G. Knepley   PetscScalar       *F;
646918dfc20SMatthew G. Knepley   PetscReal          C, gamma, omega, phi;
647918dfc20SMatthew G. Knepley 
648918dfc20SMatthew G. Knepley   PetscFunctionBegin;
649918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(x, &a));
650918dfc20SMatthew G. Knepley   PetscCall(VecGetArray(res, &F));
651918dfc20SMatthew G. Knepley   C     = PetscRealPart(a[0]);
652918dfc20SMatthew G. Knepley   gamma = PetscRealPart(a[1]);
653918dfc20SMatthew G. Knepley   omega = PetscRealPart(a[2]);
654918dfc20SMatthew G. Knepley   phi   = PetscRealPart(a[3]);
655918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(x, &a));
656918dfc20SMatthew G. Knepley   for (PetscInt i = ctx->s; i < ctx->e; ++i) F[i - ctx->s] = PetscPowReal(10., ctx->Emax[i]) - C * PetscExpReal(-gamma * ctx->t[i]) * PetscAbsReal(PetscCosReal(omega * ctx->t[i] - phi));
657918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArray(res, &F));
658918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
659918dfc20SMatthew G. Knepley }
660918dfc20SMatthew G. Knepley 
661918dfc20SMatthew G. Knepley // The Jacobian of the residual J = dr(x)/dx
ComputeEmaxJacobian(Tao tao,Vec x,Mat J,Mat Jpre,void * Ctx)662*2a8381b2SBarry Smith static PetscErrorCode ComputeEmaxJacobian(Tao tao, Vec x, Mat J, Mat Jpre, void *Ctx)
663918dfc20SMatthew G. Knepley {
664*2a8381b2SBarry Smith   EmaxCtx           *ctx = (EmaxCtx *)Ctx;
665918dfc20SMatthew G. Knepley   const PetscScalar *a;
666918dfc20SMatthew G. Knepley   PetscScalar       *jac;
667918dfc20SMatthew G. Knepley   PetscReal          C, gamma, omega, phi;
668918dfc20SMatthew G. Knepley   const PetscInt     n = ctx->e - ctx->s;
669918dfc20SMatthew G. Knepley 
670918dfc20SMatthew G. Knepley   PetscFunctionBegin;
671918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(x, &a));
672918dfc20SMatthew G. Knepley   C     = PetscRealPart(a[0]);
673918dfc20SMatthew G. Knepley   gamma = PetscRealPart(a[1]);
674918dfc20SMatthew G. Knepley   omega = PetscRealPart(a[2]);
675918dfc20SMatthew G. Knepley   phi   = PetscRealPart(a[3]);
676918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(x, &a));
677918dfc20SMatthew G. Knepley   PetscCall(MatDenseGetArray(J, &jac));
678918dfc20SMatthew G. Knepley   for (PetscInt i = 0; i < n; ++i) {
679918dfc20SMatthew G. Knepley     const PetscInt k = i + ctx->s;
680918dfc20SMatthew G. Knepley 
681918dfc20SMatthew G. Knepley     jac[i * 4 + 0] = -PetscExpReal(-gamma * ctx->t[k]) * PetscAbsReal(PetscCosReal(omega * ctx->t[k] - phi));
682918dfc20SMatthew G. Knepley     jac[i * 4 + 1] = C * ctx->t[k] * PetscExpReal(-gamma * ctx->t[k]) * PetscAbsReal(PetscCosReal(omega * ctx->t[k] - phi));
683918dfc20SMatthew G. Knepley     jac[i * 4 + 2] = C * ctx->t[k] * PetscExpReal(-gamma * ctx->t[k]) * (PetscCosReal(omega * ctx->t[k] - phi) < 0. ? -1. : 1.) * PetscSinReal(omega * ctx->t[k] - phi);
684918dfc20SMatthew G. Knepley     jac[i * 4 + 3] = -C * PetscExpReal(-gamma * ctx->t[k]) * (PetscCosReal(omega * ctx->t[k] - phi) < 0. ? -1. : 1.) * PetscSinReal(omega * ctx->t[k] - phi);
685918dfc20SMatthew G. Knepley   }
686918dfc20SMatthew G. Knepley   PetscCall(MatDenseRestoreArray(J, &jac));
687918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
688918dfc20SMatthew G. Knepley }
689918dfc20SMatthew G. Knepley 
690918dfc20SMatthew G. Knepley // Our model is log_10 E_max(t) = log_10 C - gamma t log_10 e + log_10 |cos(omega t - phi)|
ComputeLogEmaxResidual(Tao tao,Vec x,Vec res,void * Ctx)691*2a8381b2SBarry Smith static PetscErrorCode ComputeLogEmaxResidual(Tao tao, Vec x, Vec res, void *Ctx)
692918dfc20SMatthew G. Knepley {
693*2a8381b2SBarry Smith   EmaxCtx           *ctx = (EmaxCtx *)Ctx;
694918dfc20SMatthew G. Knepley   const PetscScalar *a;
695918dfc20SMatthew G. Knepley   PetscScalar       *F;
696918dfc20SMatthew G. Knepley   PetscReal          C, gamma, omega, phi;
697918dfc20SMatthew G. Knepley 
698918dfc20SMatthew G. Knepley   PetscFunctionBegin;
699918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(x, &a));
700918dfc20SMatthew G. Knepley   PetscCall(VecGetArray(res, &F));
701918dfc20SMatthew G. Knepley   C     = PetscRealPart(a[0]);
702918dfc20SMatthew G. Knepley   gamma = PetscRealPart(a[1]);
703918dfc20SMatthew G. Knepley   omega = PetscRealPart(a[2]);
704918dfc20SMatthew G. Knepley   phi   = PetscRealPart(a[3]);
705918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(x, &a));
706918dfc20SMatthew G. Knepley   for (PetscInt i = ctx->s; i < ctx->e; ++i) {
707918dfc20SMatthew G. Knepley     if (C < 0) {
708918dfc20SMatthew G. Knepley       F[i - ctx->s] = 1e10;
709918dfc20SMatthew G. Knepley       continue;
710918dfc20SMatthew G. Knepley     }
711918dfc20SMatthew G. Knepley     F[i - ctx->s] = ctx->Emax[i] - (PetscLog10Real(C) - gamma * ctx->t[i] * PetscLog10Real(PETSC_E) + PetscLog10Real(PetscAbsReal(PetscCosReal(omega * ctx->t[i] - phi))));
712918dfc20SMatthew G. Knepley   }
713918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArray(res, &F));
714918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
715918dfc20SMatthew G. Knepley }
716918dfc20SMatthew G. Knepley 
717918dfc20SMatthew G. Knepley // The Jacobian of the residual J = dr(x)/dx
ComputeLogEmaxJacobian(Tao tao,Vec x,Mat J,Mat Jpre,void * Ctx)718*2a8381b2SBarry Smith static PetscErrorCode ComputeLogEmaxJacobian(Tao tao, Vec x, Mat J, Mat Jpre, void *Ctx)
719918dfc20SMatthew G. Knepley {
720*2a8381b2SBarry Smith   EmaxCtx           *ctx = (EmaxCtx *)Ctx;
721918dfc20SMatthew G. Knepley   const PetscScalar *a;
722918dfc20SMatthew G. Knepley   PetscScalar       *jac;
723918dfc20SMatthew G. Knepley   PetscReal          C, omega, phi;
724918dfc20SMatthew G. Knepley   const PetscInt     n = ctx->e - ctx->s;
725918dfc20SMatthew G. Knepley 
726918dfc20SMatthew G. Knepley   PetscFunctionBegin;
727918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(x, &a));
728918dfc20SMatthew G. Knepley   C     = PetscRealPart(a[0]);
729918dfc20SMatthew G. Knepley   omega = PetscRealPart(a[2]);
730918dfc20SMatthew G. Knepley   phi   = PetscRealPart(a[3]);
731918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(x, &a));
732918dfc20SMatthew G. Knepley   PetscCall(MatDenseGetArray(J, &jac));
733918dfc20SMatthew G. Knepley   for (PetscInt i = 0; i < n; ++i) {
734918dfc20SMatthew G. Knepley     const PetscInt k = i + ctx->s;
735918dfc20SMatthew G. Knepley 
736918dfc20SMatthew G. Knepley     jac[0 * n + i] = -1. / (PetscLog10Real(PETSC_E) * C);
737918dfc20SMatthew G. Knepley     jac[1 * n + i] = ctx->t[k] * PetscLog10Real(PETSC_E);
738918dfc20SMatthew G. Knepley     jac[2 * n + i] = (PetscCosReal(omega * ctx->t[k] - phi) < 0. ? -1. : 1.) * ctx->t[k] * PetscSinReal(omega * ctx->t[k] - phi) / (PetscLog10Real(PETSC_E) * PetscAbsReal(PetscCosReal(omega * ctx->t[k] - phi)));
739918dfc20SMatthew G. Knepley     jac[3 * n + i] = -(PetscCosReal(omega * ctx->t[k] - phi) < 0. ? -1. : 1.) * PetscSinReal(omega * ctx->t[k] - phi) / (PetscLog10Real(PETSC_E) * PetscAbsReal(PetscCosReal(omega * ctx->t[k] - phi)));
740918dfc20SMatthew G. Knepley   }
741918dfc20SMatthew G. Knepley   PetscCall(MatDenseRestoreArray(J, &jac));
742918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(J, NULL, "-emax_jac_view"));
743918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
744918dfc20SMatthew G. Knepley }
745918dfc20SMatthew G. Knepley 
MonitorEField(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)746*2a8381b2SBarry Smith static PetscErrorCode MonitorEField(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
747918dfc20SMatthew G. Knepley {
748*2a8381b2SBarry Smith   AppCtx     *ctx = (AppCtx *)Ctx;
749918dfc20SMatthew G. Knepley   DM          sw;
750918dfc20SMatthew G. Knepley   PetscScalar intESq;
751918dfc20SMatthew G. Knepley   PetscReal  *E, *x, *weight;
752918dfc20SMatthew G. Knepley   PetscReal   Enorm = 0., lgEnorm, lgEmax, sum = 0., Emax = 0., chargesum = 0.;
753918dfc20SMatthew G. Knepley   PetscReal   pmoments[4]; /* \int f, \int v f, \int v^2 f */
754918dfc20SMatthew G. Knepley   PetscInt   *species, dim, Np, gNp;
755918dfc20SMatthew G. Knepley   MPI_Comm    comm;
756918dfc20SMatthew G. Knepley   PetscMPIInt rank;
757918dfc20SMatthew G. Knepley 
758918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
759*2a8381b2SBarry Smith   if (step < 0 || !ctx->validE) PetscFunctionReturn(PETSC_SUCCESS);
760918dfc20SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
761918dfc20SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
762918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
763918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
764918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
765918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetSize(sw, &gNp));
766918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
767918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
768918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
769918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
770918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
771918dfc20SMatthew G. Knepley 
772918dfc20SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
773918dfc20SMatthew G. Knepley     for (PetscInt d = 0; d < 1; ++d) {
774918dfc20SMatthew G. Knepley       PetscReal temp = PetscAbsReal(E[p * dim + d]);
775918dfc20SMatthew G. Knepley       if (temp > Emax) Emax = temp;
776918dfc20SMatthew G. Knepley     }
777918dfc20SMatthew G. Knepley     Enorm += PetscSqrtReal(E[p * dim] * E[p * dim]);
778918dfc20SMatthew G. Knepley     sum += E[p * dim];
779*2a8381b2SBarry Smith     chargesum += ctx->charges[0] * weight[p];
780918dfc20SMatthew G. Knepley   }
781918dfc20SMatthew G. Knepley   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &Emax, 1, MPIU_REAL, MPIU_MAX, comm));
782918dfc20SMatthew G. Knepley   lgEnorm = Enorm != 0 ? PetscLog10Real(Enorm) : -16.;
783*2a8381b2SBarry Smith   lgEmax  = Emax != 0 ? PetscLog10Real(Emax) : ctx->drawlgEmin;
784918dfc20SMatthew G. Knepley 
785918dfc20SMatthew G. Knepley   PetscDS ds;
786918dfc20SMatthew G. Knepley   Vec     phi;
787918dfc20SMatthew G. Knepley 
788*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
789*2a8381b2SBarry Smith   PetscCall(DMGetDS(ctx->dmPot, &ds));
790918dfc20SMatthew G. Knepley   PetscCall(PetscDSSetObjective(ds, 0, &f0_grad_phi2));
791*2a8381b2SBarry Smith   PetscCall(DMPlexComputeIntegralFEM(ctx->dmPot, phi, &intESq, ctx));
792*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
793918dfc20SMatthew G. Knepley 
794918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
795918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
796918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
797918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
798*2a8381b2SBarry Smith   PetscCall(PetscDrawLGAddPoint(ctx->drawlgE, &t, &lgEmax));
799*2a8381b2SBarry Smith   if (ctx->efield_monitor == E_MONITOR_FULL) {
800918dfc20SMatthew G. Knepley     PetscDraw draw;
801918dfc20SMatthew G. Knepley 
802*2a8381b2SBarry Smith     PetscCall(PetscDrawLGDraw(ctx->drawlgE));
803*2a8381b2SBarry Smith     PetscCall(PetscDrawLGGetDraw(ctx->drawlgE, &draw));
804918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSave(draw));
805918dfc20SMatthew G. Knepley 
806918dfc20SMatthew G. Knepley     PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
807918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "E: %f\t%+e\t%e\t%f\t%20.15e\t%f\t%f\t%f\t%20.15e\t%20.15e\t%20.15e\t%" PetscInt_FMT "\t(%" PetscInt_FMT ")\n", (double)t, (double)sum, (double)Enorm, (double)lgEnorm, (double)Emax, (double)lgEmax, (double)chargesum, (double)pmoments[0], (double)pmoments[1], (double)pmoments[1 + dim], (double)PetscSqrtReal(intESq), gNp, step));
808918dfc20SMatthew G. Knepley     PetscCall(DMViewFromOptions(sw, NULL, "-sw_efield_view"));
809918dfc20SMatthew G. Knepley   }
810918dfc20SMatthew G. Knepley 
811918dfc20SMatthew G. Knepley   // Compute decay rate and frequency
812*2a8381b2SBarry Smith   PetscCall(PetscDrawLGGetData(ctx->drawlgE, NULL, &ctx->emaxCtx.e, &ctx->emaxCtx.t, &ctx->emaxCtx.Emax));
813*2a8381b2SBarry Smith   if (!rank && !(ctx->emaxCtx.e % ctx->emaxCtx.per)) {
814918dfc20SMatthew G. Knepley     Tao          tao;
815918dfc20SMatthew G. Knepley     Mat          J;
816918dfc20SMatthew G. Knepley     Vec          x, r;
817918dfc20SMatthew G. Knepley     PetscScalar *a;
818918dfc20SMatthew G. Knepley     PetscBool    fitLog = PETSC_TRUE, debug = PETSC_FALSE;
819918dfc20SMatthew G. Knepley 
820918dfc20SMatthew G. Knepley     PetscCall(TaoCreate(PETSC_COMM_SELF, &tao));
821918dfc20SMatthew G. Knepley     PetscCall(TaoSetOptionsPrefix(tao, "emax_"));
822918dfc20SMatthew G. Knepley     PetscCall(VecCreateSeq(PETSC_COMM_SELF, 4, &x));
823918dfc20SMatthew G. Knepley     PetscCall(TaoSetSolution(tao, x));
824*2a8381b2SBarry Smith     PetscCall(VecCreateSeq(PETSC_COMM_SELF, ctx->emaxCtx.e - ctx->emaxCtx.s, &r));
825*2a8381b2SBarry Smith     if (fitLog) PetscCall(TaoSetResidualRoutine(tao, r, ComputeLogEmaxResidual, &ctx->emaxCtx));
826*2a8381b2SBarry Smith     else PetscCall(TaoSetResidualRoutine(tao, r, ComputeEmaxResidual, &ctx->emaxCtx));
827918dfc20SMatthew G. Knepley     PetscCall(VecDestroy(&r));
828*2a8381b2SBarry Smith     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, ctx->emaxCtx.e - ctx->emaxCtx.s, 4, NULL, &J));
829*2a8381b2SBarry Smith     if (fitLog) PetscCall(TaoSetJacobianResidualRoutine(tao, J, J, ComputeLogEmaxJacobian, &ctx->emaxCtx));
830*2a8381b2SBarry Smith     else PetscCall(TaoSetJacobianResidualRoutine(tao, J, J, ComputeEmaxJacobian, &ctx->emaxCtx));
831918dfc20SMatthew G. Knepley     PetscCall(MatDestroy(&J));
832918dfc20SMatthew G. Knepley     PetscCall(TaoSetFromOptions(tao));
833918dfc20SMatthew G. Knepley     PetscCall(VecGetArray(x, &a));
834918dfc20SMatthew G. Knepley     a[0] = 0.02;
835918dfc20SMatthew G. Knepley     a[1] = 0.15;
836918dfc20SMatthew G. Knepley     a[2] = 1.4;
837918dfc20SMatthew G. Knepley     a[3] = 0.45;
838918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArray(x, &a));
839918dfc20SMatthew G. Knepley     PetscCall(TaoSolve(tao));
840918dfc20SMatthew G. Knepley     if (debug) {
841918dfc20SMatthew G. Knepley       PetscCall(PetscPrintf(PETSC_COMM_SELF, "t = ["));
842*2a8381b2SBarry Smith       for (PetscInt i = 0; i < ctx->emaxCtx.e; ++i) {
843918dfc20SMatthew G. Knepley         if (i > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
844*2a8381b2SBarry Smith         PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", ctx->emaxCtx.t[i]));
845918dfc20SMatthew G. Knepley       }
846918dfc20SMatthew G. Knepley       PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
847918dfc20SMatthew G. Knepley       PetscCall(PetscPrintf(PETSC_COMM_SELF, "Emax = ["));
848*2a8381b2SBarry Smith       for (PetscInt i = 0; i < ctx->emaxCtx.e; ++i) {
849918dfc20SMatthew G. Knepley         if (i > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
850*2a8381b2SBarry Smith         PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", ctx->emaxCtx.Emax[i]));
851918dfc20SMatthew G. Knepley       }
852918dfc20SMatthew G. Knepley       PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
853918dfc20SMatthew G. Knepley     }
854918dfc20SMatthew G. Knepley     PetscDraw     draw;
855918dfc20SMatthew G. Knepley     PetscDrawAxis axis;
856918dfc20SMatthew G. Knepley     char          title[PETSC_MAX_PATH_LEN];
857918dfc20SMatthew G. Knepley 
858918dfc20SMatthew G. Knepley     PetscCall(VecGetArray(x, &a));
859*2a8381b2SBarry Smith     ctx->gamma = a[1];
860*2a8381b2SBarry Smith     ctx->omega = a[2];
861*2a8381b2SBarry Smith     if (ctx->efield_monitor == E_MONITOR_FULL) {
862918dfc20SMatthew G. Knepley       PetscCall(PetscPrintf(PETSC_COMM_SELF, "Emax Fit: gamma %g omega %g C %g phi %g\n", a[1], a[2], a[0], a[3]));
863*2a8381b2SBarry Smith       PetscCall(PetscDrawLGGetDraw(ctx->drawlgE, &draw));
864918dfc20SMatthew G. Knepley       PetscCall(PetscSNPrintf(title, PETSC_MAX_PATH_LEN, "Max Electric Field gamma %.4g omega %.4g", a[1], a[2]));
865918dfc20SMatthew G. Knepley       PetscCall(PetscDrawSetTitle(draw, title));
866*2a8381b2SBarry Smith       PetscCall(PetscDrawLGGetAxis(ctx->drawlgE, &axis));
867918dfc20SMatthew G. Knepley       PetscCall(PetscDrawAxisSetLabels(axis, title, "time", "E_max"));
868918dfc20SMatthew G. Knepley     }
869918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArray(x, &a));
870918dfc20SMatthew G. Knepley     PetscCall(VecDestroy(&x));
871918dfc20SMatthew G. Knepley     PetscCall(TaoDestroy(&tao));
872918dfc20SMatthew G. Knepley   }
873918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
874918dfc20SMatthew G. Knepley }
875918dfc20SMatthew G. Knepley 
MonitorMoments(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)876*2a8381b2SBarry Smith static PetscErrorCode MonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
877918dfc20SMatthew G. Knepley {
878*2a8381b2SBarry Smith   AppCtx   *ctx = (AppCtx *)Ctx;
879918dfc20SMatthew G. Knepley   DM        sw;
880918dfc20SMatthew G. Knepley   PetscReal pmoments[4], fmoments[4]; /* \int f, \int v f, \int v^2 f */
881918dfc20SMatthew G. Knepley 
882918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
883918dfc20SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
884918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
885918dfc20SMatthew G. Knepley 
886918dfc20SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
887*2a8381b2SBarry Smith   PetscCall(computeVelocityFEMMoments(sw, fmoments, ctx));
888918dfc20SMatthew G. Knepley 
889918dfc20SMatthew G. Knepley   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%f\t%f\t%f\t%f\t%f\t%f\t%f\n", (double)t, (double)pmoments[0], (double)pmoments[1], (double)pmoments[3], (double)fmoments[0], (double)fmoments[1], (double)fmoments[2]));
890918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
891918dfc20SMatthew G. Knepley }
892918dfc20SMatthew G. Knepley 
zero(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)893*2a8381b2SBarry Smith static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
894918dfc20SMatthew G. Knepley {
895918dfc20SMatthew G. Knepley   u[0] = 0.0;
896918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
897918dfc20SMatthew G. Knepley }
898918dfc20SMatthew G. Knepley 
899918dfc20SMatthew G. Knepley /*
900918dfc20SMatthew G. Knepley     M_p w_p
901918dfc20SMatthew G. Knepley       - Make M_p with "moments"
902918dfc20SMatthew G. Knepley       - Get w_p from Swarm
903918dfc20SMatthew G. Knepley     M_p v_p w_p
904918dfc20SMatthew G. Knepley       - Get v_p from Swarm
905918dfc20SMatthew G. Knepley       - pointwise multiply v_p and w_p
906918dfc20SMatthew G. Knepley     M_p (v_p - (\sum_j p_F \phi_j(x_p)) / m (\sum_k n_F \phi_k(x_p)))^2 w_p
907918dfc20SMatthew G. Knepley       - ProjectField(sw, {n, p} U, {v_p} A, tmp_p)
908918dfc20SMatthew G. Knepley       - pointwise multiply tmp_p and w_p
909918dfc20SMatthew G. Knepley 
910f14fce1bSMatthew G. Knepley   Projection works fpr swarms
911f14fce1bSMatthew G. Knepley     Fields are FE from the CellDM, and aux fields are the swarm fields
912918dfc20SMatthew G. Knepley */
ComputeMomentFields(TS ts)913918dfc20SMatthew G. Knepley static PetscErrorCode ComputeMomentFields(TS ts)
914918dfc20SMatthew G. Knepley {
915*2a8381b2SBarry Smith   AppCtx   *ctx;
916918dfc20SMatthew G. Knepley   DM        sw;
917918dfc20SMatthew G. Knepley   KSP       ksp;
918f14fce1bSMatthew G. Knepley   Mat       M_p, D_p;
919f14fce1bSMatthew G. Knepley   Vec       f, v, E, tmpMom;
920f14fce1bSMatthew G. Knepley   Vec       m, mold, mfluxold, mres, n, nrhs, nflux, nres, p, prhs, pflux, pres, e, erhs, eflux, eres;
921f14fce1bSMatthew G. Knepley   PetscReal dt, t;
922918dfc20SMatthew G. Knepley   PetscInt  Nts;
923918dfc20SMatthew G. Knepley 
924918dfc20SMatthew G. Knepley   PetscFunctionBegin;
925918dfc20SMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &Nts));
926918dfc20SMatthew G. Knepley   PetscCall(TSGetTimeStep(ts, &dt));
927f14fce1bSMatthew G. Knepley   PetscCall(TSGetTime(ts, &t));
928918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
929*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
930918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "moment fields"));
931918dfc20SMatthew G. Knepley   PetscCall(DMSwarmMigrate(sw, PETSC_FALSE));
932f14fce1bSMatthew G. Knepley   // TODO In higher dimensions, we will have to create different M_p and D_p for each field
933*2a8381b2SBarry Smith   PetscCall(DMCreateMassMatrix(sw, ctx->dmN, &M_p));
934*2a8381b2SBarry Smith   PetscCall(DMCreateGradientMatrix(sw, ctx->dmN, &D_p));
935918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
936918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &v));
937f14fce1bSMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "E_field", &E));
938918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
939918dfc20SMatthew G. Knepley 
940*2a8381b2SBarry Smith   PetscCall(MatViewFromOptions(ctx->MN, NULL, "-mn_view"));
941*2a8381b2SBarry Smith   PetscCall(MatViewFromOptions(ctx->MP, NULL, "-mp_view"));
942*2a8381b2SBarry Smith   PetscCall(MatViewFromOptions(ctx->ME, NULL, "-me_view"));
943918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
944918dfc20SMatthew G. Knepley 
945*2a8381b2SBarry Smith   PetscCall(DMGetGlobalVector(ctx->dmN, &nrhs));
946*2a8381b2SBarry Smith   PetscCall(DMGetGlobalVector(ctx->dmN, &nflux));
947f14fce1bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)nrhs, "Weak number density"));
948*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmN, "n", &n));
949*2a8381b2SBarry Smith   PetscCall(DMGetGlobalVector(ctx->dmP, &prhs));
950*2a8381b2SBarry Smith   PetscCall(DMGetGlobalVector(ctx->dmP, &pflux));
951f14fce1bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)prhs, "Weak momentum density"));
952*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmP, "p", &p));
953*2a8381b2SBarry Smith   PetscCall(DMGetGlobalVector(ctx->dmE, &erhs));
954*2a8381b2SBarry Smith   PetscCall(DMGetGlobalVector(ctx->dmE, &eflux));
955f14fce1bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)erhs, "Weak energy density (pressure)"));
956*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmE, "e", &e));
957918dfc20SMatthew G. Knepley 
958f14fce1bSMatthew G. Knepley   // Compute moments and fluxes
959f14fce1bSMatthew G. Knepley   PetscCall(VecDuplicate(f, &tmpMom));
960918dfc20SMatthew G. Knepley 
961f14fce1bSMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, nrhs));
962f14fce1bSMatthew G. Knepley 
963f14fce1bSMatthew G. Knepley   PetscCall(VecPointwiseMult(tmpMom, f, v));
964f14fce1bSMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, tmpMom, prhs));
965f14fce1bSMatthew G. Knepley   PetscCall(MatMultTranspose(D_p, tmpMom, nflux));
966f14fce1bSMatthew G. Knepley 
967f14fce1bSMatthew G. Knepley   PetscCall(VecPointwiseMult(tmpMom, tmpMom, v));
968f14fce1bSMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, tmpMom, erhs));
969f14fce1bSMatthew G. Knepley   PetscCall(MatMultTranspose(D_p, tmpMom, pflux));
970f14fce1bSMatthew G. Knepley 
971f14fce1bSMatthew G. Knepley   PetscCall(VecPointwiseMult(tmpMom, tmpMom, v));
972f14fce1bSMatthew G. Knepley   PetscCall(MatMultTranspose(D_p, tmpMom, eflux));
973f14fce1bSMatthew G. Knepley 
974f14fce1bSMatthew G. Knepley   PetscCall(VecPointwiseMult(tmpMom, f, E));
975f14fce1bSMatthew G. Knepley   PetscCall(MatMultTransposeAdd(M_p, tmpMom, pflux, pflux));
976f14fce1bSMatthew G. Knepley 
977f14fce1bSMatthew G. Knepley   PetscCall(VecPointwiseMult(tmpMom, v, E));
978f14fce1bSMatthew G. Knepley   PetscCall(VecScale(tmpMom, 2.));
979f14fce1bSMatthew G. Knepley   PetscCall(MatMultTransposeAdd(M_p, tmpMom, eflux, eflux));
980f14fce1bSMatthew G. Knepley 
981f14fce1bSMatthew G. Knepley   PetscCall(VecDestroy(&tmpMom));
982918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &v));
983918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
984f14fce1bSMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "E_field", &E));
985918dfc20SMatthew G. Knepley 
986918dfc20SMatthew G. Knepley   PetscCall(MatDestroy(&M_p));
987f14fce1bSMatthew G. Knepley   PetscCall(MatDestroy(&D_p));
988918dfc20SMatthew G. Knepley 
989918dfc20SMatthew G. Knepley   PetscCall(KSPCreate(PetscObjectComm((PetscObject)sw), &ksp));
990918dfc20SMatthew G. Knepley   PetscCall(KSPSetOptionsPrefix(ksp, "mom_proj_"));
991*2a8381b2SBarry Smith   PetscCall(KSPSetOperators(ksp, ctx->MN, ctx->MN));
992918dfc20SMatthew G. Knepley   PetscCall(KSPSetFromOptions(ksp));
993f14fce1bSMatthew G. Knepley   PetscCall(KSPSolve(ksp, nrhs, n));
994*2a8381b2SBarry Smith   PetscCall(KSPSetOperators(ksp, ctx->MP, ctx->MP));
995918dfc20SMatthew G. Knepley   PetscCall(KSPSetFromOptions(ksp));
996f14fce1bSMatthew G. Knepley   PetscCall(KSPSolve(ksp, prhs, p));
997*2a8381b2SBarry Smith   PetscCall(KSPSetOperators(ksp, ctx->ME, ctx->ME));
998918dfc20SMatthew G. Knepley   PetscCall(KSPSetFromOptions(ksp));
999f14fce1bSMatthew G. Knepley   PetscCall(KSPSolve(ksp, erhs, e));
1000918dfc20SMatthew G. Knepley   PetscCall(KSPDestroy(&ksp));
1001*2a8381b2SBarry Smith   PetscCall(DMRestoreGlobalVector(ctx->dmN, &nrhs));
1002*2a8381b2SBarry Smith   PetscCall(DMRestoreGlobalVector(ctx->dmP, &prhs));
1003*2a8381b2SBarry Smith   PetscCall(DMRestoreGlobalVector(ctx->dmE, &erhs));
1004918dfc20SMatthew G. Knepley 
1005918dfc20SMatthew G. Knepley   // Check moment residual
1006918dfc20SMatthew G. Knepley   // TODO Fix global2local here
1007f14fce1bSMatthew G. Knepley   PetscReal res[3], logres[3];
1008918dfc20SMatthew G. Knepley 
1009*2a8381b2SBarry Smith   PetscCall(DMGetGlobalVector(ctx->dmMom, &m));
1010*2a8381b2SBarry Smith   PetscCall(VecISCopy(m, ctx->isN, SCATTER_FORWARD, n));
1011*2a8381b2SBarry Smith   PetscCall(VecISCopy(m, ctx->isP, SCATTER_FORWARD, p));
1012*2a8381b2SBarry Smith   PetscCall(VecISCopy(m, ctx->isE, SCATTER_FORWARD, e));
1013*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmMom, "mold", &mold));
1014*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmMom, "mfluxold", &mfluxold));
1015f14fce1bSMatthew G. Knepley   if (!Nts) goto end;
1016f14fce1bSMatthew G. Knepley 
1017f14fce1bSMatthew G. Knepley   // e = \Tr{\tau}
1018f14fce1bSMatthew G. Knepley   // M_p w^{k+1} - M_p w^k - \Delta t D_p (w^k \vb{v}^k) = 0
1019f14fce1bSMatthew G. Knepley   // M_p \vb{p}^{k+1} - M_p \vb{p}^k - \Delta t D_p \tau - e \Delta t M_p \left( n \vb{E} \right) = 0
1020f14fce1bSMatthew G. Knepley   // M_p e^{k+1} - M_p e^k - \Delta t D_p \vb{Q} - 2 e \Delta t M_p \left( \vb{p} \cdot \vb{E} \right) = 0
1021*2a8381b2SBarry Smith   PetscCall(DMGetGlobalVector(ctx->dmMom, &mres));
1022f14fce1bSMatthew G. Knepley   PetscCall(VecCopy(mfluxold, mres));
1023f14fce1bSMatthew G. Knepley   PetscCall(VecAXPBYPCZ(mres, 1. / dt, -1. / dt, -1., m, mold));
1024f14fce1bSMatthew G. Knepley 
1025*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmN, "nres", &nres));
1026*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmP, "pres", &pres));
1027*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmE, "eres", &eres));
1028*2a8381b2SBarry Smith   PetscCall(VecISCopy(mres, ctx->isN, SCATTER_REVERSE, nres));
1029*2a8381b2SBarry Smith   PetscCall(VecISCopy(mres, ctx->isP, SCATTER_REVERSE, pres));
1030*2a8381b2SBarry Smith   PetscCall(VecISCopy(mres, ctx->isE, SCATTER_REVERSE, eres));
1031f14fce1bSMatthew G. Knepley   PetscCall(VecNorm(nres, NORM_2, &res[0]));
1032f14fce1bSMatthew G. Knepley   PetscCall(VecNorm(pres, NORM_2, &res[1]));
1033f14fce1bSMatthew G. Knepley   PetscCall(VecNorm(eres, NORM_2, &res[2]));
1034f14fce1bSMatthew G. Knepley   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)sw), "Mass Residual: %g\n", (double)res[0]));
1035f14fce1bSMatthew G. Knepley   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)sw), "Momentum Residual: %g\n", (double)res[1]));
1036f14fce1bSMatthew G. Knepley   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)sw), "Energy Residual: %g\n", (double)res[2]));
1037*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmN, "nres", &nres));
1038*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmP, "pres", &pres));
1039*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmE, "eres", &eres));
1040*2a8381b2SBarry Smith   PetscCall(DMRestoreGlobalVector(ctx->dmMom, &mres));
1041f14fce1bSMatthew G. Knepley 
1042f14fce1bSMatthew G. Knepley   for (PetscInt i = 0; i < 3; ++i) logres[i] = PetscLog10Real(res[i]);
1043*2a8381b2SBarry Smith   PetscCall(PetscDrawLGAddCommonPoint(ctx->drawlgMomRes, t, logres));
1044*2a8381b2SBarry Smith   PetscCall(PetscDrawLGDraw(ctx->drawlgMomRes));
1045f14fce1bSMatthew G. Knepley   {
1046f14fce1bSMatthew G. Knepley     PetscDraw draw;
1047f14fce1bSMatthew G. Knepley 
1048*2a8381b2SBarry Smith     PetscCall(PetscDrawLGGetDraw(ctx->drawlgMomRes, &draw));
1049f14fce1bSMatthew G. Knepley     PetscCall(PetscDrawSave(draw));
1050f14fce1bSMatthew G. Knepley   }
1051f14fce1bSMatthew G. Knepley 
1052f14fce1bSMatthew G. Knepley end:
1053918dfc20SMatthew G. Knepley   PetscCall(VecCopy(m, mold));
1054*2a8381b2SBarry Smith   PetscCall(DMRestoreGlobalVector(ctx->dmMom, &m));
1055*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmMom, "mold", &mold));
1056*2a8381b2SBarry Smith   PetscCall(VecISCopy(mfluxold, ctx->isN, SCATTER_FORWARD, nflux));
1057*2a8381b2SBarry Smith   PetscCall(VecISCopy(mfluxold, ctx->isP, SCATTER_FORWARD, pflux));
1058*2a8381b2SBarry Smith   PetscCall(VecISCopy(mfluxold, ctx->isE, SCATTER_FORWARD, eflux));
1059*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmMom, "mfluxold", &mfluxold));
1060918dfc20SMatthew G. Knepley 
1061*2a8381b2SBarry Smith   PetscCall(DMRestoreGlobalVector(ctx->dmN, &nflux));
1062*2a8381b2SBarry Smith   PetscCall(DMRestoreGlobalVector(ctx->dmP, &pflux));
1063*2a8381b2SBarry Smith   PetscCall(DMRestoreGlobalVector(ctx->dmE, &eflux));
1064*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmN, "n", &n));
1065*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmP, "p", &p));
1066*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmE, "e", &e));
1067918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
1068918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1069918dfc20SMatthew G. Knepley }
1070918dfc20SMatthew G. Knepley 
MonitorMomentFields(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)1071*2a8381b2SBarry Smith static PetscErrorCode MonitorMomentFields(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
1072918dfc20SMatthew G. Knepley {
1073*2a8381b2SBarry Smith   AppCtx *ctx = (AppCtx *)Ctx;
1074918dfc20SMatthew G. Knepley   Vec     n, p, e;
1075f14fce1bSMatthew G. Knepley   Vec     nres, pres, eres;
1076918dfc20SMatthew G. Knepley 
1077918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1078918dfc20SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
1079918dfc20SMatthew G. Knepley   PetscCall(ComputeMomentFields(ts));
1080918dfc20SMatthew G. Knepley 
1081*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmN, "n", &n));
1082*2a8381b2SBarry Smith   PetscCall(VecView(n, ctx->viewerN));
1083*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmN, "n", &n));
1084918dfc20SMatthew G. Knepley 
1085*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmP, "p", &p));
1086*2a8381b2SBarry Smith   PetscCall(VecView(p, ctx->viewerP));
1087*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmP, "p", &p));
1088918dfc20SMatthew G. Knepley 
1089*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmE, "e", &e));
1090*2a8381b2SBarry Smith   PetscCall(VecView(e, ctx->viewerE));
1091*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmE, "e", &e));
1092f14fce1bSMatthew G. Knepley 
1093*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmN, "nres", &nres));
1094*2a8381b2SBarry Smith   PetscCall(VecView(nres, ctx->viewerNRes));
1095*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmN, "nres", &nres));
1096f14fce1bSMatthew G. Knepley 
1097*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmP, "pres", &pres));
1098*2a8381b2SBarry Smith   PetscCall(VecView(pres, ctx->viewerPRes));
1099*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmP, "pres", &pres));
1100f14fce1bSMatthew G. Knepley 
1101*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmE, "eres", &eres));
1102*2a8381b2SBarry Smith   PetscCall(VecView(eres, ctx->viewerERes));
1103*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmE, "eres", &eres));
1104918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1105918dfc20SMatthew G. Knepley }
1106918dfc20SMatthew G. Knepley 
MonitorInitialConditions(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)1107*2a8381b2SBarry Smith PetscErrorCode MonitorInitialConditions(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
1108918dfc20SMatthew G. Knepley {
1109*2a8381b2SBarry Smith   AppCtx    *ctx = (AppCtx *)Ctx;
1110918dfc20SMatthew G. Knepley   DM         sw;
1111918dfc20SMatthew G. Knepley   PetscDraw  drawic_x, drawic_v;
1112918dfc20SMatthew G. Knepley   PetscReal *weight, *pos, *vel;
1113918dfc20SMatthew G. Knepley   PetscInt   dim, Np;
1114918dfc20SMatthew G. Knepley 
1115918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1116918dfc20SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
1117918dfc20SMatthew G. Knepley   if (step == 0) {
1118918dfc20SMatthew G. Knepley     PetscCall(TSGetDM(ts, &sw));
1119918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(sw, &dim));
1120918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetLocalSize(sw, &Np));
1121918dfc20SMatthew G. Knepley 
1122*2a8381b2SBarry Smith     PetscCall(PetscDrawHGReset(ctx->drawhgic_x));
1123*2a8381b2SBarry Smith     PetscCall(PetscDrawHGGetDraw(ctx->drawhgic_x, &drawic_x));
1124918dfc20SMatthew G. Knepley     PetscCall(PetscDrawClear(drawic_x));
1125918dfc20SMatthew G. Knepley     PetscCall(PetscDrawFlush(drawic_x));
1126918dfc20SMatthew G. Knepley 
1127*2a8381b2SBarry Smith     PetscCall(PetscDrawHGReset(ctx->drawhgic_v));
1128*2a8381b2SBarry Smith     PetscCall(PetscDrawHGGetDraw(ctx->drawhgic_v, &drawic_v));
1129918dfc20SMatthew G. Knepley     PetscCall(PetscDrawClear(drawic_v));
1130918dfc20SMatthew G. Knepley     PetscCall(PetscDrawFlush(drawic_v));
1131918dfc20SMatthew G. Knepley 
1132918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
1133918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
1134918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
1135918dfc20SMatthew G. Knepley     for (PetscInt p = 0; p < Np; ++p) {
1136*2a8381b2SBarry Smith       PetscCall(PetscDrawHGAddWeightedValue(ctx->drawhgic_x, pos[p * dim], weight[p]));
1137*2a8381b2SBarry Smith       PetscCall(PetscDrawHGAddWeightedValue(ctx->drawhgic_v, vel[p * dim], weight[p]));
1138918dfc20SMatthew G. Knepley     }
1139918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
1140918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
1141918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
1142918dfc20SMatthew G. Knepley 
1143*2a8381b2SBarry Smith     PetscCall(PetscDrawHGDraw(ctx->drawhgic_x));
1144*2a8381b2SBarry Smith     PetscCall(PetscDrawHGSave(ctx->drawhgic_x));
1145*2a8381b2SBarry Smith     PetscCall(PetscDrawHGDraw(ctx->drawhgic_v));
1146*2a8381b2SBarry Smith     PetscCall(PetscDrawHGSave(ctx->drawhgic_v));
1147918dfc20SMatthew G. Knepley   }
1148918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1149918dfc20SMatthew G. Knepley }
1150918dfc20SMatthew G. Knepley 
1151918dfc20SMatthew G. Knepley // Right now, make the complete velocity histogram
MonitorVelocity(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)1152*2a8381b2SBarry Smith PetscErrorCode MonitorVelocity(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
1153918dfc20SMatthew G. Knepley {
1154*2a8381b2SBarry Smith   AppCtx      *ctx = (AppCtx *)Ctx;
1155918dfc20SMatthew G. Knepley   DM           sw, dm;
1156918dfc20SMatthew G. Knepley   Vec          ks;
1157918dfc20SMatthew G. Knepley   PetscProbFn *cdf;
1158918dfc20SMatthew G. Knepley   PetscDraw    drawcell_v;
1159918dfc20SMatthew G. Knepley   PetscScalar *ksa;
1160918dfc20SMatthew G. Knepley   PetscReal   *weight, *vel;
1161918dfc20SMatthew G. Knepley   PetscInt    *pidx;
1162*2a8381b2SBarry Smith   PetscInt     dim, Npc, cStart, cEnd, cell = ctx->velocity_monitor;
1163918dfc20SMatthew G. Knepley 
1164918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1165918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
1166918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1167918dfc20SMatthew G. Knepley 
1168918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &dm));
1169918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1170918dfc20SMatthew G. Knepley   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &ks));
1171918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)ks, "KS Statistic by Cell"));
1172918dfc20SMatthew G. Knepley   PetscCall(VecSetSizes(ks, cEnd - cStart, PETSC_DETERMINE));
1173918dfc20SMatthew G. Knepley   PetscCall(VecSetFromOptions(ks));
1174918dfc20SMatthew G. Knepley   switch (dim) {
1175918dfc20SMatthew G. Knepley   case 1:
1176918dfc20SMatthew G. Knepley     //cdf = PetscCDFMaxwellBoltzmann1D;
1177918dfc20SMatthew G. Knepley     cdf = PetscCDFGaussian1D;
1178918dfc20SMatthew G. Knepley     break;
1179918dfc20SMatthew G. Knepley   case 2:
1180918dfc20SMatthew G. Knepley     cdf = PetscCDFMaxwellBoltzmann2D;
1181918dfc20SMatthew G. Knepley     break;
1182918dfc20SMatthew G. Knepley   case 3:
1183918dfc20SMatthew G. Knepley     cdf = PetscCDFMaxwellBoltzmann3D;
1184918dfc20SMatthew G. Knepley     break;
1185918dfc20SMatthew G. Knepley   default:
1186918dfc20SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim);
1187918dfc20SMatthew G. Knepley   }
1188918dfc20SMatthew G. Knepley 
1189*2a8381b2SBarry Smith   PetscCall(PetscDrawHGReset(ctx->drawhgcell_v));
1190*2a8381b2SBarry Smith   PetscCall(PetscDrawHGGetDraw(ctx->drawhgcell_v, &drawcell_v));
1191918dfc20SMatthew G. Knepley   PetscCall(PetscDrawClear(drawcell_v));
1192918dfc20SMatthew G. Knepley   PetscCall(PetscDrawFlush(drawcell_v));
1193918dfc20SMatthew G. Knepley 
1194918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
1195918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
1196918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
1197918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayWrite(ks, &ksa));
1198918dfc20SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1199918dfc20SMatthew G. Knepley     Vec          cellv, cellw;
1200918dfc20SMatthew G. Knepley     PetscScalar *cella, *cellaw;
1201918dfc20SMatthew G. Knepley     PetscReal    totWgt = 0.;
1202918dfc20SMatthew G. Knepley 
1203918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
1204918dfc20SMatthew G. Knepley     PetscCall(VecCreate(PETSC_COMM_SELF, &cellv));
1205918dfc20SMatthew G. Knepley     PetscCall(VecSetBlockSize(cellv, dim));
1206918dfc20SMatthew G. Knepley     PetscCall(VecSetSizes(cellv, Npc * dim, Npc));
1207918dfc20SMatthew G. Knepley     PetscCall(VecSetFromOptions(cellv));
1208918dfc20SMatthew G. Knepley     PetscCall(VecCreate(PETSC_COMM_SELF, &cellw));
1209918dfc20SMatthew G. Knepley     PetscCall(VecSetSizes(cellw, Npc, Npc));
1210918dfc20SMatthew G. Knepley     PetscCall(VecSetFromOptions(cellw));
1211918dfc20SMatthew G. Knepley     PetscCall(VecGetArrayWrite(cellv, &cella));
1212918dfc20SMatthew G. Knepley     PetscCall(VecGetArrayWrite(cellw, &cellaw));
1213918dfc20SMatthew G. Knepley     for (PetscInt q = 0; q < Npc; ++q) {
1214918dfc20SMatthew G. Knepley       const PetscInt p = pidx[q];
1215*2a8381b2SBarry Smith       if (c == cell) PetscCall(PetscDrawHGAddWeightedValue(ctx->drawhgcell_v, vel[p * dim], weight[p]));
1216918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) cella[q * dim + d] = vel[p * dim + d];
1217918dfc20SMatthew G. Knepley       cellaw[q] = weight[p];
1218918dfc20SMatthew G. Knepley       totWgt += weight[p];
1219918dfc20SMatthew G. Knepley     }
1220918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArrayWrite(cellv, &cella));
1221918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArrayWrite(cellw, &cellaw));
1222918dfc20SMatthew G. Knepley     PetscCall(VecScale(cellw, 1. / totWgt));
1223918dfc20SMatthew G. Knepley     PetscCall(PetscProbComputeKSStatisticWeighted(cellv, cellw, cdf, &ksa[c - cStart]));
1224918dfc20SMatthew G. Knepley     PetscCall(VecDestroy(&cellv));
1225918dfc20SMatthew G. Knepley     PetscCall(VecDestroy(&cellw));
1226918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
1227918dfc20SMatthew G. Knepley   }
1228918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayWrite(ks, &ksa));
1229918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
1230918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
1231918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
1232918dfc20SMatthew G. Knepley 
1233918dfc20SMatthew G. Knepley   PetscReal minalpha, maxalpha;
1234918dfc20SMatthew G. Knepley   PetscInt  mincell, maxcell;
1235918dfc20SMatthew G. Knepley 
1236918dfc20SMatthew G. Knepley   PetscCall(VecFilter(ks, PETSC_SMALL));
1237918dfc20SMatthew G. Knepley   PetscCall(VecMin(ks, &mincell, &minalpha));
1238918dfc20SMatthew G. Knepley   PetscCall(VecMax(ks, &maxcell, &maxalpha));
1239918dfc20SMatthew G. Knepley   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Step %" PetscInt_FMT ": Min/Max KS statistic %g/%g in cell %" PetscInt_FMT "/%" PetscInt_FMT "\n", step, minalpha, maxalpha, mincell, maxcell));
1240918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(ks, NULL, "-ks_view"));
1241918dfc20SMatthew G. Knepley   PetscCall(VecDestroy(&ks));
1242918dfc20SMatthew G. Knepley 
1243*2a8381b2SBarry Smith   PetscCall(PetscDrawHGDraw(ctx->drawhgcell_v));
1244*2a8381b2SBarry Smith   PetscCall(PetscDrawHGSave(ctx->drawhgcell_v));
1245918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1246918dfc20SMatthew G. Knepley }
1247918dfc20SMatthew G. Knepley 
MonitorPositions_2D(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)1248*2a8381b2SBarry Smith static PetscErrorCode MonitorPositions_2D(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
1249918dfc20SMatthew G. Knepley {
1250*2a8381b2SBarry Smith   AppCtx         *ctx = (AppCtx *)Ctx;
1251918dfc20SMatthew G. Knepley   DM              dm, sw;
1252f940b0e3Sdanofinn   PetscDrawAxis   axis;
1253f940b0e3Sdanofinn   char            title[1024];
1254918dfc20SMatthew G. Knepley   PetscScalar    *x, *v, *weight;
1255918dfc20SMatthew G. Knepley   PetscReal       lower[3], upper[3], speed;
1256918dfc20SMatthew G. Knepley   const PetscInt *s;
1257918dfc20SMatthew G. Knepley   PetscInt        dim, cStart, cEnd, c;
1258918dfc20SMatthew G. Knepley 
1259918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1260*2a8381b2SBarry Smith   if (step > 0 && step % ctx->ostep == 0) {
1261918dfc20SMatthew G. Knepley     PetscCall(TSGetDM(ts, &sw));
1262918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetCellDM(sw, &dm));
1263918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(dm, &dim));
1264918dfc20SMatthew G. Knepley     PetscCall(DMGetBoundingBox(dm, lower, upper));
1265918dfc20SMatthew G. Knepley     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1266918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1267918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
1268918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
1269918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&s));
1270918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetAccess(sw));
1271*2a8381b2SBarry Smith     PetscCall(PetscDrawSPReset(ctx->drawspX));
1272*2a8381b2SBarry Smith     PetscCall(PetscDrawSPGetAxis(ctx->drawspX, &axis));
1273f940b0e3Sdanofinn     PetscCall(PetscSNPrintf(title, 1024, "Step %" PetscInt_FMT " Time: %g", step, (double)t));
1274f940b0e3Sdanofinn     PetscCall(PetscDrawAxisSetLabels(axis, title, "x", "v"));
1275*2a8381b2SBarry Smith     PetscCall(PetscDrawSPSetLimits(ctx->drawspX, lower[0], upper[0], lower[1], upper[1]));
1276*2a8381b2SBarry Smith     PetscCall(PetscDrawSPSetLimits(ctx->drawspX, lower[0], upper[0], -12, 12));
1277918dfc20SMatthew G. Knepley     for (c = 0; c < cEnd - cStart; ++c) {
1278918dfc20SMatthew G. Knepley       PetscInt *pidx, Npc, q;
1279918dfc20SMatthew G. Knepley       PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
1280918dfc20SMatthew G. Knepley       for (q = 0; q < Npc; ++q) {
1281918dfc20SMatthew G. Knepley         const PetscInt p = pidx[q];
1282918dfc20SMatthew G. Knepley         if (s[p] == 0) {
1283918dfc20SMatthew G. Knepley           speed = 0.;
1284918dfc20SMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) speed += PetscSqr(v[p * dim + d]);
1285918dfc20SMatthew G. Knepley           speed = PetscSqrtReal(speed);
1286918dfc20SMatthew G. Knepley           if (dim == 1) {
1287*2a8381b2SBarry Smith             PetscCall(PetscDrawSPAddPointColorized(ctx->drawspX, &x[p * dim], &v[p * dim], &speed));
1288918dfc20SMatthew G. Knepley           } else {
1289*2a8381b2SBarry Smith             PetscCall(PetscDrawSPAddPointColorized(ctx->drawspX, &x[p * dim], &x[p * dim + 1], &speed));
1290918dfc20SMatthew G. Knepley           }
1291918dfc20SMatthew G. Knepley         } else if (s[p] == 1) {
1292*2a8381b2SBarry Smith           PetscCall(PetscDrawSPAddPoint(ctx->drawspX, &x[p * dim], &v[p * dim]));
1293918dfc20SMatthew G. Knepley         }
1294918dfc20SMatthew G. Knepley       }
1295918dfc20SMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
1296918dfc20SMatthew G. Knepley     }
1297*2a8381b2SBarry Smith     PetscCall(PetscDrawSPDraw(ctx->drawspX, PETSC_TRUE));
1298918dfc20SMatthew G. Knepley     PetscDraw draw;
1299*2a8381b2SBarry Smith     PetscCall(PetscDrawSPGetDraw(ctx->drawspX, &draw));
1300918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSave(draw));
1301918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestoreAccess(sw));
1302918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1303918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
1304918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
1305918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&s));
1306918dfc20SMatthew G. Knepley   }
1307918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1308918dfc20SMatthew G. Knepley }
1309918dfc20SMatthew G. Knepley 
MonitorPoisson(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)1310*2a8381b2SBarry Smith static PetscErrorCode MonitorPoisson(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
1311918dfc20SMatthew G. Knepley {
1312*2a8381b2SBarry Smith   AppCtx *ctx = (AppCtx *)Ctx;
1313918dfc20SMatthew G. Knepley   DM      dm, sw;
1314918dfc20SMatthew G. Knepley 
1315918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1316*2a8381b2SBarry Smith   if (step > 0 && step % ctx->ostep == 0) {
1317918dfc20SMatthew G. Knepley     PetscCall(TSGetDM(ts, &sw));
1318918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetCellDM(sw, &dm));
1319918dfc20SMatthew G. Knepley 
1320*2a8381b2SBarry Smith     if (ctx->validE) {
1321918dfc20SMatthew G. Knepley       PetscScalar *x, *E, *weight;
1322918dfc20SMatthew G. Knepley       PetscReal    lower[3], upper[3], xval;
1323918dfc20SMatthew G. Knepley       PetscDraw    draw;
1324918dfc20SMatthew G. Knepley       PetscInt     dim, cStart, cEnd;
1325918dfc20SMatthew G. Knepley 
1326918dfc20SMatthew G. Knepley       PetscCall(DMGetDimension(dm, &dim));
1327918dfc20SMatthew G. Knepley       PetscCall(DMGetBoundingBox(dm, lower, upper));
1328918dfc20SMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1329918dfc20SMatthew G. Knepley 
1330*2a8381b2SBarry Smith       PetscCall(PetscDrawSPReset(ctx->drawspE));
1331918dfc20SMatthew G. Knepley       PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1332918dfc20SMatthew G. Knepley       PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
1333918dfc20SMatthew G. Knepley       PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
1334918dfc20SMatthew G. Knepley 
1335918dfc20SMatthew G. Knepley       PetscCall(DMSwarmSortGetAccess(sw));
1336918dfc20SMatthew G. Knepley       for (PetscInt c = 0; c < cEnd - cStart; ++c) {
1337918dfc20SMatthew G. Knepley         PetscReal Eavg = 0.0;
1338918dfc20SMatthew G. Knepley         PetscInt *pidx, Npc;
1339918dfc20SMatthew G. Knepley 
1340918dfc20SMatthew G. Knepley         PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
1341918dfc20SMatthew G. Knepley         for (PetscInt q = 0; q < Npc; ++q) {
1342918dfc20SMatthew G. Knepley           const PetscInt p = pidx[q];
1343918dfc20SMatthew G. Knepley           Eavg += E[p * dim];
1344918dfc20SMatthew G. Knepley         }
1345918dfc20SMatthew G. Knepley         Eavg /= Npc;
1346918dfc20SMatthew G. Knepley         xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart));
1347*2a8381b2SBarry Smith         PetscCall(PetscDrawSPAddPoint(ctx->drawspE, &xval, &Eavg));
1348918dfc20SMatthew G. Knepley         PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
1349918dfc20SMatthew G. Knepley       }
1350*2a8381b2SBarry Smith       PetscCall(PetscDrawSPDraw(ctx->drawspE, PETSC_TRUE));
1351*2a8381b2SBarry Smith       PetscCall(PetscDrawSPGetDraw(ctx->drawspE, &draw));
1352918dfc20SMatthew G. Knepley       PetscCall(PetscDrawSave(draw));
1353918dfc20SMatthew G. Knepley       PetscCall(DMSwarmSortRestoreAccess(sw));
1354918dfc20SMatthew G. Knepley       PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1355918dfc20SMatthew G. Knepley       PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
1356918dfc20SMatthew G. Knepley       PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
1357918dfc20SMatthew G. Knepley     }
1358918dfc20SMatthew G. Knepley 
1359918dfc20SMatthew G. Knepley     Vec rho, rhohat, phi;
1360918dfc20SMatthew G. Knepley 
1361*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rho", &rho));
1362*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
1363*2a8381b2SBarry Smith     PetscCall(VecView(rho, ctx->viewerRho));
1364*2a8381b2SBarry Smith     PetscCall(VecISCopy(ctx->fftX, ctx->fftReal, SCATTER_FORWARD, rho));
1365*2a8381b2SBarry Smith     PetscCall(MatMult(ctx->fftPot, ctx->fftX, ctx->fftY));
1366*2a8381b2SBarry Smith     PetscCall(VecFilter(ctx->fftY, PETSC_SMALL));
1367*2a8381b2SBarry Smith     PetscCall(VecViewFromOptions(ctx->fftX, NULL, "-real_view"));
1368*2a8381b2SBarry Smith     PetscCall(VecViewFromOptions(ctx->fftY, NULL, "-fft_view"));
1369*2a8381b2SBarry Smith     PetscCall(VecISCopy(ctx->fftY, ctx->fftReal, SCATTER_REVERSE, rhohat));
1370918dfc20SMatthew G. Knepley     PetscCall(VecSetValue(rhohat, 0, 0., INSERT_VALUES)); // Remove large DC component
1371*2a8381b2SBarry Smith     PetscCall(VecView(rhohat, ctx->viewerRhoHat));
1372*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rho", &rho));
1373*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
1374918dfc20SMatthew G. Knepley 
1375*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
1376*2a8381b2SBarry Smith     PetscCall(VecView(phi, ctx->viewerPhi));
1377*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
1378918dfc20SMatthew G. Knepley   }
1379918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1380918dfc20SMatthew G. Knepley }
1381918dfc20SMatthew G. Knepley 
SetupParameters(MPI_Comm comm,AppCtx * ctx)1382918dfc20SMatthew G. Knepley static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx)
1383918dfc20SMatthew G. Knepley {
1384918dfc20SMatthew G. Knepley   PetscBag   bag;
1385918dfc20SMatthew G. Knepley   Parameter *p;
1386918dfc20SMatthew G. Knepley 
1387918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1388918dfc20SMatthew G. Knepley   /* setup PETSc parameter bag */
1389*2a8381b2SBarry Smith   PetscCall(PetscBagGetData(ctx->bag, &p));
1390918dfc20SMatthew G. Knepley   PetscCall(PetscBagSetName(ctx->bag, "par", "Vlasov-Poisson Parameters"));
1391918dfc20SMatthew G. Knepley   bag = ctx->bag;
1392918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "v0", "Velocity scale, m/s"));
1393918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->t0, 1.0, "t0", "Time scale, s"));
1394918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->x0, 1.0, "x0", "Space scale, m"));
1395918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "phi0", "Potential scale, kg*m^2/A*s^3"));
1396918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->q0, 1.0, "q0", "Charge Scale, A*s"));
1397918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->m0, 1.0, "m0", "Mass Scale, kg"));
1398918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->epsi0, 1.0, "epsi0", "Permittivity of Free Space, kg"));
1399918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->kb, 1.0, "kb", "Boltzmann Constant, m^2 kg/s^2 K^1"));
1400918dfc20SMatthew G. Knepley 
1401918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->sigma, 1.0, "sigma", "Charge per unit area, C/m^3"));
1402918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->poissonNumber, 1.0, "poissonNumber", "Non-Dimensional Poisson Number"));
1403918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->vlasovNumber, 1.0, "vlasovNumber", "Non-Dimensional Vlasov Number"));
1404918dfc20SMatthew G. Knepley   PetscCall(PetscBagSetFromOptions(bag));
1405918dfc20SMatthew G. Knepley   {
1406918dfc20SMatthew G. Knepley     PetscViewer       viewer;
1407918dfc20SMatthew G. Knepley     PetscViewerFormat format;
1408918dfc20SMatthew G. Knepley     PetscBool         flg;
1409918dfc20SMatthew G. Knepley 
1410918dfc20SMatthew G. Knepley     PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg));
1411918dfc20SMatthew G. Knepley     if (flg) {
1412918dfc20SMatthew G. Knepley       PetscCall(PetscViewerPushFormat(viewer, format));
1413918dfc20SMatthew G. Knepley       PetscCall(PetscBagView(bag, viewer));
1414918dfc20SMatthew G. Knepley       PetscCall(PetscViewerFlush(viewer));
1415918dfc20SMatthew G. Knepley       PetscCall(PetscViewerPopFormat(viewer));
1416918dfc20SMatthew G. Knepley       PetscCall(PetscViewerDestroy(&viewer));
1417918dfc20SMatthew G. Knepley     }
1418918dfc20SMatthew G. Knepley   }
1419918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1420918dfc20SMatthew G. Knepley }
1421918dfc20SMatthew G. Knepley 
CreateMesh(MPI_Comm comm,AppCtx * ctx,DM * dm)1422*2a8381b2SBarry Smith static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *ctx, DM *dm)
1423918dfc20SMatthew G. Knepley {
1424*2a8381b2SBarry Smith   DMField         coordField;
1425*2a8381b2SBarry Smith   IS              cellIS;
1426*2a8381b2SBarry Smith   PetscQuadrature quad;
1427*2a8381b2SBarry Smith   PetscReal      *wt, *pt;
1428*2a8381b2SBarry Smith   PetscInt        cdim, cStart, cEnd;
1429*2a8381b2SBarry Smith 
1430918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1431918dfc20SMatthew G. Knepley   PetscCall(DMCreate(comm, dm));
1432918dfc20SMatthew G. Knepley   PetscCall(DMSetType(*dm, DMPLEX));
1433918dfc20SMatthew G. Knepley   PetscCall(DMSetFromOptions(*dm));
1434918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*dm, "space"));
1435918dfc20SMatthew G. Knepley   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
1436918dfc20SMatthew G. Knepley 
1437918dfc20SMatthew G. Knepley   // Cache the mesh geometry
1438918dfc20SMatthew G. Knepley   PetscCall(DMGetCoordinateField(*dm, &coordField));
1439918dfc20SMatthew G. Knepley   PetscCheck(coordField, comm, PETSC_ERR_USER, "DM must have a coordinate field");
1440918dfc20SMatthew G. Knepley   PetscCall(DMGetCoordinateDim(*dm, &cdim));
1441918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd));
1442918dfc20SMatthew G. Knepley   PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cellIS));
1443918dfc20SMatthew G. Knepley   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
1444918dfc20SMatthew G. Knepley   PetscCall(PetscMalloc1(1, &wt));
1445918dfc20SMatthew G. Knepley   PetscCall(PetscMalloc1(2, &pt));
1446918dfc20SMatthew G. Knepley   wt[0] = 1.;
1447918dfc20SMatthew G. Knepley   pt[0] = -1.;
1448918dfc20SMatthew G. Knepley   pt[1] = -1.;
1449918dfc20SMatthew G. Knepley   PetscCall(PetscQuadratureSetData(quad, cdim, 1, 1, pt, wt));
1450*2a8381b2SBarry Smith   PetscCall(DMFieldCreateFEGeom(coordField, cellIS, quad, PETSC_FEGEOM_BASIC, &ctx->fegeom));
1451918dfc20SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&quad));
1452918dfc20SMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
1453918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1454918dfc20SMatthew G. Knepley }
1455918dfc20SMatthew G. Knepley 
ion_f0(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])1456918dfc20SMatthew G. Knepley static void ion_f0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1457918dfc20SMatthew G. Knepley {
1458918dfc20SMatthew G. Knepley   f0[0] = -constants[SIGMA];
1459918dfc20SMatthew G. Knepley }
1460918dfc20SMatthew G. Knepley 
laplacian_f1(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f1[])1461918dfc20SMatthew G. Knepley static void laplacian_f1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
1462918dfc20SMatthew G. Knepley {
1463918dfc20SMatthew G. Knepley   PetscInt d;
1464918dfc20SMatthew G. Knepley   for (d = 0; d < dim; ++d) f1[d] = u_x[d];
1465918dfc20SMatthew G. Knepley }
1466918dfc20SMatthew G. Knepley 
laplacian_g3(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g3[])1467918dfc20SMatthew G. Knepley static void laplacian_g3(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[])
1468918dfc20SMatthew G. Knepley {
1469918dfc20SMatthew G. Knepley   PetscInt d;
1470918dfc20SMatthew G. Knepley   for (d = 0; d < dim; ++d) g3[d * dim + d] = 1.0;
1471918dfc20SMatthew G. Knepley }
1472918dfc20SMatthew G. Knepley 
1473918dfc20SMatthew G. Knepley /*
1474918dfc20SMatthew G. Knepley    /  I   -grad\ / q \ = /0\
1475918dfc20SMatthew G. Knepley    \-div    0  / \phi/   \f/
1476918dfc20SMatthew G. Knepley */
f0_q(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])1477918dfc20SMatthew G. Knepley static void f0_q(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1478918dfc20SMatthew G. Knepley {
1479918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f0[d] += u[uOff[0] + d];
1480918dfc20SMatthew G. Knepley }
1481918dfc20SMatthew G. Knepley 
f1_q(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f1[])1482918dfc20SMatthew G. Knepley static void f1_q(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
1483918dfc20SMatthew G. Knepley {
1484918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f1[d * dim + d] = u[uOff[1]];
1485918dfc20SMatthew G. Knepley }
1486918dfc20SMatthew G. Knepley 
f0_phi_backgroundCharge(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])1487918dfc20SMatthew G. Knepley static void f0_phi_backgroundCharge(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1488918dfc20SMatthew G. Knepley {
1489918dfc20SMatthew G. Knepley   f0[0] += constants[SIGMA];
1490918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f0[0] += u_x[uOff_x[0] + d * dim + d];
1491918dfc20SMatthew G. Knepley }
1492918dfc20SMatthew G. Knepley 
1493918dfc20SMatthew G. Knepley /* Boundary residual. Dirichlet boundary for u means u_bdy=p*n */
g0_qq(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g0[])1494918dfc20SMatthew G. Knepley static void g0_qq(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
1495918dfc20SMatthew G. Knepley {
1496918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) g0[d * dim + d] = 1.0;
1497918dfc20SMatthew G. Knepley }
1498918dfc20SMatthew G. Knepley 
g2_qphi(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g2[])1499918dfc20SMatthew G. Knepley static void g2_qphi(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[])
1500918dfc20SMatthew G. Knepley {
1501918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) g2[d * dim + d] = 1.0;
1502918dfc20SMatthew G. Knepley }
1503918dfc20SMatthew G. Knepley 
g1_phiq(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g1[])1504918dfc20SMatthew G. Knepley static void g1_phiq(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[])
1505918dfc20SMatthew G. Knepley {
1506918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) g1[d * dim + d] = 1.0;
1507918dfc20SMatthew G. Knepley }
1508918dfc20SMatthew G. Knepley 
CreateFEM(DM dm,AppCtx * ctx)1509*2a8381b2SBarry Smith static PetscErrorCode CreateFEM(DM dm, AppCtx *ctx)
1510918dfc20SMatthew G. Knepley {
1511918dfc20SMatthew G. Knepley   PetscFE   fephi, feq;
1512918dfc20SMatthew G. Knepley   PetscDS   ds;
1513918dfc20SMatthew G. Knepley   PetscBool simplex;
1514918dfc20SMatthew G. Knepley   PetscInt  dim;
1515918dfc20SMatthew G. Knepley 
1516918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1517918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
1518918dfc20SMatthew G. Knepley   PetscCall(DMPlexIsSimplex(dm, &simplex));
1519*2a8381b2SBarry Smith   if (ctx->em == EM_MIXED) {
1520918dfc20SMatthew G. Knepley     DMLabel        label;
1521918dfc20SMatthew G. Knepley     const PetscInt id = 1;
1522918dfc20SMatthew G. Knepley 
1523918dfc20SMatthew G. Knepley     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "field_", PETSC_DETERMINE, &feq));
1524918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)feq, "field"));
1525918dfc20SMatthew G. Knepley     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "potential_", PETSC_DETERMINE, &fephi));
1526918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
1527918dfc20SMatthew G. Knepley     PetscCall(PetscFECopyQuadrature(feq, fephi));
1528918dfc20SMatthew G. Knepley     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)feq));
1529918dfc20SMatthew G. Knepley     PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fephi));
1530918dfc20SMatthew G. Knepley     PetscCall(DMCreateDS(dm));
1531918dfc20SMatthew G. Knepley     PetscCall(PetscFEDestroy(&fephi));
1532918dfc20SMatthew G. Knepley     PetscCall(PetscFEDestroy(&feq));
1533918dfc20SMatthew G. Knepley 
1534918dfc20SMatthew G. Knepley     PetscCall(DMGetLabel(dm, "marker", &label));
1535918dfc20SMatthew G. Knepley     PetscCall(DMGetDS(dm, &ds));
1536918dfc20SMatthew G. Knepley 
1537918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetResidual(ds, 0, f0_q, f1_q));
1538918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetResidual(ds, 1, f0_phi_backgroundCharge, NULL));
1539918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_qq, NULL, NULL, NULL));
1540918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_qphi, NULL));
1541918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_phiq, NULL, NULL));
1542918dfc20SMatthew G. Knepley 
154357d50842SBarry Smith     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)zero, NULL, NULL, NULL));
1544918dfc20SMatthew G. Knepley 
1545918dfc20SMatthew G. Knepley   } else {
1546918dfc20SMatthew G. Knepley     MatNullSpace nullsp;
1547918dfc20SMatthew G. Knepley     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, PETSC_DETERMINE, &fephi));
1548918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
1549918dfc20SMatthew G. Knepley     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fephi));
1550918dfc20SMatthew G. Knepley     PetscCall(DMCreateDS(dm));
1551918dfc20SMatthew G. Knepley     PetscCall(DMGetDS(dm, &ds));
1552918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetResidual(ds, 0, ion_f0, laplacian_f1));
1553918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, laplacian_g3));
1554918dfc20SMatthew G. Knepley     PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullsp));
1555918dfc20SMatthew G. Knepley     PetscCall(PetscObjectCompose((PetscObject)fephi, "nullspace", (PetscObject)nullsp));
1556918dfc20SMatthew G. Knepley     PetscCall(MatNullSpaceDestroy(&nullsp));
1557918dfc20SMatthew G. Knepley     PetscCall(PetscFEDestroy(&fephi));
1558918dfc20SMatthew G. Knepley   }
1559918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1560918dfc20SMatthew G. Knepley }
1561918dfc20SMatthew G. Knepley 
CreatePoisson(DM dm,AppCtx * ctx)1562*2a8381b2SBarry Smith static PetscErrorCode CreatePoisson(DM dm, AppCtx *ctx)
1563918dfc20SMatthew G. Knepley {
1564918dfc20SMatthew G. Knepley   SNES         snes;
1565918dfc20SMatthew G. Knepley   Mat          J;
1566918dfc20SMatthew G. Knepley   MatNullSpace nullSpace;
1567918dfc20SMatthew G. Knepley 
1568918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1569*2a8381b2SBarry Smith   PetscCall(CreateFEM(dm, ctx));
1570918dfc20SMatthew G. Knepley   PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes));
1571918dfc20SMatthew G. Knepley   PetscCall(SNESSetOptionsPrefix(snes, "em_"));
1572918dfc20SMatthew G. Knepley   PetscCall(SNESSetDM(snes, dm));
1573*2a8381b2SBarry Smith   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, ctx));
1574918dfc20SMatthew G. Knepley   PetscCall(SNESSetFromOptions(snes));
1575918dfc20SMatthew G. Knepley 
1576918dfc20SMatthew G. Knepley   PetscCall(DMCreateMatrix(dm, &J));
1577918dfc20SMatthew G. Knepley   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullSpace));
1578918dfc20SMatthew G. Knepley   PetscCall(MatSetNullSpace(J, nullSpace));
1579918dfc20SMatthew G. Knepley   PetscCall(MatNullSpaceDestroy(&nullSpace));
1580918dfc20SMatthew G. Knepley   PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL));
1581918dfc20SMatthew G. Knepley   PetscCall(MatDestroy(&J));
1582*2a8381b2SBarry Smith   if (ctx->em == EM_MIXED) {
1583918dfc20SMatthew G. Knepley     const PetscInt potential = 1;
1584918dfc20SMatthew G. Knepley 
1585*2a8381b2SBarry Smith     PetscCall(DMCreateSubDM(dm, 1, &potential, &ctx->isPot, &ctx->dmPot));
1586918dfc20SMatthew G. Knepley   } else {
1587*2a8381b2SBarry Smith     ctx->dmPot = dm;
1588*2a8381b2SBarry Smith     PetscCall(PetscObjectReference((PetscObject)ctx->dmPot));
1589918dfc20SMatthew G. Knepley   }
1590*2a8381b2SBarry Smith   PetscCall(DMCreateMassMatrix(ctx->dmPot, ctx->dmPot, &ctx->M));
1591918dfc20SMatthew G. Knepley   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
1592*2a8381b2SBarry Smith   ctx->snes = snes;
1593918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1594918dfc20SMatthew G. Knepley }
1595918dfc20SMatthew G. Knepley 
1596918dfc20SMatthew G. Knepley // Conservation of mass (m = 1.0)
1597918dfc20SMatthew G. Knepley // n_t + 1/ m p_x = 0
f0_mass(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])1598918dfc20SMatthew G. Knepley static void f0_mass(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1599918dfc20SMatthew G. Knepley {
1600918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f0[0] += u_t[uOff[0]] + u_x[uOff_x[1] + d * dim + d];
1601918dfc20SMatthew G. Knepley }
1602918dfc20SMatthew G. Knepley 
1603918dfc20SMatthew G. Knepley // Conservation of momentum (m = 1, e = 1)
1604918dfc20SMatthew G. Knepley // p_t + (u p)_x = -pr_x + e n E
1605918dfc20SMatthew G. Knepley // p_t + (div u) p + u . grad p = -pr_x + e n E
1606918dfc20SMatthew G. Knepley // p_t + (div p) p / n - (p . grad n) p / n^2 + p / n . grad p = -pr_x + e n E
f0_momentum(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])1607918dfc20SMatthew G. Knepley static void f0_momentum(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1608918dfc20SMatthew G. Knepley {
1609918dfc20SMatthew G. Knepley   const PetscScalar n = u[uOff[0]];
1610918dfc20SMatthew G. Knepley 
1611918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) {
1612918dfc20SMatthew G. Knepley     PetscReal divp = 0.;
1613918dfc20SMatthew G. Knepley 
1614918dfc20SMatthew G. Knepley     f0[d] += u_t[uOff[1] + d];
1615918dfc20SMatthew G. Knepley     for (PetscInt e = 0; e < dim; ++e) {
1616918dfc20SMatthew G. Knepley       f0[d] += u[uOff[1] + e] * u_x[uOff_x[1] + d * dim + e] / n;                    // p / n . grad p
1617918dfc20SMatthew G. Knepley       f0[d] -= (u[uOff[1] + e] * u_x[uOff_x[0] + e]) * u[uOff[1] + d] / PetscSqr(n); // -(p . grad n) p / n^2
1618918dfc20SMatthew G. Knepley       divp += u_x[uOff_x[1] + e * dim + e];
1619918dfc20SMatthew G. Knepley     }
1620918dfc20SMatthew G. Knepley     f0[d] += divp * u[uOff[1] + d] / n; // (div p) p / n
1621918dfc20SMatthew G. Knepley     f0[d] += u_x[uOff_x[2] + d];        // pr_x
1622918dfc20SMatthew G. Knepley     f0[d] -= n * a[d];                  // -e n E
1623918dfc20SMatthew G. Knepley   }
1624918dfc20SMatthew G. Knepley }
1625918dfc20SMatthew G. Knepley 
1626918dfc20SMatthew G. Knepley // Conservation of energy
1627918dfc20SMatthew G. Knepley // pr_t + (u pr)_x = -3 pr u_x - q_x
1628918dfc20SMatthew G. Knepley // pr_t + (div u) pr + u . grad pr = -3 pr (div u) - q_x
1629918dfc20SMatthew G. Knepley // pr_t + 4 (div u) pr + u . grad pr = -q_x
1630918dfc20SMatthew G. Knepley // pr_t + 4 div p pr / n - 4 (p . grad n) pr / n^2 + p . grad pr / n = -q_x
f0_energy(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])1631918dfc20SMatthew G. Knepley static void f0_energy(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1632918dfc20SMatthew G. Knepley {
1633918dfc20SMatthew G. Knepley   const PetscScalar n    = u[uOff[0]];
1634918dfc20SMatthew G. Knepley   const PetscScalar pr   = u[uOff[2]];
1635918dfc20SMatthew G. Knepley   PetscReal         divp = 0.;
1636918dfc20SMatthew G. Knepley 
1637918dfc20SMatthew G. Knepley   f0[0] += u_t[uOff[2]];
1638918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) {
1639918dfc20SMatthew G. Knepley     f0[0] += u[uOff[1] + d] * u_x[uOff_x[2] + d] / n;                     // p . grad pr / n
1640918dfc20SMatthew G. Knepley     f0[0] -= 4. * u[uOff[1] + d] * u_x[uOff_x[0] + d] * pr / PetscSqr(n); // -4 (p . grad n) pr / n^2
1641918dfc20SMatthew G. Knepley     divp += u_x[uOff_x[1] + d * dim + d];
1642918dfc20SMatthew G. Knepley   }
1643918dfc20SMatthew G. Knepley   f0[0] += 4. * divp * pr / n; // 4 div p pr / n
1644918dfc20SMatthew G. Knepley }
1645918dfc20SMatthew G. Knepley 
SetupMomentProblem(DM dm,AppCtx * ctx)1646918dfc20SMatthew G. Knepley static PetscErrorCode SetupMomentProblem(DM dm, AppCtx *ctx)
1647918dfc20SMatthew G. Knepley {
1648918dfc20SMatthew G. Knepley   PetscDS ds;
1649918dfc20SMatthew G. Knepley 
1650918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1651918dfc20SMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
1652918dfc20SMatthew G. Knepley   PetscCall(PetscDSSetResidual(ds, 0, f0_mass, NULL));
1653918dfc20SMatthew G. Knepley   PetscCall(PetscDSSetResidual(ds, 1, f0_momentum, NULL));
1654918dfc20SMatthew G. Knepley   PetscCall(PetscDSSetResidual(ds, 2, f0_energy, NULL));
1655918dfc20SMatthew G. Knepley   //PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_mass_uu, NULL, NULL, NULL));
1656918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1657918dfc20SMatthew G. Knepley }
1658918dfc20SMatthew G. Knepley 
CreateMomentFields(DM odm,AppCtx * ctx)1659*2a8381b2SBarry Smith static PetscErrorCode CreateMomentFields(DM odm, AppCtx *ctx)
1660918dfc20SMatthew G. Knepley {
1661918dfc20SMatthew G. Knepley   DM             dm;
1662918dfc20SMatthew G. Knepley   PetscFE        fe;
1663918dfc20SMatthew G. Knepley   DMPolytopeType ct;
1664918dfc20SMatthew G. Knepley   PetscInt       dim, cStart;
1665918dfc20SMatthew G. Knepley 
1666918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1667918dfc20SMatthew G. Knepley   PetscCall(DMClone(odm, &dm));
1668918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
1669918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
1670918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
1671918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, NULL, PETSC_DETERMINE, &fe));
1672918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "number density"));
1673918dfc20SMatthew G. Knepley   PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fe));
1674918dfc20SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
1675918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, dim, ct, NULL, PETSC_DETERMINE, &fe));
1676918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "momentum density"));
1677918dfc20SMatthew G. Knepley   PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fe));
1678918dfc20SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
1679918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, NULL, PETSC_DETERMINE, &fe));
1680918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "energy density"));
1681918dfc20SMatthew G. Knepley   PetscCall(DMSetField(dm, 2, NULL, (PetscObject)fe));
1682918dfc20SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
1683918dfc20SMatthew G. Knepley   PetscCall(DMCreateDS(dm));
1684*2a8381b2SBarry Smith   PetscCall(SetupMomentProblem(dm, ctx));
1685*2a8381b2SBarry Smith   ctx->dmMom = dm;
1686918dfc20SMatthew G. Knepley   PetscInt field;
1687918dfc20SMatthew G. Knepley 
1688918dfc20SMatthew G. Knepley   field = 0;
1689*2a8381b2SBarry Smith   PetscCall(DMCreateSubDM(ctx->dmMom, 1, &field, &ctx->isN, &ctx->dmN));
1690*2a8381b2SBarry Smith   PetscCall(DMCreateMassMatrix(ctx->dmN, ctx->dmN, &ctx->MN));
1691918dfc20SMatthew G. Knepley   field = 1;
1692*2a8381b2SBarry Smith   PetscCall(DMCreateSubDM(ctx->dmMom, 1, &field, &ctx->isP, &ctx->dmP));
1693*2a8381b2SBarry Smith   PetscCall(DMCreateMassMatrix(ctx->dmP, ctx->dmP, &ctx->MP));
1694918dfc20SMatthew G. Knepley   field = 2;
1695*2a8381b2SBarry Smith   PetscCall(DMCreateSubDM(ctx->dmMom, 1, &field, &ctx->isE, &ctx->dmE));
1696*2a8381b2SBarry Smith   PetscCall(DMCreateMassMatrix(ctx->dmE, ctx->dmE, &ctx->ME));
1697918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1698918dfc20SMatthew G. Knepley }
1699918dfc20SMatthew G. Knepley 
PetscPDFPertubedConstant2D(const PetscReal x[],const PetscReal dummy[],PetscReal p[])1700918dfc20SMatthew G. Knepley PetscErrorCode PetscPDFPertubedConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
1701918dfc20SMatthew G. Knepley {
1702918dfc20SMatthew G. Knepley   p[0] = (1 + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
1703918dfc20SMatthew G. Knepley   p[1] = (1 + 0.01 * PetscCosReal(0.5 * x[1])) / (2 * PETSC_PI);
1704918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
1705918dfc20SMatthew G. Knepley }
PetscPDFPertubedConstant1D(const PetscReal x[],const PetscReal dummy[],PetscReal p[])1706918dfc20SMatthew G. Knepley PetscErrorCode PetscPDFPertubedConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
1707918dfc20SMatthew G. Knepley {
1708918dfc20SMatthew G. Knepley   p[0] = (1. + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
1709918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
1710918dfc20SMatthew G. Knepley }
1711918dfc20SMatthew G. Knepley 
PetscPDFCosine1D(const PetscReal x[],const PetscReal scale[],PetscReal p[])1712918dfc20SMatthew G. Knepley PetscErrorCode PetscPDFCosine1D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
1713918dfc20SMatthew G. Knepley {
1714918dfc20SMatthew G. Knepley   const PetscReal alpha = scale ? scale[0] : 0.0;
1715918dfc20SMatthew G. Knepley   const PetscReal k     = scale ? scale[1] : 1.;
1716918dfc20SMatthew G. Knepley   p[0]                  = (1 + alpha * PetscCosReal(k * x[0]));
1717918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
1718918dfc20SMatthew G. Knepley }
1719918dfc20SMatthew G. Knepley 
PetscPDFCosine2D(const PetscReal x[],const PetscReal scale[],PetscReal p[])1720918dfc20SMatthew G. Knepley PetscErrorCode PetscPDFCosine2D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
1721918dfc20SMatthew G. Knepley {
1722918dfc20SMatthew G. Knepley   const PetscReal alpha = scale ? scale[0] : 0.;
1723918dfc20SMatthew G. Knepley   const PetscReal k     = scale ? scale[0] : 1.;
1724918dfc20SMatthew G. Knepley   p[0]                  = (1 + alpha * PetscCosReal(k * (x[0] + x[1])));
1725918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
1726918dfc20SMatthew G. Knepley }
1727918dfc20SMatthew G. Knepley 
CreateVelocityDM(DM sw,DM * vdm)1728918dfc20SMatthew G. Knepley static PetscErrorCode CreateVelocityDM(DM sw, DM *vdm)
1729918dfc20SMatthew G. Knepley {
1730918dfc20SMatthew G. Knepley   PetscFE        fe;
1731918dfc20SMatthew G. Knepley   DMPolytopeType ct;
1732918dfc20SMatthew G. Knepley   PetscInt       dim, cStart;
1733918dfc20SMatthew G. Knepley   const char    *prefix = "v";
1734918dfc20SMatthew G. Knepley 
1735918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1736918dfc20SMatthew G. Knepley   PetscCall(DMCreate(PETSC_COMM_SELF, vdm));
1737918dfc20SMatthew G. Knepley   PetscCall(DMSetType(*vdm, DMPLEX));
1738918dfc20SMatthew G. Knepley   PetscCall(DMPlexSetOptionsPrefix(*vdm, prefix));
1739918dfc20SMatthew G. Knepley   PetscCall(DMSetFromOptions(*vdm));
1740918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*vdm, "velocity"));
1741918dfc20SMatthew G. Knepley   PetscCall(DMViewFromOptions(*vdm, NULL, "-dm_view"));
1742918dfc20SMatthew G. Knepley 
1743918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(*vdm, &dim));
1744918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*vdm, 0, &cStart, NULL));
1745918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetCellType(*vdm, cStart, &ct));
1746918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe));
1747918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "distribution"));
1748918dfc20SMatthew G. Knepley   PetscCall(DMSetField(*vdm, 0, NULL, (PetscObject)fe));
1749918dfc20SMatthew G. Knepley   PetscCall(DMCreateDS(*vdm));
1750918dfc20SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
1751918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1752918dfc20SMatthew G. Knepley }
1753918dfc20SMatthew G. Knepley 
1754918dfc20SMatthew G. Knepley /*
1755918dfc20SMatthew G. Knepley   InitializeParticles_Centroid - Initialize a regular grid of particles.
1756918dfc20SMatthew G. Knepley 
1757918dfc20SMatthew G. Knepley   Input Parameters:
1758918dfc20SMatthew G. Knepley + sw      - The `DMSWARM`
1759918dfc20SMatthew G. Knepley - force1D - Treat the spatial domain as 1D
1760918dfc20SMatthew G. Knepley 
1761918dfc20SMatthew G. Knepley   Notes:
1762918dfc20SMatthew G. Knepley   This functions sets the species, cellid, spatial coordinate, and velocity fields for all particles.
1763918dfc20SMatthew G. Knepley 
1764918dfc20SMatthew G. Knepley   It places one particle in the centroid of each cell in the implicit tensor product of the spatial
1765918dfc20SMatthew G. Knepley   and velocity meshes.
1766918dfc20SMatthew G. Knepley */
InitializeParticles_Centroid(DM sw)1767918dfc20SMatthew G. Knepley static PetscErrorCode InitializeParticles_Centroid(DM sw)
1768918dfc20SMatthew G. Knepley {
1769918dfc20SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
1770918dfc20SMatthew G. Knepley   DMSwarmCellDM celldm;
1771918dfc20SMatthew G. Knepley   DM            xdm, vdm;
1772918dfc20SMatthew G. Knepley   PetscReal     vmin[3], vmax[3];
1773918dfc20SMatthew G. Knepley   PetscReal    *x, *v;
1774918dfc20SMatthew G. Knepley   PetscInt     *species, *cellid;
1775918dfc20SMatthew G. Knepley   PetscInt      dim, xcStart, xcEnd, vcStart, vcEnd, Ns, Np, Npc, debug;
1776918dfc20SMatthew G. Knepley   PetscBool     flg;
1777918dfc20SMatthew G. Knepley   MPI_Comm      comm;
1778918dfc20SMatthew G. Knepley   const char   *cellidname;
1779918dfc20SMatthew G. Knepley 
1780918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1781918dfc20SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
1782918dfc20SMatthew G. Knepley 
1783918dfc20SMatthew G. Knepley   PetscOptionsBegin(comm, "", "DMSwarm Options", "DMSWARM");
1784918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
1785f14fce1bSMatthew G. Knepley   PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg));
1786918dfc20SMatthew G. Knepley   if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns));
1787918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_coords", "Debug output level for particle coordinate computations", "InitializeParticles", 0, &swarm->printCoords, NULL, 0));
1788918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_weights", "Debug output level for particle weight computations", "InitializeWeights", 0, &swarm->printWeights, NULL, 0));
1789918dfc20SMatthew G. Knepley   PetscOptionsEnd();
1790918dfc20SMatthew G. Knepley   debug = swarm->printCoords;
1791918dfc20SMatthew G. Knepley 
1792918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1793918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
1794918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
1795918dfc20SMatthew G. Knepley 
1796918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
1797918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
1798918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
1799918dfc20SMatthew G. Knepley 
1800918dfc20SMatthew G. Knepley   // One particle per centroid on the tensor product grid
1801918dfc20SMatthew G. Knepley   Npc = (vcEnd - vcStart) * Ns;
1802918dfc20SMatthew G. Knepley   Np  = (xcEnd - xcStart) * Npc;
1803918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetLocalSizes(sw, Np, 0));
1804918dfc20SMatthew G. Knepley   if (debug) {
1805918dfc20SMatthew G. Knepley     PetscInt gNp, gNc, Nc = xcEnd - xcStart;
1806918dfc20SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Np, &gNp, 1, MPIU_INT, MPIU_SUM, comm));
1807918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global Np = %" PetscInt_FMT "\n", gNp));
1808918dfc20SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Nc, &gNc, 1, MPIU_INT, MPIU_SUM, comm));
1809918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global X-cells = %" PetscInt_FMT "\n", gNc));
1810918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global V-cells = %" PetscInt_FMT "\n", vcEnd - vcStart));
1811918dfc20SMatthew G. Knepley   }
1812918dfc20SMatthew G. Knepley 
1813918dfc20SMatthew G. Knepley   // Set species and cellid
1814918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
1815918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCellID(celldm, &cellidname));
1816918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
1817918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, cellidname, NULL, NULL, (void **)&cellid));
1818918dfc20SMatthew G. Knepley   for (PetscInt c = 0, p = 0; c < xcEnd - xcStart; ++c) {
1819918dfc20SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
1820918dfc20SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q, ++p) {
1821918dfc20SMatthew G. Knepley         species[p] = s;
1822918dfc20SMatthew G. Knepley         cellid[p]  = c;
1823918dfc20SMatthew G. Knepley       }
1824918dfc20SMatthew G. Knepley     }
1825918dfc20SMatthew G. Knepley   }
1826918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
1827918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, cellidname, NULL, NULL, (void **)&cellid));
1828918dfc20SMatthew G. Knepley 
1829918dfc20SMatthew G. Knepley   // Set particle coordinates
1830918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1831918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
1832918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
1833918dfc20SMatthew G. Knepley   PetscCall(DMGetBoundingBox(vdm, vmin, vmax));
1834918dfc20SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(xdm));
1835918dfc20SMatthew G. Knepley   for (PetscInt c = 0; c < xcEnd - xcStart; ++c) {
1836918dfc20SMatthew G. Knepley     const PetscInt cell = c + xcStart;
1837918dfc20SMatthew G. Knepley     PetscInt      *pidx, Npc;
1838918dfc20SMatthew G. Knepley     PetscReal      centroid[3], volume;
1839918dfc20SMatthew G. Knepley 
1840918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
1841918dfc20SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFVM(xdm, cell, &volume, centroid, NULL));
1842918dfc20SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
1843918dfc20SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q) {
1844918dfc20SMatthew G. Knepley         const PetscInt p = pidx[q * Ns + s];
1845918dfc20SMatthew G. Knepley 
1846918dfc20SMatthew G. Knepley         for (PetscInt d = 0; d < dim; ++d) {
1847918dfc20SMatthew G. Knepley           x[p * dim + d] = centroid[d];
1848918dfc20SMatthew G. Knepley           v[p * dim + d] = vmin[0] + (q + 0.5) * ((vmax[0] - vmin[0]) / (Npc / Ns));
1849918dfc20SMatthew G. Knepley         }
1850918dfc20SMatthew G. Knepley         if (debug > 1) {
1851918dfc20SMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "Particle %4" PetscInt_FMT " ", p));
1852918dfc20SMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  x: ("));
1853918dfc20SMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
1854918dfc20SMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
1855918dfc20SMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", x[p * dim + d]));
1856918dfc20SMatthew G. Knepley           }
1857918dfc20SMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ") v:("));
1858918dfc20SMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
1859918dfc20SMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
1860918dfc20SMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", v[p * dim + d]));
1861918dfc20SMatthew G. Knepley           }
1862918dfc20SMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
1863918dfc20SMatthew G. Knepley         }
1864918dfc20SMatthew G. Knepley       }
1865918dfc20SMatthew G. Knepley     }
1866918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
1867918dfc20SMatthew G. Knepley   }
1868918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
1869918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1870918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
1871918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1872918dfc20SMatthew G. Knepley }
1873918dfc20SMatthew G. Knepley 
1874918dfc20SMatthew G. Knepley /*
1875918dfc20SMatthew G. Knepley   InitializeWeights - Compute weight for each local particle
1876918dfc20SMatthew G. Knepley 
1877918dfc20SMatthew G. Knepley   Input Parameters:
1878918dfc20SMatthew G. Knepley + sw          - The `DMSwarm`
1879918dfc20SMatthew G. Knepley . totalWeight - The sum of all particle weights
1880918dfc20SMatthew G. Knepley . func        - The PDF for the particle spatial distribution
1881918dfc20SMatthew G. Knepley - param       - The PDF parameters
1882918dfc20SMatthew G. Knepley 
1883918dfc20SMatthew G. Knepley   Notes:
1884918dfc20SMatthew G. Knepley   The PDF for velocity is assumed to be a Gaussian
1885918dfc20SMatthew G. Knepley 
1886918dfc20SMatthew G. Knepley   The particle weights are returned in the `w_q` field of `sw`.
1887918dfc20SMatthew G. Knepley */
InitializeWeights(DM sw,PetscReal totalWeight,PetscProbFn * func,const PetscReal param[])1888918dfc20SMatthew G. Knepley static PetscErrorCode InitializeWeights(DM sw, PetscReal totalWeight, PetscProbFn *func, const PetscReal param[])
1889918dfc20SMatthew G. Knepley {
1890918dfc20SMatthew G. Knepley   DM               xdm, vdm;
1891918dfc20SMatthew G. Knepley   DMSwarmCellDM    celldm;
1892918dfc20SMatthew G. Knepley   PetscScalar     *weight;
1893918dfc20SMatthew G. Knepley   PetscQuadrature  xquad;
1894918dfc20SMatthew G. Knepley   const PetscReal *xq, *xwq;
1895918dfc20SMatthew G. Knepley   const PetscInt   order = 5;
1896918dfc20SMatthew G. Knepley   PetscReal        xi0[3];
1897918dfc20SMatthew G. Knepley   PetscReal        xwtot = 0., pwtot = 0.;
1898918dfc20SMatthew G. Knepley   PetscInt         xNq;
1899918dfc20SMatthew G. Knepley   PetscInt         dim, Ns, xcStart, xcEnd, vcStart, vcEnd, debug = ((DM_Swarm *)sw->data)->printWeights;
1900918dfc20SMatthew G. Knepley   MPI_Comm         comm;
1901918dfc20SMatthew G. Knepley   PetscMPIInt      rank;
1902918dfc20SMatthew G. Knepley 
1903918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1904918dfc20SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
1905918dfc20SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1906918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1907918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
1908918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
1909918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
1910918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
1911918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
1912918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
1913918dfc20SMatthew G. Knepley 
1914918dfc20SMatthew G. Knepley   // Setup Quadrature for spatial and velocity weight calculations
1915918dfc20SMatthew G. Knepley   PetscCall(PetscDTGaussTensorQuadrature(dim, 1, order, -1.0, 1.0, &xquad));
1916918dfc20SMatthew G. Knepley   PetscCall(PetscQuadratureGetData(xquad, NULL, NULL, &xNq, &xq, &xwq));
1917918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) xi0[d] = -1.0;
1918918dfc20SMatthew G. Knepley 
1919918dfc20SMatthew G. Knepley   // Integrate the density function to get the weights of particles in each cell
1920918dfc20SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(vdm));
1921918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
1922918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
1923918dfc20SMatthew G. Knepley   for (PetscInt c = xcStart; c < xcEnd; ++c) {
1924918dfc20SMatthew G. Knepley     PetscReal          xv0[3], xJ[9], xinvJ[9], xdetJ, xqr[3], xden, xw = 0.;
1925918dfc20SMatthew G. Knepley     PetscInt          *pidx, Npc;
1926918dfc20SMatthew G. Knepley     PetscInt           xNc;
1927918dfc20SMatthew G. Knepley     const PetscScalar *xarray;
1928918dfc20SMatthew G. Knepley     PetscScalar       *xcoords = NULL;
1929918dfc20SMatthew G. Knepley     PetscBool          xisDG;
1930918dfc20SMatthew G. Knepley 
1931918dfc20SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
1932918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
1933918dfc20SMatthew G. Knepley     PetscCheck(Npc == (vcEnd - vcStart) * Ns, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of particles %" PetscInt_FMT " in cell (rank %d) != %" PetscInt_FMT " number of velocity vertices", Npc, rank, (vcEnd - vcStart) * Ns);
1934918dfc20SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFEM(xdm, c, NULL, xv0, xJ, xinvJ, &xdetJ));
1935918dfc20SMatthew G. Knepley     for (PetscInt q = 0; q < xNq; ++q) {
1936918dfc20SMatthew G. Knepley       // Transform quadrature points from ref space to real space
1937918dfc20SMatthew G. Knepley       CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xq[q * dim], xqr);
1938918dfc20SMatthew G. Knepley       // Get probability density at quad point
1939918dfc20SMatthew G. Knepley       //   No need to scale xqr since PDF will be periodic
1940918dfc20SMatthew G. Knepley       PetscCall((*func)(xqr, param, &xden));
1941918dfc20SMatthew G. Knepley       xw += xden * (xwq[q] * xdetJ);
1942918dfc20SMatthew G. Knepley     }
1943918dfc20SMatthew G. Knepley     xwtot += xw;
1944918dfc20SMatthew G. Knepley     if (debug) {
1945918dfc20SMatthew G. Knepley       IS              globalOrdering;
1946918dfc20SMatthew G. Knepley       const PetscInt *ordering;
1947918dfc20SMatthew G. Knepley 
1948918dfc20SMatthew G. Knepley       PetscCall(DMPlexGetCellNumbering(xdm, &globalOrdering));
1949918dfc20SMatthew G. Knepley       PetscCall(ISGetIndices(globalOrdering, &ordering));
1950918dfc20SMatthew G. Knepley       PetscCall(PetscSynchronizedPrintf(comm, "c:%" PetscInt_FMT " [x_a,x_b] = %1.15f,%1.15f -> cell weight = %1.15f\n", ordering[c], (double)PetscRealPart(xcoords[0]), (double)PetscRealPart(xcoords[0 + dim]), (double)xw));
1951918dfc20SMatthew G. Knepley       PetscCall(ISRestoreIndices(globalOrdering, &ordering));
1952918dfc20SMatthew G. Knepley     }
1953918dfc20SMatthew G. Knepley     // Set weights to be Gaussian in velocity cells
1954918dfc20SMatthew G. Knepley     for (PetscInt vc = vcStart; vc < vcEnd; ++vc) {
1955918dfc20SMatthew G. Knepley       const PetscInt     p  = pidx[vc * Ns + 0];
1956918dfc20SMatthew G. Knepley       PetscReal          vw = 0.;
1957918dfc20SMatthew G. Knepley       PetscInt           vNc;
1958918dfc20SMatthew G. Knepley       const PetscScalar *varray;
1959918dfc20SMatthew G. Knepley       PetscScalar       *vcoords = NULL;
1960918dfc20SMatthew G. Knepley       PetscBool          visDG;
1961918dfc20SMatthew G. Knepley 
1962918dfc20SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
1963918dfc20SMatthew G. Knepley       // TODO: Fix 2 stream Ask Joe
1964918dfc20SMatthew G. Knepley       //   Two stream function from 1/2pi v^2 e^(-v^2/2)
1965918dfc20SMatthew G. Knepley       //   vw = 1. / (PetscSqrtReal(2 * PETSC_PI)) * (((coords_v[0] * PetscExpReal(-PetscSqr(coords_v[0]) / 2.)) - (coords_v[1] * PetscExpReal(-PetscSqr(coords_v[1]) / 2.)))) - 0.5 * PetscErfReal(coords_v[0] / PetscSqrtReal(2.)) + 0.5 * (PetscErfReal(coords_v[1] / PetscSqrtReal(2.)));
1966918dfc20SMatthew G. Knepley       vw = 0.5 * (PetscErfReal(vcoords[1] / PetscSqrtReal(2.)) - PetscErfReal(vcoords[0] / PetscSqrtReal(2.)));
1967918dfc20SMatthew G. Knepley 
1968918dfc20SMatthew G. Knepley       weight[p] = totalWeight * vw * xw;
1969918dfc20SMatthew G. Knepley       pwtot += weight[p];
1970918dfc20SMatthew G. Knepley       PetscCheck(weight[p] <= 10., PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Particle %" PetscInt_FMT " weight exceeded 1: %g, %g, %g", p, xw, vw, totalWeight);
1971918dfc20SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
1972918dfc20SMatthew G. Knepley       if (debug > 1) PetscCall(PetscPrintf(comm, "particle %" PetscInt_FMT ": %g, vw: %g xw: %g\n", p, weight[p], vw, xw));
1973918dfc20SMatthew G. Knepley     }
1974918dfc20SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
1975918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
1976918dfc20SMatthew G. Knepley   }
1977918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
1978918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
1979918dfc20SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&xquad));
1980918dfc20SMatthew G. Knepley 
1981918dfc20SMatthew G. Knepley   if (debug) {
1982918dfc20SMatthew G. Knepley     PetscReal wtot[2] = {pwtot, xwtot}, gwtot[2];
1983918dfc20SMatthew G. Knepley 
1984918dfc20SMatthew G. Knepley     PetscCall(PetscSynchronizedFlush(comm, NULL));
1985918dfc20SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(wtot, gwtot, 2, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
1986918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "particle weight sum = %1.10f cell weight sum = %1.10f\n", (double)gwtot[0], (double)gwtot[1]));
1987918dfc20SMatthew G. Knepley   }
1988918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1989918dfc20SMatthew G. Knepley }
1990918dfc20SMatthew G. Knepley 
InitializeParticles_PerturbedWeights(DM sw,AppCtx * ctx)1991*2a8381b2SBarry Smith static PetscErrorCode InitializeParticles_PerturbedWeights(DM sw, AppCtx *ctx)
1992918dfc20SMatthew G. Knepley {
1993*2a8381b2SBarry Smith   PetscReal scale[2] = {ctx->cosine_coefficients[0], ctx->cosine_coefficients[1]};
1994918dfc20SMatthew G. Knepley   PetscInt  dim;
1995918dfc20SMatthew G. Knepley 
1996918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1997918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1998918dfc20SMatthew G. Knepley   PetscCall(InitializeParticles_Centroid(sw));
1999*2a8381b2SBarry Smith   PetscCall(InitializeWeights(sw, ctx->totalWeight, dim == 1 ? PetscPDFCosine1D : PetscPDFCosine2D, scale));
2000918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2001918dfc20SMatthew G. Knepley }
2002918dfc20SMatthew G. Knepley 
InitializeConstants(DM sw,AppCtx * ctx)2003*2a8381b2SBarry Smith static PetscErrorCode InitializeConstants(DM sw, AppCtx *ctx)
2004918dfc20SMatthew G. Knepley {
2005918dfc20SMatthew G. Knepley   DM         dm;
2006918dfc20SMatthew G. Knepley   PetscInt  *species;
2007918dfc20SMatthew G. Knepley   PetscReal *weight, totalCharge = 0., totalWeight = 0., gmin[3], gmax[3], global_charge, global_weight;
2008918dfc20SMatthew G. Knepley   PetscInt   Np, dim;
2009918dfc20SMatthew G. Knepley 
2010918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2011918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &dm));
2012918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2013918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2014918dfc20SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, gmin, gmax));
2015918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
2016918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
2017918dfc20SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
2018918dfc20SMatthew G. Knepley     totalWeight += weight[p];
2019*2a8381b2SBarry Smith     totalCharge += ctx->charges[species[p]] * weight[p];
2020918dfc20SMatthew G. Knepley   }
2021918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
2022918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
2023918dfc20SMatthew G. Knepley   {
2024918dfc20SMatthew G. Knepley     Parameter *param;
2025918dfc20SMatthew G. Knepley     PetscReal  Area;
2026918dfc20SMatthew G. Knepley 
2027*2a8381b2SBarry Smith     PetscCall(PetscBagGetData(ctx->bag, &param));
2028918dfc20SMatthew G. Knepley     switch (dim) {
2029918dfc20SMatthew G. Knepley     case 1:
2030918dfc20SMatthew G. Knepley       Area = (gmax[0] - gmin[0]);
2031918dfc20SMatthew G. Knepley       break;
2032918dfc20SMatthew G. Knepley     case 2:
2033918dfc20SMatthew G. Knepley       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]);
2034918dfc20SMatthew G. Knepley       break;
2035918dfc20SMatthew G. Knepley     case 3:
2036918dfc20SMatthew G. Knepley       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]) * (gmax[2] - gmin[2]);
2037918dfc20SMatthew G. Knepley       break;
2038918dfc20SMatthew G. Knepley     default:
2039918dfc20SMatthew G. Knepley       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", dim);
2040918dfc20SMatthew G. Knepley     }
2041918dfc20SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&totalWeight, &global_weight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
2042918dfc20SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&totalCharge, &global_charge, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
2043*2a8381b2SBarry Smith     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "dim = %" PetscInt_FMT "\ttotalWeight = %f, ctx->charges[species[0]] = %f\ttotalCharge = %f, Total Area = %f\n", dim, (double)global_weight, (double)ctx->charges[0], (double)global_charge, (double)Area));
2044918dfc20SMatthew G. Knepley     param->sigma = PetscAbsReal(global_charge / (Area));
2045918dfc20SMatthew G. Knepley 
2046918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "sigma: %g\n", (double)param->sigma));
2047918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "(x0,v0,t0,m0,q0,phi0): (%e, %e, %e, %e, %e, %e) - (P, V) = (%e, %e)\n", (double)param->x0, (double)param->v0, (double)param->t0, (double)param->m0, (double)param->q0, (double)param->phi0, (double)param->poissonNumber,
2048918dfc20SMatthew G. Knepley                           (double)param->vlasovNumber));
2049918dfc20SMatthew G. Knepley   }
2050918dfc20SMatthew G. Knepley   /* Setup Constants */
2051918dfc20SMatthew G. Knepley   {
2052918dfc20SMatthew G. Knepley     PetscDS    ds;
2053918dfc20SMatthew G. Knepley     Parameter *param;
2054*2a8381b2SBarry Smith     PetscCall(PetscBagGetData(ctx->bag, &param));
2055918dfc20SMatthew G. Knepley     PetscScalar constants[NUM_CONSTANTS];
2056918dfc20SMatthew G. Knepley     constants[SIGMA]   = param->sigma;
2057918dfc20SMatthew G. Knepley     constants[V0]      = param->v0;
2058918dfc20SMatthew G. Knepley     constants[T0]      = param->t0;
2059918dfc20SMatthew G. Knepley     constants[X0]      = param->x0;
2060918dfc20SMatthew G. Knepley     constants[M0]      = param->m0;
2061918dfc20SMatthew G. Knepley     constants[Q0]      = param->q0;
2062918dfc20SMatthew G. Knepley     constants[PHI0]    = param->phi0;
2063918dfc20SMatthew G. Knepley     constants[POISSON] = param->poissonNumber;
2064918dfc20SMatthew G. Knepley     constants[VLASOV]  = param->vlasovNumber;
2065918dfc20SMatthew G. Knepley     PetscCall(DMGetDS(dm, &ds));
2066918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants));
2067918dfc20SMatthew G. Knepley   }
2068918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2069918dfc20SMatthew G. Knepley }
2070918dfc20SMatthew G. Knepley 
CreateSwarm(DM dm,AppCtx * ctx,DM * sw)2071*2a8381b2SBarry Smith static PetscErrorCode CreateSwarm(DM dm, AppCtx *ctx, DM *sw)
2072918dfc20SMatthew G. Knepley {
2073918dfc20SMatthew G. Knepley   DMSwarmCellDM celldm;
2074918dfc20SMatthew G. Knepley   DM            vdm;
2075918dfc20SMatthew G. Knepley   PetscReal     v0[2] = {1., 0.};
2076918dfc20SMatthew G. Knepley   PetscInt      dim;
2077918dfc20SMatthew G. Knepley 
2078918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2079918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
2080918dfc20SMatthew G. Knepley   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw));
2081918dfc20SMatthew G. Knepley   PetscCall(DMSetType(*sw, DMSWARM));
2082918dfc20SMatthew G. Knepley   PetscCall(DMSetDimension(*sw, dim));
2083918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC));
2084*2a8381b2SBarry Smith   PetscCall(DMSetApplicationContext(*sw, ctx));
2085918dfc20SMatthew G. Knepley 
2086918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR));
2087918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL));
2088918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "species", 1, PETSC_INT));
2089918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "E_field", dim, PETSC_REAL));
2090918dfc20SMatthew G. Knepley 
2091918dfc20SMatthew G. Knepley   const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"};
2092918dfc20SMatthew G. Knepley 
2093918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(dm, 2, fieldnames, 1, fieldnames, &celldm));
2094918dfc20SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
2095918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
2096918dfc20SMatthew G. Knepley 
2097918dfc20SMatthew G. Knepley   const char *vfieldnames[2] = {"w_q"};
2098918dfc20SMatthew G. Knepley 
2099918dfc20SMatthew G. Knepley   PetscCall(CreateVelocityDM(*sw, &vdm));
2100918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(vdm, 1, vfieldnames, 1, &fieldnames[1], &celldm));
2101918dfc20SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
2102918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
2103918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&vdm));
2104918dfc20SMatthew G. Knepley 
2105918dfc20SMatthew G. Knepley   DM mdm;
2106918dfc20SMatthew G. Knepley 
2107918dfc20SMatthew G. Knepley   PetscCall(DMClone(dm, &mdm));
2108918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)mdm, "moments"));
2109918dfc20SMatthew G. Knepley   PetscCall(DMCopyDisc(dm, mdm));
2110918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(mdm, 1, vfieldnames, 1, fieldnames, &celldm));
2111918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&mdm));
2112918dfc20SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
2113918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
2114918dfc20SMatthew G. Knepley 
2115918dfc20SMatthew G. Knepley   DM mfdm;
2116918dfc20SMatthew G. Knepley 
2117918dfc20SMatthew G. Knepley   PetscCall(DMClone(dm, &mfdm));
2118918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)mfdm, "moment fields"));
2119918dfc20SMatthew G. Knepley   PetscCall(DMCopyDisc(dm, mfdm));
2120918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(mfdm, 1, &fieldnames[1], 1, fieldnames, &celldm));
2121918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&mfdm));
2122918dfc20SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
2123918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
2124918dfc20SMatthew G. Knepley 
2125918dfc20SMatthew G. Knepley   PetscCall(DMSetFromOptions(*sw));
2126918dfc20SMatthew G. Knepley   PetscCall(DMSetUp(*sw));
2127918dfc20SMatthew G. Knepley 
2128918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(*sw, "space"));
2129*2a8381b2SBarry Smith   ctx->swarm = *sw;
2130918dfc20SMatthew G. Knepley   // TODO: This is redundant init since it is done in InitializeSolveAndSwarm, however DMSetUp() requires the local size be set
2131*2a8381b2SBarry Smith   if (ctx->perturbed_weights) {
2132*2a8381b2SBarry Smith     PetscCall(InitializeParticles_PerturbedWeights(*sw, ctx));
2133918dfc20SMatthew G. Knepley   } else {
2134918dfc20SMatthew G. Knepley     PetscCall(DMSwarmComputeLocalSizeFromOptions(*sw));
2135918dfc20SMatthew G. Knepley     PetscCall(DMSwarmInitializeCoordinates(*sw));
2136918dfc20SMatthew G. Knepley     PetscCall(DMSwarmInitializeVelocitiesFromOptions(*sw, v0));
2137918dfc20SMatthew G. Knepley   }
2138918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles"));
2139918dfc20SMatthew G. Knepley   PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view"));
2140918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2141918dfc20SMatthew G. Knepley }
2142918dfc20SMatthew G. Knepley 
ComputeFieldAtParticles_Coulomb(SNES snes,DM sw,PetscReal E[])2143918dfc20SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Coulomb(SNES snes, DM sw, PetscReal E[])
2144918dfc20SMatthew G. Knepley {
2145*2a8381b2SBarry Smith   AppCtx     *ctx;
2146918dfc20SMatthew G. Knepley   PetscReal  *coords;
2147918dfc20SMatthew G. Knepley   PetscInt   *species, dim, Np, Ns;
2148918dfc20SMatthew G. Knepley   PetscMPIInt size;
2149918dfc20SMatthew G. Knepley 
2150918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2151918dfc20SMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)snes), &size));
2152918dfc20SMatthew G. Knepley   PetscCheck(size == 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Coulomb code only works in serial");
2153918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2154918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2155918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
2156*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
2157918dfc20SMatthew G. Knepley 
2158918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2159918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
2160918dfc20SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
2161918dfc20SMatthew G. Knepley     PetscReal *pcoord = &coords[p * dim];
2162918dfc20SMatthew G. Knepley     PetscReal  pE[3]  = {0., 0., 0.};
2163918dfc20SMatthew G. Knepley 
2164918dfc20SMatthew G. Knepley     /* Calculate field at particle p due to particle q */
2165918dfc20SMatthew G. Knepley     for (PetscInt q = 0; q < Np; ++q) {
2166918dfc20SMatthew G. Knepley       PetscReal *qcoord = &coords[q * dim];
2167918dfc20SMatthew G. Knepley       PetscReal  rpq[3], r, r3, q_q;
2168918dfc20SMatthew G. Knepley 
2169918dfc20SMatthew G. Knepley       if (p == q) continue;
2170*2a8381b2SBarry Smith       q_q = ctx->charges[species[q]] * 1.;
2171918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) rpq[d] = pcoord[d] - qcoord[d];
2172918dfc20SMatthew G. Knepley       r = DMPlex_NormD_Internal(dim, rpq);
2173918dfc20SMatthew G. Knepley       if (r < PETSC_SQRT_MACHINE_EPSILON) continue;
2174918dfc20SMatthew G. Knepley       r3 = PetscPowRealInt(r, 3);
2175918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) pE[d] += q_q * rpq[d] / r3;
2176918dfc20SMatthew G. Knepley     }
2177918dfc20SMatthew G. Knepley     for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = pE[d];
2178918dfc20SMatthew G. Knepley   }
2179918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
2180918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2181918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2182918dfc20SMatthew G. Knepley }
2183918dfc20SMatthew G. Knepley 
ComputeFieldAtParticles_Primal(SNES snes,DM sw,Mat M_p,PetscReal E[])2184918dfc20SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Primal(SNES snes, DM sw, Mat M_p, PetscReal E[])
2185918dfc20SMatthew G. Knepley {
2186918dfc20SMatthew G. Knepley   DM         dm;
2187*2a8381b2SBarry Smith   AppCtx    *ctx;
2188918dfc20SMatthew G. Knepley   PetscDS    ds;
2189918dfc20SMatthew G. Knepley   PetscFE    fe;
2190918dfc20SMatthew G. Knepley   KSP        ksp;
2191918dfc20SMatthew G. Knepley   Vec        rhoRhs;      // Weak charge density, \int phi_i rho
2192918dfc20SMatthew G. Knepley   Vec        rho;         // Charge density, M^{-1} rhoRhs
2193918dfc20SMatthew G. Knepley   Vec        phi, locPhi; // Potential
2194918dfc20SMatthew G. Knepley   Vec        f;           // Particle weights
2195918dfc20SMatthew G. Knepley   PetscReal *coords;
2196918dfc20SMatthew G. Knepley   PetscInt   dim, cStart, cEnd, Np;
2197918dfc20SMatthew G. Knepley 
2198918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2199*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
2200*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->ESolveEvent, snes, sw, 0, 0));
2201918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2202918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2203918dfc20SMatthew G. Knepley 
2204918dfc20SMatthew G. Knepley   PetscCall(SNESGetDM(snes, &dm));
2205918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhs));
2206918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
2207*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rho", &rho));
2208918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
2209918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
2210918dfc20SMatthew G. Knepley 
2211918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
2212*2a8381b2SBarry Smith   PetscCall(MatViewFromOptions(ctx->M, NULL, "-m_view"));
2213918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
2214918dfc20SMatthew G. Knepley 
2215918dfc20SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
2216918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
2217918dfc20SMatthew G. Knepley 
2218918dfc20SMatthew G. Knepley   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
2219918dfc20SMatthew G. Knepley   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj_"));
2220*2a8381b2SBarry Smith   PetscCall(KSPSetOperators(ksp, ctx->M, ctx->M));
2221918dfc20SMatthew G. Knepley   PetscCall(KSPSetFromOptions(ksp));
2222918dfc20SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
2223918dfc20SMatthew G. Knepley 
2224918dfc20SMatthew G. Knepley   PetscCall(VecScale(rhoRhs, -1.0));
2225918dfc20SMatthew G. Knepley 
2226918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
2227*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rho", &rho));
2228918dfc20SMatthew G. Knepley   PetscCall(KSPDestroy(&ksp));
2229918dfc20SMatthew G. Knepley 
2230*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
2231918dfc20SMatthew G. Knepley   PetscCall(VecSet(phi, 0.0));
2232918dfc20SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhs, phi));
2233918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhs));
2234918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
2235918dfc20SMatthew G. Knepley 
2236918dfc20SMatthew G. Knepley   PetscCall(DMGetLocalVector(dm, &locPhi));
2237918dfc20SMatthew G. Knepley   PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi));
2238918dfc20SMatthew G. Knepley   PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi));
2239*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
2240*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->ESolveEvent, snes, sw, 0, 0));
2241918dfc20SMatthew G. Knepley 
2242918dfc20SMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
2243918dfc20SMatthew G. Knepley   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
2244918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
2245918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2246918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2247918dfc20SMatthew G. Knepley 
2248*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->ETabEvent, snes, sw, 0, 0));
2249918dfc20SMatthew G. Knepley   PetscTabulation tab;
2250918dfc20SMatthew G. Knepley   PetscReal      *pcoord, *refcoord;
2251918dfc20SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
2252918dfc20SMatthew G. Knepley   PetscInt        maxNcp    = 0;
2253918dfc20SMatthew G. Knepley 
2254918dfc20SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
2255918dfc20SMatthew G. Knepley     PetscInt Ncp;
2256918dfc20SMatthew G. Knepley 
2257918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
2258918dfc20SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
2259918dfc20SMatthew G. Knepley   }
2260918dfc20SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
2261918dfc20SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
2262918dfc20SMatthew G. Knepley   // This can raise an FP_INEXACT in the dgemm inside
2263918dfc20SMatthew G. Knepley   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
2264918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
2265918dfc20SMatthew G. Knepley   PetscCall(PetscFPTrapPop());
2266918dfc20SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
2267918dfc20SMatthew G. Knepley     PetscScalar *clPhi = NULL;
2268918dfc20SMatthew G. Knepley     PetscInt    *points;
2269918dfc20SMatthew G. Knepley     PetscInt     Ncp;
2270918dfc20SMatthew G. Knepley 
2271918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
2272918dfc20SMatthew G. Knepley     for (PetscInt cp = 0; cp < Ncp; ++cp)
2273918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
2274918dfc20SMatthew G. Knepley     {
2275*2a8381b2SBarry Smith       PetscCall(PetscFEGeomGetChunk(ctx->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
2276918dfc20SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
2277918dfc20SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
2278918dfc20SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
2279918dfc20SMatthew G. Knepley       }
2280918dfc20SMatthew G. Knepley     }
2281918dfc20SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
2282918dfc20SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
2283918dfc20SMatthew G. Knepley     for (PetscInt cp = 0; cp < Ncp; ++cp) {
2284918dfc20SMatthew G. Knepley       const PetscReal *basisDer = tab->T[1];
2285918dfc20SMatthew G. Knepley       const PetscInt   p        = points[cp];
2286918dfc20SMatthew G. Knepley 
2287918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
2288918dfc20SMatthew G. Knepley       PetscCall(PetscFEFreeInterpolateGradient_Static(fe, basisDer, clPhi, dim, chunkgeom->invJ, NULL, cp, &E[p * dim]));
2289918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
2290918dfc20SMatthew G. Knepley     }
2291918dfc20SMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
2292918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
2293918dfc20SMatthew G. Knepley   }
2294918dfc20SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
2295918dfc20SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
2296918dfc20SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
2297918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2298918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
2299918dfc20SMatthew G. Knepley   PetscCall(DMRestoreLocalVector(dm, &locPhi));
2300*2a8381b2SBarry Smith   PetscCall(PetscFEGeomRestoreChunk(ctx->fegeom, 0, 1, &chunkgeom));
2301*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->ETabEvent, snes, sw, 0, 0));
2302918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2303918dfc20SMatthew G. Knepley }
2304918dfc20SMatthew G. Knepley 
ComputeFieldAtParticles_Mixed(SNES snes,DM sw,Mat M_p,PetscReal E[])2305918dfc20SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Mixed(SNES snes, DM sw, Mat M_p, PetscReal E[])
2306918dfc20SMatthew G. Knepley {
2307918dfc20SMatthew G. Knepley   DM         dm;
2308*2a8381b2SBarry Smith   AppCtx    *ctx;
2309918dfc20SMatthew G. Knepley   PetscDS    ds;
2310918dfc20SMatthew G. Knepley   PetscFE    fe;
2311918dfc20SMatthew G. Knepley   KSP        ksp;
2312918dfc20SMatthew G. Knepley   Vec        rhoRhs, rhoRhsFull;   // Weak charge density, \int phi_i rho, and embedding in mixed problem
2313918dfc20SMatthew G. Knepley   Vec        rho;                  // Charge density, M^{-1} rhoRhs
2314918dfc20SMatthew G. Knepley   Vec        phi, locPhi, phiFull; // Potential and embedding in mixed problem
2315918dfc20SMatthew G. Knepley   Vec        f;                    // Particle weights
2316918dfc20SMatthew G. Knepley   PetscReal *coords;
2317918dfc20SMatthew G. Knepley   PetscInt   dim, cStart, cEnd, Np;
2318918dfc20SMatthew G. Knepley 
2319918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2320*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
2321*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->ESolveEvent, snes, sw, 0, 0));
2322918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2323918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2324918dfc20SMatthew G. Knepley 
2325918dfc20SMatthew G. Knepley   PetscCall(SNESGetDM(snes, &dm));
2326*2a8381b2SBarry Smith   PetscCall(DMGetGlobalVector(ctx->dmPot, &rhoRhs));
2327918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
2328918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhsFull));
2329918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhsFull, "Weak charge density"));
2330*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rho", &rho));
2331918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
2332918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
2333918dfc20SMatthew G. Knepley 
2334918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
2335*2a8381b2SBarry Smith   PetscCall(MatViewFromOptions(ctx->M, NULL, "-m_view"));
2336918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
2337918dfc20SMatthew G. Knepley 
2338918dfc20SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
2339918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
2340918dfc20SMatthew G. Knepley 
2341918dfc20SMatthew G. Knepley   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
2342918dfc20SMatthew G. Knepley   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj"));
2343*2a8381b2SBarry Smith   PetscCall(KSPSetOperators(ksp, ctx->M, ctx->M));
2344918dfc20SMatthew G. Knepley   PetscCall(KSPSetFromOptions(ksp));
2345918dfc20SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
2346918dfc20SMatthew G. Knepley 
2347*2a8381b2SBarry Smith   PetscCall(VecISCopy(rhoRhsFull, ctx->isPot, SCATTER_FORWARD, rhoRhs));
2348918dfc20SMatthew G. Knepley   //PetscCall(VecScale(rhoRhsFull, -1.0));
2349918dfc20SMatthew G. Knepley 
2350918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
2351918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhsFull, NULL, "-rho_full_view"));
2352*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rho", &rho));
2353*2a8381b2SBarry Smith   PetscCall(DMRestoreGlobalVector(ctx->dmPot, &rhoRhs));
2354918dfc20SMatthew G. Knepley   PetscCall(KSPDestroy(&ksp));
2355918dfc20SMatthew G. Knepley 
2356918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &phiFull));
2357*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
2358918dfc20SMatthew G. Knepley   PetscCall(VecSet(phiFull, 0.0));
2359918dfc20SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhsFull, phiFull));
2360918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhsFull));
2361918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
2362918dfc20SMatthew G. Knepley 
2363*2a8381b2SBarry Smith   PetscCall(VecISCopy(phiFull, ctx->isPot, SCATTER_REVERSE, phi));
2364*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
2365918dfc20SMatthew G. Knepley 
2366918dfc20SMatthew G. Knepley   PetscCall(DMGetLocalVector(dm, &locPhi));
2367918dfc20SMatthew G. Knepley   PetscCall(DMGlobalToLocalBegin(dm, phiFull, INSERT_VALUES, locPhi));
2368918dfc20SMatthew G. Knepley   PetscCall(DMGlobalToLocalEnd(dm, phiFull, INSERT_VALUES, locPhi));
2369918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &phiFull));
2370*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->ESolveEvent, snes, sw, 0, 0));
2371918dfc20SMatthew G. Knepley 
2372918dfc20SMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
2373918dfc20SMatthew G. Knepley   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
2374918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
2375918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2376918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2377918dfc20SMatthew G. Knepley 
2378*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->ETabEvent, snes, sw, 0, 0));
2379918dfc20SMatthew G. Knepley   PetscTabulation tab;
2380918dfc20SMatthew G. Knepley   PetscReal      *pcoord, *refcoord;
2381918dfc20SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
2382918dfc20SMatthew G. Knepley   PetscInt        maxNcp    = 0;
2383918dfc20SMatthew G. Knepley 
2384918dfc20SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
2385918dfc20SMatthew G. Knepley     PetscInt Ncp;
2386918dfc20SMatthew G. Knepley 
2387918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
2388918dfc20SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
2389918dfc20SMatthew G. Knepley   }
2390918dfc20SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
2391918dfc20SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
2392918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
2393918dfc20SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
2394918dfc20SMatthew G. Knepley     PetscScalar *clPhi = NULL;
2395918dfc20SMatthew G. Knepley     PetscInt    *points;
2396918dfc20SMatthew G. Knepley     PetscInt     Ncp;
2397918dfc20SMatthew G. Knepley 
2398918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
2399918dfc20SMatthew G. Knepley     for (PetscInt cp = 0; cp < Ncp; ++cp)
2400918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
2401918dfc20SMatthew G. Knepley     {
2402*2a8381b2SBarry Smith       PetscCall(PetscFEGeomGetChunk(ctx->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
2403918dfc20SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
2404918dfc20SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
2405918dfc20SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
2406918dfc20SMatthew G. Knepley       }
2407918dfc20SMatthew G. Knepley     }
2408918dfc20SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
2409918dfc20SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
2410918dfc20SMatthew G. Knepley     for (PetscInt cp = 0; cp < Ncp; ++cp) {
2411918dfc20SMatthew G. Knepley       const PetscInt p = points[cp];
2412918dfc20SMatthew G. Knepley 
2413918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
2414918dfc20SMatthew G. Knepley       PetscCall(PetscFEInterpolateAtPoints_Static(fe, tab, clPhi, chunkgeom, cp, &E[p * dim]));
2415918dfc20SMatthew G. Knepley       PetscCall(PetscFEPushforward(fe, chunkgeom, 1, &E[p * dim]));
2416918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
2417918dfc20SMatthew G. Knepley     }
2418918dfc20SMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
2419918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
2420918dfc20SMatthew G. Knepley   }
2421918dfc20SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
2422918dfc20SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
2423918dfc20SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
2424918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2425918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
2426918dfc20SMatthew G. Knepley   PetscCall(DMRestoreLocalVector(dm, &locPhi));
2427*2a8381b2SBarry Smith   PetscCall(PetscFEGeomRestoreChunk(ctx->fegeom, 0, 1, &chunkgeom));
2428*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->ETabEvent, snes, sw, 0, 0));
2429918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2430918dfc20SMatthew G. Knepley }
2431918dfc20SMatthew G. Knepley 
ComputeFieldAtParticles(SNES snes,DM sw)2432918dfc20SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles(SNES snes, DM sw)
2433918dfc20SMatthew G. Knepley {
2434*2a8381b2SBarry Smith   AppCtx    *ctx;
2435918dfc20SMatthew G. Knepley   Mat        M_p;
2436918dfc20SMatthew G. Knepley   PetscReal *E;
2437918dfc20SMatthew G. Knepley   PetscInt   dim, Np;
2438918dfc20SMatthew G. Knepley 
2439918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2440918dfc20SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2441918dfc20SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 2);
2442918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2443918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2444*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
2445918dfc20SMatthew G. Knepley 
2446918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "moments"));
2447918dfc20SMatthew G. Knepley   // TODO: Could share sort context with space cellDM
2448918dfc20SMatthew G. Knepley   PetscCall(DMSwarmMigrate(sw, PETSC_FALSE));
2449*2a8381b2SBarry Smith   PetscCall(DMCreateMassMatrix(sw, ctx->dmPot, &M_p));
2450918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
2451918dfc20SMatthew G. Knepley 
2452918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
2453918dfc20SMatthew G. Knepley   PetscCall(PetscArrayzero(E, Np * dim));
2454*2a8381b2SBarry Smith   ctx->validE = PETSC_TRUE;
2455918dfc20SMatthew G. Knepley 
2456*2a8381b2SBarry Smith   switch (ctx->em) {
2457918dfc20SMatthew G. Knepley   case EM_COULOMB:
2458918dfc20SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Coulomb(snes, sw, E));
2459918dfc20SMatthew G. Knepley     break;
2460f14fce1bSMatthew G. Knepley   case EM_PRIMAL:
2461918dfc20SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Primal(snes, sw, M_p, E));
2462918dfc20SMatthew G. Knepley     break;
2463918dfc20SMatthew G. Knepley   case EM_MIXED:
2464918dfc20SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Mixed(snes, sw, M_p, E));
2465918dfc20SMatthew G. Knepley     break;
2466f14fce1bSMatthew G. Knepley   case EM_NONE:
2467918dfc20SMatthew G. Knepley     break;
2468918dfc20SMatthew G. Knepley   default:
2469*2a8381b2SBarry Smith     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No solver for electrostatic model %s", EMTypes[ctx->em]);
2470918dfc20SMatthew G. Knepley   }
2471918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
2472918dfc20SMatthew G. Knepley   PetscCall(MatDestroy(&M_p));
2473918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2474918dfc20SMatthew G. Knepley }
2475918dfc20SMatthew G. Knepley 
RHSFunction(TS ts,PetscReal t,Vec U,Vec G,PetscCtx ctx)2476*2a8381b2SBarry Smith static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec G, PetscCtx ctx)
2477918dfc20SMatthew G. Knepley {
2478918dfc20SMatthew G. Knepley   DM                 sw;
2479918dfc20SMatthew G. Knepley   SNES               snes = ((AppCtx *)ctx)->snes;
2480918dfc20SMatthew G. Knepley   const PetscScalar *u;
2481918dfc20SMatthew G. Knepley   PetscScalar       *g;
2482918dfc20SMatthew G. Knepley   PetscReal         *E, m_p = 1., q_p = -1.;
2483918dfc20SMatthew G. Knepley   PetscInt           dim, d, Np, p;
2484918dfc20SMatthew G. Knepley 
2485918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2486918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2487918dfc20SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
2488918dfc20SMatthew G. Knepley 
2489918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2490918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2491918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
2492918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(U, &u));
2493918dfc20SMatthew G. Knepley   PetscCall(VecGetArray(G, &g));
2494918dfc20SMatthew G. Knepley   Np /= 2 * dim;
2495918dfc20SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
2496918dfc20SMatthew G. Knepley     for (d = 0; d < dim; ++d) {
2497918dfc20SMatthew G. Knepley       g[(p * 2 + 0) * dim + d] = u[(p * 2 + 1) * dim + d];
2498918dfc20SMatthew G. Knepley       g[(p * 2 + 1) * dim + d] = q_p * E[p * dim + d] / m_p;
2499918dfc20SMatthew G. Knepley     }
2500918dfc20SMatthew G. Knepley   }
2501918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
2502918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(U, &u));
2503918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArray(G, &g));
2504918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2505918dfc20SMatthew G. Knepley }
2506918dfc20SMatthew G. Knepley 
2507918dfc20SMatthew G. Knepley /* J_{ij} = dF_i/dx_j
2508918dfc20SMatthew G. Knepley    J_p = (  0   1)
2509918dfc20SMatthew G. Knepley          (-w^2  0)
2510918dfc20SMatthew G. Knepley    TODO Now there is another term with w^2 from the electric field. I think we will need to invert the operator.
2511918dfc20SMatthew G. Knepley         Perhaps we can approximate the Jacobian using only the cellwise P-P gradient from Coulomb
2512918dfc20SMatthew G. Knepley */
RHSJacobian(TS ts,PetscReal t,Vec U,Mat J,Mat P,PetscCtx ctx)2513*2a8381b2SBarry Smith static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat P, PetscCtx ctx)
2514918dfc20SMatthew G. Knepley {
2515918dfc20SMatthew G. Knepley   DM               sw;
2516918dfc20SMatthew G. Knepley   const PetscReal *coords, *vel;
2517918dfc20SMatthew G. Knepley   PetscInt         dim, d, Np, p, rStart;
2518918dfc20SMatthew G. Knepley 
2519918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2520918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2521918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2522918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2523918dfc20SMatthew G. Knepley   PetscCall(MatGetOwnershipRange(J, &rStart, NULL));
2524918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2525918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
2526918dfc20SMatthew G. Knepley   Np /= 2 * dim;
2527918dfc20SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
2528f940b0e3Sdanofinn     // TODO This is not right because dv/dx has the electric field in it
2529f940b0e3Sdanofinn     PetscScalar vals[4] = {0., 1., -1., 0.};
2530918dfc20SMatthew G. Knepley 
2531918dfc20SMatthew G. Knepley     for (d = 0; d < dim; ++d) {
2532918dfc20SMatthew G. Knepley       const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart};
2533918dfc20SMatthew G. Knepley       PetscCall(MatSetValues(J, 2, rows, 2, rows, vals, INSERT_VALUES));
2534918dfc20SMatthew G. Knepley     }
2535918dfc20SMatthew G. Knepley   }
2536918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2537918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
2538918dfc20SMatthew G. Knepley   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
2539918dfc20SMatthew G. Knepley   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
2540918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2541918dfc20SMatthew G. Knepley }
2542918dfc20SMatthew G. Knepley 
RHSFunctionX(TS ts,PetscReal t,Vec V,Vec Xres,void * Ctx)2543*2a8381b2SBarry Smith static PetscErrorCode RHSFunctionX(TS ts, PetscReal t, Vec V, Vec Xres, void *Ctx)
2544918dfc20SMatthew G. Knepley {
2545*2a8381b2SBarry Smith   AppCtx            *ctx = (AppCtx *)Ctx;
2546918dfc20SMatthew G. Knepley   DM                 sw;
2547918dfc20SMatthew G. Knepley   const PetscScalar *v;
2548918dfc20SMatthew G. Knepley   PetscScalar       *xres;
2549918dfc20SMatthew G. Knepley   PetscInt           Np, p, d, dim;
2550918dfc20SMatthew G. Knepley 
2551918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2552*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->RhsXEvent, ts, 0, 0, 0));
2553918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2554918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2555918dfc20SMatthew G. Knepley   PetscCall(VecGetLocalSize(Xres, &Np));
2556918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(V, &v));
2557918dfc20SMatthew G. Knepley   PetscCall(VecGetArray(Xres, &xres));
2558918dfc20SMatthew G. Knepley   Np /= dim;
2559918dfc20SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
2560918dfc20SMatthew G. Knepley     for (d = 0; d < dim; ++d) xres[p * dim + d] = v[p * dim + d];
2561918dfc20SMatthew G. Knepley   }
2562918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(V, &v));
2563918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArray(Xres, &xres));
2564*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->RhsXEvent, ts, 0, 0, 0));
2565918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2566918dfc20SMatthew G. Knepley }
2567918dfc20SMatthew G. Knepley 
RHSFunctionV(TS ts,PetscReal t,Vec X,Vec Vres,void * Ctx)2568*2a8381b2SBarry Smith static PetscErrorCode RHSFunctionV(TS ts, PetscReal t, Vec X, Vec Vres, void *Ctx)
2569918dfc20SMatthew G. Knepley {
2570918dfc20SMatthew G. Knepley   DM                 sw;
2571*2a8381b2SBarry Smith   AppCtx            *ctx  = (AppCtx *)Ctx;
2572918dfc20SMatthew G. Knepley   SNES               snes = ((AppCtx *)ctx)->snes;
2573918dfc20SMatthew G. Knepley   const PetscScalar *x;
2574918dfc20SMatthew G. Knepley   PetscScalar       *vres;
2575918dfc20SMatthew G. Knepley   PetscReal         *E, m_p, q_p;
2576918dfc20SMatthew G. Knepley   PetscInt           Np, p, dim, d;
2577918dfc20SMatthew G. Knepley   Parameter         *param;
2578918dfc20SMatthew G. Knepley 
2579918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2580*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->RhsVEvent, ts, 0, 0, 0));
2581918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2582918dfc20SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
2583918dfc20SMatthew G. Knepley 
2584918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2585918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
2586*2a8381b2SBarry Smith   PetscCall(PetscBagGetData(ctx->bag, &param));
2587*2a8381b2SBarry Smith   m_p = ctx->masses[0] * param->m0;
2588*2a8381b2SBarry Smith   q_p = ctx->charges[0] * param->q0;
2589918dfc20SMatthew G. Knepley   PetscCall(VecGetLocalSize(Vres, &Np));
2590918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(X, &x));
2591918dfc20SMatthew G. Knepley   PetscCall(VecGetArray(Vres, &vres));
2592918dfc20SMatthew G. Knepley   Np /= dim;
2593918dfc20SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
2594918dfc20SMatthew G. Knepley     for (d = 0; d < dim; ++d) vres[p * dim + d] = q_p * E[p * dim + d] / m_p;
2595918dfc20SMatthew G. Knepley   }
2596918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(X, &x));
2597918dfc20SMatthew G. Knepley   /*
2598918dfc20SMatthew G. Knepley     Synchronized, ordered output for parallel/sequential test cases.
2599918dfc20SMatthew G. Knepley     In the 1D (on the 2D mesh) case, every y component should be zero.
2600918dfc20SMatthew G. Knepley   */
2601*2a8381b2SBarry Smith   if (ctx->checkVRes) {
2602*2a8381b2SBarry Smith     PetscBool pr = ctx->checkVRes > 1 ? PETSC_TRUE : PETSC_FALSE;
2603918dfc20SMatthew G. Knepley     PetscInt  step;
2604918dfc20SMatthew G. Knepley 
2605918dfc20SMatthew G. Knepley     PetscCall(TSGetStepNumber(ts, &step));
2606918dfc20SMatthew G. Knepley     if (pr) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step: %" PetscInt_FMT "\n", step));
2607918dfc20SMatthew G. Knepley     for (PetscInt p = 0; p < Np; ++p) {
2608918dfc20SMatthew G. Knepley       if (pr) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Residual: %.12g %.12g\n", (double)PetscRealPart(vres[p * dim + 0]), (double)PetscRealPart(vres[p * dim + 1])));
2609918dfc20SMatthew G. Knepley       PetscCheck(PetscAbsScalar(vres[p * dim + 1]) < PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Y velocity should be 0., not %g", (double)PetscRealPart(vres[p * dim + 1]));
2610918dfc20SMatthew G. Knepley     }
2611918dfc20SMatthew G. Knepley     if (pr) PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
2612918dfc20SMatthew G. Knepley   }
2613918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArray(Vres, &vres));
2614918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
2615*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->RhsVEvent, ts, 0, 0, 0));
2616918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2617918dfc20SMatthew G. Knepley }
2618918dfc20SMatthew G. Knepley 
2619f940b0e3Sdanofinn /* Discrete Gradients Formulation: S, F, gradF (G) */
RHSJacobianS(TS ts,PetscReal t,Vec U,Mat S,PetscCtx ctx)2620*2a8381b2SBarry Smith PetscErrorCode RHSJacobianS(TS ts, PetscReal t, Vec U, Mat S, PetscCtx ctx)
2621f940b0e3Sdanofinn {
2622f940b0e3Sdanofinn   PetscScalar vals[4] = {0., 1., -1., 0.};
2623f940b0e3Sdanofinn   DM          sw;
2624f940b0e3Sdanofinn   PetscInt    dim, d, Np, p, rStart;
2625f940b0e3Sdanofinn 
2626f940b0e3Sdanofinn   PetscFunctionBeginUser;
2627f940b0e3Sdanofinn   PetscCall(TSGetDM(ts, &sw));
2628f940b0e3Sdanofinn   PetscCall(DMGetDimension(sw, &dim));
2629f940b0e3Sdanofinn   PetscCall(VecGetLocalSize(U, &Np));
2630f940b0e3Sdanofinn   PetscCall(MatGetOwnershipRange(S, &rStart, NULL));
2631f940b0e3Sdanofinn   Np /= 2 * dim;
2632f940b0e3Sdanofinn   for (p = 0; p < Np; ++p) {
2633f940b0e3Sdanofinn     for (d = 0; d < dim; ++d) {
2634f940b0e3Sdanofinn       const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart};
2635f940b0e3Sdanofinn       PetscCall(MatSetValues(S, 2, rows, 2, rows, vals, INSERT_VALUES));
2636f940b0e3Sdanofinn     }
2637f940b0e3Sdanofinn   }
2638f940b0e3Sdanofinn   PetscCall(MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY));
2639f940b0e3Sdanofinn   PetscCall(MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY));
2640f940b0e3Sdanofinn   PetscFunctionReturn(PETSC_SUCCESS);
2641f940b0e3Sdanofinn }
2642f940b0e3Sdanofinn 
RHSObjectiveF(TS ts,PetscReal t,Vec U,PetscScalar * F,void * Ctx)2643*2a8381b2SBarry Smith PetscErrorCode RHSObjectiveF(TS ts, PetscReal t, Vec U, PetscScalar *F, void *Ctx)
2644f940b0e3Sdanofinn {
2645*2a8381b2SBarry Smith   AppCtx            *ctx = (AppCtx *)Ctx;
2646f940b0e3Sdanofinn   DM                 sw;
2647f940b0e3Sdanofinn   Vec                phi;
2648f940b0e3Sdanofinn   const PetscScalar *u;
2649f940b0e3Sdanofinn   PetscInt           dim, Np, cStart, cEnd;
2650f940b0e3Sdanofinn   PetscReal         *vel, *coords, m_p = 1.;
2651f940b0e3Sdanofinn 
2652f940b0e3Sdanofinn   PetscFunctionBeginUser;
2653f940b0e3Sdanofinn   PetscCall(TSGetDM(ts, &sw));
2654f940b0e3Sdanofinn   PetscCall(DMGetDimension(sw, &dim));
2655*2a8381b2SBarry Smith   PetscCall(DMPlexGetHeightStratum(ctx->dmPot, 0, &cStart, &cEnd));
2656f940b0e3Sdanofinn 
2657*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
2658f940b0e3Sdanofinn   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view_dg"));
2659*2a8381b2SBarry Smith   PetscCall(computeFieldEnergy(ctx->dmPot, phi, F));
2660*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
2661f940b0e3Sdanofinn 
2662f940b0e3Sdanofinn   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2663f940b0e3Sdanofinn   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
2664f940b0e3Sdanofinn   PetscCall(DMSwarmSortGetAccess(sw));
2665f940b0e3Sdanofinn   PetscCall(VecGetArrayRead(U, &u));
2666f940b0e3Sdanofinn   PetscCall(VecGetLocalSize(U, &Np));
2667f940b0e3Sdanofinn   Np /= 2 * dim;
2668f940b0e3Sdanofinn   for (PetscInt c = cStart; c < cEnd; ++c) {
2669f940b0e3Sdanofinn     PetscInt *points;
2670f940b0e3Sdanofinn     PetscInt  Ncp;
2671f940b0e3Sdanofinn 
2672f940b0e3Sdanofinn     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
2673f940b0e3Sdanofinn     for (PetscInt cp = 0; cp < Ncp; ++cp) {
2674f940b0e3Sdanofinn       const PetscInt  p  = points[cp];
2675f940b0e3Sdanofinn       const PetscReal v2 = DMPlex_DotRealD_Internal(dim, &u[(p * 2 + 1) * dim], &u[(p * 2 + 1) * dim]);
2676f940b0e3Sdanofinn 
2677f940b0e3Sdanofinn       *F += 0.5 * m_p * v2;
2678f940b0e3Sdanofinn     }
2679f940b0e3Sdanofinn     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
2680f940b0e3Sdanofinn   }
2681f940b0e3Sdanofinn   PetscCall(VecRestoreArrayRead(U, &u));
2682f940b0e3Sdanofinn   PetscCall(DMSwarmSortRestoreAccess(sw));
2683f940b0e3Sdanofinn   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2684f940b0e3Sdanofinn   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
2685f940b0e3Sdanofinn   PetscFunctionReturn(PETSC_SUCCESS);
2686f940b0e3Sdanofinn }
2687f940b0e3Sdanofinn 
2688f940b0e3Sdanofinn /* dF/dx = q E   dF/dv = v */
RHSFunctionG(TS ts,PetscReal t,Vec U,Vec G,PetscCtx ctx)2689*2a8381b2SBarry Smith PetscErrorCode RHSFunctionG(TS ts, PetscReal t, Vec U, Vec G, PetscCtx ctx)
2690f940b0e3Sdanofinn {
2691f940b0e3Sdanofinn   DM                 sw;
2692f940b0e3Sdanofinn   SNES               snes = ((AppCtx *)ctx)->snes;
2693f940b0e3Sdanofinn   const PetscReal   *coords, *vel, *E;
2694f940b0e3Sdanofinn   const PetscScalar *u;
2695f940b0e3Sdanofinn   PetscScalar       *g;
2696f940b0e3Sdanofinn   PetscReal          m_p = 1., q_p = -1.;
2697f940b0e3Sdanofinn   PetscInt           dim, d, Np, p;
2698f940b0e3Sdanofinn 
2699f940b0e3Sdanofinn   PetscFunctionBeginUser;
2700f940b0e3Sdanofinn   PetscCall(TSGetDM(ts, &sw));
2701f940b0e3Sdanofinn   PetscCall(DMGetDimension(sw, &dim));
2702f940b0e3Sdanofinn   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2703f940b0e3Sdanofinn   PetscCall(VecGetArrayRead(U, &u));
2704f940b0e3Sdanofinn   PetscCall(VecGetArray(G, &g));
2705f940b0e3Sdanofinn 
2706f940b0e3Sdanofinn   PetscLogEvent COMPUTEFIELD;
2707f940b0e3Sdanofinn   PetscCall(PetscLogEventRegister("COMPFIELDATPART", TS_CLASSID, &COMPUTEFIELD));
2708f940b0e3Sdanofinn   PetscCall(PetscLogEventBegin(COMPUTEFIELD, 0, 0, 0, 0));
2709f940b0e3Sdanofinn   PetscCall(ComputeFieldAtParticles(snes, sw));
2710f940b0e3Sdanofinn   PetscCall(PetscLogEventEnd(COMPUTEFIELD, 0, 0, 0, 0));
2711f940b0e3Sdanofinn   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2712f940b0e3Sdanofinn   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
2713f940b0e3Sdanofinn   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
2714f940b0e3Sdanofinn   for (p = 0; p < Np; ++p) {
2715f940b0e3Sdanofinn     for (d = 0; d < dim; ++d) {
2716f940b0e3Sdanofinn       g[(p * 2 + 0) * dim + d] = -(q_p / m_p) * E[p * dim + d];
2717f940b0e3Sdanofinn       g[(p * 2 + 1) * dim + d] = m_p * u[(p * 2 + 1) * dim + d];
2718f940b0e3Sdanofinn     }
2719f940b0e3Sdanofinn   }
2720f940b0e3Sdanofinn   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
2721f940b0e3Sdanofinn   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2722f940b0e3Sdanofinn   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
2723f940b0e3Sdanofinn   PetscCall(VecRestoreArrayRead(U, &u));
2724f940b0e3Sdanofinn   PetscCall(VecRestoreArray(G, &g));
2725f940b0e3Sdanofinn   PetscFunctionReturn(PETSC_SUCCESS);
2726f940b0e3Sdanofinn }
2727f940b0e3Sdanofinn 
CreateSolution(TS ts)2728918dfc20SMatthew G. Knepley static PetscErrorCode CreateSolution(TS ts)
2729918dfc20SMatthew G. Knepley {
2730918dfc20SMatthew G. Knepley   DM       sw;
2731918dfc20SMatthew G. Knepley   Vec      u;
2732918dfc20SMatthew G. Knepley   PetscInt dim, Np;
2733918dfc20SMatthew G. Knepley 
2734918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2735918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2736918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2737918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2738918dfc20SMatthew G. Knepley   PetscCall(VecCreate(PETSC_COMM_WORLD, &u));
2739918dfc20SMatthew G. Knepley   PetscCall(VecSetBlockSize(u, dim));
2740918dfc20SMatthew G. Knepley   PetscCall(VecSetSizes(u, 2 * Np * dim, PETSC_DECIDE));
2741918dfc20SMatthew G. Knepley   PetscCall(VecSetUp(u));
2742918dfc20SMatthew G. Knepley   PetscCall(TSSetSolution(ts, u));
2743918dfc20SMatthew G. Knepley   PetscCall(VecDestroy(&u));
2744918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2745918dfc20SMatthew G. Knepley }
2746918dfc20SMatthew G. Knepley 
SetProblem(TS ts)2747918dfc20SMatthew G. Knepley static PetscErrorCode SetProblem(TS ts)
2748918dfc20SMatthew G. Knepley {
2749*2a8381b2SBarry Smith   AppCtx *ctx;
2750918dfc20SMatthew G. Knepley   DM      sw;
2751918dfc20SMatthew G. Knepley 
2752918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2753918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2754*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
2755918dfc20SMatthew G. Knepley   // Define unified system for (X, V)
2756918dfc20SMatthew G. Knepley   {
2757918dfc20SMatthew G. Knepley     Mat      J;
2758918dfc20SMatthew G. Knepley     PetscInt dim, Np;
2759918dfc20SMatthew G. Knepley 
2760918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(sw, &dim));
2761918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetLocalSize(sw, &Np));
2762918dfc20SMatthew G. Knepley     PetscCall(MatCreate(PETSC_COMM_WORLD, &J));
2763918dfc20SMatthew G. Knepley     PetscCall(MatSetSizes(J, 2 * Np * dim, 2 * Np * dim, PETSC_DECIDE, PETSC_DECIDE));
2764918dfc20SMatthew G. Knepley     PetscCall(MatSetBlockSize(J, 2 * dim));
2765918dfc20SMatthew G. Knepley     PetscCall(MatSetFromOptions(J));
2766918dfc20SMatthew G. Knepley     PetscCall(MatSetUp(J));
2767*2a8381b2SBarry Smith     PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, ctx));
2768*2a8381b2SBarry Smith     PetscCall(TSSetRHSJacobian(ts, J, J, RHSJacobian, ctx));
2769918dfc20SMatthew G. Knepley     PetscCall(MatDestroy(&J));
2770918dfc20SMatthew G. Knepley   }
2771918dfc20SMatthew G. Knepley   /* Define split system for X and V */
2772918dfc20SMatthew G. Knepley   {
2773918dfc20SMatthew G. Knepley     Vec             u;
2774918dfc20SMatthew G. Knepley     IS              isx, isv, istmp;
2775918dfc20SMatthew G. Knepley     const PetscInt *idx;
2776918dfc20SMatthew G. Knepley     PetscInt        dim, Np, rstart;
2777918dfc20SMatthew G. Knepley 
2778918dfc20SMatthew G. Knepley     PetscCall(TSGetSolution(ts, &u));
2779918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(sw, &dim));
2780918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetLocalSize(sw, &Np));
2781918dfc20SMatthew G. Knepley     PetscCall(VecGetOwnershipRange(u, &rstart, NULL));
2782918dfc20SMatthew G. Knepley     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 0, 2, &istmp));
2783918dfc20SMatthew G. Knepley     PetscCall(ISGetIndices(istmp, &idx));
2784918dfc20SMatthew G. Knepley     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isx));
2785918dfc20SMatthew G. Knepley     PetscCall(ISRestoreIndices(istmp, &idx));
2786918dfc20SMatthew G. Knepley     PetscCall(ISDestroy(&istmp));
2787918dfc20SMatthew G. Knepley     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 1, 2, &istmp));
2788918dfc20SMatthew G. Knepley     PetscCall(ISGetIndices(istmp, &idx));
2789918dfc20SMatthew G. Knepley     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isv));
2790918dfc20SMatthew G. Knepley     PetscCall(ISRestoreIndices(istmp, &idx));
2791918dfc20SMatthew G. Knepley     PetscCall(ISDestroy(&istmp));
2792918dfc20SMatthew G. Knepley     PetscCall(TSRHSSplitSetIS(ts, "position", isx));
2793918dfc20SMatthew G. Knepley     PetscCall(TSRHSSplitSetIS(ts, "momentum", isv));
2794918dfc20SMatthew G. Knepley     PetscCall(ISDestroy(&isx));
2795918dfc20SMatthew G. Knepley     PetscCall(ISDestroy(&isv));
2796*2a8381b2SBarry Smith     PetscCall(TSRHSSplitSetRHSFunction(ts, "position", NULL, RHSFunctionX, ctx));
2797*2a8381b2SBarry Smith     PetscCall(TSRHSSplitSetRHSFunction(ts, "momentum", NULL, RHSFunctionV, ctx));
2798918dfc20SMatthew G. Knepley   }
2799f940b0e3Sdanofinn   // Define symplectic formulation U_t = S . G, where G = grad F
2800f940b0e3Sdanofinn   {
2801*2a8381b2SBarry Smith     PetscCall(TSDiscGradSetFormulation(ts, RHSJacobianS, RHSObjectiveF, RHSFunctionG, ctx));
2802f940b0e3Sdanofinn   }
2803918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2804918dfc20SMatthew G. Knepley }
2805918dfc20SMatthew G. Knepley 
DMSwarmTSRedistribute(TS ts)2806918dfc20SMatthew G. Knepley static PetscErrorCode DMSwarmTSRedistribute(TS ts)
2807918dfc20SMatthew G. Knepley {
2808918dfc20SMatthew G. Knepley   DM        sw;
2809918dfc20SMatthew G. Knepley   Vec       u;
2810918dfc20SMatthew G. Knepley   PetscReal t, maxt, dt;
2811918dfc20SMatthew G. Knepley   PetscInt  n, maxn;
2812918dfc20SMatthew G. Knepley 
2813918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2814918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2815918dfc20SMatthew G. Knepley   PetscCall(TSGetTime(ts, &t));
2816918dfc20SMatthew G. Knepley   PetscCall(TSGetMaxTime(ts, &maxt));
2817918dfc20SMatthew G. Knepley   PetscCall(TSGetTimeStep(ts, &dt));
2818918dfc20SMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &n));
2819918dfc20SMatthew G. Knepley   PetscCall(TSGetMaxSteps(ts, &maxn));
2820918dfc20SMatthew G. Knepley 
2821918dfc20SMatthew G. Knepley   PetscCall(TSReset(ts));
2822918dfc20SMatthew G. Knepley   PetscCall(TSSetDM(ts, sw));
2823918dfc20SMatthew G. Knepley   PetscCall(TSSetFromOptions(ts));
2824918dfc20SMatthew G. Knepley   PetscCall(TSSetTime(ts, t));
2825918dfc20SMatthew G. Knepley   PetscCall(TSSetMaxTime(ts, maxt));
2826918dfc20SMatthew G. Knepley   PetscCall(TSSetTimeStep(ts, dt));
2827918dfc20SMatthew G. Knepley   PetscCall(TSSetStepNumber(ts, n));
2828918dfc20SMatthew G. Knepley   PetscCall(TSSetMaxSteps(ts, maxn));
2829918dfc20SMatthew G. Knepley 
2830918dfc20SMatthew G. Knepley   PetscCall(CreateSolution(ts));
2831918dfc20SMatthew G. Knepley   PetscCall(SetProblem(ts));
2832918dfc20SMatthew G. Knepley   PetscCall(TSGetSolution(ts, &u));
2833918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2834918dfc20SMatthew G. Knepley }
2835918dfc20SMatthew G. Knepley 
line(PetscInt dim,PetscReal time,const PetscReal dummy[],PetscInt p,PetscScalar x[],void * Ctx)2836*2a8381b2SBarry Smith PetscErrorCode line(PetscInt dim, PetscReal time, const PetscReal dummy[], PetscInt p, PetscScalar x[], void *Ctx)
2837918dfc20SMatthew G. Knepley {
2838918dfc20SMatthew G. Knepley   DM        sw, cdm;
2839918dfc20SMatthew G. Knepley   PetscInt  Np;
2840918dfc20SMatthew G. Knepley   PetscReal low[2], high[2];
2841*2a8381b2SBarry Smith   AppCtx   *ctx = (AppCtx *)Ctx;
2842918dfc20SMatthew G. Knepley 
2843*2a8381b2SBarry Smith   sw = ctx->swarm;
2844918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &cdm));
2845918dfc20SMatthew G. Knepley   // Get the bounding box so we can equally space the particles
2846918dfc20SMatthew G. Knepley   PetscCall(DMGetLocalBoundingBox(cdm, low, high));
2847918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2848918dfc20SMatthew G. Knepley   // shift it by h/2 so nothing is initialized directly on a boundary
2849918dfc20SMatthew G. Knepley   x[0] = ((high[0] - low[0]) / Np) * (p + 0.5);
2850918dfc20SMatthew G. Knepley   x[1] = 0.;
2851918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
2852918dfc20SMatthew G. Knepley }
2853918dfc20SMatthew G. Knepley 
2854918dfc20SMatthew G. Knepley /*
2855918dfc20SMatthew G. Knepley   InitializeSolveAndSwarm - Set the solution values to the swarm coordinates and velocities, and also possibly set the initial values.
2856918dfc20SMatthew G. Knepley 
2857918dfc20SMatthew G. Knepley   Input Parameters:
2858918dfc20SMatthew G. Knepley + ts         - The TS
2859918dfc20SMatthew G. Knepley - useInitial - Flag to also set the initial conditions to the current coordinates and velocities and setup the problem
2860918dfc20SMatthew G. Knepley 
2861918dfc20SMatthew G. Knepley   Output Parameters:
2862918dfc20SMatthew G. Knepley . u - The initialized solution vector
2863918dfc20SMatthew G. Knepley 
2864918dfc20SMatthew G. Knepley   Level: advanced
2865918dfc20SMatthew G. Knepley 
2866918dfc20SMatthew G. Knepley .seealso: InitializeSolve()
2867918dfc20SMatthew G. Knepley */
InitializeSolveAndSwarm(TS ts,PetscBool useInitial)2868918dfc20SMatthew G. Knepley static PetscErrorCode InitializeSolveAndSwarm(TS ts, PetscBool useInitial)
2869918dfc20SMatthew G. Knepley {
2870918dfc20SMatthew G. Knepley   DM       sw;
2871918dfc20SMatthew G. Knepley   Vec      u, gc, gv;
2872918dfc20SMatthew G. Knepley   IS       isx, isv;
2873918dfc20SMatthew G. Knepley   PetscInt dim;
2874*2a8381b2SBarry Smith   AppCtx  *ctx;
2875918dfc20SMatthew G. Knepley 
2876918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2877918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2878*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
2879918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2880918dfc20SMatthew G. Knepley   if (useInitial) {
2881918dfc20SMatthew G. Knepley     PetscReal v0[2] = {1., 0.};
2882*2a8381b2SBarry Smith     if (ctx->perturbed_weights) {
2883*2a8381b2SBarry Smith       PetscCall(InitializeParticles_PerturbedWeights(sw, ctx));
2884918dfc20SMatthew G. Knepley     } else {
2885918dfc20SMatthew G. Knepley       PetscCall(DMSwarmComputeLocalSizeFromOptions(sw));
2886918dfc20SMatthew G. Knepley       PetscCall(DMSwarmInitializeCoordinates(sw));
2887918dfc20SMatthew G. Knepley       PetscCall(DMSwarmInitializeVelocitiesFromOptions(sw, v0));
2888918dfc20SMatthew G. Knepley     }
2889918dfc20SMatthew G. Knepley     PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
2890918dfc20SMatthew G. Knepley     PetscCall(DMSwarmTSRedistribute(ts));
2891918dfc20SMatthew G. Knepley   }
2892918dfc20SMatthew G. Knepley   PetscCall(DMSetUp(sw));
2893918dfc20SMatthew G. Knepley   PetscCall(TSGetSolution(ts, &u));
2894918dfc20SMatthew G. Knepley   PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
2895918dfc20SMatthew G. Knepley   PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
2896918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
2897918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
2898918dfc20SMatthew G. Knepley   PetscCall(VecISCopy(u, isx, SCATTER_FORWARD, gc));
2899918dfc20SMatthew G. Knepley   PetscCall(VecISCopy(u, isv, SCATTER_FORWARD, gv));
2900918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
2901918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
2902918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2903918dfc20SMatthew G. Knepley }
2904918dfc20SMatthew G. Knepley 
InitializeSolve(TS ts,Vec u)2905918dfc20SMatthew G. Knepley static PetscErrorCode InitializeSolve(TS ts, Vec u)
2906918dfc20SMatthew G. Knepley {
2907918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2908918dfc20SMatthew G. Knepley   PetscCall(TSSetSolution(ts, u));
2909918dfc20SMatthew G. Knepley   PetscCall(InitializeSolveAndSwarm(ts, PETSC_TRUE));
2910918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2911918dfc20SMatthew G. Knepley }
2912918dfc20SMatthew G. Knepley 
MigrateParticles(TS ts)2913918dfc20SMatthew G. Knepley static PetscErrorCode MigrateParticles(TS ts)
2914918dfc20SMatthew G. Knepley {
2915918dfc20SMatthew G. Knepley   DM               sw, cdm;
2916918dfc20SMatthew G. Knepley   const PetscReal *L;
2917918dfc20SMatthew G. Knepley   AppCtx          *ctx;
2918918dfc20SMatthew G. Knepley 
2919918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2920918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2921918dfc20SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &ctx));
2922918dfc20SMatthew G. Knepley   PetscCall(DMViewFromOptions(sw, NULL, "-migrate_view_pre"));
2923918dfc20SMatthew G. Knepley   {
2924918dfc20SMatthew G. Knepley     Vec        u, gc, gv, position, momentum;
2925918dfc20SMatthew G. Knepley     IS         isx, isv;
2926918dfc20SMatthew G. Knepley     PetscReal *pos, *mom;
2927918dfc20SMatthew G. Knepley 
2928918dfc20SMatthew G. Knepley     PetscCall(TSGetSolution(ts, &u));
2929918dfc20SMatthew G. Knepley     PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
2930918dfc20SMatthew G. Knepley     PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
2931918dfc20SMatthew G. Knepley     PetscCall(VecGetSubVector(u, isx, &position));
2932918dfc20SMatthew G. Knepley     PetscCall(VecGetSubVector(u, isv, &momentum));
2933918dfc20SMatthew G. Knepley     PetscCall(VecGetArray(position, &pos));
2934918dfc20SMatthew G. Knepley     PetscCall(VecGetArray(momentum, &mom));
2935918dfc20SMatthew G. Knepley     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
2936918dfc20SMatthew G. Knepley     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
2937918dfc20SMatthew G. Knepley     PetscCall(VecISCopy(u, isx, SCATTER_REVERSE, gc));
2938918dfc20SMatthew G. Knepley     PetscCall(VecISCopy(u, isv, SCATTER_REVERSE, gv));
2939918dfc20SMatthew G. Knepley 
2940918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetCellDM(sw, &cdm));
2941918dfc20SMatthew G. Knepley     PetscCall(DMGetPeriodicity(cdm, NULL, NULL, &L));
2942918dfc20SMatthew G. Knepley     PetscCheck(L, PetscObjectComm((PetscObject)cdm), PETSC_ERR_ARG_WRONG, "Mesh must be periodic");
2943918dfc20SMatthew G. Knepley     if ((L[0] || L[1]) >= 0.) {
2944918dfc20SMatthew G. Knepley       PetscReal *x, *v, upper[3], lower[3];
2945918dfc20SMatthew G. Knepley       PetscInt   Np, dim;
2946918dfc20SMatthew G. Knepley 
2947918dfc20SMatthew G. Knepley       PetscCall(DMSwarmGetLocalSize(sw, &Np));
2948918dfc20SMatthew G. Knepley       PetscCall(DMGetDimension(cdm, &dim));
2949918dfc20SMatthew G. Knepley       PetscCall(DMGetBoundingBox(cdm, lower, upper));
2950918dfc20SMatthew G. Knepley       PetscCall(VecGetArray(gc, &x));
2951918dfc20SMatthew G. Knepley       PetscCall(VecGetArray(gv, &v));
2952918dfc20SMatthew G. Knepley       for (PetscInt p = 0; p < Np; ++p) {
2953918dfc20SMatthew G. Knepley         for (PetscInt d = 0; d < dim; ++d) {
2954918dfc20SMatthew G. Knepley           if (pos[p * dim + d] < lower[d]) {
2955918dfc20SMatthew G. Knepley             x[p * dim + d] = pos[p * dim + d] + (upper[d] - lower[d]);
2956918dfc20SMatthew G. Knepley           } else if (pos[p * dim + d] > upper[d]) {
2957918dfc20SMatthew G. Knepley             x[p * dim + d] = pos[p * dim + d] - (upper[d] - lower[d]);
2958918dfc20SMatthew G. Knepley           } else {
2959918dfc20SMatthew G. Knepley             x[p * dim + d] = pos[p * dim + d];
2960918dfc20SMatthew G. Knepley           }
2961918dfc20SMatthew G. Knepley           PetscCheck(x[p * dim + d] >= lower[d] && x[p * dim + d] <= upper[d], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "p: %" PetscInt_FMT "x[%" PetscInt_FMT "] %g", p, d, (double)x[p * dim + d]);
2962918dfc20SMatthew G. Knepley           v[p * dim + d] = mom[p * dim + d];
2963918dfc20SMatthew G. Knepley         }
2964918dfc20SMatthew G. Knepley       }
2965918dfc20SMatthew G. Knepley       PetscCall(VecRestoreArray(gc, &x));
2966918dfc20SMatthew G. Knepley       PetscCall(VecRestoreArray(gv, &v));
2967918dfc20SMatthew G. Knepley     }
2968918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArray(position, &pos));
2969918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArray(momentum, &mom));
2970918dfc20SMatthew G. Knepley     PetscCall(VecRestoreSubVector(u, isx, &position));
2971918dfc20SMatthew G. Knepley     PetscCall(VecRestoreSubVector(u, isv, &momentum));
2972918dfc20SMatthew G. Knepley     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
2973918dfc20SMatthew G. Knepley     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
2974918dfc20SMatthew G. Knepley   }
2975918dfc20SMatthew G. Knepley   PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
2976918dfc20SMatthew G. Knepley   PetscInt step;
2977918dfc20SMatthew G. Knepley 
2978918dfc20SMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &step));
2979918dfc20SMatthew G. Knepley   if (!(step % ctx->remapFreq)) {
2980918dfc20SMatthew G. Knepley     // Monitor electric field before we destroy it
2981918dfc20SMatthew G. Knepley     PetscReal ptime;
2982918dfc20SMatthew G. Knepley     PetscInt  step;
2983918dfc20SMatthew G. Knepley 
2984918dfc20SMatthew G. Knepley     PetscCall(TSGetStepNumber(ts, &step));
2985918dfc20SMatthew G. Knepley     PetscCall(TSGetTime(ts, &ptime));
2986918dfc20SMatthew G. Knepley     if (ctx->efield_monitor) PetscCall(MonitorEField(ts, step, ptime, NULL, ctx));
2987918dfc20SMatthew G. Knepley     if (ctx->poisson_monitor) PetscCall(MonitorPoisson(ts, step, ptime, NULL, ctx));
2988918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRemap(sw));
2989918dfc20SMatthew G. Knepley     ctx->validE = PETSC_FALSE;
2990918dfc20SMatthew G. Knepley   }
2991918dfc20SMatthew G. Knepley   // This MUST come last, since it recreates the subswarms and they must DMClone() the new swarm
2992918dfc20SMatthew G. Knepley   PetscCall(DMSwarmTSRedistribute(ts));
2993918dfc20SMatthew G. Knepley   PetscCall(InitializeSolveAndSwarm(ts, PETSC_FALSE));
2994918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2995918dfc20SMatthew G. Knepley }
2996918dfc20SMatthew G. Knepley 
main(int argc,char ** argv)2997918dfc20SMatthew G. Knepley int main(int argc, char **argv)
2998918dfc20SMatthew G. Knepley {
2999918dfc20SMatthew G. Knepley   DM        dm, sw;
3000918dfc20SMatthew G. Knepley   TS        ts;
3001918dfc20SMatthew G. Knepley   Vec       u;
3002918dfc20SMatthew G. Knepley   PetscReal dt;
3003918dfc20SMatthew G. Knepley   PetscInt  maxn;
3004*2a8381b2SBarry Smith   AppCtx    ctx;
3005918dfc20SMatthew G. Knepley 
3006918dfc20SMatthew G. Knepley   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
3007*2a8381b2SBarry Smith   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &ctx));
3008*2a8381b2SBarry Smith   PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &ctx.bag));
3009*2a8381b2SBarry Smith   PetscCall(CreateMesh(PETSC_COMM_WORLD, &ctx, &dm));
3010*2a8381b2SBarry Smith   PetscCall(CreatePoisson(dm, &ctx));
3011*2a8381b2SBarry Smith   PetscCall(CreateMomentFields(dm, &ctx));
3012*2a8381b2SBarry Smith   PetscCall(CreateSwarm(dm, &ctx, &sw));
3013*2a8381b2SBarry Smith   PetscCall(SetupParameters(PETSC_COMM_WORLD, &ctx));
3014*2a8381b2SBarry Smith   PetscCall(InitializeConstants(sw, &ctx));
3015*2a8381b2SBarry Smith   PetscCall(DMSetApplicationContext(sw, &ctx));
3016918dfc20SMatthew G. Knepley 
3017918dfc20SMatthew G. Knepley   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
3018918dfc20SMatthew G. Knepley   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
3019918dfc20SMatthew G. Knepley   PetscCall(TSSetDM(ts, sw));
3020918dfc20SMatthew G. Knepley   PetscCall(TSSetMaxTime(ts, 0.1));
3021918dfc20SMatthew G. Knepley   PetscCall(TSSetTimeStep(ts, 0.00001));
3022918dfc20SMatthew G. Knepley   PetscCall(TSSetMaxSteps(ts, 100));
3023918dfc20SMatthew G. Knepley   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
3024918dfc20SMatthew G. Knepley 
3025*2a8381b2SBarry Smith   if (ctx.efield_monitor) PetscCall(TSMonitorSet(ts, MonitorEField, &ctx, NULL));
3026*2a8381b2SBarry Smith   if (ctx.moment_monitor) PetscCall(TSMonitorSet(ts, MonitorMoments, &ctx, NULL));
3027*2a8381b2SBarry Smith   if (ctx.moment_field_monitor) PetscCall(TSMonitorSet(ts, MonitorMomentFields, &ctx, NULL));
3028*2a8381b2SBarry Smith   if (ctx.initial_monitor) PetscCall(TSMonitorSet(ts, MonitorInitialConditions, &ctx, NULL));
3029*2a8381b2SBarry Smith   if (ctx.positions_monitor) PetscCall(TSMonitorSet(ts, MonitorPositions_2D, &ctx, NULL));
3030*2a8381b2SBarry Smith   if (ctx.poisson_monitor) PetscCall(TSMonitorSet(ts, MonitorPoisson, &ctx, NULL));
3031*2a8381b2SBarry Smith   if (ctx.velocity_monitor >= 0) PetscCall(TSMonitorSet(ts, MonitorVelocity, &ctx, NULL));
3032918dfc20SMatthew G. Knepley 
3033918dfc20SMatthew G. Knepley   PetscCall(TSSetFromOptions(ts));
3034918dfc20SMatthew G. Knepley   PetscCall(TSGetTimeStep(ts, &dt));
3035918dfc20SMatthew G. Knepley   PetscCall(TSGetMaxSteps(ts, &maxn));
3036*2a8381b2SBarry Smith   ctx.steps    = maxn;
3037*2a8381b2SBarry Smith   ctx.stepSize = dt;
3038*2a8381b2SBarry Smith   PetscCall(SetupContext(dm, sw, &ctx));
3039918dfc20SMatthew G. Knepley   PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve));
3040918dfc20SMatthew G. Knepley   PetscCall(TSSetPostStep(ts, MigrateParticles));
3041918dfc20SMatthew G. Knepley   PetscCall(CreateSolution(ts));
3042918dfc20SMatthew G. Knepley   PetscCall(TSGetSolution(ts, &u));
3043918dfc20SMatthew G. Knepley   PetscCall(TSComputeInitialCondition(ts, u));
3044*2a8381b2SBarry Smith   PetscCall(CheckNonNegativeWeights(sw, &ctx));
3045918dfc20SMatthew G. Knepley   PetscCall(TSSolve(ts, NULL));
3046918dfc20SMatthew G. Knepley 
3047*2a8381b2SBarry Smith   if (ctx.checkLandau) {
3048918dfc20SMatthew G. Knepley     // We should get a lookup table based on charge density and \hat k
3049918dfc20SMatthew G. Knepley     const PetscReal gammaEx = -0.15336;
3050918dfc20SMatthew G. Knepley     const PetscReal omegaEx = 1.4156;
3051918dfc20SMatthew G. Knepley     const PetscReal tol     = 1e-2;
3052918dfc20SMatthew G. Knepley 
3053*2a8381b2SBarry Smith     PetscCheck(PetscAbsReal((ctx.gamma - gammaEx) / gammaEx) < tol, PETSC_COMM_WORLD, PETSC_ERR_LIB, "Invalid Landau gamma %g != %g", ctx.gamma, gammaEx);
3054*2a8381b2SBarry Smith     PetscCheck(PetscAbsReal((ctx.omega - omegaEx) / omegaEx) < tol, PETSC_COMM_WORLD, PETSC_ERR_LIB, "Invalid Landau omega %g != %g", ctx.omega, omegaEx);
3055918dfc20SMatthew G. Knepley   }
3056918dfc20SMatthew G. Knepley 
3057*2a8381b2SBarry Smith   PetscCall(SNESDestroy(&ctx.snes));
3058*2a8381b2SBarry Smith   PetscCall(DMDestroy(&ctx.dmN));
3059*2a8381b2SBarry Smith   PetscCall(ISDestroy(&ctx.isN));
3060*2a8381b2SBarry Smith   PetscCall(MatDestroy(&ctx.MN));
3061*2a8381b2SBarry Smith   PetscCall(DMDestroy(&ctx.dmP));
3062*2a8381b2SBarry Smith   PetscCall(ISDestroy(&ctx.isP));
3063*2a8381b2SBarry Smith   PetscCall(MatDestroy(&ctx.MP));
3064*2a8381b2SBarry Smith   PetscCall(DMDestroy(&ctx.dmE));
3065*2a8381b2SBarry Smith   PetscCall(ISDestroy(&ctx.isE));
3066*2a8381b2SBarry Smith   PetscCall(MatDestroy(&ctx.ME));
3067*2a8381b2SBarry Smith   PetscCall(DMDestroy(&ctx.dmMom));
3068*2a8381b2SBarry Smith   PetscCall(DMDestroy(&ctx.dmPot));
3069*2a8381b2SBarry Smith   PetscCall(ISDestroy(&ctx.isPot));
3070*2a8381b2SBarry Smith   PetscCall(MatDestroy(&ctx.M));
3071*2a8381b2SBarry Smith   PetscCall(PetscFEGeomDestroy(&ctx.fegeom));
3072918dfc20SMatthew G. Knepley   PetscCall(TSDestroy(&ts));
3073918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&sw));
3074918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&dm));
3075*2a8381b2SBarry Smith   PetscCall(DestroyContext(&ctx));
3076918dfc20SMatthew G. Knepley   PetscCall(PetscFinalize());
3077918dfc20SMatthew G. Knepley   return 0;
3078918dfc20SMatthew G. Knepley }
3079918dfc20SMatthew G. Knepley 
3080918dfc20SMatthew G. Knepley /*TEST
3081918dfc20SMatthew G. Knepley 
3082918dfc20SMatthew G. Knepley   build:
3083918dfc20SMatthew G. Knepley     requires: !complex double
3084918dfc20SMatthew G. Knepley 
3085918dfc20SMatthew G. Knepley   # This tests that we can compute the correct decay rate and frequency
3086f940b0e3Sdanofinn   #   For gold runs, use -dm_plex_box_faces 160 -vdm_plex_box_faces 450 -remap_dm_plex_box_faces 80,150 -ts_max_steps 1000
3087f940b0e3Sdanofinn   #                      -remap_freq 100 -emax_start_step 50 -emax_solve_step 100
3088f940b0e3Sdanofinn   testset:
3089918dfc20SMatthew G. Knepley     args: -cosine_coefficients 0.01 -charges -1. -perturbed_weights -total_weight 1. \
3090918dfc20SMatthew G. Knepley           -dm_plex_dim 1 -dm_plex_box_faces 80 -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 \
3091918dfc20SMatthew G. Knepley             -dm_plex_box_bd periodic -dm_plex_hash_location \
3092918dfc20SMatthew G. Knepley           -vdm_plex_dim 1 -vdm_plex_box_faces 220 -vdm_plex_box_lower -6 -vdm_plex_box_upper 6 \
3093918dfc20SMatthew G. Knepley             -vpetscspace_degree 2 -vdm_plex_hash_location \
3094f940b0e3Sdanofinn           -remap_freq 1 -dm_swarm_remap_type pfak -remap_dm_plex_dim 2 -remap_dm_plex_simplex 0 \
3095918dfc20SMatthew G. Knepley             -remap_dm_plex_box_faces 40,110 -remap_dm_plex_box_bd periodic,none \
3096918dfc20SMatthew G. Knepley             -remap_dm_plex_box_lower 0.,-6. -remap_dm_plex_box_upper 12.5664,6. \
3097918dfc20SMatthew G. Knepley             -remap_petscspace_degree 1 -remap_dm_plex_hash_location \
3098918dfc20SMatthew G. Knepley             -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 -ptof_pc_type lu \
3099918dfc20SMatthew G. Knepley           -em_type primal -petscspace_degree 1 -em_snes_atol 1.e-12 -em_snes_error_if_not_converged \
3100918dfc20SMatthew G. Knepley             -em_ksp_error_if_not_converged -em_pc_type svd -em_proj_pc_type lu \
3101188af4bfSBarry Smith           -ts_time_step 0.03 -ts_max_steps 2 -ts_max_time 100 \
3102918dfc20SMatthew G. Knepley           -emax_tao_type brgn -emax_tao_max_it 100 -emax_tao_brgn_regularization_type l2pure \
3103918dfc20SMatthew G. Knepley             -emax_tao_brgn_regularizer_weight 1e-5 -tao_brgn_subsolver_tao_bnk_ksp_rtol 1e-12 \
3104f940b0e3Sdanofinn             -emax_start_step 1 -emax_solve_step 1 \
3105918dfc20SMatthew G. Knepley           -output_step 1 -efield_monitor quiet
3106918dfc20SMatthew G. Knepley 
3107f940b0e3Sdanofinn     test:
3108f940b0e3Sdanofinn       suffix: landau_damping_1d_bs
3109f940b0e3Sdanofinn       args: -ts_type basicsymplectic -ts_basicsymplectic_type 1
3110f940b0e3Sdanofinn 
3111f940b0e3Sdanofinn     test:
3112f940b0e3Sdanofinn       suffix: landau_damping_1d_dg
3113f940b0e3Sdanofinn       args: -ts_type discgrad -ts_discgrad_type average -snes_type qn
3114f940b0e3Sdanofinn 
3115918dfc20SMatthew G. Knepley TEST*/
3116