xref: /petsc/src/ts/tutorials/hamiltonian/ex4.c (revision 918dfc20b7e1fedebebc659479286e424e811b28)
1*918dfc20SMatthew G. Knepley static char help[] = "Two-level system for Landau Damping using Vlasov-Poisson equations\n";
2*918dfc20SMatthew G. Knepley 
3*918dfc20SMatthew G. Knepley /*
4*918dfc20SMatthew G. Knepley   Moment Equations:
5*918dfc20SMatthew G. Knepley 
6*918dfc20SMatthew 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
7*918dfc20SMatthew G. Knepley 
8*918dfc20SMatthew G. Knepley       \int dx \phi_i n_f = \int dx \phi_i n_p
9*918dfc20SMatthew G. Knepley       \int dx \phi_i n_f = \int dx \phi_i \int dv f
10*918dfc20SMatthew 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)
11*918dfc20SMatthew G. Knepley       \int dx \phi_i n_f = \int dx \phi_i \sum_p w_p \delta(x - x_p)
12*918dfc20SMatthew G. Knepley                    M n_F = M_p w_p
13*918dfc20SMatthew G. Knepley 
14*918dfc20SMatthew G. Knepley     where
15*918dfc20SMatthew G. Knepley 
16*918dfc20SMatthew G. Knepley       (M_p){ip} = \phi_i(x_p)
17*918dfc20SMatthew G. Knepley 
18*918dfc20SMatthew G. Knepley     which is just a scaled version of the charge density. The second moment, momentum density, is given by
19*918dfc20SMatthew G. Knepley 
20*918dfc20SMatthew G. Knepley       \int dx \phi_i p_f = m \int dx \phi_i \int dv v f
21*918dfc20SMatthew G. Knepley       \int dx \phi_i p_f = m \int dx \phi_i \sum_p w_p \delta(x - x_p) v_p
22*918dfc20SMatthew G. Knepley                    M p_F = M_p v_p w_p
23*918dfc20SMatthew G. Knepley 
24*918dfc20SMatthew G. Knepley     And finally the third moment, pressure, is given by
25*918dfc20SMatthew G. Knepley 
26*918dfc20SMatthew G. Knepley       \int dx \phi_i pr_f = m \int dx \phi_i \int dv (v - u)^2 f
27*918dfc20SMatthew 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
28*918dfc20SMatthew G. Knepley                    M pr_F = M_p (v_p - u)^2 w_p
29*918dfc20SMatthew G. Knepley                           = M_p (v_p - p_F(x_p) / m n_F(x_p))^2 w_p
30*918dfc20SMatthew 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
31*918dfc20SMatthew G. Knepley 
32*918dfc20SMatthew G. Knepley     Here we need all FEM basis functions \phi_i that see that particle p.
33*918dfc20SMatthew G. Knepley 
34*918dfc20SMatthew 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"
35*918dfc20SMatthew G. Knepley   According to Lukas, good damping results come at ~16k particles per cell
36*918dfc20SMatthew G. Knepley 
37*918dfc20SMatthew G. Knepley   Swarm CellDMs
38*918dfc20SMatthew G. Knepley   =============
39*918dfc20SMatthew G. Knepley   Name: "space"
40*918dfc20SMatthew G. Knepley   Fields: DMSwarmPICField_coor, "velocity"
41*918dfc20SMatthew G. Knepley   Coordinates: DMSwarmPICField_coor
42*918dfc20SMatthew G. Knepley 
43*918dfc20SMatthew G. Knepley   Name: "velocity"
44*918dfc20SMatthew G. Knepley   Fields: "w_q"
45*918dfc20SMatthew G. Knepley   Coordinates: "velocity"
46*918dfc20SMatthew G. Knepley 
47*918dfc20SMatthew G. Knepley   Name: "moments"
48*918dfc20SMatthew G. Knepley   Fields: "w_q"
49*918dfc20SMatthew G. Knepley   Coordinates: DMSwarmPICField_coor
50*918dfc20SMatthew G. Knepley 
51*918dfc20SMatthew G. Knepley   Name: "moment fields"
52*918dfc20SMatthew G. Knepley   Fields: "velocity"
53*918dfc20SMatthew G. Knepley   Coordinates: DMSwarmPICField_coor
54*918dfc20SMatthew G. Knepley 
55*918dfc20SMatthew G. Knepley   To visualize the maximum electric field use
56*918dfc20SMatthew G. Knepley 
57*918dfc20SMatthew G. Knepley     -efield_monitor
58*918dfc20SMatthew G. Knepley 
59*918dfc20SMatthew G. Knepley   To monitor velocity moments of the distribution use
60*918dfc20SMatthew G. Knepley 
61*918dfc20SMatthew G. Knepley     -ptof_pc_type lu -moments_monitor
62*918dfc20SMatthew G. Knepley 
63*918dfc20SMatthew G. Knepley   To monitor the particle positions in phase space use
64*918dfc20SMatthew G. Knepley 
65*918dfc20SMatthew G. Knepley     -positions_monitor
66*918dfc20SMatthew G. Knepley 
67*918dfc20SMatthew G. Knepley   To monitor the charge density, E field, and potential use
68*918dfc20SMatthew G. Knepley 
69*918dfc20SMatthew G. Knepley     -poisson_monitor
70*918dfc20SMatthew G. Knepley 
71*918dfc20SMatthew G. Knepley   To monitor the remapping field use
72*918dfc20SMatthew G. Knepley 
73*918dfc20SMatthew G. Knepley     -remap_uf_view draw
74*918dfc20SMatthew G. Knepley 
75*918dfc20SMatthew G. Knepley   To visualize the swarm distribution use
76*918dfc20SMatthew G. Knepley 
77*918dfc20SMatthew G. Knepley     -ts_monitor_hg_swarm
78*918dfc20SMatthew G. Knepley 
79*918dfc20SMatthew G. Knepley   To visualize the particles, we can use
80*918dfc20SMatthew G. Knepley 
81*918dfc20SMatthew G. Knepley     -ts_monitor_sp_swarm -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500
82*918dfc20SMatthew G. Knepley */
83*918dfc20SMatthew G. Knepley #include <petsctao.h>
84*918dfc20SMatthew G. Knepley #include <petscts.h>
85*918dfc20SMatthew G. Knepley #include <petscdmplex.h>
86*918dfc20SMatthew G. Knepley #include <petscdmswarm.h>
87*918dfc20SMatthew G. Knepley #include <petscfe.h>
88*918dfc20SMatthew G. Knepley #include <petscds.h>
89*918dfc20SMatthew G. Knepley #include <petscbag.h>
90*918dfc20SMatthew G. Knepley #include <petscdraw.h>
91*918dfc20SMatthew G. Knepley #include <petsc/private/petscfeimpl.h> /* For interpolation */
92*918dfc20SMatthew G. Knepley #include <petsc/private/dmswarmimpl.h> /* For swarm debugging */
93*918dfc20SMatthew G. Knepley #include "petscdm.h"
94*918dfc20SMatthew G. Knepley #include "petscdmlabel.h"
95*918dfc20SMatthew G. Knepley 
96*918dfc20SMatthew G. Knepley PETSC_EXTERN PetscErrorCode stream(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
97*918dfc20SMatthew G. Knepley PETSC_EXTERN PetscErrorCode line(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
98*918dfc20SMatthew G. Knepley 
99*918dfc20SMatthew G. Knepley const char *EMTypes[] = {"primal", "mixed", "coulomb", "none", "EMType", "EM_", NULL};
100*918dfc20SMatthew G. Knepley typedef enum {
101*918dfc20SMatthew G. Knepley   EMPRIMAL,
102*918dfc20SMatthew G. Knepley   EM_MIXED,
103*918dfc20SMatthew G. Knepley   EM_COULOMB,
104*918dfc20SMatthew G. Knepley   EMNONE
105*918dfc20SMatthew G. Knepley } EMType;
106*918dfc20SMatthew G. Knepley 
107*918dfc20SMatthew G. Knepley typedef enum {
108*918dfc20SMatthew G. Knepley   V0,
109*918dfc20SMatthew G. Knepley   X0,
110*918dfc20SMatthew G. Knepley   T0,
111*918dfc20SMatthew G. Knepley   M0,
112*918dfc20SMatthew G. Knepley   Q0,
113*918dfc20SMatthew G. Knepley   PHI0,
114*918dfc20SMatthew G. Knepley   POISSON,
115*918dfc20SMatthew G. Knepley   VLASOV,
116*918dfc20SMatthew G. Knepley   SIGMA,
117*918dfc20SMatthew G. Knepley   NUM_CONSTANTS
118*918dfc20SMatthew G. Knepley } ConstantType;
119*918dfc20SMatthew G. Knepley 
120*918dfc20SMatthew G. Knepley typedef enum {
121*918dfc20SMatthew G. Knepley   E_MONITOR_NONE,
122*918dfc20SMatthew G. Knepley   E_MONITOR_FULL,
123*918dfc20SMatthew G. Knepley   E_MONITOR_QUIET
124*918dfc20SMatthew G. Knepley } EMonitorType;
125*918dfc20SMatthew G. Knepley const char *const EMonitorTypes[] = {"NONE", "FULL", "QUIET", "EMonitorType", "E_MONITOR_", NULL};
126*918dfc20SMatthew G. Knepley 
127*918dfc20SMatthew G. Knepley typedef struct {
128*918dfc20SMatthew G. Knepley   PetscScalar v0; /* Velocity scale, often the thermal velocity */
129*918dfc20SMatthew G. Knepley   PetscScalar t0; /* Time scale */
130*918dfc20SMatthew G. Knepley   PetscScalar x0; /* Space scale */
131*918dfc20SMatthew G. Knepley   PetscScalar m0; /* Mass scale */
132*918dfc20SMatthew G. Knepley   PetscScalar q0; /* Charge scale */
133*918dfc20SMatthew G. Knepley   PetscScalar kb;
134*918dfc20SMatthew G. Knepley   PetscScalar epsi0;
135*918dfc20SMatthew G. Knepley   PetscScalar phi0;          /* Potential scale */
136*918dfc20SMatthew G. Knepley   PetscScalar poissonNumber; /* Non-Dimensional Poisson Number */
137*918dfc20SMatthew G. Knepley   PetscScalar vlasovNumber;  /* Non-Dimensional Vlasov Number */
138*918dfc20SMatthew G. Knepley   PetscReal   sigma;         /* Nondimensional charge per length in x */
139*918dfc20SMatthew G. Knepley } Parameter;
140*918dfc20SMatthew G. Knepley 
141*918dfc20SMatthew G. Knepley typedef struct {
142*918dfc20SMatthew G. Knepley   PetscBag     bag;                  // Problem parameters
143*918dfc20SMatthew G. Knepley   PetscBool    error;                // Flag for printing the error
144*918dfc20SMatthew G. Knepley   PetscInt     remapFreq;            // Number of timesteps between remapping
145*918dfc20SMatthew G. Knepley   EMonitorType efield_monitor;       // Flag to show electric field monitor
146*918dfc20SMatthew G. Knepley   PetscBool    moment_monitor;       // Flag to show distribution moment monitor
147*918dfc20SMatthew G. Knepley   PetscBool    moment_field_monitor; // Flag to show moment field monitor
148*918dfc20SMatthew G. Knepley   PetscBool    positions_monitor;    // Flag to show particle positins at each time step
149*918dfc20SMatthew G. Knepley   PetscBool    poisson_monitor;      // Flag to display charge, E field, and potential at each solve
150*918dfc20SMatthew G. Knepley   PetscBool    initial_monitor;      // Flag to monitor the initial conditions
151*918dfc20SMatthew G. Knepley   PetscInt     velocity_monitor;     // Cell to monitor the velocity distribution for
152*918dfc20SMatthew G. Knepley   PetscBool    perturbed_weights;    // Uniformly sample x,v space with gaussian weights
153*918dfc20SMatthew G. Knepley   PetscInt     ostep;                // Print the energy at each ostep time steps
154*918dfc20SMatthew G. Knepley   PetscInt     numParticles;
155*918dfc20SMatthew G. Knepley   PetscReal    timeScale;              /* Nondimensionalizing time scale */
156*918dfc20SMatthew G. Knepley   PetscReal    charges[2];             /* The charges of each species */
157*918dfc20SMatthew G. Knepley   PetscReal    masses[2];              /* The masses of each species */
158*918dfc20SMatthew G. Knepley   PetscReal    thermal_energy[2];      /* Thermal Energy (used to get other constants)*/
159*918dfc20SMatthew G. Knepley   PetscReal    cosine_coefficients[2]; /*(alpha, k)*/
160*918dfc20SMatthew G. Knepley   PetscReal    totalWeight;
161*918dfc20SMatthew G. Knepley   PetscReal    stepSize;
162*918dfc20SMatthew G. Knepley   PetscInt     steps;
163*918dfc20SMatthew G. Knepley   PetscReal    initVel;
164*918dfc20SMatthew G. Knepley   EMType       em;           // Type of electrostatic model
165*918dfc20SMatthew G. Knepley   SNES         snes;         // EM solver
166*918dfc20SMatthew G. Knepley   DM           dmMom;        // The DM for moment fields
167*918dfc20SMatthew G. Knepley   DM           dmN;          // The DM for number density fields
168*918dfc20SMatthew G. Knepley   IS           isN;          // The IS mapping dmN into dmMom
169*918dfc20SMatthew G. Knepley   Mat          MN;           // The finite element mass matrix for number density
170*918dfc20SMatthew G. Knepley   DM           dmP;          // The DM for momentum density fields
171*918dfc20SMatthew G. Knepley   IS           isP;          // The IS mapping dmP into dmMom
172*918dfc20SMatthew G. Knepley   Mat          MP;           // The finite element mass matrix for momentum density
173*918dfc20SMatthew G. Knepley   DM           dmE;          // The DM for energy density (pressure) fields
174*918dfc20SMatthew G. Knepley   IS           isE;          // The IS mapping dmE into dmMom
175*918dfc20SMatthew G. Knepley   Mat          ME;           // The finite element mass matrix for energy density (pressure)
176*918dfc20SMatthew G. Knepley   DM           dmPot;        // The DM for potential
177*918dfc20SMatthew G. Knepley   Mat          fftPot;       // Fourier Transform operator for the potential
178*918dfc20SMatthew G. Knepley   Vec          fftX, fftY;   //   FFT vectors with phases added (complex parts)
179*918dfc20SMatthew G. Knepley   IS           fftReal;      //   The indices for real parts
180*918dfc20SMatthew G. Knepley   IS           isPot;        // The IS for potential, or NULL in primal
181*918dfc20SMatthew G. Knepley   Mat          M;            // The finite element mass matrix for potential
182*918dfc20SMatthew G. Knepley   PetscFEGeom *fegeom;       // Geometric information for the DM cells
183*918dfc20SMatthew G. Knepley   PetscDrawHG  drawhgic_x;   // Histogram of the particle weight in each X cell
184*918dfc20SMatthew G. Knepley   PetscDrawHG  drawhgic_v;   // Histogram of the particle weight in each X cell
185*918dfc20SMatthew G. Knepley   PetscDrawHG  drawhgcell_v; // Histogram of the particle weight in a given cell
186*918dfc20SMatthew G. Knepley   PetscBool    validE;       // Flag to indicate E-field in swarm is valid
187*918dfc20SMatthew G. Knepley   PetscReal    drawlgEmin;   // The minimum lg(E) to plot
188*918dfc20SMatthew G. Knepley   PetscDrawLG  drawlgE;      // Logarithm of maximum electric field
189*918dfc20SMatthew G. Knepley   PetscDrawSP  drawspE;      // Electric field at particle positions
190*918dfc20SMatthew G. Knepley   PetscDrawSP  drawspX;      // Particle positions
191*918dfc20SMatthew G. Knepley   PetscViewer  viewerRho;    // Charge density viewer
192*918dfc20SMatthew G. Knepley   PetscViewer  viewerRhoHat; // Charge density Fourier Transform viewer
193*918dfc20SMatthew G. Knepley   PetscViewer  viewerPhi;    // Potential viewer
194*918dfc20SMatthew G. Knepley   PetscViewer  viewerN;      // Number density viewer
195*918dfc20SMatthew G. Knepley   PetscViewer  viewerP;      // Momentum density viewer
196*918dfc20SMatthew G. Knepley   PetscViewer  viewerE;      // Energy density (pressure) viewer
197*918dfc20SMatthew G. Knepley   DM           swarm;        // The particle swarm
198*918dfc20SMatthew G. Knepley   PetscRandom  random;       // Used for particle perturbations
199*918dfc20SMatthew G. Knepley   PetscBool    twostream;    // Flag for activating 2-stream setup
200*918dfc20SMatthew G. Knepley   PetscBool    checkweights; // Check weight normalization
201*918dfc20SMatthew G. Knepley   PetscInt     checkVRes;    // Flag to check/output velocity residuals for nightly tests
202*918dfc20SMatthew G. Knepley   PetscBool    checkLandau;  // Check the Landau damping result
203*918dfc20SMatthew G. Knepley   PetscReal    gamma;        // The damping rate for Landau damping
204*918dfc20SMatthew G. Knepley   PetscReal    omega;        // The perturbed oscillation frequency for Landau damping
205*918dfc20SMatthew G. Knepley 
206*918dfc20SMatthew G. Knepley   PetscLogEvent RhsXEvent, RhsVEvent, ESolveEvent, ETabEvent;
207*918dfc20SMatthew G. Knepley } AppCtx;
208*918dfc20SMatthew G. Knepley 
209*918dfc20SMatthew G. Knepley static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
210*918dfc20SMatthew G. Knepley {
211*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
212*918dfc20SMatthew G. Knepley   PetscInt d                      = 2;
213*918dfc20SMatthew G. Knepley   PetscInt maxSpecies             = 2;
214*918dfc20SMatthew G. Knepley   options->error                  = PETSC_FALSE;
215*918dfc20SMatthew G. Knepley   options->remapFreq              = 1;
216*918dfc20SMatthew G. Knepley   options->efield_monitor         = E_MONITOR_NONE;
217*918dfc20SMatthew G. Knepley   options->moment_monitor         = PETSC_FALSE;
218*918dfc20SMatthew G. Knepley   options->moment_field_monitor   = PETSC_FALSE;
219*918dfc20SMatthew G. Knepley   options->initial_monitor        = PETSC_FALSE;
220*918dfc20SMatthew G. Knepley   options->perturbed_weights      = PETSC_FALSE;
221*918dfc20SMatthew G. Knepley   options->poisson_monitor        = PETSC_FALSE;
222*918dfc20SMatthew G. Knepley   options->positions_monitor      = PETSC_FALSE;
223*918dfc20SMatthew G. Knepley   options->velocity_monitor       = -1;
224*918dfc20SMatthew G. Knepley   options->ostep                  = 100;
225*918dfc20SMatthew G. Knepley   options->timeScale              = 2.0e-14;
226*918dfc20SMatthew G. Knepley   options->charges[0]             = -1.0;
227*918dfc20SMatthew G. Knepley   options->charges[1]             = 1.0;
228*918dfc20SMatthew G. Knepley   options->masses[0]              = 1.0;
229*918dfc20SMatthew G. Knepley   options->masses[1]              = 1000.0;
230*918dfc20SMatthew G. Knepley   options->thermal_energy[0]      = 1.0;
231*918dfc20SMatthew G. Knepley   options->thermal_energy[1]      = 1.0;
232*918dfc20SMatthew G. Knepley   options->cosine_coefficients[0] = 0.01;
233*918dfc20SMatthew G. Knepley   options->cosine_coefficients[1] = 0.5;
234*918dfc20SMatthew G. Knepley   options->initVel                = 1;
235*918dfc20SMatthew G. Knepley   options->totalWeight            = 1.0;
236*918dfc20SMatthew G. Knepley   options->drawhgic_x             = NULL;
237*918dfc20SMatthew G. Knepley   options->drawhgic_v             = NULL;
238*918dfc20SMatthew G. Knepley   options->drawhgcell_v           = NULL;
239*918dfc20SMatthew G. Knepley   options->drawlgEmin             = -6;
240*918dfc20SMatthew G. Knepley   options->drawlgE                = NULL;
241*918dfc20SMatthew G. Knepley   options->drawspE                = NULL;
242*918dfc20SMatthew G. Knepley   options->drawspX                = NULL;
243*918dfc20SMatthew G. Knepley   options->viewerRho              = NULL;
244*918dfc20SMatthew G. Knepley   options->viewerRhoHat           = NULL;
245*918dfc20SMatthew G. Knepley   options->viewerPhi              = NULL;
246*918dfc20SMatthew G. Knepley   options->viewerN                = NULL;
247*918dfc20SMatthew G. Knepley   options->viewerP                = NULL;
248*918dfc20SMatthew G. Knepley   options->viewerE                = NULL;
249*918dfc20SMatthew G. Knepley   options->em                     = EM_COULOMB;
250*918dfc20SMatthew G. Knepley   options->snes                   = NULL;
251*918dfc20SMatthew G. Knepley   options->dmMom                  = NULL;
252*918dfc20SMatthew G. Knepley   options->dmN                    = NULL;
253*918dfc20SMatthew G. Knepley   options->MN                     = NULL;
254*918dfc20SMatthew G. Knepley   options->dmP                    = NULL;
255*918dfc20SMatthew G. Knepley   options->MP                     = NULL;
256*918dfc20SMatthew G. Knepley   options->dmE                    = NULL;
257*918dfc20SMatthew G. Knepley   options->ME                     = NULL;
258*918dfc20SMatthew G. Knepley   options->dmPot                  = NULL;
259*918dfc20SMatthew G. Knepley   options->fftPot                 = NULL;
260*918dfc20SMatthew G. Knepley   options->fftX                   = NULL;
261*918dfc20SMatthew G. Knepley   options->fftY                   = NULL;
262*918dfc20SMatthew G. Knepley   options->fftReal                = NULL;
263*918dfc20SMatthew G. Knepley   options->isPot                  = NULL;
264*918dfc20SMatthew G. Knepley   options->M                      = NULL;
265*918dfc20SMatthew G. Knepley   options->numParticles           = 32768;
266*918dfc20SMatthew G. Knepley   options->twostream              = PETSC_FALSE;
267*918dfc20SMatthew G. Knepley   options->checkweights           = PETSC_FALSE;
268*918dfc20SMatthew G. Knepley   options->checkVRes              = 0;
269*918dfc20SMatthew G. Knepley   options->checkLandau            = PETSC_FALSE;
270*918dfc20SMatthew G. Knepley 
271*918dfc20SMatthew G. Knepley   PetscOptionsBegin(comm, "", "Landau Damping and Two Stream options", "DMSWARM");
272*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-error", "Flag to print the error", __FILE__, options->error, &options->error, NULL));
273*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsInt("-remap_freq", "Number", __FILE__, options->remapFreq, &options->remapFreq, NULL));
274*918dfc20SMatthew 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));
275*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsReal("-efield_min_monitor", "Minimum E field to plot", __FILE__, options->drawlgEmin, &options->drawlgEmin, NULL));
276*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-moments_monitor", "Flag to show moments table", __FILE__, options->moment_monitor, &options->moment_monitor, NULL));
277*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-moment_field_monitor", "Flag to show moment fields", __FILE__, options->moment_field_monitor, &options->moment_field_monitor, NULL));
278*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-ics_monitor", "Flag to show initial condition histograms", __FILE__, options->initial_monitor, &options->initial_monitor, NULL));
279*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-positions_monitor", "The flag to show particle positions", __FILE__, options->positions_monitor, &options->positions_monitor, NULL));
280*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-poisson_monitor", "The flag to show charges, Efield and potential solve", __FILE__, options->poisson_monitor, &options->poisson_monitor, NULL));
281*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsInt("-velocity_monitor", "Cell to show velocity histograms", __FILE__, options->velocity_monitor, &options->velocity_monitor, NULL));
282*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-twostream", "Run two stream instability", __FILE__, options->twostream, &options->twostream, NULL));
283*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-perturbed_weights", "Flag to run uniform sampling with perturbed weights", __FILE__, options->perturbed_weights, &options->perturbed_weights, NULL));
284*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-check_weights", "Ensure all particle weights are positive", __FILE__, options->checkweights, &options->checkweights, NULL));
285*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBool("-check_landau", "Check the decay from Landau damping", __FILE__, options->checkLandau, &options->checkLandau, NULL));
286*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", __FILE__, options->ostep, &options->ostep, NULL));
287*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsReal("-timeScale", "Nondimensionalizing time scale", __FILE__, options->timeScale, &options->timeScale, NULL));
288*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsInt("-check_vel_res", "Check particle velocity residuals for nightly tests", __FILE__, options->checkVRes, &options->checkVRes, NULL));
289*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsReal("-initial_velocity", "Initial velocity of perturbed particle", __FILE__, options->initVel, &options->initVel, NULL));
290*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsReal("-total_weight", "Total weight of all particles", __FILE__, options->totalWeight, &options->totalWeight, NULL));
291*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsRealArray("-cosine_coefficients", "Amplitude and frequency of cosine equation used in initialization", __FILE__, options->cosine_coefficients, &d, NULL));
292*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsRealArray("-charges", "Species charges", __FILE__, options->charges, &maxSpecies, NULL));
293*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsEnum("-em_type", "Type of electrostatic solver", __FILE__, EMTypes, (PetscEnum)options->em, (PetscEnum *)&options->em, NULL));
294*918dfc20SMatthew G. Knepley   PetscOptionsEnd();
295*918dfc20SMatthew G. Knepley 
296*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsX", TS_CLASSID, &options->RhsXEvent));
297*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsV", TS_CLASSID, &options->RhsVEvent));
298*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ESolve", TS_CLASSID, &options->ESolveEvent));
299*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ETab", TS_CLASSID, &options->ETabEvent));
300*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
301*918dfc20SMatthew G. Knepley }
302*918dfc20SMatthew G. Knepley 
303*918dfc20SMatthew G. Knepley static PetscErrorCode SetupContext(DM dm, DM sw, AppCtx *user)
304*918dfc20SMatthew G. Knepley {
305*918dfc20SMatthew G. Knepley   MPI_Comm comm;
306*918dfc20SMatthew G. Knepley 
307*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
308*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
309*918dfc20SMatthew G. Knepley   if (user->efield_monitor) {
310*918dfc20SMatthew G. Knepley     PetscDraw     draw;
311*918dfc20SMatthew G. Knepley     PetscDrawAxis axis;
312*918dfc20SMatthew G. Knepley 
313*918dfc20SMatthew G. Knepley     if (user->efield_monitor == E_MONITOR_FULL) {
314*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawCreate(comm, NULL, "Max Electric Field", 0, 300, 400, 300, &draw));
315*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawSetSave(draw, "ex2_Efield"));
316*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawSetFromOptions(draw));
317*918dfc20SMatthew G. Knepley     } else {
318*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawOpenNull(comm, &draw));
319*918dfc20SMatthew G. Knepley     }
320*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawLGCreate(draw, 1, &user->drawlgE));
321*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
322*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawLGGetAxis(user->drawlgE, &axis));
323*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Max Electric Field", "time", "E_max"));
324*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawLGSetLimits(user->drawlgE, 0., user->steps * user->stepSize, user->drawlgEmin, 0.));
325*918dfc20SMatthew G. Knepley   }
326*918dfc20SMatthew G. Knepley 
327*918dfc20SMatthew G. Knepley   if (user->initial_monitor) {
328*918dfc20SMatthew G. Knepley     PetscDraw     drawic_x, drawic_v;
329*918dfc20SMatthew G. Knepley     PetscDrawAxis axis1, axis2;
330*918dfc20SMatthew G. Knepley     PetscReal     dmboxlower[2], dmboxupper[2];
331*918dfc20SMatthew G. Knepley     PetscInt      dim, cStart, cEnd;
332*918dfc20SMatthew G. Knepley 
333*918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(sw, &dim));
334*918dfc20SMatthew G. Knepley     PetscCall(DMGetBoundingBox(dm, dmboxlower, dmboxupper));
335*918dfc20SMatthew G. Knepley     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
336*918dfc20SMatthew G. Knepley 
337*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_x", 0, 300, 400, 300, &drawic_x));
338*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawic_x, "ex2_ic_x"));
339*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawic_x));
340*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGCreate(drawic_x, (int)dim, &user->drawhgic_x));
341*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGCalcStats(user->drawhgic_x, PETSC_TRUE));
342*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGGetAxis(user->drawhgic_x, &axis1));
343*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_x, (int)(cEnd - cStart)));
344*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis1, "Initial X Distribution", "X", "weight"));
345*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis1, dmboxlower[0], dmboxupper[0], 0, 0));
346*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawic_x));
347*918dfc20SMatthew G. Knepley 
348*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_v", 400, 300, 400, 300, &drawic_v));
349*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawic_v, "ex9_ic_v"));
350*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawic_v));
351*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGCreate(drawic_v, (int)dim, &user->drawhgic_v));
352*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGCalcStats(user->drawhgic_v, PETSC_TRUE));
353*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGGetAxis(user->drawhgic_v, &axis2));
354*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_v, 21));
355*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis2, "Initial V_x Distribution", "V", "weight"));
356*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis2, -6, 6, 0, 0));
357*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawic_v));
358*918dfc20SMatthew G. Knepley   }
359*918dfc20SMatthew G. Knepley 
360*918dfc20SMatthew G. Knepley   if (user->velocity_monitor >= 0) {
361*918dfc20SMatthew G. Knepley     DM            vdm;
362*918dfc20SMatthew G. Knepley     DMSwarmCellDM celldm;
363*918dfc20SMatthew G. Knepley     PetscDraw     drawcell_v;
364*918dfc20SMatthew G. Knepley     PetscDrawAxis axis;
365*918dfc20SMatthew G. Knepley     PetscReal     dmboxlower[2], dmboxupper[2];
366*918dfc20SMatthew G. Knepley     PetscInt      dim;
367*918dfc20SMatthew G. Knepley     char          title[PETSC_MAX_PATH_LEN];
368*918dfc20SMatthew G. Knepley 
369*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
370*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
371*918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(vdm, &dim));
372*918dfc20SMatthew G. Knepley     PetscCall(DMGetBoundingBox(vdm, dmboxlower, dmboxupper));
373*918dfc20SMatthew G. Knepley 
374*918dfc20SMatthew G. Knepley     PetscCall(PetscSNPrintf(title, PETSC_MAX_PATH_LEN, "Cell %" PetscInt_FMT ": Velocity Distribution", user->velocity_monitor));
375*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, title, 400, 300, 400, 300, &drawcell_v));
376*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawcell_v, "ex2_cell_v"));
377*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawcell_v));
378*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGCreate(drawcell_v, (int)dim, &user->drawhgcell_v));
379*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGCalcStats(user->drawhgcell_v, PETSC_TRUE));
380*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGGetAxis(user->drawhgcell_v, &axis));
381*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGSetNumberBins(user->drawhgcell_v, 21));
382*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "V_x Distribution", "V", "weight"));
383*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis, dmboxlower[0], dmboxupper[0], 0, 0));
384*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawcell_v));
385*918dfc20SMatthew G. Knepley   }
386*918dfc20SMatthew G. Knepley 
387*918dfc20SMatthew G. Knepley   if (user->positions_monitor) {
388*918dfc20SMatthew G. Knepley     PetscDraw     draw;
389*918dfc20SMatthew G. Knepley     PetscDrawAxis axis;
390*918dfc20SMatthew G. Knepley 
391*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Particle Position", 0, 0, 400, 300, &draw));
392*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_pos"));
393*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
394*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspX));
395*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
396*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPSetDimension(user->drawspX, 1));
397*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPGetAxis(user->drawspX, &axis));
398*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "v"));
399*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspX));
400*918dfc20SMatthew G. Knepley   }
401*918dfc20SMatthew G. Knepley   if (user->poisson_monitor) {
402*918dfc20SMatthew G. Knepley     Vec           rho, rhohat, phi;
403*918dfc20SMatthew G. Knepley     PetscDraw     draw;
404*918dfc20SMatthew G. Knepley     PetscDrawAxis axis;
405*918dfc20SMatthew G. Knepley 
406*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Electric_Field", 0, 0, 400, 300, &draw));
407*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
408*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_E_spatial"));
409*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspE));
410*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
411*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPSetDimension(user->drawspE, 1));
412*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPGetAxis(user->drawspE, &axis));
413*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "E"));
414*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspE));
415*918dfc20SMatthew G. Knepley 
416*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "Charge Density", 0, 0, 400, 300, &user->viewerRho));
417*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerRho, "rho_"));
418*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerRho, 0, &draw));
419*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_spatial"));
420*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerRho));
421*918dfc20SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
422*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rho, "charge_density"));
423*918dfc20SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
424*918dfc20SMatthew G. Knepley 
425*918dfc20SMatthew G. Knepley     PetscInt dim, N;
426*918dfc20SMatthew G. Knepley 
427*918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(user->dmPot, &dim));
428*918dfc20SMatthew G. Knepley     if (dim == 1) {
429*918dfc20SMatthew G. Knepley       PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
430*918dfc20SMatthew G. Knepley       PetscCall(VecGetSize(rhohat, &N));
431*918dfc20SMatthew G. Knepley       PetscCall(MatCreateFFT(comm, dim, &N, MATFFTW, &user->fftPot));
432*918dfc20SMatthew G. Knepley       PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
433*918dfc20SMatthew G. Knepley       PetscCall(MatCreateVecs(user->fftPot, &user->fftX, &user->fftY));
434*918dfc20SMatthew G. Knepley       PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &user->fftReal));
435*918dfc20SMatthew G. Knepley     }
436*918dfc20SMatthew G. Knepley 
437*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "rhohat: Charge Density FT", 0, 0, 400, 300, &user->viewerRhoHat));
438*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerRhoHat, "rhohat_"));
439*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerRhoHat, 0, &draw));
440*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_ft"));
441*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerRhoHat));
442*918dfc20SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
443*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rhohat, "charge_density_ft"));
444*918dfc20SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
445*918dfc20SMatthew G. Knepley 
446*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "Potential", 400, 0, 400, 300, &user->viewerPhi));
447*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerPhi, "phi_"));
448*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerPhi, 0, &draw));
449*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_phi_spatial"));
450*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerPhi));
451*918dfc20SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
452*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)phi, "potential"));
453*918dfc20SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
454*918dfc20SMatthew G. Knepley   }
455*918dfc20SMatthew G. Knepley   if (user->moment_field_monitor) {
456*918dfc20SMatthew G. Knepley     Vec       n, p, e;
457*918dfc20SMatthew G. Knepley     PetscDraw draw;
458*918dfc20SMatthew G. Knepley 
459*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "Number Density", 0, 800, 400, 300, &user->viewerN));
460*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerN, "n_"));
461*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerN, 0, &draw));
462*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_n_spatial"));
463*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerN));
464*918dfc20SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmN, "n", &n));
465*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)n, "Number Density"));
466*918dfc20SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmN, "n", &n));
467*918dfc20SMatthew G. Knepley 
468*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "Momentum Density", 400, 800, 400, 300, &user->viewerP));
469*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerP, "p_"));
470*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerP, 0, &draw));
471*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_p_spatial"));
472*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerP));
473*918dfc20SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmP, "p", &p));
474*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)p, "Momentum Density"));
475*918dfc20SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmP, "p", &p));
476*918dfc20SMatthew G. Knepley 
477*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "Emergy Density (Pressure)", 800, 800, 400, 300, &user->viewerE));
478*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerE, "e_"));
479*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerE, 0, &draw));
480*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_e_spatial"));
481*918dfc20SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerE));
482*918dfc20SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmE, "e", &e));
483*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)e, "Energy Density (Pressure)"));
484*918dfc20SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmE, "e", &e));
485*918dfc20SMatthew G. Knepley   }
486*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
487*918dfc20SMatthew G. Knepley }
488*918dfc20SMatthew G. Knepley 
489*918dfc20SMatthew G. Knepley static PetscErrorCode DestroyContext(AppCtx *user)
490*918dfc20SMatthew G. Knepley {
491*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
492*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawHGDestroy(&user->drawhgic_x));
493*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawHGDestroy(&user->drawhgic_v));
494*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawHGDestroy(&user->drawhgcell_v));
495*918dfc20SMatthew G. Knepley 
496*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawLGDestroy(&user->drawlgE));
497*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawSPDestroy(&user->drawspE));
498*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawSPDestroy(&user->drawspX));
499*918dfc20SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerRho));
500*918dfc20SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerRhoHat));
501*918dfc20SMatthew G. Knepley   PetscCall(MatDestroy(&user->fftPot));
502*918dfc20SMatthew G. Knepley   PetscCall(VecDestroy(&user->fftX));
503*918dfc20SMatthew G. Knepley   PetscCall(VecDestroy(&user->fftY));
504*918dfc20SMatthew G. Knepley   PetscCall(ISDestroy(&user->fftReal));
505*918dfc20SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerPhi));
506*918dfc20SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerN));
507*918dfc20SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerP));
508*918dfc20SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerE));
509*918dfc20SMatthew G. Knepley 
510*918dfc20SMatthew G. Knepley   PetscCall(PetscBagDestroy(&user->bag));
511*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
512*918dfc20SMatthew G. Knepley }
513*918dfc20SMatthew G. Knepley 
514*918dfc20SMatthew G. Knepley static PetscErrorCode CheckNonNegativeWeights(DM sw, AppCtx *user)
515*918dfc20SMatthew G. Knepley {
516*918dfc20SMatthew G. Knepley   const PetscScalar *w;
517*918dfc20SMatthew G. Knepley   PetscInt           Np;
518*918dfc20SMatthew G. Knepley 
519*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
520*918dfc20SMatthew G. Knepley   if (!user->checkweights) PetscFunctionReturn(PETSC_SUCCESS);
521*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w));
522*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
523*918dfc20SMatthew 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]);
524*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w));
525*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
526*918dfc20SMatthew G. Knepley }
527*918dfc20SMatthew G. Knepley 
528*918dfc20SMatthew G. Knepley static PetscErrorCode computeVelocityFEMMoments(DM sw, PetscReal moments[], AppCtx *user)
529*918dfc20SMatthew G. Knepley {
530*918dfc20SMatthew G. Knepley   DMSwarmCellDM celldm;
531*918dfc20SMatthew G. Knepley   DM            vdm;
532*918dfc20SMatthew G. Knepley   Vec           u[1];
533*918dfc20SMatthew G. Knepley   const char   *fields[1] = {"w_q"};
534*918dfc20SMatthew G. Knepley 
535*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
536*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "velocity"));
537*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
538*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
539*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(vdm, &u[0]));
540*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmProjectFields(sw, vdm, 1, fields, u, SCATTER_FORWARD));
541*918dfc20SMatthew G. Knepley   PetscCall(DMPlexComputeMoments(vdm, u[0], moments));
542*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(vdm, &u[0]));
543*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
544*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
545*918dfc20SMatthew G. Knepley }
546*918dfc20SMatthew G. Knepley 
547*918dfc20SMatthew 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[])
548*918dfc20SMatthew G. Knepley {
549*918dfc20SMatthew G. Knepley   f0[0] = 0.;
550*918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f0[0] += PetscSqr(u_x[uOff_x[0] + d * dim + d]);
551*918dfc20SMatthew G. Knepley }
552*918dfc20SMatthew G. Knepley 
553*918dfc20SMatthew G. Knepley typedef struct {
554*918dfc20SMatthew G. Knepley   PetscInt         s;    // Starting sample (we ignore some in the beginning)
555*918dfc20SMatthew G. Knepley   PetscInt         e;    // Ending sample
556*918dfc20SMatthew G. Knepley   const PetscReal *t;    // Time for each sample
557*918dfc20SMatthew G. Knepley   const PetscReal *Emax; // Emax for each sample
558*918dfc20SMatthew G. Knepley } EmaxCtx;
559*918dfc20SMatthew G. Knepley 
560*918dfc20SMatthew G. Knepley // Our model is E_max(t) = C e^{-gamma t} |cos(omega t - phi)|
561*918dfc20SMatthew G. Knepley static PetscErrorCode ComputeEmaxResidual(Tao tao, Vec x, Vec res, void *user)
562*918dfc20SMatthew G. Knepley {
563*918dfc20SMatthew G. Knepley   EmaxCtx           *ctx = (EmaxCtx *)user;
564*918dfc20SMatthew G. Knepley   const PetscScalar *a;
565*918dfc20SMatthew G. Knepley   PetscScalar       *F;
566*918dfc20SMatthew G. Knepley   PetscReal          C, gamma, omega, phi;
567*918dfc20SMatthew G. Knepley 
568*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
569*918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(x, &a));
570*918dfc20SMatthew G. Knepley   PetscCall(VecGetArray(res, &F));
571*918dfc20SMatthew G. Knepley   C     = PetscRealPart(a[0]);
572*918dfc20SMatthew G. Knepley   gamma = PetscRealPart(a[1]);
573*918dfc20SMatthew G. Knepley   omega = PetscRealPart(a[2]);
574*918dfc20SMatthew G. Knepley   phi   = PetscRealPart(a[3]);
575*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(x, &a));
576*918dfc20SMatthew 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));
577*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArray(res, &F));
578*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
579*918dfc20SMatthew G. Knepley }
580*918dfc20SMatthew G. Knepley 
581*918dfc20SMatthew G. Knepley // The Jacobian of the residual J = dr(x)/dx
582*918dfc20SMatthew G. Knepley static PetscErrorCode ComputeEmaxJacobian(Tao tao, Vec x, Mat J, Mat Jpre, void *user)
583*918dfc20SMatthew G. Knepley {
584*918dfc20SMatthew G. Knepley   EmaxCtx           *ctx = (EmaxCtx *)user;
585*918dfc20SMatthew G. Knepley   const PetscScalar *a;
586*918dfc20SMatthew G. Knepley   PetscScalar       *jac;
587*918dfc20SMatthew G. Knepley   PetscReal          C, gamma, omega, phi;
588*918dfc20SMatthew G. Knepley   const PetscInt     n = ctx->e - ctx->s;
589*918dfc20SMatthew G. Knepley 
590*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
591*918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(x, &a));
592*918dfc20SMatthew G. Knepley   C     = PetscRealPart(a[0]);
593*918dfc20SMatthew G. Knepley   gamma = PetscRealPart(a[1]);
594*918dfc20SMatthew G. Knepley   omega = PetscRealPart(a[2]);
595*918dfc20SMatthew G. Knepley   phi   = PetscRealPart(a[3]);
596*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(x, &a));
597*918dfc20SMatthew G. Knepley   PetscCall(MatDenseGetArray(J, &jac));
598*918dfc20SMatthew G. Knepley   for (PetscInt i = 0; i < n; ++i) {
599*918dfc20SMatthew G. Knepley     const PetscInt k = i + ctx->s;
600*918dfc20SMatthew G. Knepley 
601*918dfc20SMatthew G. Knepley     jac[i * 4 + 0] = -PetscExpReal(-gamma * ctx->t[k]) * PetscAbsReal(PetscCosReal(omega * ctx->t[k] - phi));
602*918dfc20SMatthew G. Knepley     jac[i * 4 + 1] = C * ctx->t[k] * PetscExpReal(-gamma * ctx->t[k]) * PetscAbsReal(PetscCosReal(omega * ctx->t[k] - phi));
603*918dfc20SMatthew 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);
604*918dfc20SMatthew 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);
605*918dfc20SMatthew G. Knepley   }
606*918dfc20SMatthew G. Knepley   PetscCall(MatDenseRestoreArray(J, &jac));
607*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
608*918dfc20SMatthew G. Knepley }
609*918dfc20SMatthew G. Knepley 
610*918dfc20SMatthew G. Knepley // Our model is log_10 E_max(t) = log_10 C - gamma t log_10 e + log_10 |cos(omega t - phi)|
611*918dfc20SMatthew G. Knepley static PetscErrorCode ComputeLogEmaxResidual(Tao tao, Vec x, Vec res, void *user)
612*918dfc20SMatthew G. Knepley {
613*918dfc20SMatthew G. Knepley   EmaxCtx           *ctx = (EmaxCtx *)user;
614*918dfc20SMatthew G. Knepley   const PetscScalar *a;
615*918dfc20SMatthew G. Knepley   PetscScalar       *F;
616*918dfc20SMatthew G. Knepley   PetscReal          C, gamma, omega, phi;
617*918dfc20SMatthew G. Knepley 
618*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
619*918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(x, &a));
620*918dfc20SMatthew G. Knepley   PetscCall(VecGetArray(res, &F));
621*918dfc20SMatthew G. Knepley   C     = PetscRealPart(a[0]);
622*918dfc20SMatthew G. Knepley   gamma = PetscRealPart(a[1]);
623*918dfc20SMatthew G. Knepley   omega = PetscRealPart(a[2]);
624*918dfc20SMatthew G. Knepley   phi   = PetscRealPart(a[3]);
625*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(x, &a));
626*918dfc20SMatthew G. Knepley   for (PetscInt i = ctx->s; i < ctx->e; ++i) {
627*918dfc20SMatthew G. Knepley     if (C < 0) {
628*918dfc20SMatthew G. Knepley       F[i - ctx->s] = 1e10;
629*918dfc20SMatthew G. Knepley       continue;
630*918dfc20SMatthew G. Knepley     }
631*918dfc20SMatthew 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))));
632*918dfc20SMatthew G. Knepley   }
633*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArray(res, &F));
634*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
635*918dfc20SMatthew G. Knepley }
636*918dfc20SMatthew G. Knepley 
637*918dfc20SMatthew G. Knepley // The Jacobian of the residual J = dr(x)/dx
638*918dfc20SMatthew G. Knepley static PetscErrorCode ComputeLogEmaxJacobian(Tao tao, Vec x, Mat J, Mat Jpre, void *user)
639*918dfc20SMatthew G. Knepley {
640*918dfc20SMatthew G. Knepley   EmaxCtx           *ctx = (EmaxCtx *)user;
641*918dfc20SMatthew G. Knepley   const PetscScalar *a;
642*918dfc20SMatthew G. Knepley   PetscScalar       *jac;
643*918dfc20SMatthew G. Knepley   PetscReal          C, omega, phi;
644*918dfc20SMatthew G. Knepley   const PetscInt     n = ctx->e - ctx->s;
645*918dfc20SMatthew G. Knepley 
646*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
647*918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(x, &a));
648*918dfc20SMatthew G. Knepley   C     = PetscRealPart(a[0]);
649*918dfc20SMatthew G. Knepley   omega = PetscRealPart(a[2]);
650*918dfc20SMatthew G. Knepley   phi   = PetscRealPart(a[3]);
651*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(x, &a));
652*918dfc20SMatthew G. Knepley   PetscCall(MatDenseGetArray(J, &jac));
653*918dfc20SMatthew G. Knepley   for (PetscInt i = 0; i < n; ++i) {
654*918dfc20SMatthew G. Knepley     const PetscInt k = i + ctx->s;
655*918dfc20SMatthew G. Knepley 
656*918dfc20SMatthew G. Knepley     jac[0 * n + i] = -1. / (PetscLog10Real(PETSC_E) * C);
657*918dfc20SMatthew G. Knepley     jac[1 * n + i] = ctx->t[k] * PetscLog10Real(PETSC_E);
658*918dfc20SMatthew 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)));
659*918dfc20SMatthew 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)));
660*918dfc20SMatthew G. Knepley   }
661*918dfc20SMatthew G. Knepley   PetscCall(MatDenseRestoreArray(J, &jac));
662*918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(J, NULL, "-emax_jac_view"));
663*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
664*918dfc20SMatthew G. Knepley }
665*918dfc20SMatthew G. Knepley 
666*918dfc20SMatthew G. Knepley static PetscErrorCode MonitorEField(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
667*918dfc20SMatthew G. Knepley {
668*918dfc20SMatthew G. Knepley   AppCtx     *user = (AppCtx *)ctx;
669*918dfc20SMatthew G. Knepley   DM          sw;
670*918dfc20SMatthew G. Knepley   PetscScalar intESq;
671*918dfc20SMatthew G. Knepley   PetscReal  *E, *x, *weight;
672*918dfc20SMatthew G. Knepley   PetscReal   Enorm = 0., lgEnorm, lgEmax, sum = 0., Emax = 0., chargesum = 0.;
673*918dfc20SMatthew G. Knepley   PetscReal   pmoments[4]; /* \int f, \int v f, \int v^2 f */
674*918dfc20SMatthew G. Knepley   PetscInt   *species, dim, Np, gNp;
675*918dfc20SMatthew G. Knepley   MPI_Comm    comm;
676*918dfc20SMatthew G. Knepley   PetscMPIInt rank;
677*918dfc20SMatthew G. Knepley 
678*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
679*918dfc20SMatthew G. Knepley   if (step < 0 || !user->validE) PetscFunctionReturn(PETSC_SUCCESS);
680*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
681*918dfc20SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
682*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
683*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
684*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
685*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetSize(sw, &gNp));
686*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
687*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
688*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
689*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
690*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
691*918dfc20SMatthew G. Knepley 
692*918dfc20SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
693*918dfc20SMatthew G. Knepley     for (PetscInt d = 0; d < 1; ++d) {
694*918dfc20SMatthew G. Knepley       PetscReal temp = PetscAbsReal(E[p * dim + d]);
695*918dfc20SMatthew G. Knepley       if (temp > Emax) Emax = temp;
696*918dfc20SMatthew G. Knepley     }
697*918dfc20SMatthew G. Knepley     Enorm += PetscSqrtReal(E[p * dim] * E[p * dim]);
698*918dfc20SMatthew G. Knepley     sum += E[p * dim];
699*918dfc20SMatthew G. Knepley     chargesum += user->charges[0] * weight[p];
700*918dfc20SMatthew G. Knepley   }
701*918dfc20SMatthew G. Knepley   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &Emax, 1, MPIU_REAL, MPIU_MAX, comm));
702*918dfc20SMatthew G. Knepley   lgEnorm = Enorm != 0 ? PetscLog10Real(Enorm) : -16.;
703*918dfc20SMatthew G. Knepley   lgEmax  = Emax != 0 ? PetscLog10Real(Emax) : user->drawlgEmin;
704*918dfc20SMatthew G. Knepley 
705*918dfc20SMatthew G. Knepley   PetscDS ds;
706*918dfc20SMatthew G. Knepley   Vec     phi;
707*918dfc20SMatthew G. Knepley 
708*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
709*918dfc20SMatthew G. Knepley   PetscCall(DMGetDS(user->dmPot, &ds));
710*918dfc20SMatthew G. Knepley   PetscCall(PetscDSSetObjective(ds, 0, &f0_grad_phi2));
711*918dfc20SMatthew G. Knepley   PetscCall(DMPlexComputeIntegralFEM(user->dmPot, phi, &intESq, user));
712*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
713*918dfc20SMatthew G. Knepley 
714*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
715*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
716*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
717*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
718*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawLGAddPoint(user->drawlgE, &t, &lgEmax));
719*918dfc20SMatthew G. Knepley   if (user->efield_monitor == E_MONITOR_FULL) {
720*918dfc20SMatthew G. Knepley     PetscDraw draw;
721*918dfc20SMatthew G. Knepley 
722*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawLGDraw(user->drawlgE));
723*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawLGGetDraw(user->drawlgE, &draw));
724*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSave(draw));
725*918dfc20SMatthew G. Knepley 
726*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
727*918dfc20SMatthew 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));
728*918dfc20SMatthew G. Knepley     PetscCall(DMViewFromOptions(sw, NULL, "-sw_efield_view"));
729*918dfc20SMatthew G. Knepley   }
730*918dfc20SMatthew G. Knepley 
731*918dfc20SMatthew G. Knepley   // Compute decay rate and frequency
732*918dfc20SMatthew G. Knepley   EmaxCtx ectx;
733*918dfc20SMatthew G. Knepley 
734*918dfc20SMatthew G. Knepley   ectx.s = 50;
735*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawLGGetData(user->drawlgE, NULL, &ectx.e, &ectx.t, &ectx.Emax));
736*918dfc20SMatthew G. Knepley   if (!rank && !(ectx.e % 100)) {
737*918dfc20SMatthew G. Knepley     Tao          tao;
738*918dfc20SMatthew G. Knepley     Mat          J;
739*918dfc20SMatthew G. Knepley     Vec          x, r;
740*918dfc20SMatthew G. Knepley     PetscScalar *a;
741*918dfc20SMatthew G. Knepley     PetscBool    fitLog = PETSC_TRUE, debug = PETSC_FALSE;
742*918dfc20SMatthew G. Knepley 
743*918dfc20SMatthew G. Knepley     PetscCall(TaoCreate(PETSC_COMM_SELF, &tao));
744*918dfc20SMatthew G. Knepley     PetscCall(TaoSetOptionsPrefix(tao, "emax_"));
745*918dfc20SMatthew G. Knepley     PetscCall(VecCreateSeq(PETSC_COMM_SELF, 4, &x));
746*918dfc20SMatthew G. Knepley     PetscCall(TaoSetSolution(tao, x));
747*918dfc20SMatthew G. Knepley     PetscCall(VecCreateSeq(PETSC_COMM_SELF, ectx.e - ectx.s, &r));
748*918dfc20SMatthew G. Knepley     if (fitLog) PetscCall(TaoSetResidualRoutine(tao, r, ComputeLogEmaxResidual, &ectx));
749*918dfc20SMatthew G. Knepley     else PetscCall(TaoSetResidualRoutine(tao, r, ComputeEmaxResidual, &ectx));
750*918dfc20SMatthew G. Knepley     PetscCall(VecDestroy(&r));
751*918dfc20SMatthew G. Knepley     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, ectx.e - ectx.s, 4, NULL, &J));
752*918dfc20SMatthew G. Knepley     if (fitLog) PetscCall(TaoSetJacobianResidualRoutine(tao, J, J, ComputeLogEmaxJacobian, &ectx));
753*918dfc20SMatthew G. Knepley     else PetscCall(TaoSetJacobianResidualRoutine(tao, J, J, ComputeEmaxJacobian, &ectx));
754*918dfc20SMatthew G. Knepley     PetscCall(MatDestroy(&J));
755*918dfc20SMatthew G. Knepley     PetscCall(TaoSetFromOptions(tao));
756*918dfc20SMatthew G. Knepley     PetscCall(VecGetArray(x, &a));
757*918dfc20SMatthew G. Knepley     a[0] = 0.02;
758*918dfc20SMatthew G. Knepley     a[1] = 0.15;
759*918dfc20SMatthew G. Knepley     a[2] = 1.4;
760*918dfc20SMatthew G. Knepley     a[3] = 0.45;
761*918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArray(x, &a));
762*918dfc20SMatthew G. Knepley     PetscCall(TaoSolve(tao));
763*918dfc20SMatthew G. Knepley     if (debug) {
764*918dfc20SMatthew G. Knepley       PetscCall(PetscPrintf(PETSC_COMM_SELF, "t = ["));
765*918dfc20SMatthew G. Knepley       for (PetscInt i = 0; i < ectx.e; ++i) {
766*918dfc20SMatthew G. Knepley         if (i > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
767*918dfc20SMatthew G. Knepley         PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", ectx.t[i]));
768*918dfc20SMatthew G. Knepley       }
769*918dfc20SMatthew G. Knepley       PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
770*918dfc20SMatthew G. Knepley       PetscCall(PetscPrintf(PETSC_COMM_SELF, "Emax = ["));
771*918dfc20SMatthew G. Knepley       for (PetscInt i = 0; i < ectx.e; ++i) {
772*918dfc20SMatthew G. Knepley         if (i > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
773*918dfc20SMatthew G. Knepley         PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", ectx.Emax[i]));
774*918dfc20SMatthew G. Knepley       }
775*918dfc20SMatthew G. Knepley       PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
776*918dfc20SMatthew G. Knepley     }
777*918dfc20SMatthew G. Knepley     PetscDraw     draw;
778*918dfc20SMatthew G. Knepley     PetscDrawAxis axis;
779*918dfc20SMatthew G. Knepley     char          title[PETSC_MAX_PATH_LEN];
780*918dfc20SMatthew G. Knepley 
781*918dfc20SMatthew G. Knepley     PetscCall(VecGetArray(x, &a));
782*918dfc20SMatthew G. Knepley     user->gamma = a[1];
783*918dfc20SMatthew G. Knepley     user->omega = a[2];
784*918dfc20SMatthew G. Knepley     if (user->efield_monitor == E_MONITOR_FULL) {
785*918dfc20SMatthew 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]));
786*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawLGGetDraw(user->drawlgE, &draw));
787*918dfc20SMatthew G. Knepley       PetscCall(PetscSNPrintf(title, PETSC_MAX_PATH_LEN, "Max Electric Field gamma %.4g omega %.4g", a[1], a[2]));
788*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawSetTitle(draw, title));
789*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawLGGetAxis(user->drawlgE, &axis));
790*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawAxisSetLabels(axis, title, "time", "E_max"));
791*918dfc20SMatthew G. Knepley     }
792*918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArray(x, &a));
793*918dfc20SMatthew G. Knepley     PetscCall(VecDestroy(&x));
794*918dfc20SMatthew G. Knepley     PetscCall(TaoDestroy(&tao));
795*918dfc20SMatthew G. Knepley   }
796*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
797*918dfc20SMatthew G. Knepley }
798*918dfc20SMatthew G. Knepley 
799*918dfc20SMatthew G. Knepley static PetscErrorCode MonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
800*918dfc20SMatthew G. Knepley {
801*918dfc20SMatthew G. Knepley   AppCtx   *user = (AppCtx *)ctx;
802*918dfc20SMatthew G. Knepley   DM        sw;
803*918dfc20SMatthew G. Knepley   PetscReal pmoments[4], fmoments[4]; /* \int f, \int v f, \int v^2 f */
804*918dfc20SMatthew G. Knepley 
805*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
806*918dfc20SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
807*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
808*918dfc20SMatthew G. Knepley 
809*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
810*918dfc20SMatthew G. Knepley   PetscCall(computeVelocityFEMMoments(sw, fmoments, user));
811*918dfc20SMatthew G. Knepley 
812*918dfc20SMatthew 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]));
813*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
814*918dfc20SMatthew G. Knepley }
815*918dfc20SMatthew G. Knepley 
816*918dfc20SMatthew G. Knepley static void f0_pres(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[])
817*918dfc20SMatthew G. Knepley {
818*918dfc20SMatthew G. Knepley   const PetscReal v = a[0];
819*918dfc20SMatthew G. Knepley   const PetscReal n = u[0];
820*918dfc20SMatthew G. Knepley   const PetscReal p = u[1];
821*918dfc20SMatthew G. Knepley 
822*918dfc20SMatthew G. Knepley   f1[0] = PetscSqr(v - p / n);
823*918dfc20SMatthew G. Knepley }
824*918dfc20SMatthew G. Knepley 
825*918dfc20SMatthew G. Knepley static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
826*918dfc20SMatthew G. Knepley {
827*918dfc20SMatthew G. Knepley   u[0] = 0.0;
828*918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
829*918dfc20SMatthew G. Knepley }
830*918dfc20SMatthew G. Knepley 
831*918dfc20SMatthew G. Knepley /*
832*918dfc20SMatthew G. Knepley     M_p w_p
833*918dfc20SMatthew G. Knepley       - Make M_p with "moments"
834*918dfc20SMatthew G. Knepley       - Get w_p from Swarm
835*918dfc20SMatthew G. Knepley     M_p v_p w_p
836*918dfc20SMatthew G. Knepley       - Get v_p from Swarm
837*918dfc20SMatthew G. Knepley       - pointwise multiply v_p and w_p
838*918dfc20SMatthew 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
839*918dfc20SMatthew G. Knepley       - ProjectField(sw, {n, p} U, {v_p} A, tmp_p)
840*918dfc20SMatthew G. Knepley       - pointwise multiply tmp_p and w_p
841*918dfc20SMatthew G. Knepley 
842*918dfc20SMatthew G. Knepley */
843*918dfc20SMatthew G. Knepley static PetscErrorCode ComputeMomentFields(TS ts)
844*918dfc20SMatthew G. Knepley {
845*918dfc20SMatthew G. Knepley   AppCtx   *user;
846*918dfc20SMatthew G. Knepley   DM        sw;
847*918dfc20SMatthew G. Knepley   KSP       ksp;
848*918dfc20SMatthew G. Knepley   Mat       M_p;
849*918dfc20SMatthew G. Knepley   Vec       f, v, vf, vuf;
850*918dfc20SMatthew G. Knepley   Vec       m, n, nRhs, p, pRhs, e, eRhs;
851*918dfc20SMatthew G. Knepley   PetscReal dt;
852*918dfc20SMatthew G. Knepley   PetscInt  Nts;
853*918dfc20SMatthew G. Knepley 
854*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
855*918dfc20SMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &Nts));
856*918dfc20SMatthew G. Knepley   PetscCall(TSGetTimeStep(ts, &dt));
857*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
858*918dfc20SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, (void *)&user));
859*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "moment fields"));
860*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmMigrate(sw, PETSC_FALSE));
861*918dfc20SMatthew G. Knepley   // TODO Will have to create different M_p in higher dimensions for velocity
862*918dfc20SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(sw, user->dmN, &M_p));
863*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
864*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &v));
865*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
866*918dfc20SMatthew G. Knepley 
867*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(user->dmN, &nRhs));
868*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)nRhs, "Weak number density"));
869*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmN, "n", &n));
870*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(user->dmP, &pRhs));
871*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)pRhs, "Weak momentum density"));
872*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmP, "p", &p));
873*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(user->dmE, &eRhs));
874*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)eRhs, "Weak energy density (pressure)"));
875*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmE, "e", &e));
876*918dfc20SMatthew G. Knepley 
877*918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
878*918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->MN, NULL, "-mn_view"));
879*918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->MP, NULL, "-mp_view"));
880*918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->ME, NULL, "-me_view"));
881*918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
882*918dfc20SMatthew G. Knepley 
883*918dfc20SMatthew G. Knepley   PetscCall(VecDuplicate(f, &vf));
884*918dfc20SMatthew G. Knepley   PetscCall(VecDuplicate(f, &vuf));
885*918dfc20SMatthew G. Knepley 
886*918dfc20SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, nRhs));
887*918dfc20SMatthew G. Knepley 
888*918dfc20SMatthew G. Knepley   PetscCall(VecPointwiseMult(vf, f, v));
889*918dfc20SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, vf, pRhs));
890*918dfc20SMatthew G. Knepley   PetscCall(VecDestroy(&vf));
891*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &v));
892*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
893*918dfc20SMatthew G. Knepley 
894*918dfc20SMatthew G. Knepley   PetscPointFn *funcs[1] = {f0_pres};
895*918dfc20SMatthew G. Knepley 
896*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(user->dmMom, &m));
897*918dfc20SMatthew G. Knepley   PetscCall(VecISCopy(m, user->isN, SCATTER_FORWARD, n));
898*918dfc20SMatthew G. Knepley   PetscCall(VecISCopy(m, user->isP, SCATTER_FORWARD, p));
899*918dfc20SMatthew G. Knepley   PetscCall(DMProjectField(sw, 0., m, funcs, INSERT_VALUES, vuf));
900*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(user->dmMom, &m));
901*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
902*918dfc20SMatthew G. Knepley   PetscCall(VecPointwiseMult(vuf, f, vuf));
903*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
904*918dfc20SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, vuf, eRhs));
905*918dfc20SMatthew G. Knepley   PetscCall(VecDestroy(&vuf));
906*918dfc20SMatthew G. Knepley 
907*918dfc20SMatthew G. Knepley   PetscCall(MatDestroy(&M_p));
908*918dfc20SMatthew G. Knepley 
909*918dfc20SMatthew G. Knepley   PetscCall(KSPCreate(PetscObjectComm((PetscObject)sw), &ksp));
910*918dfc20SMatthew G. Knepley   PetscCall(KSPSetOptionsPrefix(ksp, "mom_proj_"));
911*918dfc20SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->MN, user->MN));
912*918dfc20SMatthew G. Knepley   PetscCall(KSPSetFromOptions(ksp));
913*918dfc20SMatthew G. Knepley   PetscCall(KSPSolve(ksp, nRhs, n));
914*918dfc20SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->MP, user->MP));
915*918dfc20SMatthew G. Knepley   PetscCall(KSPSetFromOptions(ksp));
916*918dfc20SMatthew G. Knepley   PetscCall(KSPSolve(ksp, pRhs, p));
917*918dfc20SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->ME, user->ME));
918*918dfc20SMatthew G. Knepley   PetscCall(KSPSetFromOptions(ksp));
919*918dfc20SMatthew G. Knepley   PetscCall(KSPSolve(ksp, eRhs, e));
920*918dfc20SMatthew G. Knepley   PetscCall(KSPDestroy(&ksp));
921*918dfc20SMatthew G. Knepley 
922*918dfc20SMatthew G. Knepley   // Check moment residual
923*918dfc20SMatthew G. Knepley   // TODO Fix global2local here
924*918dfc20SMatthew G. Knepley   PetscSimplePointFn *exacts[3] = {zero, zero, zero};
925*918dfc20SMatthew G. Knepley   Vec                 mold, m_t, locF, phi;
926*918dfc20SMatthew G. Knepley   PetscReal           res[3];
927*918dfc20SMatthew G. Knepley 
928*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmMom, "mold", &mold));
929*918dfc20SMatthew G. Knepley   if (!Nts) PetscCall(VecSet(mold, 0.));
930*918dfc20SMatthew G. Knepley 
931*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(user->dmMom, &m));
932*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(user->dmMom, &m_t));
933*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(user->dmMom, &locF));
934*918dfc20SMatthew G. Knepley   PetscCall(VecISCopy(m, user->isN, SCATTER_FORWARD, n));
935*918dfc20SMatthew G. Knepley   PetscCall(VecISCopy(m, user->isP, SCATTER_FORWARD, p));
936*918dfc20SMatthew G. Knepley   PetscCall(VecISCopy(m, user->isE, SCATTER_FORWARD, e));
937*918dfc20SMatthew G. Knepley   PetscCall(VecAXPBYPCZ(m_t, -1.0, 1.0, 0.0, mold, m));
938*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
939*918dfc20SMatthew G. Knepley   PetscCall(DMSetAuxiliaryVec(user->dmMom, NULL, 0, 0, phi));
940*918dfc20SMatthew G. Knepley   PetscCall(DMPlexTSComputeIFunctionFEM(user->dmMom, PETSC_MIN_REAL, m, m_t, locF, user));
941*918dfc20SMatthew G. Knepley   PetscCall(DMSetAuxiliaryVec(user->dmMom, NULL, 0, 0, NULL));
942*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
943*918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(locF, NULL, "-moment_residual_view"));
944*918dfc20SMatthew G. Knepley   PetscCall(VecNorm(locF, NORM_2, &res[0]));
945*918dfc20SMatthew G. Knepley   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)sw), "Moment Residual: %g\n", (double)res[0]));
946*918dfc20SMatthew G. Knepley   PetscCall(DMComputeL2FieldDiff(user->dmMom, 0., exacts, NULL, locF, res));
947*918dfc20SMatthew G. Knepley   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)sw), "Moment Residuals: %g %g %g\n", (double)res[0], (double)res[1], (double)res[2]));
948*918dfc20SMatthew G. Knepley   PetscCall(VecCopy(m, mold));
949*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(user->dmMom, &locF));
950*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(user->dmMom, &m));
951*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmMom, "mold", &mold));
952*918dfc20SMatthew G. Knepley 
953*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(user->dmN, &nRhs));
954*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(user->dmP, &pRhs));
955*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(user->dmE, &eRhs));
956*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmN, "n", &n));
957*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmP, "p", &p));
958*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmE, "e", &e));
959*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
960*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
961*918dfc20SMatthew G. Knepley }
962*918dfc20SMatthew G. Knepley 
963*918dfc20SMatthew G. Knepley static PetscErrorCode MonitorMomentFields(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
964*918dfc20SMatthew G. Knepley {
965*918dfc20SMatthew G. Knepley   AppCtx *user = (AppCtx *)ctx;
966*918dfc20SMatthew G. Knepley   Vec     n, p, e;
967*918dfc20SMatthew G. Knepley 
968*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
969*918dfc20SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
970*918dfc20SMatthew G. Knepley   PetscCall(ComputeMomentFields(ts));
971*918dfc20SMatthew G. Knepley 
972*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmN, "n", &n));
973*918dfc20SMatthew G. Knepley   PetscCall(VecView(n, user->viewerN));
974*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmN, "n", &n));
975*918dfc20SMatthew G. Knepley 
976*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmP, "p", &p));
977*918dfc20SMatthew G. Knepley   PetscCall(VecView(p, user->viewerP));
978*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmP, "p", &p));
979*918dfc20SMatthew G. Knepley 
980*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmE, "e", &e));
981*918dfc20SMatthew G. Knepley   PetscCall(VecView(e, user->viewerE));
982*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmE, "e", &e));
983*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
984*918dfc20SMatthew G. Knepley }
985*918dfc20SMatthew G. Knepley 
986*918dfc20SMatthew G. Knepley PetscErrorCode MonitorInitialConditions(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
987*918dfc20SMatthew G. Knepley {
988*918dfc20SMatthew G. Knepley   AppCtx    *user = (AppCtx *)ctx;
989*918dfc20SMatthew G. Knepley   DM         sw;
990*918dfc20SMatthew G. Knepley   PetscDraw  drawic_x, drawic_v;
991*918dfc20SMatthew G. Knepley   PetscReal *weight, *pos, *vel;
992*918dfc20SMatthew G. Knepley   PetscInt   dim, Np;
993*918dfc20SMatthew G. Knepley 
994*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
995*918dfc20SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
996*918dfc20SMatthew G. Knepley   if (step == 0) {
997*918dfc20SMatthew G. Knepley     PetscCall(TSGetDM(ts, &sw));
998*918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(sw, &dim));
999*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetLocalSize(sw, &Np));
1000*918dfc20SMatthew G. Knepley 
1001*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGReset(user->drawhgic_x));
1002*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGGetDraw(user->drawhgic_x, &drawic_x));
1003*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawClear(drawic_x));
1004*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawFlush(drawic_x));
1005*918dfc20SMatthew G. Knepley 
1006*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGReset(user->drawhgic_v));
1007*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGGetDraw(user->drawhgic_v, &drawic_v));
1008*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawClear(drawic_v));
1009*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawFlush(drawic_v));
1010*918dfc20SMatthew G. Knepley 
1011*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
1012*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
1013*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
1014*918dfc20SMatthew G. Knepley     for (PetscInt p = 0; p < Np; ++p) {
1015*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawHGAddWeightedValue(user->drawhgic_x, pos[p * dim], weight[p]));
1016*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawHGAddWeightedValue(user->drawhgic_v, vel[p * dim], weight[p]));
1017*918dfc20SMatthew G. Knepley     }
1018*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
1019*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
1020*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
1021*918dfc20SMatthew G. Knepley 
1022*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGDraw(user->drawhgic_x));
1023*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGSave(user->drawhgic_x));
1024*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGDraw(user->drawhgic_v));
1025*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawHGSave(user->drawhgic_v));
1026*918dfc20SMatthew G. Knepley   }
1027*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1028*918dfc20SMatthew G. Knepley }
1029*918dfc20SMatthew G. Knepley 
1030*918dfc20SMatthew G. Knepley // Right now, make the complete velocity histogram
1031*918dfc20SMatthew G. Knepley PetscErrorCode MonitorVelocity(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
1032*918dfc20SMatthew G. Knepley {
1033*918dfc20SMatthew G. Knepley   AppCtx      *user = (AppCtx *)ctx;
1034*918dfc20SMatthew G. Knepley   DM           sw, dm;
1035*918dfc20SMatthew G. Knepley   Vec          ks;
1036*918dfc20SMatthew G. Knepley   PetscProbFn *cdf;
1037*918dfc20SMatthew G. Knepley   PetscDraw    drawcell_v;
1038*918dfc20SMatthew G. Knepley   PetscScalar *ksa;
1039*918dfc20SMatthew G. Knepley   PetscReal   *weight, *vel;
1040*918dfc20SMatthew G. Knepley   PetscInt    *pidx;
1041*918dfc20SMatthew G. Knepley   PetscInt     dim, Npc, cStart, cEnd, cell = user->velocity_monitor;
1042*918dfc20SMatthew G. Knepley 
1043*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1044*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
1045*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1046*918dfc20SMatthew G. Knepley 
1047*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &dm));
1048*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1049*918dfc20SMatthew G. Knepley   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &ks));
1050*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)ks, "KS Statistic by Cell"));
1051*918dfc20SMatthew G. Knepley   PetscCall(VecSetSizes(ks, cEnd - cStart, PETSC_DETERMINE));
1052*918dfc20SMatthew G. Knepley   PetscCall(VecSetFromOptions(ks));
1053*918dfc20SMatthew G. Knepley   switch (dim) {
1054*918dfc20SMatthew G. Knepley   case 1:
1055*918dfc20SMatthew G. Knepley     //cdf = PetscCDFMaxwellBoltzmann1D;
1056*918dfc20SMatthew G. Knepley     cdf = PetscCDFGaussian1D;
1057*918dfc20SMatthew G. Knepley     break;
1058*918dfc20SMatthew G. Knepley   case 2:
1059*918dfc20SMatthew G. Knepley     cdf = PetscCDFMaxwellBoltzmann2D;
1060*918dfc20SMatthew G. Knepley     break;
1061*918dfc20SMatthew G. Knepley   case 3:
1062*918dfc20SMatthew G. Knepley     cdf = PetscCDFMaxwellBoltzmann3D;
1063*918dfc20SMatthew G. Knepley     break;
1064*918dfc20SMatthew G. Knepley   default:
1065*918dfc20SMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim);
1066*918dfc20SMatthew G. Knepley   }
1067*918dfc20SMatthew G. Knepley 
1068*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawHGReset(user->drawhgcell_v));
1069*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawHGGetDraw(user->drawhgcell_v, &drawcell_v));
1070*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawClear(drawcell_v));
1071*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawFlush(drawcell_v));
1072*918dfc20SMatthew G. Knepley 
1073*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
1074*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
1075*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
1076*918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayWrite(ks, &ksa));
1077*918dfc20SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1078*918dfc20SMatthew G. Knepley     Vec          cellv, cellw;
1079*918dfc20SMatthew G. Knepley     PetscScalar *cella, *cellaw;
1080*918dfc20SMatthew G. Knepley     PetscReal    totWgt = 0.;
1081*918dfc20SMatthew G. Knepley 
1082*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
1083*918dfc20SMatthew G. Knepley     PetscCall(VecCreate(PETSC_COMM_SELF, &cellv));
1084*918dfc20SMatthew G. Knepley     PetscCall(VecSetBlockSize(cellv, dim));
1085*918dfc20SMatthew G. Knepley     PetscCall(VecSetSizes(cellv, Npc * dim, Npc));
1086*918dfc20SMatthew G. Knepley     PetscCall(VecSetFromOptions(cellv));
1087*918dfc20SMatthew G. Knepley     PetscCall(VecCreate(PETSC_COMM_SELF, &cellw));
1088*918dfc20SMatthew G. Knepley     PetscCall(VecSetSizes(cellw, Npc, Npc));
1089*918dfc20SMatthew G. Knepley     PetscCall(VecSetFromOptions(cellw));
1090*918dfc20SMatthew G. Knepley     PetscCall(VecGetArrayWrite(cellv, &cella));
1091*918dfc20SMatthew G. Knepley     PetscCall(VecGetArrayWrite(cellw, &cellaw));
1092*918dfc20SMatthew G. Knepley     for (PetscInt q = 0; q < Npc; ++q) {
1093*918dfc20SMatthew G. Knepley       const PetscInt p = pidx[q];
1094*918dfc20SMatthew G. Knepley       if (c == cell) PetscCall(PetscDrawHGAddWeightedValue(user->drawhgcell_v, vel[p * dim], weight[p]));
1095*918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) cella[q * dim + d] = vel[p * dim + d];
1096*918dfc20SMatthew G. Knepley       cellaw[q] = weight[p];
1097*918dfc20SMatthew G. Knepley       totWgt += weight[p];
1098*918dfc20SMatthew G. Knepley     }
1099*918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArrayWrite(cellv, &cella));
1100*918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArrayWrite(cellw, &cellaw));
1101*918dfc20SMatthew G. Knepley     PetscCall(VecScale(cellw, 1. / totWgt));
1102*918dfc20SMatthew G. Knepley     PetscCall(PetscProbComputeKSStatisticWeighted(cellv, cellw, cdf, &ksa[c - cStart]));
1103*918dfc20SMatthew G. Knepley     PetscCall(VecDestroy(&cellv));
1104*918dfc20SMatthew G. Knepley     PetscCall(VecDestroy(&cellw));
1105*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
1106*918dfc20SMatthew G. Knepley   }
1107*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayWrite(ks, &ksa));
1108*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
1109*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
1110*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
1111*918dfc20SMatthew G. Knepley 
1112*918dfc20SMatthew G. Knepley   PetscReal minalpha, maxalpha;
1113*918dfc20SMatthew G. Knepley   PetscInt  mincell, maxcell;
1114*918dfc20SMatthew G. Knepley 
1115*918dfc20SMatthew G. Knepley   PetscCall(VecFilter(ks, PETSC_SMALL));
1116*918dfc20SMatthew G. Knepley   PetscCall(VecMin(ks, &mincell, &minalpha));
1117*918dfc20SMatthew G. Knepley   PetscCall(VecMax(ks, &maxcell, &maxalpha));
1118*918dfc20SMatthew 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));
1119*918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(ks, NULL, "-ks_view"));
1120*918dfc20SMatthew G. Knepley   PetscCall(VecDestroy(&ks));
1121*918dfc20SMatthew G. Knepley 
1122*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawHGDraw(user->drawhgcell_v));
1123*918dfc20SMatthew G. Knepley   PetscCall(PetscDrawHGSave(user->drawhgcell_v));
1124*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1125*918dfc20SMatthew G. Knepley }
1126*918dfc20SMatthew G. Knepley 
1127*918dfc20SMatthew G. Knepley static PetscErrorCode MonitorPositions_2D(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
1128*918dfc20SMatthew G. Knepley {
1129*918dfc20SMatthew G. Knepley   AppCtx         *user = (AppCtx *)ctx;
1130*918dfc20SMatthew G. Knepley   DM              dm, sw;
1131*918dfc20SMatthew G. Knepley   PetscScalar    *x, *v, *weight;
1132*918dfc20SMatthew G. Knepley   PetscReal       lower[3], upper[3], speed;
1133*918dfc20SMatthew G. Knepley   const PetscInt *s;
1134*918dfc20SMatthew G. Knepley   PetscInt        dim, cStart, cEnd, c;
1135*918dfc20SMatthew G. Knepley 
1136*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1137*918dfc20SMatthew G. Knepley   if (step > 0 && step % user->ostep == 0) {
1138*918dfc20SMatthew G. Knepley     PetscCall(TSGetDM(ts, &sw));
1139*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetCellDM(sw, &dm));
1140*918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(dm, &dim));
1141*918dfc20SMatthew G. Knepley     PetscCall(DMGetBoundingBox(dm, lower, upper));
1142*918dfc20SMatthew G. Knepley     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1143*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1144*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
1145*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
1146*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&s));
1147*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetAccess(sw));
1148*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspX));
1149*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], lower[1], upper[1]));
1150*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], -12, 12));
1151*918dfc20SMatthew G. Knepley     for (c = 0; c < cEnd - cStart; ++c) {
1152*918dfc20SMatthew G. Knepley       PetscInt *pidx, Npc, q;
1153*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
1154*918dfc20SMatthew G. Knepley       for (q = 0; q < Npc; ++q) {
1155*918dfc20SMatthew G. Knepley         const PetscInt p = pidx[q];
1156*918dfc20SMatthew G. Knepley         if (s[p] == 0) {
1157*918dfc20SMatthew G. Knepley           speed = 0.;
1158*918dfc20SMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) speed += PetscSqr(v[p * dim + d]);
1159*918dfc20SMatthew G. Knepley           speed = PetscSqrtReal(speed);
1160*918dfc20SMatthew G. Knepley           if (dim == 1) {
1161*918dfc20SMatthew G. Knepley             PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &v[p * dim], &speed));
1162*918dfc20SMatthew G. Knepley           } else {
1163*918dfc20SMatthew G. Knepley             PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &x[p * dim + 1], &speed));
1164*918dfc20SMatthew G. Knepley           }
1165*918dfc20SMatthew G. Knepley         } else if (s[p] == 1) {
1166*918dfc20SMatthew G. Knepley           PetscCall(PetscDrawSPAddPoint(user->drawspX, &x[p * dim], &v[p * dim]));
1167*918dfc20SMatthew G. Knepley         }
1168*918dfc20SMatthew G. Knepley       }
1169*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
1170*918dfc20SMatthew G. Knepley     }
1171*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPDraw(user->drawspX, PETSC_TRUE));
1172*918dfc20SMatthew G. Knepley     PetscDraw draw;
1173*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSPGetDraw(user->drawspX, &draw));
1174*918dfc20SMatthew G. Knepley     PetscCall(PetscDrawSave(draw));
1175*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestoreAccess(sw));
1176*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1177*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
1178*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
1179*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&s));
1180*918dfc20SMatthew G. Knepley   }
1181*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1182*918dfc20SMatthew G. Knepley }
1183*918dfc20SMatthew G. Knepley 
1184*918dfc20SMatthew G. Knepley static PetscErrorCode MonitorPoisson(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
1185*918dfc20SMatthew G. Knepley {
1186*918dfc20SMatthew G. Knepley   AppCtx *user = (AppCtx *)ctx;
1187*918dfc20SMatthew G. Knepley   DM      dm, sw;
1188*918dfc20SMatthew G. Knepley 
1189*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1190*918dfc20SMatthew G. Knepley   if (step > 0 && step % user->ostep == 0) {
1191*918dfc20SMatthew G. Knepley     PetscCall(TSGetDM(ts, &sw));
1192*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetCellDM(sw, &dm));
1193*918dfc20SMatthew G. Knepley 
1194*918dfc20SMatthew G. Knepley     if (user->validE) {
1195*918dfc20SMatthew G. Knepley       PetscScalar *x, *E, *weight;
1196*918dfc20SMatthew G. Knepley       PetscReal    lower[3], upper[3], xval;
1197*918dfc20SMatthew G. Knepley       PetscDraw    draw;
1198*918dfc20SMatthew G. Knepley       PetscInt     dim, cStart, cEnd;
1199*918dfc20SMatthew G. Knepley 
1200*918dfc20SMatthew G. Knepley       PetscCall(DMGetDimension(dm, &dim));
1201*918dfc20SMatthew G. Knepley       PetscCall(DMGetBoundingBox(dm, lower, upper));
1202*918dfc20SMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1203*918dfc20SMatthew G. Knepley 
1204*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawSPReset(user->drawspE));
1205*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1206*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
1207*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
1208*918dfc20SMatthew G. Knepley 
1209*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmSortGetAccess(sw));
1210*918dfc20SMatthew G. Knepley       for (PetscInt c = 0; c < cEnd - cStart; ++c) {
1211*918dfc20SMatthew G. Knepley         PetscReal Eavg = 0.0;
1212*918dfc20SMatthew G. Knepley         PetscInt *pidx, Npc;
1213*918dfc20SMatthew G. Knepley 
1214*918dfc20SMatthew G. Knepley         PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
1215*918dfc20SMatthew G. Knepley         for (PetscInt q = 0; q < Npc; ++q) {
1216*918dfc20SMatthew G. Knepley           const PetscInt p = pidx[q];
1217*918dfc20SMatthew G. Knepley           Eavg += E[p * dim];
1218*918dfc20SMatthew G. Knepley         }
1219*918dfc20SMatthew G. Knepley         Eavg /= Npc;
1220*918dfc20SMatthew G. Knepley         xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart));
1221*918dfc20SMatthew G. Knepley         PetscCall(PetscDrawSPAddPoint(user->drawspE, &xval, &Eavg));
1222*918dfc20SMatthew G. Knepley         PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
1223*918dfc20SMatthew G. Knepley       }
1224*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawSPDraw(user->drawspE, PETSC_TRUE));
1225*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawSPGetDraw(user->drawspE, &draw));
1226*918dfc20SMatthew G. Knepley       PetscCall(PetscDrawSave(draw));
1227*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmSortRestoreAccess(sw));
1228*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1229*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
1230*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
1231*918dfc20SMatthew G. Knepley     }
1232*918dfc20SMatthew G. Knepley 
1233*918dfc20SMatthew G. Knepley     Vec rho, rhohat, phi;
1234*918dfc20SMatthew G. Knepley 
1235*918dfc20SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
1236*918dfc20SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
1237*918dfc20SMatthew G. Knepley     PetscCall(VecView(rho, user->viewerRho));
1238*918dfc20SMatthew G. Knepley     PetscCall(VecISCopy(user->fftX, user->fftReal, SCATTER_FORWARD, rho));
1239*918dfc20SMatthew G. Knepley     PetscCall(MatMult(user->fftPot, user->fftX, user->fftY));
1240*918dfc20SMatthew G. Knepley     PetscCall(VecFilter(user->fftY, PETSC_SMALL));
1241*918dfc20SMatthew G. Knepley     PetscCall(VecViewFromOptions(user->fftX, NULL, "-real_view"));
1242*918dfc20SMatthew G. Knepley     PetscCall(VecViewFromOptions(user->fftY, NULL, "-fft_view"));
1243*918dfc20SMatthew G. Knepley     PetscCall(VecISCopy(user->fftY, user->fftReal, SCATTER_REVERSE, rhohat));
1244*918dfc20SMatthew G. Knepley     PetscCall(VecSetValue(rhohat, 0, 0., INSERT_VALUES)); // Remove large DC component
1245*918dfc20SMatthew G. Knepley     PetscCall(VecView(rhohat, user->viewerRhoHat));
1246*918dfc20SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
1247*918dfc20SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
1248*918dfc20SMatthew G. Knepley 
1249*918dfc20SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
1250*918dfc20SMatthew G. Knepley     PetscCall(VecView(phi, user->viewerPhi));
1251*918dfc20SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
1252*918dfc20SMatthew G. Knepley   }
1253*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1254*918dfc20SMatthew G. Knepley }
1255*918dfc20SMatthew G. Knepley 
1256*918dfc20SMatthew G. Knepley static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx)
1257*918dfc20SMatthew G. Knepley {
1258*918dfc20SMatthew G. Knepley   PetscBag   bag;
1259*918dfc20SMatthew G. Knepley   Parameter *p;
1260*918dfc20SMatthew G. Knepley 
1261*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1262*918dfc20SMatthew G. Knepley   /* setup PETSc parameter bag */
1263*918dfc20SMatthew G. Knepley   PetscCall(PetscBagGetData(ctx->bag, (void **)&p));
1264*918dfc20SMatthew G. Knepley   PetscCall(PetscBagSetName(ctx->bag, "par", "Vlasov-Poisson Parameters"));
1265*918dfc20SMatthew G. Knepley   bag = ctx->bag;
1266*918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "v0", "Velocity scale, m/s"));
1267*918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->t0, 1.0, "t0", "Time scale, s"));
1268*918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->x0, 1.0, "x0", "Space scale, m"));
1269*918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "phi0", "Potential scale, kg*m^2/A*s^3"));
1270*918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->q0, 1.0, "q0", "Charge Scale, A*s"));
1271*918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->m0, 1.0, "m0", "Mass Scale, kg"));
1272*918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->epsi0, 1.0, "epsi0", "Permittivity of Free Space, kg"));
1273*918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->kb, 1.0, "kb", "Boltzmann Constant, m^2 kg/s^2 K^1"));
1274*918dfc20SMatthew G. Knepley 
1275*918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->sigma, 1.0, "sigma", "Charge per unit area, C/m^3"));
1276*918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->poissonNumber, 1.0, "poissonNumber", "Non-Dimensional Poisson Number"));
1277*918dfc20SMatthew G. Knepley   PetscCall(PetscBagRegisterScalar(bag, &p->vlasovNumber, 1.0, "vlasovNumber", "Non-Dimensional Vlasov Number"));
1278*918dfc20SMatthew G. Knepley   PetscCall(PetscBagSetFromOptions(bag));
1279*918dfc20SMatthew G. Knepley   {
1280*918dfc20SMatthew G. Knepley     PetscViewer       viewer;
1281*918dfc20SMatthew G. Knepley     PetscViewerFormat format;
1282*918dfc20SMatthew G. Knepley     PetscBool         flg;
1283*918dfc20SMatthew G. Knepley 
1284*918dfc20SMatthew G. Knepley     PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg));
1285*918dfc20SMatthew G. Knepley     if (flg) {
1286*918dfc20SMatthew G. Knepley       PetscCall(PetscViewerPushFormat(viewer, format));
1287*918dfc20SMatthew G. Knepley       PetscCall(PetscBagView(bag, viewer));
1288*918dfc20SMatthew G. Knepley       PetscCall(PetscViewerFlush(viewer));
1289*918dfc20SMatthew G. Knepley       PetscCall(PetscViewerPopFormat(viewer));
1290*918dfc20SMatthew G. Knepley       PetscCall(PetscViewerDestroy(&viewer));
1291*918dfc20SMatthew G. Knepley     }
1292*918dfc20SMatthew G. Knepley   }
1293*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1294*918dfc20SMatthew G. Knepley }
1295*918dfc20SMatthew G. Knepley 
1296*918dfc20SMatthew G. Knepley static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
1297*918dfc20SMatthew G. Knepley {
1298*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1299*918dfc20SMatthew G. Knepley   PetscCall(DMCreate(comm, dm));
1300*918dfc20SMatthew G. Knepley   PetscCall(DMSetType(*dm, DMPLEX));
1301*918dfc20SMatthew G. Knepley   PetscCall(DMSetFromOptions(*dm));
1302*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*dm, "space"));
1303*918dfc20SMatthew G. Knepley   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
1304*918dfc20SMatthew G. Knepley 
1305*918dfc20SMatthew G. Knepley   // Cache the mesh geometry
1306*918dfc20SMatthew G. Knepley   DMField         coordField;
1307*918dfc20SMatthew G. Knepley   IS              cellIS;
1308*918dfc20SMatthew G. Knepley   PetscQuadrature quad;
1309*918dfc20SMatthew G. Knepley   PetscReal      *wt, *pt;
1310*918dfc20SMatthew G. Knepley   PetscInt        cdim, cStart, cEnd;
1311*918dfc20SMatthew G. Knepley 
1312*918dfc20SMatthew G. Knepley   PetscCall(DMGetCoordinateField(*dm, &coordField));
1313*918dfc20SMatthew G. Knepley   PetscCheck(coordField, comm, PETSC_ERR_USER, "DM must have a coordinate field");
1314*918dfc20SMatthew G. Knepley   PetscCall(DMGetCoordinateDim(*dm, &cdim));
1315*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd));
1316*918dfc20SMatthew G. Knepley   PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cellIS));
1317*918dfc20SMatthew G. Knepley   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
1318*918dfc20SMatthew G. Knepley   PetscCall(PetscMalloc1(1, &wt));
1319*918dfc20SMatthew G. Knepley   PetscCall(PetscMalloc1(2, &pt));
1320*918dfc20SMatthew G. Knepley   wt[0] = 1.;
1321*918dfc20SMatthew G. Knepley   pt[0] = -1.;
1322*918dfc20SMatthew G. Knepley   pt[1] = -1.;
1323*918dfc20SMatthew G. Knepley   PetscCall(PetscQuadratureSetData(quad, cdim, 1, 1, pt, wt));
1324*918dfc20SMatthew G. Knepley   PetscCall(DMFieldCreateFEGeom(coordField, cellIS, quad, PETSC_FEGEOM_BASIC, &user->fegeom));
1325*918dfc20SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&quad));
1326*918dfc20SMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
1327*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1328*918dfc20SMatthew G. Knepley }
1329*918dfc20SMatthew G. Knepley 
1330*918dfc20SMatthew 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[])
1331*918dfc20SMatthew G. Knepley {
1332*918dfc20SMatthew G. Knepley   f0[0] = -constants[SIGMA];
1333*918dfc20SMatthew G. Knepley }
1334*918dfc20SMatthew G. Knepley 
1335*918dfc20SMatthew 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[])
1336*918dfc20SMatthew G. Knepley {
1337*918dfc20SMatthew G. Knepley   PetscInt d;
1338*918dfc20SMatthew G. Knepley   for (d = 0; d < dim; ++d) f1[d] = u_x[d];
1339*918dfc20SMatthew G. Knepley }
1340*918dfc20SMatthew G. Knepley 
1341*918dfc20SMatthew 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[])
1342*918dfc20SMatthew G. Knepley {
1343*918dfc20SMatthew G. Knepley   PetscInt d;
1344*918dfc20SMatthew G. Knepley   for (d = 0; d < dim; ++d) g3[d * dim + d] = 1.0;
1345*918dfc20SMatthew G. Knepley }
1346*918dfc20SMatthew G. Knepley 
1347*918dfc20SMatthew G. Knepley /*
1348*918dfc20SMatthew G. Knepley    /  I   -grad\ / q \ = /0\
1349*918dfc20SMatthew G. Knepley    \-div    0  / \phi/   \f/
1350*918dfc20SMatthew G. Knepley */
1351*918dfc20SMatthew 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[])
1352*918dfc20SMatthew G. Knepley {
1353*918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f0[d] += u[uOff[0] + d];
1354*918dfc20SMatthew G. Knepley }
1355*918dfc20SMatthew G. Knepley 
1356*918dfc20SMatthew 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[])
1357*918dfc20SMatthew G. Knepley {
1358*918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f1[d * dim + d] = u[uOff[1]];
1359*918dfc20SMatthew G. Knepley }
1360*918dfc20SMatthew G. Knepley 
1361*918dfc20SMatthew 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[])
1362*918dfc20SMatthew G. Knepley {
1363*918dfc20SMatthew G. Knepley   f0[0] += constants[SIGMA];
1364*918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f0[0] += u_x[uOff_x[0] + d * dim + d];
1365*918dfc20SMatthew G. Knepley }
1366*918dfc20SMatthew G. Knepley 
1367*918dfc20SMatthew G. Knepley /* Boundary residual. Dirichlet boundary for u means u_bdy=p*n */
1368*918dfc20SMatthew 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[])
1369*918dfc20SMatthew G. Knepley {
1370*918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) g0[d * dim + d] = 1.0;
1371*918dfc20SMatthew G. Knepley }
1372*918dfc20SMatthew G. Knepley 
1373*918dfc20SMatthew 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[])
1374*918dfc20SMatthew G. Knepley {
1375*918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) g2[d * dim + d] = 1.0;
1376*918dfc20SMatthew G. Knepley }
1377*918dfc20SMatthew G. Knepley 
1378*918dfc20SMatthew 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[])
1379*918dfc20SMatthew G. Knepley {
1380*918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) g1[d * dim + d] = 1.0;
1381*918dfc20SMatthew G. Knepley }
1382*918dfc20SMatthew G. Knepley 
1383*918dfc20SMatthew G. Knepley static PetscErrorCode CreateFEM(DM dm, AppCtx *user)
1384*918dfc20SMatthew G. Knepley {
1385*918dfc20SMatthew G. Knepley   PetscFE   fephi, feq;
1386*918dfc20SMatthew G. Knepley   PetscDS   ds;
1387*918dfc20SMatthew G. Knepley   PetscBool simplex;
1388*918dfc20SMatthew G. Knepley   PetscInt  dim;
1389*918dfc20SMatthew G. Knepley 
1390*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1391*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
1392*918dfc20SMatthew G. Knepley   PetscCall(DMPlexIsSimplex(dm, &simplex));
1393*918dfc20SMatthew G. Knepley   if (user->em == EM_MIXED) {
1394*918dfc20SMatthew G. Knepley     DMLabel        label;
1395*918dfc20SMatthew G. Knepley     const PetscInt id = 1;
1396*918dfc20SMatthew G. Knepley 
1397*918dfc20SMatthew G. Knepley     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "field_", PETSC_DETERMINE, &feq));
1398*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)feq, "field"));
1399*918dfc20SMatthew G. Knepley     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "potential_", PETSC_DETERMINE, &fephi));
1400*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
1401*918dfc20SMatthew G. Knepley     PetscCall(PetscFECopyQuadrature(feq, fephi));
1402*918dfc20SMatthew G. Knepley     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)feq));
1403*918dfc20SMatthew G. Knepley     PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fephi));
1404*918dfc20SMatthew G. Knepley     PetscCall(DMCreateDS(dm));
1405*918dfc20SMatthew G. Knepley     PetscCall(PetscFEDestroy(&fephi));
1406*918dfc20SMatthew G. Knepley     PetscCall(PetscFEDestroy(&feq));
1407*918dfc20SMatthew G. Knepley 
1408*918dfc20SMatthew G. Knepley     PetscCall(DMGetLabel(dm, "marker", &label));
1409*918dfc20SMatthew G. Knepley     PetscCall(DMGetDS(dm, &ds));
1410*918dfc20SMatthew G. Knepley 
1411*918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetResidual(ds, 0, f0_q, f1_q));
1412*918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetResidual(ds, 1, f0_phi_backgroundCharge, NULL));
1413*918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_qq, NULL, NULL, NULL));
1414*918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_qphi, NULL));
1415*918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_phiq, NULL, NULL));
1416*918dfc20SMatthew G. Knepley 
1417*918dfc20SMatthew G. Knepley     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void))zero, NULL, NULL, NULL));
1418*918dfc20SMatthew G. Knepley 
1419*918dfc20SMatthew G. Knepley   } else {
1420*918dfc20SMatthew G. Knepley     MatNullSpace nullsp;
1421*918dfc20SMatthew G. Knepley     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, PETSC_DETERMINE, &fephi));
1422*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
1423*918dfc20SMatthew G. Knepley     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fephi));
1424*918dfc20SMatthew G. Knepley     PetscCall(DMCreateDS(dm));
1425*918dfc20SMatthew G. Knepley     PetscCall(DMGetDS(dm, &ds));
1426*918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetResidual(ds, 0, ion_f0, laplacian_f1));
1427*918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, laplacian_g3));
1428*918dfc20SMatthew G. Knepley     PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullsp));
1429*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectCompose((PetscObject)fephi, "nullspace", (PetscObject)nullsp));
1430*918dfc20SMatthew G. Knepley     PetscCall(MatNullSpaceDestroy(&nullsp));
1431*918dfc20SMatthew G. Knepley     PetscCall(PetscFEDestroy(&fephi));
1432*918dfc20SMatthew G. Knepley   }
1433*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1434*918dfc20SMatthew G. Knepley }
1435*918dfc20SMatthew G. Knepley 
1436*918dfc20SMatthew G. Knepley static PetscErrorCode CreatePoisson(DM dm, AppCtx *user)
1437*918dfc20SMatthew G. Knepley {
1438*918dfc20SMatthew G. Knepley   SNES         snes;
1439*918dfc20SMatthew G. Knepley   Mat          J;
1440*918dfc20SMatthew G. Knepley   MatNullSpace nullSpace;
1441*918dfc20SMatthew G. Knepley 
1442*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1443*918dfc20SMatthew G. Knepley   PetscCall(CreateFEM(dm, user));
1444*918dfc20SMatthew G. Knepley   PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes));
1445*918dfc20SMatthew G. Knepley   PetscCall(SNESSetOptionsPrefix(snes, "em_"));
1446*918dfc20SMatthew G. Knepley   PetscCall(SNESSetDM(snes, dm));
1447*918dfc20SMatthew G. Knepley   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, user));
1448*918dfc20SMatthew G. Knepley   PetscCall(SNESSetFromOptions(snes));
1449*918dfc20SMatthew G. Knepley 
1450*918dfc20SMatthew G. Knepley   PetscCall(DMCreateMatrix(dm, &J));
1451*918dfc20SMatthew G. Knepley   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullSpace));
1452*918dfc20SMatthew G. Knepley   PetscCall(MatSetNullSpace(J, nullSpace));
1453*918dfc20SMatthew G. Knepley   PetscCall(MatNullSpaceDestroy(&nullSpace));
1454*918dfc20SMatthew G. Knepley   PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL));
1455*918dfc20SMatthew G. Knepley   PetscCall(MatDestroy(&J));
1456*918dfc20SMatthew G. Knepley   if (user->em == EM_MIXED) {
1457*918dfc20SMatthew G. Knepley     const PetscInt potential = 1;
1458*918dfc20SMatthew G. Knepley 
1459*918dfc20SMatthew G. Knepley     PetscCall(DMCreateSubDM(dm, 1, &potential, &user->isPot, &user->dmPot));
1460*918dfc20SMatthew G. Knepley   } else {
1461*918dfc20SMatthew G. Knepley     user->dmPot = dm;
1462*918dfc20SMatthew G. Knepley     PetscCall(PetscObjectReference((PetscObject)user->dmPot));
1463*918dfc20SMatthew G. Knepley   }
1464*918dfc20SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(user->dmPot, user->dmPot, &user->M));
1465*918dfc20SMatthew G. Knepley   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
1466*918dfc20SMatthew G. Knepley   user->snes = snes;
1467*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1468*918dfc20SMatthew G. Knepley }
1469*918dfc20SMatthew G. Knepley 
1470*918dfc20SMatthew G. Knepley // Conservation of mass (m = 1.0)
1471*918dfc20SMatthew G. Knepley // n_t + 1/ m p_x = 0
1472*918dfc20SMatthew 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[])
1473*918dfc20SMatthew G. Knepley {
1474*918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f0[0] += u_t[uOff[0]] + u_x[uOff_x[1] + d * dim + d];
1475*918dfc20SMatthew G. Knepley }
1476*918dfc20SMatthew G. Knepley 
1477*918dfc20SMatthew G. Knepley // Conservation of momentum (m = 1, e = 1)
1478*918dfc20SMatthew G. Knepley // p_t + (u p)_x = -pr_x + e n E
1479*918dfc20SMatthew G. Knepley // p_t + (div u) p + u . grad p = -pr_x + e n E
1480*918dfc20SMatthew G. Knepley // p_t + (div p) p / n - (p . grad n) p / n^2 + p / n . grad p = -pr_x + e n E
1481*918dfc20SMatthew 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[])
1482*918dfc20SMatthew G. Knepley {
1483*918dfc20SMatthew G. Knepley   const PetscScalar n = u[uOff[0]];
1484*918dfc20SMatthew G. Knepley 
1485*918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) {
1486*918dfc20SMatthew G. Knepley     PetscReal divp = 0.;
1487*918dfc20SMatthew G. Knepley 
1488*918dfc20SMatthew G. Knepley     f0[d] += u_t[uOff[1] + d];
1489*918dfc20SMatthew G. Knepley     for (PetscInt e = 0; e < dim; ++e) {
1490*918dfc20SMatthew G. Knepley       f0[d] += u[uOff[1] + e] * u_x[uOff_x[1] + d * dim + e] / n;                    // p / n . grad p
1491*918dfc20SMatthew 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
1492*918dfc20SMatthew G. Knepley       divp += u_x[uOff_x[1] + e * dim + e];
1493*918dfc20SMatthew G. Knepley     }
1494*918dfc20SMatthew G. Knepley     f0[d] += divp * u[uOff[1] + d] / n; // (div p) p / n
1495*918dfc20SMatthew G. Knepley     f0[d] += u_x[uOff_x[2] + d];        // pr_x
1496*918dfc20SMatthew G. Knepley     f0[d] -= n * a[d];                  // -e n E
1497*918dfc20SMatthew G. Knepley   }
1498*918dfc20SMatthew G. Knepley }
1499*918dfc20SMatthew G. Knepley 
1500*918dfc20SMatthew G. Knepley // Conservation of energy
1501*918dfc20SMatthew G. Knepley // pr_t + (u pr)_x = -3 pr u_x - q_x
1502*918dfc20SMatthew G. Knepley // pr_t + (div u) pr + u . grad pr = -3 pr (div u) - q_x
1503*918dfc20SMatthew G. Knepley // pr_t + 4 (div u) pr + u . grad pr = -q_x
1504*918dfc20SMatthew G. Knepley // pr_t + 4 div p pr / n - 4 (p . grad n) pr / n^2 + p . grad pr / n = -q_x
1505*918dfc20SMatthew 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[])
1506*918dfc20SMatthew G. Knepley {
1507*918dfc20SMatthew G. Knepley   const PetscScalar n    = u[uOff[0]];
1508*918dfc20SMatthew G. Knepley   const PetscScalar pr   = u[uOff[2]];
1509*918dfc20SMatthew G. Knepley   PetscReal         divp = 0.;
1510*918dfc20SMatthew G. Knepley 
1511*918dfc20SMatthew G. Knepley   f0[0] += u_t[uOff[2]];
1512*918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) {
1513*918dfc20SMatthew G. Knepley     f0[0] += u[uOff[1] + d] * u_x[uOff_x[2] + d] / n;                     // p . grad pr / n
1514*918dfc20SMatthew 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
1515*918dfc20SMatthew G. Knepley     divp += u_x[uOff_x[1] + d * dim + d];
1516*918dfc20SMatthew G. Knepley   }
1517*918dfc20SMatthew G. Knepley   f0[0] += 4. * divp * pr / n; // 4 div p pr / n
1518*918dfc20SMatthew G. Knepley }
1519*918dfc20SMatthew G. Knepley 
1520*918dfc20SMatthew G. Knepley static PetscErrorCode SetupMomentProblem(DM dm, AppCtx *ctx)
1521*918dfc20SMatthew G. Knepley {
1522*918dfc20SMatthew G. Knepley   PetscDS ds;
1523*918dfc20SMatthew G. Knepley 
1524*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1525*918dfc20SMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
1526*918dfc20SMatthew G. Knepley   PetscCall(PetscDSSetResidual(ds, 0, f0_mass, NULL));
1527*918dfc20SMatthew G. Knepley   PetscCall(PetscDSSetResidual(ds, 1, f0_momentum, NULL));
1528*918dfc20SMatthew G. Knepley   PetscCall(PetscDSSetResidual(ds, 2, f0_energy, NULL));
1529*918dfc20SMatthew G. Knepley   //PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_mass_uu, NULL, NULL, NULL));
1530*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1531*918dfc20SMatthew G. Knepley }
1532*918dfc20SMatthew G. Knepley 
1533*918dfc20SMatthew G. Knepley static PetscErrorCode CreateMomentFields(DM odm, AppCtx *user)
1534*918dfc20SMatthew G. Knepley {
1535*918dfc20SMatthew G. Knepley   DM             dm;
1536*918dfc20SMatthew G. Knepley   PetscFE        fe;
1537*918dfc20SMatthew G. Knepley   DMPolytopeType ct;
1538*918dfc20SMatthew G. Knepley   PetscInt       dim, cStart;
1539*918dfc20SMatthew G. Knepley 
1540*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1541*918dfc20SMatthew G. Knepley   PetscCall(DMClone(odm, &dm));
1542*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
1543*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
1544*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
1545*918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, NULL, PETSC_DETERMINE, &fe));
1546*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "number density"));
1547*918dfc20SMatthew G. Knepley   PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fe));
1548*918dfc20SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
1549*918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, dim, ct, NULL, PETSC_DETERMINE, &fe));
1550*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "momentum density"));
1551*918dfc20SMatthew G. Knepley   PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fe));
1552*918dfc20SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
1553*918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, NULL, PETSC_DETERMINE, &fe));
1554*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "energy density"));
1555*918dfc20SMatthew G. Knepley   PetscCall(DMSetField(dm, 2, NULL, (PetscObject)fe));
1556*918dfc20SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
1557*918dfc20SMatthew G. Knepley   PetscCall(DMCreateDS(dm));
1558*918dfc20SMatthew G. Knepley   PetscCall(SetupMomentProblem(dm, user));
1559*918dfc20SMatthew G. Knepley   user->dmMom = dm;
1560*918dfc20SMatthew G. Knepley   PetscInt field;
1561*918dfc20SMatthew G. Knepley 
1562*918dfc20SMatthew G. Knepley   field = 0;
1563*918dfc20SMatthew G. Knepley   PetscCall(DMCreateSubDM(user->dmMom, 1, &field, &user->isN, &user->dmN));
1564*918dfc20SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(user->dmN, user->dmN, &user->MN));
1565*918dfc20SMatthew G. Knepley   field = 1;
1566*918dfc20SMatthew G. Knepley   PetscCall(DMCreateSubDM(user->dmMom, 1, &field, &user->isP, &user->dmP));
1567*918dfc20SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(user->dmP, user->dmP, &user->MP));
1568*918dfc20SMatthew G. Knepley   field = 2;
1569*918dfc20SMatthew G. Knepley   PetscCall(DMCreateSubDM(user->dmMom, 1, &field, &user->isE, &user->dmE));
1570*918dfc20SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(user->dmE, user->dmE, &user->ME));
1571*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1572*918dfc20SMatthew G. Knepley }
1573*918dfc20SMatthew G. Knepley 
1574*918dfc20SMatthew G. Knepley PetscErrorCode PetscPDFPertubedConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
1575*918dfc20SMatthew G. Knepley {
1576*918dfc20SMatthew G. Knepley   p[0] = (1 + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
1577*918dfc20SMatthew G. Knepley   p[1] = (1 + 0.01 * PetscCosReal(0.5 * x[1])) / (2 * PETSC_PI);
1578*918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
1579*918dfc20SMatthew G. Knepley }
1580*918dfc20SMatthew G. Knepley PetscErrorCode PetscPDFPertubedConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
1581*918dfc20SMatthew G. Knepley {
1582*918dfc20SMatthew G. Knepley   p[0] = (1. + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
1583*918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
1584*918dfc20SMatthew G. Knepley }
1585*918dfc20SMatthew G. Knepley 
1586*918dfc20SMatthew G. Knepley PetscErrorCode PetscPDFCosine1D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
1587*918dfc20SMatthew G. Knepley {
1588*918dfc20SMatthew G. Knepley   const PetscReal alpha = scale ? scale[0] : 0.0;
1589*918dfc20SMatthew G. Knepley   const PetscReal k     = scale ? scale[1] : 1.;
1590*918dfc20SMatthew G. Knepley   p[0]                  = (1 + alpha * PetscCosReal(k * x[0]));
1591*918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
1592*918dfc20SMatthew G. Knepley }
1593*918dfc20SMatthew G. Knepley 
1594*918dfc20SMatthew G. Knepley PetscErrorCode PetscPDFCosine2D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
1595*918dfc20SMatthew G. Knepley {
1596*918dfc20SMatthew G. Knepley   const PetscReal alpha = scale ? scale[0] : 0.;
1597*918dfc20SMatthew G. Knepley   const PetscReal k     = scale ? scale[0] : 1.;
1598*918dfc20SMatthew G. Knepley   p[0]                  = (1 + alpha * PetscCosReal(k * (x[0] + x[1])));
1599*918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
1600*918dfc20SMatthew G. Knepley }
1601*918dfc20SMatthew G. Knepley 
1602*918dfc20SMatthew G. Knepley static PetscErrorCode CreateVelocityDM(DM sw, DM *vdm)
1603*918dfc20SMatthew G. Knepley {
1604*918dfc20SMatthew G. Knepley   PetscFE        fe;
1605*918dfc20SMatthew G. Knepley   DMPolytopeType ct;
1606*918dfc20SMatthew G. Knepley   PetscInt       dim, cStart;
1607*918dfc20SMatthew G. Knepley   const char    *prefix = "v";
1608*918dfc20SMatthew G. Knepley 
1609*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1610*918dfc20SMatthew G. Knepley   PetscCall(DMCreate(PETSC_COMM_SELF, vdm));
1611*918dfc20SMatthew G. Knepley   PetscCall(DMSetType(*vdm, DMPLEX));
1612*918dfc20SMatthew G. Knepley   PetscCall(DMPlexSetOptionsPrefix(*vdm, prefix));
1613*918dfc20SMatthew G. Knepley   PetscCall(DMSetFromOptions(*vdm));
1614*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*vdm, "velocity"));
1615*918dfc20SMatthew G. Knepley   PetscCall(DMViewFromOptions(*vdm, NULL, "-dm_view"));
1616*918dfc20SMatthew G. Knepley 
1617*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(*vdm, &dim));
1618*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*vdm, 0, &cStart, NULL));
1619*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetCellType(*vdm, cStart, &ct));
1620*918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe));
1621*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "distribution"));
1622*918dfc20SMatthew G. Knepley   PetscCall(DMSetField(*vdm, 0, NULL, (PetscObject)fe));
1623*918dfc20SMatthew G. Knepley   PetscCall(DMCreateDS(*vdm));
1624*918dfc20SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
1625*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1626*918dfc20SMatthew G. Knepley }
1627*918dfc20SMatthew G. Knepley 
1628*918dfc20SMatthew G. Knepley /*
1629*918dfc20SMatthew G. Knepley   InitializeParticles_Centroid - Initialize a regular grid of particles.
1630*918dfc20SMatthew G. Knepley 
1631*918dfc20SMatthew G. Knepley   Input Parameters:
1632*918dfc20SMatthew G. Knepley + sw      - The `DMSWARM`
1633*918dfc20SMatthew G. Knepley - force1D - Treat the spatial domain as 1D
1634*918dfc20SMatthew G. Knepley 
1635*918dfc20SMatthew G. Knepley   Notes:
1636*918dfc20SMatthew G. Knepley   This functions sets the species, cellid, spatial coordinate, and velocity fields for all particles.
1637*918dfc20SMatthew G. Knepley 
1638*918dfc20SMatthew G. Knepley   It places one particle in the centroid of each cell in the implicit tensor product of the spatial
1639*918dfc20SMatthew G. Knepley   and velocity meshes.
1640*918dfc20SMatthew G. Knepley */
1641*918dfc20SMatthew G. Knepley static PetscErrorCode InitializeParticles_Centroid(DM sw)
1642*918dfc20SMatthew G. Knepley {
1643*918dfc20SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
1644*918dfc20SMatthew G. Knepley   DMSwarmCellDM celldm;
1645*918dfc20SMatthew G. Knepley   DM            xdm, vdm;
1646*918dfc20SMatthew G. Knepley   PetscReal     vmin[3], vmax[3];
1647*918dfc20SMatthew G. Knepley   PetscReal    *x, *v;
1648*918dfc20SMatthew G. Knepley   PetscInt     *species, *cellid;
1649*918dfc20SMatthew G. Knepley   PetscInt      dim, xcStart, xcEnd, vcStart, vcEnd, Ns, Np, Npc, debug;
1650*918dfc20SMatthew G. Knepley   PetscBool     flg;
1651*918dfc20SMatthew G. Knepley   MPI_Comm      comm;
1652*918dfc20SMatthew G. Knepley   const char   *cellidname;
1653*918dfc20SMatthew G. Knepley 
1654*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1655*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
1656*918dfc20SMatthew G. Knepley 
1657*918dfc20SMatthew G. Knepley   PetscOptionsBegin(comm, "", "DMSwarm Options", "DMSWARM");
1658*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
1659*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsInt("-dm_swarMNum_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg));
1660*918dfc20SMatthew G. Knepley   if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns));
1661*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_coords", "Debug output level for particle coordinate computations", "InitializeParticles", 0, &swarm->printCoords, NULL, 0));
1662*918dfc20SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_weights", "Debug output level for particle weight computations", "InitializeWeights", 0, &swarm->printWeights, NULL, 0));
1663*918dfc20SMatthew G. Knepley   PetscOptionsEnd();
1664*918dfc20SMatthew G. Knepley   debug = swarm->printCoords;
1665*918dfc20SMatthew G. Knepley 
1666*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1667*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
1668*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
1669*918dfc20SMatthew G. Knepley 
1670*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
1671*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
1672*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
1673*918dfc20SMatthew G. Knepley 
1674*918dfc20SMatthew G. Knepley   // One particle per centroid on the tensor product grid
1675*918dfc20SMatthew G. Knepley   Npc = (vcEnd - vcStart) * Ns;
1676*918dfc20SMatthew G. Knepley   Np  = (xcEnd - xcStart) * Npc;
1677*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetLocalSizes(sw, Np, 0));
1678*918dfc20SMatthew G. Knepley   if (debug) {
1679*918dfc20SMatthew G. Knepley     PetscInt gNp, gNc, Nc = xcEnd - xcStart;
1680*918dfc20SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Np, &gNp, 1, MPIU_INT, MPIU_SUM, comm));
1681*918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global Np = %" PetscInt_FMT "\n", gNp));
1682*918dfc20SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Nc, &gNc, 1, MPIU_INT, MPIU_SUM, comm));
1683*918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global X-cells = %" PetscInt_FMT "\n", gNc));
1684*918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global V-cells = %" PetscInt_FMT "\n", vcEnd - vcStart));
1685*918dfc20SMatthew G. Knepley   }
1686*918dfc20SMatthew G. Knepley 
1687*918dfc20SMatthew G. Knepley   // Set species and cellid
1688*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
1689*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCellID(celldm, &cellidname));
1690*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
1691*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, cellidname, NULL, NULL, (void **)&cellid));
1692*918dfc20SMatthew G. Knepley   for (PetscInt c = 0, p = 0; c < xcEnd - xcStart; ++c) {
1693*918dfc20SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
1694*918dfc20SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q, ++p) {
1695*918dfc20SMatthew G. Knepley         species[p] = s;
1696*918dfc20SMatthew G. Knepley         cellid[p]  = c;
1697*918dfc20SMatthew G. Knepley       }
1698*918dfc20SMatthew G. Knepley     }
1699*918dfc20SMatthew G. Knepley   }
1700*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
1701*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, cellidname, NULL, NULL, (void **)&cellid));
1702*918dfc20SMatthew G. Knepley 
1703*918dfc20SMatthew G. Knepley   // Set particle coordinates
1704*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1705*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
1706*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
1707*918dfc20SMatthew G. Knepley   PetscCall(DMGetBoundingBox(vdm, vmin, vmax));
1708*918dfc20SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(xdm));
1709*918dfc20SMatthew G. Knepley   for (PetscInt c = 0; c < xcEnd - xcStart; ++c) {
1710*918dfc20SMatthew G. Knepley     const PetscInt cell = c + xcStart;
1711*918dfc20SMatthew G. Knepley     PetscInt      *pidx, Npc;
1712*918dfc20SMatthew G. Knepley     PetscReal      centroid[3], volume;
1713*918dfc20SMatthew G. Knepley 
1714*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
1715*918dfc20SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFVM(xdm, cell, &volume, centroid, NULL));
1716*918dfc20SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
1717*918dfc20SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q) {
1718*918dfc20SMatthew G. Knepley         const PetscInt p = pidx[q * Ns + s];
1719*918dfc20SMatthew G. Knepley 
1720*918dfc20SMatthew G. Knepley         for (PetscInt d = 0; d < dim; ++d) {
1721*918dfc20SMatthew G. Knepley           x[p * dim + d] = centroid[d];
1722*918dfc20SMatthew G. Knepley           v[p * dim + d] = vmin[0] + (q + 0.5) * ((vmax[0] - vmin[0]) / (Npc / Ns));
1723*918dfc20SMatthew G. Knepley         }
1724*918dfc20SMatthew G. Knepley         if (debug > 1) {
1725*918dfc20SMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "Particle %4" PetscInt_FMT " ", p));
1726*918dfc20SMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  x: ("));
1727*918dfc20SMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
1728*918dfc20SMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
1729*918dfc20SMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", x[p * dim + d]));
1730*918dfc20SMatthew G. Knepley           }
1731*918dfc20SMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ") v:("));
1732*918dfc20SMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
1733*918dfc20SMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
1734*918dfc20SMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", v[p * dim + d]));
1735*918dfc20SMatthew G. Knepley           }
1736*918dfc20SMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
1737*918dfc20SMatthew G. Knepley         }
1738*918dfc20SMatthew G. Knepley       }
1739*918dfc20SMatthew G. Knepley     }
1740*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
1741*918dfc20SMatthew G. Knepley   }
1742*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
1743*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
1744*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
1745*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1746*918dfc20SMatthew G. Knepley }
1747*918dfc20SMatthew G. Knepley 
1748*918dfc20SMatthew G. Knepley /*
1749*918dfc20SMatthew G. Knepley   InitializeWeights - Compute weight for each local particle
1750*918dfc20SMatthew G. Knepley 
1751*918dfc20SMatthew G. Knepley   Input Parameters:
1752*918dfc20SMatthew G. Knepley + sw          - The `DMSwarm`
1753*918dfc20SMatthew G. Knepley . totalWeight - The sum of all particle weights
1754*918dfc20SMatthew G. Knepley . func        - The PDF for the particle spatial distribution
1755*918dfc20SMatthew G. Knepley - param       - The PDF parameters
1756*918dfc20SMatthew G. Knepley 
1757*918dfc20SMatthew G. Knepley   Notes:
1758*918dfc20SMatthew G. Knepley   The PDF for velocity is assumed to be a Gaussian
1759*918dfc20SMatthew G. Knepley 
1760*918dfc20SMatthew G. Knepley   The particle weights are returned in the `w_q` field of `sw`.
1761*918dfc20SMatthew G. Knepley */
1762*918dfc20SMatthew G. Knepley static PetscErrorCode InitializeWeights(DM sw, PetscReal totalWeight, PetscProbFn *func, const PetscReal param[])
1763*918dfc20SMatthew G. Knepley {
1764*918dfc20SMatthew G. Knepley   DM               xdm, vdm;
1765*918dfc20SMatthew G. Knepley   DMSwarmCellDM    celldm;
1766*918dfc20SMatthew G. Knepley   PetscScalar     *weight;
1767*918dfc20SMatthew G. Knepley   PetscQuadrature  xquad;
1768*918dfc20SMatthew G. Knepley   const PetscReal *xq, *xwq;
1769*918dfc20SMatthew G. Knepley   const PetscInt   order = 5;
1770*918dfc20SMatthew G. Knepley   PetscReal        xi0[3];
1771*918dfc20SMatthew G. Knepley   PetscReal        xwtot = 0., pwtot = 0.;
1772*918dfc20SMatthew G. Knepley   PetscInt         xNq;
1773*918dfc20SMatthew G. Knepley   PetscInt         dim, Ns, xcStart, xcEnd, vcStart, vcEnd, debug = ((DM_Swarm *)sw->data)->printWeights;
1774*918dfc20SMatthew G. Knepley   MPI_Comm         comm;
1775*918dfc20SMatthew G. Knepley   PetscMPIInt      rank;
1776*918dfc20SMatthew G. Knepley 
1777*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1778*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
1779*918dfc20SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1780*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1781*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
1782*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
1783*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
1784*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
1785*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
1786*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
1787*918dfc20SMatthew G. Knepley 
1788*918dfc20SMatthew G. Knepley   // Setup Quadrature for spatial and velocity weight calculations
1789*918dfc20SMatthew G. Knepley   PetscCall(PetscDTGaussTensorQuadrature(dim, 1, order, -1.0, 1.0, &xquad));
1790*918dfc20SMatthew G. Knepley   PetscCall(PetscQuadratureGetData(xquad, NULL, NULL, &xNq, &xq, &xwq));
1791*918dfc20SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) xi0[d] = -1.0;
1792*918dfc20SMatthew G. Knepley 
1793*918dfc20SMatthew G. Knepley   // Integrate the density function to get the weights of particles in each cell
1794*918dfc20SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(vdm));
1795*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
1796*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
1797*918dfc20SMatthew G. Knepley   for (PetscInt c = xcStart; c < xcEnd; ++c) {
1798*918dfc20SMatthew G. Knepley     PetscReal          xv0[3], xJ[9], xinvJ[9], xdetJ, xqr[3], xden, xw = 0.;
1799*918dfc20SMatthew G. Knepley     PetscInt          *pidx, Npc;
1800*918dfc20SMatthew G. Knepley     PetscInt           xNc;
1801*918dfc20SMatthew G. Knepley     const PetscScalar *xarray;
1802*918dfc20SMatthew G. Knepley     PetscScalar       *xcoords = NULL;
1803*918dfc20SMatthew G. Knepley     PetscBool          xisDG;
1804*918dfc20SMatthew G. Knepley 
1805*918dfc20SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
1806*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
1807*918dfc20SMatthew 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);
1808*918dfc20SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFEM(xdm, c, NULL, xv0, xJ, xinvJ, &xdetJ));
1809*918dfc20SMatthew G. Knepley     for (PetscInt q = 0; q < xNq; ++q) {
1810*918dfc20SMatthew G. Knepley       // Transform quadrature points from ref space to real space
1811*918dfc20SMatthew G. Knepley       CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xq[q * dim], xqr);
1812*918dfc20SMatthew G. Knepley       // Get probability density at quad point
1813*918dfc20SMatthew G. Knepley       //   No need to scale xqr since PDF will be periodic
1814*918dfc20SMatthew G. Knepley       PetscCall((*func)(xqr, param, &xden));
1815*918dfc20SMatthew G. Knepley       xw += xden * (xwq[q] * xdetJ);
1816*918dfc20SMatthew G. Knepley     }
1817*918dfc20SMatthew G. Knepley     xwtot += xw;
1818*918dfc20SMatthew G. Knepley     if (debug) {
1819*918dfc20SMatthew G. Knepley       IS              globalOrdering;
1820*918dfc20SMatthew G. Knepley       const PetscInt *ordering;
1821*918dfc20SMatthew G. Knepley 
1822*918dfc20SMatthew G. Knepley       PetscCall(DMPlexGetCellNumbering(xdm, &globalOrdering));
1823*918dfc20SMatthew G. Knepley       PetscCall(ISGetIndices(globalOrdering, &ordering));
1824*918dfc20SMatthew 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));
1825*918dfc20SMatthew G. Knepley       PetscCall(ISRestoreIndices(globalOrdering, &ordering));
1826*918dfc20SMatthew G. Knepley     }
1827*918dfc20SMatthew G. Knepley     // Set weights to be Gaussian in velocity cells
1828*918dfc20SMatthew G. Knepley     for (PetscInt vc = vcStart; vc < vcEnd; ++vc) {
1829*918dfc20SMatthew G. Knepley       const PetscInt     p  = pidx[vc * Ns + 0];
1830*918dfc20SMatthew G. Knepley       PetscReal          vw = 0.;
1831*918dfc20SMatthew G. Knepley       PetscInt           vNc;
1832*918dfc20SMatthew G. Knepley       const PetscScalar *varray;
1833*918dfc20SMatthew G. Knepley       PetscScalar       *vcoords = NULL;
1834*918dfc20SMatthew G. Knepley       PetscBool          visDG;
1835*918dfc20SMatthew G. Knepley 
1836*918dfc20SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
1837*918dfc20SMatthew G. Knepley       // TODO: Fix 2 stream Ask Joe
1838*918dfc20SMatthew G. Knepley       //   Two stream function from 1/2pi v^2 e^(-v^2/2)
1839*918dfc20SMatthew 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.)));
1840*918dfc20SMatthew G. Knepley       vw = 0.5 * (PetscErfReal(vcoords[1] / PetscSqrtReal(2.)) - PetscErfReal(vcoords[0] / PetscSqrtReal(2.)));
1841*918dfc20SMatthew G. Knepley 
1842*918dfc20SMatthew G. Knepley       weight[p] = totalWeight * vw * xw;
1843*918dfc20SMatthew G. Knepley       pwtot += weight[p];
1844*918dfc20SMatthew 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);
1845*918dfc20SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
1846*918dfc20SMatthew G. Knepley       if (debug > 1) PetscCall(PetscPrintf(comm, "particle %" PetscInt_FMT ": %g, vw: %g xw: %g\n", p, weight[p], vw, xw));
1847*918dfc20SMatthew G. Knepley     }
1848*918dfc20SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
1849*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
1850*918dfc20SMatthew G. Knepley   }
1851*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
1852*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
1853*918dfc20SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&xquad));
1854*918dfc20SMatthew G. Knepley 
1855*918dfc20SMatthew G. Knepley   if (debug) {
1856*918dfc20SMatthew G. Knepley     PetscReal wtot[2] = {pwtot, xwtot}, gwtot[2];
1857*918dfc20SMatthew G. Knepley 
1858*918dfc20SMatthew G. Knepley     PetscCall(PetscSynchronizedFlush(comm, NULL));
1859*918dfc20SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(wtot, gwtot, 2, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
1860*918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "particle weight sum = %1.10f cell weight sum = %1.10f\n", (double)gwtot[0], (double)gwtot[1]));
1861*918dfc20SMatthew G. Knepley   }
1862*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1863*918dfc20SMatthew G. Knepley }
1864*918dfc20SMatthew G. Knepley 
1865*918dfc20SMatthew G. Knepley static PetscErrorCode InitializeParticles_PerturbedWeights(DM sw, AppCtx *user)
1866*918dfc20SMatthew G. Knepley {
1867*918dfc20SMatthew G. Knepley   PetscReal scale[2] = {user->cosine_coefficients[0], user->cosine_coefficients[1]};
1868*918dfc20SMatthew G. Knepley   PetscInt  dim;
1869*918dfc20SMatthew G. Knepley 
1870*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1871*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1872*918dfc20SMatthew G. Knepley   PetscCall(InitializeParticles_Centroid(sw));
1873*918dfc20SMatthew G. Knepley   PetscCall(InitializeWeights(sw, user->totalWeight, dim == 1 ? PetscPDFCosine1D : PetscPDFCosine2D, scale));
1874*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1875*918dfc20SMatthew G. Knepley }
1876*918dfc20SMatthew G. Knepley 
1877*918dfc20SMatthew G. Knepley static PetscErrorCode InitializeConstants(DM sw, AppCtx *user)
1878*918dfc20SMatthew G. Knepley {
1879*918dfc20SMatthew G. Knepley   DM         dm;
1880*918dfc20SMatthew G. Knepley   PetscInt  *species;
1881*918dfc20SMatthew G. Knepley   PetscReal *weight, totalCharge = 0., totalWeight = 0., gmin[3], gmax[3], global_charge, global_weight;
1882*918dfc20SMatthew G. Knepley   PetscInt   Np, dim;
1883*918dfc20SMatthew G. Knepley 
1884*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
1885*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &dm));
1886*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1887*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
1888*918dfc20SMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, gmin, gmax));
1889*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
1890*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
1891*918dfc20SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
1892*918dfc20SMatthew G. Knepley     totalWeight += weight[p];
1893*918dfc20SMatthew G. Knepley     totalCharge += user->charges[species[p]] * weight[p];
1894*918dfc20SMatthew G. Knepley   }
1895*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
1896*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
1897*918dfc20SMatthew G. Knepley   {
1898*918dfc20SMatthew G. Knepley     Parameter *param;
1899*918dfc20SMatthew G. Knepley     PetscReal  Area;
1900*918dfc20SMatthew G. Knepley 
1901*918dfc20SMatthew G. Knepley     PetscCall(PetscBagGetData(user->bag, (void **)&param));
1902*918dfc20SMatthew G. Knepley     switch (dim) {
1903*918dfc20SMatthew G. Knepley     case 1:
1904*918dfc20SMatthew G. Knepley       Area = (gmax[0] - gmin[0]);
1905*918dfc20SMatthew G. Knepley       break;
1906*918dfc20SMatthew G. Knepley     case 2:
1907*918dfc20SMatthew G. Knepley       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]);
1908*918dfc20SMatthew G. Knepley       break;
1909*918dfc20SMatthew G. Knepley     case 3:
1910*918dfc20SMatthew G. Knepley       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]) * (gmax[2] - gmin[2]);
1911*918dfc20SMatthew G. Knepley       break;
1912*918dfc20SMatthew G. Knepley     default:
1913*918dfc20SMatthew G. Knepley       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", dim);
1914*918dfc20SMatthew G. Knepley     }
1915*918dfc20SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&totalWeight, &global_weight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
1916*918dfc20SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&totalCharge, &global_charge, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
1917*918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "dim = %" PetscInt_FMT "\ttotalWeight = %f, user->charges[species[0]] = %f\ttotalCharge = %f, Total Area = %f\n", dim, (double)global_weight, (double)user->charges[0], (double)global_charge, (double)Area));
1918*918dfc20SMatthew G. Knepley     param->sigma = PetscAbsReal(global_charge / (Area));
1919*918dfc20SMatthew G. Knepley 
1920*918dfc20SMatthew G. Knepley     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "sigma: %g\n", (double)param->sigma));
1921*918dfc20SMatthew 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,
1922*918dfc20SMatthew G. Knepley                           (double)param->vlasovNumber));
1923*918dfc20SMatthew G. Knepley   }
1924*918dfc20SMatthew G. Knepley   /* Setup Constants */
1925*918dfc20SMatthew G. Knepley   {
1926*918dfc20SMatthew G. Knepley     PetscDS    ds;
1927*918dfc20SMatthew G. Knepley     Parameter *param;
1928*918dfc20SMatthew G. Knepley     PetscCall(PetscBagGetData(user->bag, (void **)&param));
1929*918dfc20SMatthew G. Knepley     PetscScalar constants[NUM_CONSTANTS];
1930*918dfc20SMatthew G. Knepley     constants[SIGMA]   = param->sigma;
1931*918dfc20SMatthew G. Knepley     constants[V0]      = param->v0;
1932*918dfc20SMatthew G. Knepley     constants[T0]      = param->t0;
1933*918dfc20SMatthew G. Knepley     constants[X0]      = param->x0;
1934*918dfc20SMatthew G. Knepley     constants[M0]      = param->m0;
1935*918dfc20SMatthew G. Knepley     constants[Q0]      = param->q0;
1936*918dfc20SMatthew G. Knepley     constants[PHI0]    = param->phi0;
1937*918dfc20SMatthew G. Knepley     constants[POISSON] = param->poissonNumber;
1938*918dfc20SMatthew G. Knepley     constants[VLASOV]  = param->vlasovNumber;
1939*918dfc20SMatthew G. Knepley     PetscCall(DMGetDS(dm, &ds));
1940*918dfc20SMatthew G. Knepley     PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants));
1941*918dfc20SMatthew G. Knepley   }
1942*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1943*918dfc20SMatthew G. Knepley }
1944*918dfc20SMatthew G. Knepley 
1945*918dfc20SMatthew G. Knepley static PetscErrorCode CreateSwarm(DM dm, AppCtx *user, DM *sw)
1946*918dfc20SMatthew G. Knepley {
1947*918dfc20SMatthew G. Knepley   DMSwarmCellDM celldm;
1948*918dfc20SMatthew G. Knepley   DM            vdm;
1949*918dfc20SMatthew G. Knepley   PetscReal     v0[2] = {1., 0.};
1950*918dfc20SMatthew G. Knepley   PetscInt      dim;
1951*918dfc20SMatthew G. Knepley 
1952*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
1953*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
1954*918dfc20SMatthew G. Knepley   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw));
1955*918dfc20SMatthew G. Knepley   PetscCall(DMSetType(*sw, DMSWARM));
1956*918dfc20SMatthew G. Knepley   PetscCall(DMSetDimension(*sw, dim));
1957*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC));
1958*918dfc20SMatthew G. Knepley   PetscCall(DMSetApplicationContext(*sw, user));
1959*918dfc20SMatthew G. Knepley 
1960*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR));
1961*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL));
1962*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "species", 1, PETSC_INT));
1963*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "E_field", dim, PETSC_REAL));
1964*918dfc20SMatthew G. Knepley 
1965*918dfc20SMatthew G. Knepley   const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"};
1966*918dfc20SMatthew G. Knepley 
1967*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(dm, 2, fieldnames, 1, fieldnames, &celldm));
1968*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
1969*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
1970*918dfc20SMatthew G. Knepley 
1971*918dfc20SMatthew G. Knepley   const char *vfieldnames[2] = {"w_q"};
1972*918dfc20SMatthew G. Knepley 
1973*918dfc20SMatthew G. Knepley   PetscCall(CreateVelocityDM(*sw, &vdm));
1974*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(vdm, 1, vfieldnames, 1, &fieldnames[1], &celldm));
1975*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
1976*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
1977*918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&vdm));
1978*918dfc20SMatthew G. Knepley 
1979*918dfc20SMatthew G. Knepley   DM mdm;
1980*918dfc20SMatthew G. Knepley 
1981*918dfc20SMatthew G. Knepley   PetscCall(DMClone(dm, &mdm));
1982*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)mdm, "moments"));
1983*918dfc20SMatthew G. Knepley   PetscCall(DMCopyDisc(dm, mdm));
1984*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(mdm, 1, vfieldnames, 1, fieldnames, &celldm));
1985*918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&mdm));
1986*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
1987*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
1988*918dfc20SMatthew G. Knepley 
1989*918dfc20SMatthew G. Knepley   DM mfdm;
1990*918dfc20SMatthew G. Knepley 
1991*918dfc20SMatthew G. Knepley   PetscCall(DMClone(dm, &mfdm));
1992*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)mfdm, "moment fields"));
1993*918dfc20SMatthew G. Knepley   PetscCall(DMCopyDisc(dm, mfdm));
1994*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(mfdm, 1, &fieldnames[1], 1, fieldnames, &celldm));
1995*918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&mfdm));
1996*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
1997*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
1998*918dfc20SMatthew G. Knepley 
1999*918dfc20SMatthew G. Knepley   PetscCall(DMSetFromOptions(*sw));
2000*918dfc20SMatthew G. Knepley   PetscCall(DMSetUp(*sw));
2001*918dfc20SMatthew G. Knepley 
2002*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(*sw, "space"));
2003*918dfc20SMatthew G. Knepley   user->swarm = *sw;
2004*918dfc20SMatthew G. Knepley   // TODO: This is redundant init since it is done in InitializeSolveAndSwarm, however DMSetUp() requires the local size be set
2005*918dfc20SMatthew G. Knepley   if (user->perturbed_weights) {
2006*918dfc20SMatthew G. Knepley     PetscCall(InitializeParticles_PerturbedWeights(*sw, user));
2007*918dfc20SMatthew G. Knepley   } else {
2008*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmComputeLocalSizeFromOptions(*sw));
2009*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmInitializeCoordinates(*sw));
2010*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmInitializeVelocitiesFromOptions(*sw, v0));
2011*918dfc20SMatthew G. Knepley   }
2012*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles"));
2013*918dfc20SMatthew G. Knepley   PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view"));
2014*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2015*918dfc20SMatthew G. Knepley }
2016*918dfc20SMatthew G. Knepley 
2017*918dfc20SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Coulomb(SNES snes, DM sw, PetscReal E[])
2018*918dfc20SMatthew G. Knepley {
2019*918dfc20SMatthew G. Knepley   AppCtx     *user;
2020*918dfc20SMatthew G. Knepley   PetscReal  *coords;
2021*918dfc20SMatthew G. Knepley   PetscInt   *species, dim, Np, Ns;
2022*918dfc20SMatthew G. Knepley   PetscMPIInt size;
2023*918dfc20SMatthew G. Knepley 
2024*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2025*918dfc20SMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)snes), &size));
2026*918dfc20SMatthew G. Knepley   PetscCheck(size == 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Coulomb code only works in serial");
2027*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2028*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2029*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
2030*918dfc20SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, (void *)&user));
2031*918dfc20SMatthew G. Knepley 
2032*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2033*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
2034*918dfc20SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
2035*918dfc20SMatthew G. Knepley     PetscReal *pcoord = &coords[p * dim];
2036*918dfc20SMatthew G. Knepley     PetscReal  pE[3]  = {0., 0., 0.};
2037*918dfc20SMatthew G. Knepley 
2038*918dfc20SMatthew G. Knepley     /* Calculate field at particle p due to particle q */
2039*918dfc20SMatthew G. Knepley     for (PetscInt q = 0; q < Np; ++q) {
2040*918dfc20SMatthew G. Knepley       PetscReal *qcoord = &coords[q * dim];
2041*918dfc20SMatthew G. Knepley       PetscReal  rpq[3], r, r3, q_q;
2042*918dfc20SMatthew G. Knepley 
2043*918dfc20SMatthew G. Knepley       if (p == q) continue;
2044*918dfc20SMatthew G. Knepley       q_q = user->charges[species[q]] * 1.;
2045*918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) rpq[d] = pcoord[d] - qcoord[d];
2046*918dfc20SMatthew G. Knepley       r = DMPlex_NormD_Internal(dim, rpq);
2047*918dfc20SMatthew G. Knepley       if (r < PETSC_SQRT_MACHINE_EPSILON) continue;
2048*918dfc20SMatthew G. Knepley       r3 = PetscPowRealInt(r, 3);
2049*918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) pE[d] += q_q * rpq[d] / r3;
2050*918dfc20SMatthew G. Knepley     }
2051*918dfc20SMatthew G. Knepley     for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = pE[d];
2052*918dfc20SMatthew G. Knepley   }
2053*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
2054*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2055*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2056*918dfc20SMatthew G. Knepley }
2057*918dfc20SMatthew G. Knepley 
2058*918dfc20SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Primal(SNES snes, DM sw, Mat M_p, PetscReal E[])
2059*918dfc20SMatthew G. Knepley {
2060*918dfc20SMatthew G. Knepley   DM         dm;
2061*918dfc20SMatthew G. Knepley   AppCtx    *user;
2062*918dfc20SMatthew G. Knepley   PetscDS    ds;
2063*918dfc20SMatthew G. Knepley   PetscFE    fe;
2064*918dfc20SMatthew G. Knepley   KSP        ksp;
2065*918dfc20SMatthew G. Knepley   Vec        rhoRhs;      // Weak charge density, \int phi_i rho
2066*918dfc20SMatthew G. Knepley   Vec        rho;         // Charge density, M^{-1} rhoRhs
2067*918dfc20SMatthew G. Knepley   Vec        phi, locPhi; // Potential
2068*918dfc20SMatthew G. Knepley   Vec        f;           // Particle weights
2069*918dfc20SMatthew G. Knepley   PetscReal *coords;
2070*918dfc20SMatthew G. Knepley   PetscInt   dim, cStart, cEnd, Np;
2071*918dfc20SMatthew G. Knepley 
2072*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2073*918dfc20SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, (void *)&user));
2074*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
2075*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2076*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2077*918dfc20SMatthew G. Knepley 
2078*918dfc20SMatthew G. Knepley   PetscCall(SNESGetDM(snes, &dm));
2079*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhs));
2080*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
2081*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
2082*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
2083*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
2084*918dfc20SMatthew G. Knepley 
2085*918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
2086*918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->M, NULL, "-m_view"));
2087*918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
2088*918dfc20SMatthew G. Knepley 
2089*918dfc20SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
2090*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
2091*918dfc20SMatthew G. Knepley 
2092*918dfc20SMatthew G. Knepley   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
2093*918dfc20SMatthew G. Knepley   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj_"));
2094*918dfc20SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->M, user->M));
2095*918dfc20SMatthew G. Knepley   PetscCall(KSPSetFromOptions(ksp));
2096*918dfc20SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
2097*918dfc20SMatthew G. Knepley 
2098*918dfc20SMatthew G. Knepley   PetscCall(VecScale(rhoRhs, -1.0));
2099*918dfc20SMatthew G. Knepley 
2100*918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
2101*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
2102*918dfc20SMatthew G. Knepley   PetscCall(KSPDestroy(&ksp));
2103*918dfc20SMatthew G. Knepley 
2104*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
2105*918dfc20SMatthew G. Knepley   PetscCall(VecSet(phi, 0.0));
2106*918dfc20SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhs, phi));
2107*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhs));
2108*918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
2109*918dfc20SMatthew G. Knepley 
2110*918dfc20SMatthew G. Knepley   PetscCall(DMGetLocalVector(dm, &locPhi));
2111*918dfc20SMatthew G. Knepley   PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi));
2112*918dfc20SMatthew G. Knepley   PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi));
2113*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
2114*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
2115*918dfc20SMatthew G. Knepley 
2116*918dfc20SMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
2117*918dfc20SMatthew G. Knepley   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
2118*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
2119*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2120*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2121*918dfc20SMatthew G. Knepley 
2122*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
2123*918dfc20SMatthew G. Knepley   PetscTabulation tab;
2124*918dfc20SMatthew G. Knepley   PetscReal      *pcoord, *refcoord;
2125*918dfc20SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
2126*918dfc20SMatthew G. Knepley   PetscInt        maxNcp    = 0;
2127*918dfc20SMatthew G. Knepley 
2128*918dfc20SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
2129*918dfc20SMatthew G. Knepley     PetscInt Ncp;
2130*918dfc20SMatthew G. Knepley 
2131*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
2132*918dfc20SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
2133*918dfc20SMatthew G. Knepley   }
2134*918dfc20SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
2135*918dfc20SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
2136*918dfc20SMatthew G. Knepley   // This can raise an FP_INEXACT in the dgemm inside
2137*918dfc20SMatthew G. Knepley   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
2138*918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
2139*918dfc20SMatthew G. Knepley   PetscCall(PetscFPTrapPop());
2140*918dfc20SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
2141*918dfc20SMatthew G. Knepley     PetscScalar *clPhi = NULL;
2142*918dfc20SMatthew G. Knepley     PetscInt    *points;
2143*918dfc20SMatthew G. Knepley     PetscInt     Ncp;
2144*918dfc20SMatthew G. Knepley 
2145*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
2146*918dfc20SMatthew G. Knepley     for (PetscInt cp = 0; cp < Ncp; ++cp)
2147*918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
2148*918dfc20SMatthew G. Knepley     {
2149*918dfc20SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
2150*918dfc20SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
2151*918dfc20SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
2152*918dfc20SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
2153*918dfc20SMatthew G. Knepley       }
2154*918dfc20SMatthew G. Knepley     }
2155*918dfc20SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
2156*918dfc20SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
2157*918dfc20SMatthew G. Knepley     for (PetscInt cp = 0; cp < Ncp; ++cp) {
2158*918dfc20SMatthew G. Knepley       const PetscReal *basisDer = tab->T[1];
2159*918dfc20SMatthew G. Knepley       const PetscInt   p        = points[cp];
2160*918dfc20SMatthew G. Knepley 
2161*918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
2162*918dfc20SMatthew G. Knepley       PetscCall(PetscFEFreeInterpolateGradient_Static(fe, basisDer, clPhi, dim, chunkgeom->invJ, NULL, cp, &E[p * dim]));
2163*918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
2164*918dfc20SMatthew G. Knepley     }
2165*918dfc20SMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
2166*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
2167*918dfc20SMatthew G. Knepley   }
2168*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
2169*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
2170*918dfc20SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
2171*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2172*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
2173*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreLocalVector(dm, &locPhi));
2174*918dfc20SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
2175*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
2176*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2177*918dfc20SMatthew G. Knepley }
2178*918dfc20SMatthew G. Knepley 
2179*918dfc20SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Mixed(SNES snes, DM sw, Mat M_p, PetscReal E[])
2180*918dfc20SMatthew G. Knepley {
2181*918dfc20SMatthew G. Knepley   DM         dm;
2182*918dfc20SMatthew G. Knepley   AppCtx    *user;
2183*918dfc20SMatthew G. Knepley   PetscDS    ds;
2184*918dfc20SMatthew G. Knepley   PetscFE    fe;
2185*918dfc20SMatthew G. Knepley   KSP        ksp;
2186*918dfc20SMatthew G. Knepley   Vec        rhoRhs, rhoRhsFull;   // Weak charge density, \int phi_i rho, and embedding in mixed problem
2187*918dfc20SMatthew G. Knepley   Vec        rho;                  // Charge density, M^{-1} rhoRhs
2188*918dfc20SMatthew G. Knepley   Vec        phi, locPhi, phiFull; // Potential and embedding in mixed problem
2189*918dfc20SMatthew G. Knepley   Vec        f;                    // Particle weights
2190*918dfc20SMatthew G. Knepley   PetscReal *coords;
2191*918dfc20SMatthew G. Knepley   PetscInt   dim, cStart, cEnd, Np;
2192*918dfc20SMatthew G. Knepley 
2193*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2194*918dfc20SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &user));
2195*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
2196*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2197*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2198*918dfc20SMatthew G. Knepley 
2199*918dfc20SMatthew G. Knepley   PetscCall(SNESGetDM(snes, &dm));
2200*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(user->dmPot, &rhoRhs));
2201*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
2202*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhsFull));
2203*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhsFull, "Weak charge density"));
2204*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
2205*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
2206*918dfc20SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
2207*918dfc20SMatthew G. Knepley 
2208*918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
2209*918dfc20SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->M, NULL, "-m_view"));
2210*918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
2211*918dfc20SMatthew G. Knepley 
2212*918dfc20SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
2213*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
2214*918dfc20SMatthew G. Knepley 
2215*918dfc20SMatthew G. Knepley   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
2216*918dfc20SMatthew G. Knepley   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj"));
2217*918dfc20SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->M, user->M));
2218*918dfc20SMatthew G. Knepley   PetscCall(KSPSetFromOptions(ksp));
2219*918dfc20SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
2220*918dfc20SMatthew G. Knepley 
2221*918dfc20SMatthew G. Knepley   PetscCall(VecISCopy(rhoRhsFull, user->isPot, SCATTER_FORWARD, rhoRhs));
2222*918dfc20SMatthew G. Knepley   //PetscCall(VecScale(rhoRhsFull, -1.0));
2223*918dfc20SMatthew G. Knepley 
2224*918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
2225*918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhsFull, NULL, "-rho_full_view"));
2226*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
2227*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(user->dmPot, &rhoRhs));
2228*918dfc20SMatthew G. Knepley   PetscCall(KSPDestroy(&ksp));
2229*918dfc20SMatthew G. Knepley 
2230*918dfc20SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &phiFull));
2231*918dfc20SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
2232*918dfc20SMatthew G. Knepley   PetscCall(VecSet(phiFull, 0.0));
2233*918dfc20SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhsFull, phiFull));
2234*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhsFull));
2235*918dfc20SMatthew G. Knepley   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
2236*918dfc20SMatthew G. Knepley 
2237*918dfc20SMatthew G. Knepley   PetscCall(VecISCopy(phiFull, user->isPot, SCATTER_REVERSE, phi));
2238*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
2239*918dfc20SMatthew G. Knepley 
2240*918dfc20SMatthew G. Knepley   PetscCall(DMGetLocalVector(dm, &locPhi));
2241*918dfc20SMatthew G. Knepley   PetscCall(DMGlobalToLocalBegin(dm, phiFull, INSERT_VALUES, locPhi));
2242*918dfc20SMatthew G. Knepley   PetscCall(DMGlobalToLocalEnd(dm, phiFull, INSERT_VALUES, locPhi));
2243*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &phiFull));
2244*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
2245*918dfc20SMatthew G. Knepley 
2246*918dfc20SMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
2247*918dfc20SMatthew G. Knepley   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
2248*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
2249*918dfc20SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2250*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2251*918dfc20SMatthew G. Knepley 
2252*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
2253*918dfc20SMatthew G. Knepley   PetscTabulation tab;
2254*918dfc20SMatthew G. Knepley   PetscReal      *pcoord, *refcoord;
2255*918dfc20SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
2256*918dfc20SMatthew G. Knepley   PetscInt        maxNcp    = 0;
2257*918dfc20SMatthew G. Knepley 
2258*918dfc20SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
2259*918dfc20SMatthew G. Knepley     PetscInt Ncp;
2260*918dfc20SMatthew G. Knepley 
2261*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
2262*918dfc20SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
2263*918dfc20SMatthew G. Knepley   }
2264*918dfc20SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
2265*918dfc20SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
2266*918dfc20SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
2267*918dfc20SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
2268*918dfc20SMatthew G. Knepley     PetscScalar *clPhi = NULL;
2269*918dfc20SMatthew G. Knepley     PetscInt    *points;
2270*918dfc20SMatthew G. Knepley     PetscInt     Ncp;
2271*918dfc20SMatthew G. Knepley 
2272*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
2273*918dfc20SMatthew G. Knepley     for (PetscInt cp = 0; cp < Ncp; ++cp)
2274*918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
2275*918dfc20SMatthew G. Knepley     {
2276*918dfc20SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
2277*918dfc20SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
2278*918dfc20SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
2279*918dfc20SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
2280*918dfc20SMatthew G. Knepley       }
2281*918dfc20SMatthew G. Knepley     }
2282*918dfc20SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
2283*918dfc20SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
2284*918dfc20SMatthew G. Knepley     for (PetscInt cp = 0; cp < Ncp; ++cp) {
2285*918dfc20SMatthew G. Knepley       const PetscInt p = points[cp];
2286*918dfc20SMatthew G. Knepley 
2287*918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
2288*918dfc20SMatthew G. Knepley       PetscCall(PetscFEInterpolateAtPoints_Static(fe, tab, clPhi, chunkgeom, cp, &E[p * dim]));
2289*918dfc20SMatthew G. Knepley       PetscCall(PetscFEPushforward(fe, chunkgeom, 1, &E[p * dim]));
2290*918dfc20SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
2291*918dfc20SMatthew G. Knepley     }
2292*918dfc20SMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
2293*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
2294*918dfc20SMatthew G. Knepley   }
2295*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
2296*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
2297*918dfc20SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
2298*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2299*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
2300*918dfc20SMatthew G. Knepley   PetscCall(DMRestoreLocalVector(dm, &locPhi));
2301*918dfc20SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
2302*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
2303*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2304*918dfc20SMatthew G. Knepley }
2305*918dfc20SMatthew G. Knepley 
2306*918dfc20SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles(SNES snes, DM sw)
2307*918dfc20SMatthew G. Knepley {
2308*918dfc20SMatthew G. Knepley   AppCtx    *user;
2309*918dfc20SMatthew G. Knepley   Mat        M_p;
2310*918dfc20SMatthew G. Knepley   PetscReal *E;
2311*918dfc20SMatthew G. Knepley   PetscInt   dim, Np;
2312*918dfc20SMatthew G. Knepley 
2313*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2314*918dfc20SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2315*918dfc20SMatthew G. Knepley   PetscValidHeaderSpecific(sw, DM_CLASSID, 2);
2316*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2317*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2318*918dfc20SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &user));
2319*918dfc20SMatthew G. Knepley 
2320*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "moments"));
2321*918dfc20SMatthew G. Knepley   // TODO: Could share sort context with space cellDM
2322*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmMigrate(sw, PETSC_FALSE));
2323*918dfc20SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(sw, user->dmPot, &M_p));
2324*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
2325*918dfc20SMatthew G. Knepley 
2326*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
2327*918dfc20SMatthew G. Knepley   PetscCall(PetscArrayzero(E, Np * dim));
2328*918dfc20SMatthew G. Knepley   user->validE = PETSC_TRUE;
2329*918dfc20SMatthew G. Knepley 
2330*918dfc20SMatthew G. Knepley   switch (user->em) {
2331*918dfc20SMatthew G. Knepley   case EM_COULOMB:
2332*918dfc20SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Coulomb(snes, sw, E));
2333*918dfc20SMatthew G. Knepley     break;
2334*918dfc20SMatthew G. Knepley   case EMPRIMAL:
2335*918dfc20SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Primal(snes, sw, M_p, E));
2336*918dfc20SMatthew G. Knepley     break;
2337*918dfc20SMatthew G. Knepley   case EM_MIXED:
2338*918dfc20SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Mixed(snes, sw, M_p, E));
2339*918dfc20SMatthew G. Knepley     break;
2340*918dfc20SMatthew G. Knepley   case EMNONE:
2341*918dfc20SMatthew G. Knepley     break;
2342*918dfc20SMatthew G. Knepley   default:
2343*918dfc20SMatthew G. Knepley     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No solver for electrostatic model %s", EMTypes[user->em]);
2344*918dfc20SMatthew G. Knepley   }
2345*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
2346*918dfc20SMatthew G. Knepley   PetscCall(MatDestroy(&M_p));
2347*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2348*918dfc20SMatthew G. Knepley }
2349*918dfc20SMatthew G. Knepley 
2350*918dfc20SMatthew G. Knepley static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec G, void *ctx)
2351*918dfc20SMatthew G. Knepley {
2352*918dfc20SMatthew G. Knepley   DM                 sw;
2353*918dfc20SMatthew G. Knepley   SNES               snes = ((AppCtx *)ctx)->snes;
2354*918dfc20SMatthew G. Knepley   const PetscScalar *u;
2355*918dfc20SMatthew G. Knepley   PetscScalar       *g;
2356*918dfc20SMatthew G. Knepley   PetscReal         *E, m_p = 1., q_p = -1.;
2357*918dfc20SMatthew G. Knepley   PetscInt           dim, d, Np, p;
2358*918dfc20SMatthew G. Knepley 
2359*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2360*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2361*918dfc20SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
2362*918dfc20SMatthew G. Knepley 
2363*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2364*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2365*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
2366*918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(U, &u));
2367*918dfc20SMatthew G. Knepley   PetscCall(VecGetArray(G, &g));
2368*918dfc20SMatthew G. Knepley   Np /= 2 * dim;
2369*918dfc20SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
2370*918dfc20SMatthew G. Knepley     for (d = 0; d < dim; ++d) {
2371*918dfc20SMatthew G. Knepley       g[(p * 2 + 0) * dim + d] = u[(p * 2 + 1) * dim + d];
2372*918dfc20SMatthew G. Knepley       g[(p * 2 + 1) * dim + d] = q_p * E[p * dim + d] / m_p;
2373*918dfc20SMatthew G. Knepley     }
2374*918dfc20SMatthew G. Knepley   }
2375*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
2376*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(U, &u));
2377*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArray(G, &g));
2378*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2379*918dfc20SMatthew G. Knepley }
2380*918dfc20SMatthew G. Knepley 
2381*918dfc20SMatthew G. Knepley /* J_{ij} = dF_i/dx_j
2382*918dfc20SMatthew G. Knepley    J_p = (  0   1)
2383*918dfc20SMatthew G. Knepley          (-w^2  0)
2384*918dfc20SMatthew G. Knepley    TODO Now there is another term with w^2 from the electric field. I think we will need to invert the operator.
2385*918dfc20SMatthew G. Knepley         Perhaps we can approximate the Jacobian using only the cellwise P-P gradient from Coulomb
2386*918dfc20SMatthew G. Knepley */
2387*918dfc20SMatthew G. Knepley static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat P, void *ctx)
2388*918dfc20SMatthew G. Knepley {
2389*918dfc20SMatthew G. Knepley   DM               sw;
2390*918dfc20SMatthew G. Knepley   const PetscReal *coords, *vel;
2391*918dfc20SMatthew G. Knepley   PetscInt         dim, d, Np, p, rStart;
2392*918dfc20SMatthew G. Knepley 
2393*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2394*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2395*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2396*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2397*918dfc20SMatthew G. Knepley   PetscCall(MatGetOwnershipRange(J, &rStart, NULL));
2398*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2399*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
2400*918dfc20SMatthew G. Knepley   Np /= 2 * dim;
2401*918dfc20SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
2402*918dfc20SMatthew G. Knepley     const PetscReal x0      = coords[p * dim + 0];
2403*918dfc20SMatthew G. Knepley     const PetscReal vy0     = vel[p * dim + 1];
2404*918dfc20SMatthew G. Knepley     const PetscReal omega   = vy0 / x0;
2405*918dfc20SMatthew G. Knepley     PetscScalar     vals[4] = {0., 1., -PetscSqr(omega), 0.};
2406*918dfc20SMatthew G. Knepley 
2407*918dfc20SMatthew G. Knepley     for (d = 0; d < dim; ++d) {
2408*918dfc20SMatthew G. Knepley       const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart};
2409*918dfc20SMatthew G. Knepley       PetscCall(MatSetValues(J, 2, rows, 2, rows, vals, INSERT_VALUES));
2410*918dfc20SMatthew G. Knepley     }
2411*918dfc20SMatthew G. Knepley   }
2412*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2413*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
2414*918dfc20SMatthew G. Knepley   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
2415*918dfc20SMatthew G. Knepley   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
2416*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2417*918dfc20SMatthew G. Knepley }
2418*918dfc20SMatthew G. Knepley 
2419*918dfc20SMatthew G. Knepley static PetscErrorCode RHSFunctionX(TS ts, PetscReal t, Vec V, Vec Xres, void *ctx)
2420*918dfc20SMatthew G. Knepley {
2421*918dfc20SMatthew G. Knepley   AppCtx            *user = (AppCtx *)ctx;
2422*918dfc20SMatthew G. Knepley   DM                 sw;
2423*918dfc20SMatthew G. Knepley   const PetscScalar *v;
2424*918dfc20SMatthew G. Knepley   PetscScalar       *xres;
2425*918dfc20SMatthew G. Knepley   PetscInt           Np, p, d, dim;
2426*918dfc20SMatthew G. Knepley 
2427*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2428*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsXEvent, ts, 0, 0, 0));
2429*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2430*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2431*918dfc20SMatthew G. Knepley   PetscCall(VecGetLocalSize(Xres, &Np));
2432*918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(V, &v));
2433*918dfc20SMatthew G. Knepley   PetscCall(VecGetArray(Xres, &xres));
2434*918dfc20SMatthew G. Knepley   Np /= dim;
2435*918dfc20SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
2436*918dfc20SMatthew G. Knepley     for (d = 0; d < dim; ++d) xres[p * dim + d] = v[p * dim + d];
2437*918dfc20SMatthew G. Knepley   }
2438*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(V, &v));
2439*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArray(Xres, &xres));
2440*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsXEvent, ts, 0, 0, 0));
2441*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2442*918dfc20SMatthew G. Knepley }
2443*918dfc20SMatthew G. Knepley 
2444*918dfc20SMatthew G. Knepley static PetscErrorCode RHSFunctionV(TS ts, PetscReal t, Vec X, Vec Vres, void *ctx)
2445*918dfc20SMatthew G. Knepley {
2446*918dfc20SMatthew G. Knepley   DM                 sw;
2447*918dfc20SMatthew G. Knepley   AppCtx            *user = (AppCtx *)ctx;
2448*918dfc20SMatthew G. Knepley   SNES               snes = ((AppCtx *)ctx)->snes;
2449*918dfc20SMatthew G. Knepley   const PetscScalar *x;
2450*918dfc20SMatthew G. Knepley   PetscScalar       *vres;
2451*918dfc20SMatthew G. Knepley   PetscReal         *E, m_p, q_p;
2452*918dfc20SMatthew G. Knepley   PetscInt           Np, p, dim, d;
2453*918dfc20SMatthew G. Knepley   Parameter         *param;
2454*918dfc20SMatthew G. Knepley 
2455*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2456*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsVEvent, ts, 0, 0, 0));
2457*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2458*918dfc20SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
2459*918dfc20SMatthew G. Knepley 
2460*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2461*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
2462*918dfc20SMatthew G. Knepley   PetscCall(PetscBagGetData(user->bag, (void **)&param));
2463*918dfc20SMatthew G. Knepley   m_p = user->masses[0] * param->m0;
2464*918dfc20SMatthew G. Knepley   q_p = user->charges[0] * param->q0;
2465*918dfc20SMatthew G. Knepley   PetscCall(VecGetLocalSize(Vres, &Np));
2466*918dfc20SMatthew G. Knepley   PetscCall(VecGetArrayRead(X, &x));
2467*918dfc20SMatthew G. Knepley   PetscCall(VecGetArray(Vres, &vres));
2468*918dfc20SMatthew G. Knepley   Np /= dim;
2469*918dfc20SMatthew G. Knepley   for (p = 0; p < Np; ++p) {
2470*918dfc20SMatthew G. Knepley     for (d = 0; d < dim; ++d) vres[p * dim + d] = q_p * E[p * dim + d] / m_p;
2471*918dfc20SMatthew G. Knepley   }
2472*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArrayRead(X, &x));
2473*918dfc20SMatthew G. Knepley   /*
2474*918dfc20SMatthew G. Knepley     Synchronized, ordered output for parallel/sequential test cases.
2475*918dfc20SMatthew G. Knepley     In the 1D (on the 2D mesh) case, every y component should be zero.
2476*918dfc20SMatthew G. Knepley   */
2477*918dfc20SMatthew G. Knepley   if (user->checkVRes) {
2478*918dfc20SMatthew G. Knepley     PetscBool pr = user->checkVRes > 1 ? PETSC_TRUE : PETSC_FALSE;
2479*918dfc20SMatthew G. Knepley     PetscInt  step;
2480*918dfc20SMatthew G. Knepley 
2481*918dfc20SMatthew G. Knepley     PetscCall(TSGetStepNumber(ts, &step));
2482*918dfc20SMatthew G. Knepley     if (pr) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step: %" PetscInt_FMT "\n", step));
2483*918dfc20SMatthew G. Knepley     for (PetscInt p = 0; p < Np; ++p) {
2484*918dfc20SMatthew 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])));
2485*918dfc20SMatthew 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]));
2486*918dfc20SMatthew G. Knepley     }
2487*918dfc20SMatthew G. Knepley     if (pr) PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
2488*918dfc20SMatthew G. Knepley   }
2489*918dfc20SMatthew G. Knepley   PetscCall(VecRestoreArray(Vres, &vres));
2490*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
2491*918dfc20SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsVEvent, ts, 0, 0, 0));
2492*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2493*918dfc20SMatthew G. Knepley }
2494*918dfc20SMatthew G. Knepley 
2495*918dfc20SMatthew G. Knepley static PetscErrorCode CreateSolution(TS ts)
2496*918dfc20SMatthew G. Knepley {
2497*918dfc20SMatthew G. Knepley   DM       sw;
2498*918dfc20SMatthew G. Knepley   Vec      u;
2499*918dfc20SMatthew G. Knepley   PetscInt dim, Np;
2500*918dfc20SMatthew G. Knepley 
2501*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2502*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2503*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2504*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2505*918dfc20SMatthew G. Knepley   PetscCall(VecCreate(PETSC_COMM_WORLD, &u));
2506*918dfc20SMatthew G. Knepley   PetscCall(VecSetBlockSize(u, dim));
2507*918dfc20SMatthew G. Knepley   PetscCall(VecSetSizes(u, 2 * Np * dim, PETSC_DECIDE));
2508*918dfc20SMatthew G. Knepley   PetscCall(VecSetUp(u));
2509*918dfc20SMatthew G. Knepley   PetscCall(TSSetSolution(ts, u));
2510*918dfc20SMatthew G. Knepley   PetscCall(VecDestroy(&u));
2511*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2512*918dfc20SMatthew G. Knepley }
2513*918dfc20SMatthew G. Knepley 
2514*918dfc20SMatthew G. Knepley static PetscErrorCode SetProblem(TS ts)
2515*918dfc20SMatthew G. Knepley {
2516*918dfc20SMatthew G. Knepley   AppCtx *user;
2517*918dfc20SMatthew G. Knepley   DM      sw;
2518*918dfc20SMatthew G. Knepley 
2519*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2520*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2521*918dfc20SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, (void **)&user));
2522*918dfc20SMatthew G. Knepley   // Define unified system for (X, V)
2523*918dfc20SMatthew G. Knepley   {
2524*918dfc20SMatthew G. Knepley     Mat      J;
2525*918dfc20SMatthew G. Knepley     PetscInt dim, Np;
2526*918dfc20SMatthew G. Knepley 
2527*918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(sw, &dim));
2528*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetLocalSize(sw, &Np));
2529*918dfc20SMatthew G. Knepley     PetscCall(MatCreate(PETSC_COMM_WORLD, &J));
2530*918dfc20SMatthew G. Knepley     PetscCall(MatSetSizes(J, 2 * Np * dim, 2 * Np * dim, PETSC_DECIDE, PETSC_DECIDE));
2531*918dfc20SMatthew G. Knepley     PetscCall(MatSetBlockSize(J, 2 * dim));
2532*918dfc20SMatthew G. Knepley     PetscCall(MatSetFromOptions(J));
2533*918dfc20SMatthew G. Knepley     PetscCall(MatSetUp(J));
2534*918dfc20SMatthew G. Knepley     PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, user));
2535*918dfc20SMatthew G. Knepley     PetscCall(TSSetRHSJacobian(ts, J, J, RHSJacobian, user));
2536*918dfc20SMatthew G. Knepley     PetscCall(MatDestroy(&J));
2537*918dfc20SMatthew G. Knepley   }
2538*918dfc20SMatthew G. Knepley   /* Define split system for X and V */
2539*918dfc20SMatthew G. Knepley   {
2540*918dfc20SMatthew G. Knepley     Vec             u;
2541*918dfc20SMatthew G. Knepley     IS              isx, isv, istmp;
2542*918dfc20SMatthew G. Knepley     const PetscInt *idx;
2543*918dfc20SMatthew G. Knepley     PetscInt        dim, Np, rstart;
2544*918dfc20SMatthew G. Knepley 
2545*918dfc20SMatthew G. Knepley     PetscCall(TSGetSolution(ts, &u));
2546*918dfc20SMatthew G. Knepley     PetscCall(DMGetDimension(sw, &dim));
2547*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetLocalSize(sw, &Np));
2548*918dfc20SMatthew G. Knepley     PetscCall(VecGetOwnershipRange(u, &rstart, NULL));
2549*918dfc20SMatthew G. Knepley     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 0, 2, &istmp));
2550*918dfc20SMatthew G. Knepley     PetscCall(ISGetIndices(istmp, &idx));
2551*918dfc20SMatthew G. Knepley     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isx));
2552*918dfc20SMatthew G. Knepley     PetscCall(ISRestoreIndices(istmp, &idx));
2553*918dfc20SMatthew G. Knepley     PetscCall(ISDestroy(&istmp));
2554*918dfc20SMatthew G. Knepley     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 1, 2, &istmp));
2555*918dfc20SMatthew G. Knepley     PetscCall(ISGetIndices(istmp, &idx));
2556*918dfc20SMatthew G. Knepley     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isv));
2557*918dfc20SMatthew G. Knepley     PetscCall(ISRestoreIndices(istmp, &idx));
2558*918dfc20SMatthew G. Knepley     PetscCall(ISDestroy(&istmp));
2559*918dfc20SMatthew G. Knepley     PetscCall(TSRHSSplitSetIS(ts, "position", isx));
2560*918dfc20SMatthew G. Knepley     PetscCall(TSRHSSplitSetIS(ts, "momentum", isv));
2561*918dfc20SMatthew G. Knepley     PetscCall(ISDestroy(&isx));
2562*918dfc20SMatthew G. Knepley     PetscCall(ISDestroy(&isv));
2563*918dfc20SMatthew G. Knepley     PetscCall(TSRHSSplitSetRHSFunction(ts, "position", NULL, RHSFunctionX, user));
2564*918dfc20SMatthew G. Knepley     PetscCall(TSRHSSplitSetRHSFunction(ts, "momentum", NULL, RHSFunctionV, user));
2565*918dfc20SMatthew G. Knepley   }
2566*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2567*918dfc20SMatthew G. Knepley }
2568*918dfc20SMatthew G. Knepley 
2569*918dfc20SMatthew G. Knepley static PetscErrorCode DMSwarmTSRedistribute(TS ts)
2570*918dfc20SMatthew G. Knepley {
2571*918dfc20SMatthew G. Knepley   DM        sw;
2572*918dfc20SMatthew G. Knepley   Vec       u;
2573*918dfc20SMatthew G. Knepley   PetscReal t, maxt, dt;
2574*918dfc20SMatthew G. Knepley   PetscInt  n, maxn;
2575*918dfc20SMatthew G. Knepley 
2576*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2577*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2578*918dfc20SMatthew G. Knepley   PetscCall(TSGetTime(ts, &t));
2579*918dfc20SMatthew G. Knepley   PetscCall(TSGetMaxTime(ts, &maxt));
2580*918dfc20SMatthew G. Knepley   PetscCall(TSGetTimeStep(ts, &dt));
2581*918dfc20SMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &n));
2582*918dfc20SMatthew G. Knepley   PetscCall(TSGetMaxSteps(ts, &maxn));
2583*918dfc20SMatthew G. Knepley 
2584*918dfc20SMatthew G. Knepley   PetscCall(TSReset(ts));
2585*918dfc20SMatthew G. Knepley   PetscCall(TSSetDM(ts, sw));
2586*918dfc20SMatthew G. Knepley   PetscCall(TSSetFromOptions(ts));
2587*918dfc20SMatthew G. Knepley   PetscCall(TSSetTime(ts, t));
2588*918dfc20SMatthew G. Knepley   PetscCall(TSSetMaxTime(ts, maxt));
2589*918dfc20SMatthew G. Knepley   PetscCall(TSSetTimeStep(ts, dt));
2590*918dfc20SMatthew G. Knepley   PetscCall(TSSetStepNumber(ts, n));
2591*918dfc20SMatthew G. Knepley   PetscCall(TSSetMaxSteps(ts, maxn));
2592*918dfc20SMatthew G. Knepley 
2593*918dfc20SMatthew G. Knepley   PetscCall(CreateSolution(ts));
2594*918dfc20SMatthew G. Knepley   PetscCall(SetProblem(ts));
2595*918dfc20SMatthew G. Knepley   PetscCall(TSGetSolution(ts, &u));
2596*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2597*918dfc20SMatthew G. Knepley }
2598*918dfc20SMatthew G. Knepley 
2599*918dfc20SMatthew G. Knepley PetscErrorCode line(PetscInt dim, PetscReal time, const PetscReal dummy[], PetscInt p, PetscScalar x[], void *ctx)
2600*918dfc20SMatthew G. Knepley {
2601*918dfc20SMatthew G. Knepley   DM        sw, cdm;
2602*918dfc20SMatthew G. Knepley   PetscInt  Np;
2603*918dfc20SMatthew G. Knepley   PetscReal low[2], high[2];
2604*918dfc20SMatthew G. Knepley   AppCtx   *user = (AppCtx *)ctx;
2605*918dfc20SMatthew G. Knepley 
2606*918dfc20SMatthew G. Knepley   sw = user->swarm;
2607*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &cdm));
2608*918dfc20SMatthew G. Knepley   // Get the bounding box so we can equally space the particles
2609*918dfc20SMatthew G. Knepley   PetscCall(DMGetLocalBoundingBox(cdm, low, high));
2610*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2611*918dfc20SMatthew G. Knepley   // shift it by h/2 so nothing is initialized directly on a boundary
2612*918dfc20SMatthew G. Knepley   x[0] = ((high[0] - low[0]) / Np) * (p + 0.5);
2613*918dfc20SMatthew G. Knepley   x[1] = 0.;
2614*918dfc20SMatthew G. Knepley   return PETSC_SUCCESS;
2615*918dfc20SMatthew G. Knepley }
2616*918dfc20SMatthew G. Knepley 
2617*918dfc20SMatthew G. Knepley /*
2618*918dfc20SMatthew G. Knepley   InitializeSolveAndSwarm - Set the solution values to the swarm coordinates and velocities, and also possibly set the initial values.
2619*918dfc20SMatthew G. Knepley 
2620*918dfc20SMatthew G. Knepley   Input Parameters:
2621*918dfc20SMatthew G. Knepley + ts         - The TS
2622*918dfc20SMatthew G. Knepley - useInitial - Flag to also set the initial conditions to the current coordinates and velocities and setup the problem
2623*918dfc20SMatthew G. Knepley 
2624*918dfc20SMatthew G. Knepley   Output Parameters:
2625*918dfc20SMatthew G. Knepley . u - The initialized solution vector
2626*918dfc20SMatthew G. Knepley 
2627*918dfc20SMatthew G. Knepley   Level: advanced
2628*918dfc20SMatthew G. Knepley 
2629*918dfc20SMatthew G. Knepley .seealso: InitializeSolve()
2630*918dfc20SMatthew G. Knepley */
2631*918dfc20SMatthew G. Knepley static PetscErrorCode InitializeSolveAndSwarm(TS ts, PetscBool useInitial)
2632*918dfc20SMatthew G. Knepley {
2633*918dfc20SMatthew G. Knepley   DM       sw;
2634*918dfc20SMatthew G. Knepley   Vec      u, gc, gv;
2635*918dfc20SMatthew G. Knepley   IS       isx, isv;
2636*918dfc20SMatthew G. Knepley   PetscInt dim;
2637*918dfc20SMatthew G. Knepley   AppCtx  *user;
2638*918dfc20SMatthew G. Knepley 
2639*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2640*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2641*918dfc20SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &user));
2642*918dfc20SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2643*918dfc20SMatthew G. Knepley   if (useInitial) {
2644*918dfc20SMatthew G. Knepley     PetscReal v0[2] = {1., 0.};
2645*918dfc20SMatthew G. Knepley     if (user->perturbed_weights) {
2646*918dfc20SMatthew G. Knepley       PetscCall(InitializeParticles_PerturbedWeights(sw, user));
2647*918dfc20SMatthew G. Knepley     } else {
2648*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmComputeLocalSizeFromOptions(sw));
2649*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmInitializeCoordinates(sw));
2650*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmInitializeVelocitiesFromOptions(sw, v0));
2651*918dfc20SMatthew G. Knepley     }
2652*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
2653*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmTSRedistribute(ts));
2654*918dfc20SMatthew G. Knepley   }
2655*918dfc20SMatthew G. Knepley   PetscCall(DMSetUp(sw));
2656*918dfc20SMatthew G. Knepley   PetscCall(TSGetSolution(ts, &u));
2657*918dfc20SMatthew G. Knepley   PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
2658*918dfc20SMatthew G. Knepley   PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
2659*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
2660*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
2661*918dfc20SMatthew G. Knepley   PetscCall(VecISCopy(u, isx, SCATTER_FORWARD, gc));
2662*918dfc20SMatthew G. Knepley   PetscCall(VecISCopy(u, isv, SCATTER_FORWARD, gv));
2663*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
2664*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
2665*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2666*918dfc20SMatthew G. Knepley }
2667*918dfc20SMatthew G. Knepley 
2668*918dfc20SMatthew G. Knepley static PetscErrorCode InitializeSolve(TS ts, Vec u)
2669*918dfc20SMatthew G. Knepley {
2670*918dfc20SMatthew G. Knepley   PetscFunctionBegin;
2671*918dfc20SMatthew G. Knepley   PetscCall(TSSetSolution(ts, u));
2672*918dfc20SMatthew G. Knepley   PetscCall(InitializeSolveAndSwarm(ts, PETSC_TRUE));
2673*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2674*918dfc20SMatthew G. Knepley }
2675*918dfc20SMatthew G. Knepley 
2676*918dfc20SMatthew G. Knepley static PetscErrorCode MigrateParticles(TS ts)
2677*918dfc20SMatthew G. Knepley {
2678*918dfc20SMatthew G. Knepley   DM               sw, cdm;
2679*918dfc20SMatthew G. Knepley   const PetscReal *L;
2680*918dfc20SMatthew G. Knepley   AppCtx          *ctx;
2681*918dfc20SMatthew G. Knepley 
2682*918dfc20SMatthew G. Knepley   PetscFunctionBeginUser;
2683*918dfc20SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
2684*918dfc20SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &ctx));
2685*918dfc20SMatthew G. Knepley   PetscCall(DMViewFromOptions(sw, NULL, "-migrate_view_pre"));
2686*918dfc20SMatthew G. Knepley   {
2687*918dfc20SMatthew G. Knepley     Vec        u, gc, gv, position, momentum;
2688*918dfc20SMatthew G. Knepley     IS         isx, isv;
2689*918dfc20SMatthew G. Knepley     PetscReal *pos, *mom;
2690*918dfc20SMatthew G. Knepley 
2691*918dfc20SMatthew G. Knepley     PetscCall(TSGetSolution(ts, &u));
2692*918dfc20SMatthew G. Knepley     PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
2693*918dfc20SMatthew G. Knepley     PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
2694*918dfc20SMatthew G. Knepley     PetscCall(VecGetSubVector(u, isx, &position));
2695*918dfc20SMatthew G. Knepley     PetscCall(VecGetSubVector(u, isv, &momentum));
2696*918dfc20SMatthew G. Knepley     PetscCall(VecGetArray(position, &pos));
2697*918dfc20SMatthew G. Knepley     PetscCall(VecGetArray(momentum, &mom));
2698*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
2699*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
2700*918dfc20SMatthew G. Knepley     PetscCall(VecISCopy(u, isx, SCATTER_REVERSE, gc));
2701*918dfc20SMatthew G. Knepley     PetscCall(VecISCopy(u, isv, SCATTER_REVERSE, gv));
2702*918dfc20SMatthew G. Knepley 
2703*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmGetCellDM(sw, &cdm));
2704*918dfc20SMatthew G. Knepley     PetscCall(DMGetPeriodicity(cdm, NULL, NULL, &L));
2705*918dfc20SMatthew G. Knepley     PetscCheck(L, PetscObjectComm((PetscObject)cdm), PETSC_ERR_ARG_WRONG, "Mesh must be periodic");
2706*918dfc20SMatthew G. Knepley     if ((L[0] || L[1]) >= 0.) {
2707*918dfc20SMatthew G. Knepley       PetscReal *x, *v, upper[3], lower[3];
2708*918dfc20SMatthew G. Knepley       PetscInt   Np, dim;
2709*918dfc20SMatthew G. Knepley 
2710*918dfc20SMatthew G. Knepley       PetscCall(DMSwarmGetLocalSize(sw, &Np));
2711*918dfc20SMatthew G. Knepley       PetscCall(DMGetDimension(cdm, &dim));
2712*918dfc20SMatthew G. Knepley       PetscCall(DMGetBoundingBox(cdm, lower, upper));
2713*918dfc20SMatthew G. Knepley       PetscCall(VecGetArray(gc, &x));
2714*918dfc20SMatthew G. Knepley       PetscCall(VecGetArray(gv, &v));
2715*918dfc20SMatthew G. Knepley       for (PetscInt p = 0; p < Np; ++p) {
2716*918dfc20SMatthew G. Knepley         for (PetscInt d = 0; d < dim; ++d) {
2717*918dfc20SMatthew G. Knepley           if (pos[p * dim + d] < lower[d]) {
2718*918dfc20SMatthew G. Knepley             x[p * dim + d] = pos[p * dim + d] + (upper[d] - lower[d]);
2719*918dfc20SMatthew G. Knepley           } else if (pos[p * dim + d] > upper[d]) {
2720*918dfc20SMatthew G. Knepley             x[p * dim + d] = pos[p * dim + d] - (upper[d] - lower[d]);
2721*918dfc20SMatthew G. Knepley           } else {
2722*918dfc20SMatthew G. Knepley             x[p * dim + d] = pos[p * dim + d];
2723*918dfc20SMatthew G. Knepley           }
2724*918dfc20SMatthew 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]);
2725*918dfc20SMatthew G. Knepley           v[p * dim + d] = mom[p * dim + d];
2726*918dfc20SMatthew G. Knepley         }
2727*918dfc20SMatthew G. Knepley       }
2728*918dfc20SMatthew G. Knepley       PetscCall(VecRestoreArray(gc, &x));
2729*918dfc20SMatthew G. Knepley       PetscCall(VecRestoreArray(gv, &v));
2730*918dfc20SMatthew G. Knepley     }
2731*918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArray(position, &pos));
2732*918dfc20SMatthew G. Knepley     PetscCall(VecRestoreArray(momentum, &mom));
2733*918dfc20SMatthew G. Knepley     PetscCall(VecRestoreSubVector(u, isx, &position));
2734*918dfc20SMatthew G. Knepley     PetscCall(VecRestoreSubVector(u, isv, &momentum));
2735*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
2736*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
2737*918dfc20SMatthew G. Knepley   }
2738*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
2739*918dfc20SMatthew G. Knepley   PetscInt step;
2740*918dfc20SMatthew G. Knepley 
2741*918dfc20SMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &step));
2742*918dfc20SMatthew G. Knepley   if (!(step % ctx->remapFreq)) {
2743*918dfc20SMatthew G. Knepley     // Monitor electric field before we destroy it
2744*918dfc20SMatthew G. Knepley     PetscReal ptime;
2745*918dfc20SMatthew G. Knepley     PetscInt  step;
2746*918dfc20SMatthew G. Knepley 
2747*918dfc20SMatthew G. Knepley     PetscCall(TSGetStepNumber(ts, &step));
2748*918dfc20SMatthew G. Knepley     PetscCall(TSGetTime(ts, &ptime));
2749*918dfc20SMatthew G. Knepley     if (ctx->efield_monitor) PetscCall(MonitorEField(ts, step, ptime, NULL, ctx));
2750*918dfc20SMatthew G. Knepley     if (ctx->poisson_monitor) PetscCall(MonitorPoisson(ts, step, ptime, NULL, ctx));
2751*918dfc20SMatthew G. Knepley     PetscCall(DMSwarmRemap(sw));
2752*918dfc20SMatthew G. Knepley     ctx->validE = PETSC_FALSE;
2753*918dfc20SMatthew G. Knepley   }
2754*918dfc20SMatthew G. Knepley   // This MUST come last, since it recreates the subswarms and they must DMClone() the new swarm
2755*918dfc20SMatthew G. Knepley   PetscCall(DMSwarmTSRedistribute(ts));
2756*918dfc20SMatthew G. Knepley   PetscCall(InitializeSolveAndSwarm(ts, PETSC_FALSE));
2757*918dfc20SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2758*918dfc20SMatthew G. Knepley }
2759*918dfc20SMatthew G. Knepley 
2760*918dfc20SMatthew G. Knepley int main(int argc, char **argv)
2761*918dfc20SMatthew G. Knepley {
2762*918dfc20SMatthew G. Knepley   DM        dm, sw;
2763*918dfc20SMatthew G. Knepley   TS        ts;
2764*918dfc20SMatthew G. Knepley   Vec       u;
2765*918dfc20SMatthew G. Knepley   PetscReal dt;
2766*918dfc20SMatthew G. Knepley   PetscInt  maxn;
2767*918dfc20SMatthew G. Knepley   AppCtx    user;
2768*918dfc20SMatthew G. Knepley 
2769*918dfc20SMatthew G. Knepley   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
2770*918dfc20SMatthew G. Knepley   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
2771*918dfc20SMatthew G. Knepley   PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &user.bag));
2772*918dfc20SMatthew G. Knepley   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
2773*918dfc20SMatthew G. Knepley   PetscCall(CreatePoisson(dm, &user));
2774*918dfc20SMatthew G. Knepley   PetscCall(CreateMomentFields(dm, &user));
2775*918dfc20SMatthew G. Knepley   PetscCall(CreateSwarm(dm, &user, &sw));
2776*918dfc20SMatthew G. Knepley   PetscCall(SetupParameters(PETSC_COMM_WORLD, &user));
2777*918dfc20SMatthew G. Knepley   PetscCall(InitializeConstants(sw, &user));
2778*918dfc20SMatthew G. Knepley   PetscCall(DMSetApplicationContext(sw, &user));
2779*918dfc20SMatthew G. Knepley 
2780*918dfc20SMatthew G. Knepley   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
2781*918dfc20SMatthew G. Knepley   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
2782*918dfc20SMatthew G. Knepley   PetscCall(TSSetDM(ts, sw));
2783*918dfc20SMatthew G. Knepley   PetscCall(TSSetMaxTime(ts, 0.1));
2784*918dfc20SMatthew G. Knepley   PetscCall(TSSetTimeStep(ts, 0.00001));
2785*918dfc20SMatthew G. Knepley   PetscCall(TSSetMaxSteps(ts, 100));
2786*918dfc20SMatthew G. Knepley   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
2787*918dfc20SMatthew G. Knepley 
2788*918dfc20SMatthew G. Knepley   if (user.efield_monitor) PetscCall(TSMonitorSet(ts, MonitorEField, &user, NULL));
2789*918dfc20SMatthew G. Knepley   if (user.moment_monitor) PetscCall(TSMonitorSet(ts, MonitorMoments, &user, NULL));
2790*918dfc20SMatthew G. Knepley   if (user.moment_field_monitor) PetscCall(TSMonitorSet(ts, MonitorMomentFields, &user, NULL));
2791*918dfc20SMatthew G. Knepley   if (user.initial_monitor) PetscCall(TSMonitorSet(ts, MonitorInitialConditions, &user, NULL));
2792*918dfc20SMatthew G. Knepley   if (user.positions_monitor) PetscCall(TSMonitorSet(ts, MonitorPositions_2D, &user, NULL));
2793*918dfc20SMatthew G. Knepley   if (user.poisson_monitor) PetscCall(TSMonitorSet(ts, MonitorPoisson, &user, NULL));
2794*918dfc20SMatthew G. Knepley   if (user.velocity_monitor >= 0) PetscCall(TSMonitorSet(ts, MonitorVelocity, &user, NULL));
2795*918dfc20SMatthew G. Knepley 
2796*918dfc20SMatthew G. Knepley   PetscCall(TSSetFromOptions(ts));
2797*918dfc20SMatthew G. Knepley   PetscCall(TSGetTimeStep(ts, &dt));
2798*918dfc20SMatthew G. Knepley   PetscCall(TSGetMaxSteps(ts, &maxn));
2799*918dfc20SMatthew G. Knepley   user.steps    = maxn;
2800*918dfc20SMatthew G. Knepley   user.stepSize = dt;
2801*918dfc20SMatthew G. Knepley   PetscCall(SetupContext(dm, sw, &user));
2802*918dfc20SMatthew G. Knepley   PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve));
2803*918dfc20SMatthew G. Knepley   PetscCall(TSSetPostStep(ts, MigrateParticles));
2804*918dfc20SMatthew G. Knepley   PetscCall(CreateSolution(ts));
2805*918dfc20SMatthew G. Knepley   PetscCall(TSGetSolution(ts, &u));
2806*918dfc20SMatthew G. Knepley   PetscCall(TSComputeInitialCondition(ts, u));
2807*918dfc20SMatthew G. Knepley   PetscCall(CheckNonNegativeWeights(sw, &user));
2808*918dfc20SMatthew G. Knepley   PetscCall(TSSolve(ts, NULL));
2809*918dfc20SMatthew G. Knepley 
2810*918dfc20SMatthew G. Knepley   if (user.checkLandau) {
2811*918dfc20SMatthew G. Knepley     // We should get a lookup table based on charge density and \hat k
2812*918dfc20SMatthew G. Knepley     const PetscReal gammaEx = -0.15336;
2813*918dfc20SMatthew G. Knepley     const PetscReal omegaEx = 1.4156;
2814*918dfc20SMatthew G. Knepley     const PetscReal tol     = 1e-2;
2815*918dfc20SMatthew G. Knepley 
2816*918dfc20SMatthew G. Knepley     PetscCheck(PetscAbsReal((user.gamma - gammaEx) / gammaEx) < tol, PETSC_COMM_WORLD, PETSC_ERR_LIB, "Invalid Landau gamma %g != %g", user.gamma, gammaEx);
2817*918dfc20SMatthew G. Knepley     PetscCheck(PetscAbsReal((user.omega - omegaEx) / omegaEx) < tol, PETSC_COMM_WORLD, PETSC_ERR_LIB, "Invalid Landau omega %g != %g", user.omega, omegaEx);
2818*918dfc20SMatthew G. Knepley   }
2819*918dfc20SMatthew G. Knepley 
2820*918dfc20SMatthew G. Knepley   PetscCall(SNESDestroy(&user.snes));
2821*918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&user.dmN));
2822*918dfc20SMatthew G. Knepley   PetscCall(ISDestroy(&user.isN));
2823*918dfc20SMatthew G. Knepley   PetscCall(MatDestroy(&user.MN));
2824*918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&user.dmP));
2825*918dfc20SMatthew G. Knepley   PetscCall(ISDestroy(&user.isP));
2826*918dfc20SMatthew G. Knepley   PetscCall(MatDestroy(&user.MP));
2827*918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&user.dmE));
2828*918dfc20SMatthew G. Knepley   PetscCall(ISDestroy(&user.isE));
2829*918dfc20SMatthew G. Knepley   PetscCall(MatDestroy(&user.ME));
2830*918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&user.dmMom));
2831*918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&user.dmPot));
2832*918dfc20SMatthew G. Knepley   PetscCall(ISDestroy(&user.isPot));
2833*918dfc20SMatthew G. Knepley   PetscCall(MatDestroy(&user.M));
2834*918dfc20SMatthew G. Knepley   PetscCall(PetscFEGeomDestroy(&user.fegeom));
2835*918dfc20SMatthew G. Knepley   PetscCall(TSDestroy(&ts));
2836*918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&sw));
2837*918dfc20SMatthew G. Knepley   PetscCall(DMDestroy(&dm));
2838*918dfc20SMatthew G. Knepley   PetscCall(DestroyContext(&user));
2839*918dfc20SMatthew G. Knepley   PetscCall(PetscFinalize());
2840*918dfc20SMatthew G. Knepley   return 0;
2841*918dfc20SMatthew G. Knepley }
2842*918dfc20SMatthew G. Knepley 
2843*918dfc20SMatthew G. Knepley /*TEST
2844*918dfc20SMatthew G. Knepley 
2845*918dfc20SMatthew G. Knepley   build:
2846*918dfc20SMatthew G. Knepley     requires: !complex double
2847*918dfc20SMatthew G. Knepley 
2848*918dfc20SMatthew G. Knepley   # This tests that we can compute the correct decay rate and frequency
2849*918dfc20SMatthew G. Knepley   #   For gold runs, use -dm_plex_box_faces 160 -vdm_plex_box_faces 450 -remap_dm_plex_box_faces 80,150
2850*918dfc20SMatthew G. Knepley   test:
2851*918dfc20SMatthew G. Knepley     suffix: 0
2852*918dfc20SMatthew G. Knepley     args: -cosine_coefficients 0.01 -charges -1. -perturbed_weights -total_weight 1. \
2853*918dfc20SMatthew G. Knepley           -dm_plex_dim 1 -dm_plex_box_faces 80 -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 \
2854*918dfc20SMatthew G. Knepley             -dm_plex_box_bd periodic -dm_plex_hash_location \
2855*918dfc20SMatthew G. Knepley           -vdm_plex_dim 1 -vdm_plex_box_faces 220 -vdm_plex_box_lower -6 -vdm_plex_box_upper 6 \
2856*918dfc20SMatthew G. Knepley             -vpetscspace_degree 2 -vdm_plex_hash_location \
2857*918dfc20SMatthew G. Knepley           -remap_freq 100 -dm_swarm_remap_type pfak -remap_dm_plex_dim 2 -remap_dm_plex_simplex 0 \
2858*918dfc20SMatthew G. Knepley             -remap_dm_plex_box_faces 40,110 -remap_dm_plex_box_bd periodic,none \
2859*918dfc20SMatthew G. Knepley             -remap_dm_plex_box_lower 0.,-6. -remap_dm_plex_box_upper 12.5664,6. \
2860*918dfc20SMatthew G. Knepley             -remap_petscspace_degree 1 -remap_dm_plex_hash_location \
2861*918dfc20SMatthew G. Knepley             -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 -ptof_pc_type lu \
2862*918dfc20SMatthew G. Knepley           -em_type primal -petscspace_degree 1 -em_snes_atol 1.e-12 -em_snes_error_if_not_converged \
2863*918dfc20SMatthew G. Knepley             -em_ksp_error_if_not_converged -em_pc_type svd -em_proj_pc_type lu \
2864*918dfc20SMatthew G. Knepley           -ts_type basicsymplectic -ts_basicsymplectic_type 1 -ts_dt 0.03 -ts_max_steps 500 \
2865*918dfc20SMatthew G. Knepley             -ts_max_time 100 \
2866*918dfc20SMatthew G. Knepley           -emax_tao_type brgn -emax_tao_max_it 100 -emax_tao_brgn_regularization_type l2pure \
2867*918dfc20SMatthew G. Knepley             -emax_tao_brgn_regularizer_weight 1e-5 -tao_brgn_subsolver_tao_bnk_ksp_rtol 1e-12 \
2868*918dfc20SMatthew G. Knepley           -output_step 1 -efield_monitor quiet
2869*918dfc20SMatthew G. Knepley 
2870*918dfc20SMatthew G. Knepley TEST*/
2871