xref: /petsc/src/ts/tutorials/hamiltonian/ex2.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
18214e71cSJoe static char help[] = "Landau Damping/Two Stream instability test using Vlasov-Poisson equations\n";
2b80bf5b1SJoe Pusztay 
38214e71cSJoe /*
49072cb8bSMatthew G. Knepley   TODO:
59072cb8bSMatthew G. Knepley   - Cache mesh geometry
69072cb8bSMatthew G. Knepley   - Move electrostatic solver to MG+SVD
79072cb8bSMatthew G. Knepley 
88214e71cSJoe   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"
98214e71cSJoe   According to Lukas, good damping results come at ~16k particles per cell
108214e71cSJoe 
119072cb8bSMatthew G. Knepley   To visualize the maximum electric field use
128214e71cSJoe 
139072cb8bSMatthew G. Knepley     -efield_monitor
148214e71cSJoe 
159072cb8bSMatthew G. Knepley   To monitor velocity moments of the distribution use
16f1e6e573SMatthew G. Knepley 
179072cb8bSMatthew G. Knepley     -ptof_pc_type lu -moments_monitor
189072cb8bSMatthew G. Knepley 
199072cb8bSMatthew G. Knepley   To monitor the particle positions in phase space use
209072cb8bSMatthew G. Knepley 
219072cb8bSMatthew G. Knepley     -positions_monitor
229072cb8bSMatthew G. Knepley 
239072cb8bSMatthew G. Knepley   To monitor the charge density, E field, and potential use
249072cb8bSMatthew G. Knepley 
259072cb8bSMatthew G. Knepley     -poisson_monitor
269072cb8bSMatthew G. Knepley 
279072cb8bSMatthew G. Knepley   To monitor the remapping field use
289072cb8bSMatthew G. Knepley 
299072cb8bSMatthew G. Knepley     -remap_uf_view draw
30f1e6e573SMatthew G. Knepley 
318214e71cSJoe   To visualize the swarm distribution use
328214e71cSJoe 
338214e71cSJoe     -ts_monitor_hg_swarm
348214e71cSJoe 
358214e71cSJoe   To visualize the particles, we can use
368214e71cSJoe 
378214e71cSJoe     -ts_monitor_sp_swarm -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500
388214e71cSJoe 
3984467f86SMatthew G. Knepley For a Landau Damping verification run, we use
4084467f86SMatthew G. Knepley 
41045208b8SMatthew G. Knepley   # Physics
42045208b8SMatthew G. Knepley   -cosine_coefficients 0.01 -dm_swarm_num_species 1 -charges -1. -perturbed_weights -total_weight 1.
43045208b8SMatthew G. Knepley   # Spatial Mesh
44045208b8SMatthew G. Knepley   -dm_plex_dim 1 -dm_plex_box_faces 40 -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic  -dm_plex_hash_location
45045208b8SMatthew G. Knepley   # Velocity Mesh
46045208b8SMatthew G. Knepley   -vdm_plex_dim 1 -vdm_plex_box_faces 40 -vdm_plex_box_lower -6 -vdm_plex_box_upper 6 -vpetscspace_degree 2 -vdm_plex_hash_location
47045208b8SMatthew G. Knepley   # Remap Space
48045208b8SMatthew G. Knepley   -dm_swarm_remap_type pfak -remap_freq 100
49045208b8SMatthew G. Knepley   -remap_dm_plex_dim 2 -remap_dm_plex_simplex 0 -remap_dm_plex_box_faces 20,20 -remap_dm_plex_box_bd periodic,none -remap_dm_plex_box_lower 0.,-6.
50045208b8SMatthew G. Knepley     -remap_dm_plex_box_upper 12.5664,6. -remap_petscspace_degree 1 -remap_dm_plex_hash_location
51045208b8SMatthew G. Knepley   # Remap Solve
52045208b8SMatthew G. Knepley   -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 -ptof_pc_type lu
53045208b8SMatthew G. Knepley   # EM Solve
54045208b8SMatthew G. Knepley   -em_type primal -petscspace_degree 1 -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged -em_pc_type svd -em_proj_pc_type lu
55045208b8SMatthew G. Knepley   # Timestepping
56188af4bfSBarry Smith   -ts_type basicsymplectic -ts_basicsymplectic_type 1 -ts_time_step 0.03 -ts_max_steps 1500 -ts_max_time 100
57045208b8SMatthew G. Knepley   # Monitoring
58045208b8SMatthew G. Knepley   -output_step 1 -check_vel_res -efield_monitor -poisson_monitor -positions_monitor -dm_swarm_print_coords 0 -remap_uf_view draw
59045208b8SMatthew G. Knepley     -ftop_ksp_lsqr_monitor -ftop_ksp_converged_reason
6084467f86SMatthew G. Knepley 
618214e71cSJoe */
62b80bf5b1SJoe Pusztay #include <petscts.h>
638214e71cSJoe #include <petscdmplex.h>
648214e71cSJoe #include <petscdmswarm.h>
658214e71cSJoe #include <petscfe.h>
668214e71cSJoe #include <petscds.h>
678214e71cSJoe #include <petscbag.h>
688214e71cSJoe #include <petscdraw.h>
698214e71cSJoe #include <petsc/private/dmpleximpl.h>  /* For norm and dot */
708214e71cSJoe #include <petsc/private/petscfeimpl.h> /* For interpolation */
7184467f86SMatthew G. Knepley #include <petsc/private/dmswarmimpl.h> /* For swarm debugging */
728214e71cSJoe #include "petscdm.h"
738214e71cSJoe #include "petscdmlabel.h"
748214e71cSJoe 
758214e71cSJoe PETSC_EXTERN PetscErrorCode stream(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
768214e71cSJoe PETSC_EXTERN PetscErrorCode line(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
778214e71cSJoe 
788214e71cSJoe const char *EMTypes[] = {"primal", "mixed", "coulomb", "none", "EMType", "EM_", NULL};
798214e71cSJoe typedef enum {
808214e71cSJoe   EM_PRIMAL,
818214e71cSJoe   EM_MIXED,
828214e71cSJoe   EM_COULOMB,
838214e71cSJoe   EM_NONE
848214e71cSJoe } EMType;
858214e71cSJoe 
868214e71cSJoe typedef enum {
878214e71cSJoe   V0,
888214e71cSJoe   X0,
898214e71cSJoe   T0,
908214e71cSJoe   M0,
918214e71cSJoe   Q0,
928214e71cSJoe   PHI0,
938214e71cSJoe   POISSON,
948214e71cSJoe   VLASOV,
958214e71cSJoe   SIGMA,
968214e71cSJoe   NUM_CONSTANTS
978214e71cSJoe } ConstantType;
988214e71cSJoe typedef struct {
998214e71cSJoe   PetscScalar v0; /* Velocity scale, often the thermal velocity */
1008214e71cSJoe   PetscScalar t0; /* Time scale */
1018214e71cSJoe   PetscScalar x0; /* Space scale */
1028214e71cSJoe   PetscScalar m0; /* Mass scale */
1038214e71cSJoe   PetscScalar q0; /* Charge scale */
1048214e71cSJoe   PetscScalar kb;
1058214e71cSJoe   PetscScalar epsi0;
1068214e71cSJoe   PetscScalar phi0;          /* Potential scale */
1078214e71cSJoe   PetscScalar poissonNumber; /* Non-Dimensional Poisson Number */
1088214e71cSJoe   PetscScalar vlasovNumber;  /* Non-Dimensional Vlasov Number */
1098214e71cSJoe   PetscReal   sigma;         /* Nondimensional charge per length in x */
1108214e71cSJoe } Parameter;
111b80bf5b1SJoe Pusztay 
112b80bf5b1SJoe Pusztay typedef struct {
1139072cb8bSMatthew G. Knepley   PetscBag     bag;               // Problem parameters
1149072cb8bSMatthew G. Knepley   PetscBool    error;             // Flag for printing the error
1159072cb8bSMatthew G. Knepley   PetscInt     remapFreq;         // Number of timesteps between remapping
1169072cb8bSMatthew G. Knepley   PetscBool    efield_monitor;    // Flag to show electric field monitor
1179072cb8bSMatthew G. Knepley   PetscBool    moment_monitor;    // Flag to show distribution moment monitor
1189072cb8bSMatthew G. Knepley   PetscBool    positions_monitor; // Flag to show particle positins at each time step
1199072cb8bSMatthew G. Knepley   PetscBool    poisson_monitor;   // Flag to display charge, E field, and potential at each solve
1209072cb8bSMatthew G. Knepley   PetscBool    initial_monitor;   // Flag to monitor the initial conditions
121fd7102fcSMatthew G. Knepley   PetscInt     velocity_monitor;  // Cell to monitor the velocity distribution for
1229072cb8bSMatthew G. Knepley   PetscBool    perturbed_weights; // Uniformly sample x,v space with gaussian weights
1239072cb8bSMatthew G. Knepley   PetscInt     ostep;             // Print the energy at each ostep time steps
1248214e71cSJoe   PetscInt     numParticles;
1258214e71cSJoe   PetscReal    timeScale;              /* Nondimensionalizing time scale */
1268214e71cSJoe   PetscReal    charges[2];             /* The charges of each species */
1278214e71cSJoe   PetscReal    masses[2];              /* The masses of each species */
1288214e71cSJoe   PetscReal    thermal_energy[2];      /* Thermal Energy (used to get other constants)*/
1298214e71cSJoe   PetscReal    cosine_coefficients[2]; /*(alpha, k)*/
1308214e71cSJoe   PetscReal    totalWeight;
1318214e71cSJoe   PetscReal    stepSize;
1328214e71cSJoe   PetscInt     steps;
1338214e71cSJoe   PetscReal    initVel;
134f1e6e573SMatthew G. Knepley   EMType       em;           // Type of electrostatic model
135f1e6e573SMatthew G. Knepley   SNES         snes;         // EM solver
1364a0cbf56SMatthew G. Knepley   DM           dmPot;        // The DM for potential
137b02f317dSMatthew G. Knepley   Mat          fftPot;       // Fourier Transform operator for the potential
138fd7102fcSMatthew G. Knepley   Vec          fftX, fftY;   //   FFT vectors with phases added (complex parts)
139fd7102fcSMatthew G. Knepley   IS           fftReal;      //   The indices for real parts
1404a0cbf56SMatthew G. Knepley   IS           isPot;        // The IS for potential, or NULL in primal
1414a0cbf56SMatthew G. Knepley   Mat          M;            // The finite element mass matrix for potential
142f1e6e573SMatthew G. Knepley   PetscFEGeom *fegeom;       // Geometric information for the DM cells
143b02f317dSMatthew G. Knepley   PetscDrawHG  drawhgic_x;   // Histogram of the particle weight in each X cell
144b02f317dSMatthew G. Knepley   PetscDrawHG  drawhgic_v;   // Histogram of the particle weight in each X cell
145fd7102fcSMatthew G. Knepley   PetscDrawHG  drawhgcell_v; // Histogram of the particle weight in a given cell
1469072cb8bSMatthew G. Knepley   PetscBool    validE;       // Flag to indicate E-field in swarm is valid
14775155f48SMatthew G. Knepley   PetscReal    drawlgEmin;   // The minimum lg(E) to plot
14875155f48SMatthew G. Knepley   PetscDrawLG  drawlgE;      // Logarithm of maximum electric field
14975155f48SMatthew G. Knepley   PetscDrawSP  drawspE;      // Electric field at particle positions
15075155f48SMatthew G. Knepley   PetscDrawSP  drawspX;      // Particle positions
15175155f48SMatthew G. Knepley   PetscViewer  viewerRho;    // Charge density viewer
152b02f317dSMatthew G. Knepley   PetscViewer  viewerRhoHat; // Charge density Fourier Transform viewer
15375155f48SMatthew G. Knepley   PetscViewer  viewerPhi;    // Potential viewer
1548214e71cSJoe   DM           swarm;
1558214e71cSJoe   PetscRandom  random;
1568214e71cSJoe   PetscBool    twostream;
1578214e71cSJoe   PetscBool    checkweights;
158b02f317dSMatthew G. Knepley   PetscInt     checkVRes; // Flag to check/output velocity residuals for nightly tests
15984467f86SMatthew G. Knepley 
16084467f86SMatthew G. Knepley   PetscLogEvent RhsXEvent, RhsVEvent, ESolveEvent, ETabEvent;
161b80bf5b1SJoe Pusztay } AppCtx;
162b80bf5b1SJoe Pusztay 
ProcessOptions(MPI_Comm comm,AppCtx * options)163d71ae5a4SJacob Faibussowitsch static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
164d71ae5a4SJacob Faibussowitsch {
165b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
1668214e71cSJoe   PetscInt d                      = 2;
1678214e71cSJoe   PetscInt maxSpecies             = 2;
1688214e71cSJoe   options->error                  = PETSC_FALSE;
1699072cb8bSMatthew G. Knepley   options->remapFreq              = 1;
1708214e71cSJoe   options->efield_monitor         = PETSC_FALSE;
171f1e6e573SMatthew G. Knepley   options->moment_monitor         = PETSC_FALSE;
1728214e71cSJoe   options->initial_monitor        = PETSC_FALSE;
1738214e71cSJoe   options->perturbed_weights      = PETSC_FALSE;
1748214e71cSJoe   options->poisson_monitor        = PETSC_FALSE;
1759072cb8bSMatthew G. Knepley   options->positions_monitor      = PETSC_FALSE;
176fd7102fcSMatthew G. Knepley   options->velocity_monitor       = -1;
1778214e71cSJoe   options->ostep                  = 100;
1788214e71cSJoe   options->timeScale              = 2.0e-14;
1798214e71cSJoe   options->charges[0]             = -1.0;
1808214e71cSJoe   options->charges[1]             = 1.0;
1818214e71cSJoe   options->masses[0]              = 1.0;
1828214e71cSJoe   options->masses[1]              = 1000.0;
1838214e71cSJoe   options->thermal_energy[0]      = 1.0;
1848214e71cSJoe   options->thermal_energy[1]      = 1.0;
1858214e71cSJoe   options->cosine_coefficients[0] = 0.01;
1868214e71cSJoe   options->cosine_coefficients[1] = 0.5;
1878214e71cSJoe   options->initVel                = 1;
1888214e71cSJoe   options->totalWeight            = 1.0;
1898214e71cSJoe   options->drawhgic_x             = NULL;
1908214e71cSJoe   options->drawhgic_v             = NULL;
191fd7102fcSMatthew G. Knepley   options->drawhgcell_v           = NULL;
192f940b0e3Sdanofinn   options->validE                 = PETSC_FALSE;
19375155f48SMatthew G. Knepley   options->drawlgEmin             = -6;
19475155f48SMatthew G. Knepley   options->drawlgE                = NULL;
19575155f48SMatthew G. Knepley   options->drawspE                = NULL;
19675155f48SMatthew G. Knepley   options->drawspX                = NULL;
19775155f48SMatthew G. Knepley   options->viewerRho              = NULL;
198b02f317dSMatthew G. Knepley   options->viewerRhoHat           = NULL;
19975155f48SMatthew G. Knepley   options->viewerPhi              = NULL;
2008214e71cSJoe   options->em                     = EM_COULOMB;
2014a0cbf56SMatthew G. Knepley   options->snes                   = NULL;
2024a0cbf56SMatthew G. Knepley   options->dmPot                  = NULL;
203b02f317dSMatthew G. Knepley   options->fftPot                 = NULL;
204fd7102fcSMatthew G. Knepley   options->fftX                   = NULL;
205fd7102fcSMatthew G. Knepley   options->fftY                   = NULL;
206fd7102fcSMatthew G. Knepley   options->fftReal                = NULL;
2074a0cbf56SMatthew G. Knepley   options->isPot                  = NULL;
2084a0cbf56SMatthew G. Knepley   options->M                      = NULL;
2098214e71cSJoe   options->numParticles           = 32768;
2108214e71cSJoe   options->twostream              = PETSC_FALSE;
2118214e71cSJoe   options->checkweights           = PETSC_FALSE;
2128214e71cSJoe   options->checkVRes              = 0;
213b80bf5b1SJoe Pusztay 
2148214e71cSJoe   PetscOptionsBegin(comm, "", "Landau Damping and Two Stream options", "DMSWARM");
2158214e71cSJoe   PetscCall(PetscOptionsBool("-error", "Flag to print the error", "ex2.c", options->error, &options->error, NULL));
2169072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsInt("-remap_freq", "Number", "ex2.c", options->remapFreq, &options->remapFreq, NULL));
2179072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-efield_monitor", "Flag to plot log(max E) over time", "ex2.c", options->efield_monitor, &options->efield_monitor, NULL));
2189072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsReal("-efield_min_monitor", "Minimum E field to plot", "ex2.c", options->drawlgEmin, &options->drawlgEmin, NULL));
2199072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-moments_monitor", "Flag to show moments table", "ex2.c", options->moment_monitor, &options->moment_monitor, NULL));
2209072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-ics_monitor", "Flag to show initial condition histograms", "ex2.c", options->initial_monitor, &options->initial_monitor, NULL));
2219072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-positions_monitor", "The flag to show particle positions", "ex2.c", options->positions_monitor, &options->positions_monitor, NULL));
2229072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-poisson_monitor", "The flag to show charges, Efield and potential solve", "ex2.c", options->poisson_monitor, &options->poisson_monitor, NULL));
223fd7102fcSMatthew G. Knepley   PetscCall(PetscOptionsInt("-velocity_monitor", "Cell to show velocity histograms", "ex2.c", options->velocity_monitor, &options->velocity_monitor, NULL));
2248214e71cSJoe   PetscCall(PetscOptionsBool("-twostream", "Run two stream instability", "ex2.c", options->twostream, &options->twostream, NULL));
2258214e71cSJoe   PetscCall(PetscOptionsBool("-perturbed_weights", "Flag to run uniform sampling with perturbed weights", "ex2.c", options->perturbed_weights, &options->perturbed_weights, NULL));
2268214e71cSJoe   PetscCall(PetscOptionsBool("-check_weights", "Ensure all particle weights are positive", "ex2.c", options->checkweights, &options->checkweights, NULL));
2278214e71cSJoe   PetscCall(PetscOptionsInt("-check_vel_res", "Check particle velocity residuals for nightly tests", "ex2.c", options->checkVRes, &options->checkVRes, NULL));
2288214e71cSJoe   PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", "ex2.c", options->ostep, &options->ostep, NULL));
2298214e71cSJoe   PetscCall(PetscOptionsReal("-timeScale", "Nondimensionalizing time scale", "ex2.c", options->timeScale, &options->timeScale, NULL));
2308214e71cSJoe   PetscCall(PetscOptionsReal("-initial_velocity", "Initial velocity of perturbed particle", "ex2.c", options->initVel, &options->initVel, NULL));
2318214e71cSJoe   PetscCall(PetscOptionsReal("-total_weight", "Total weight of all particles", "ex2.c", options->totalWeight, &options->totalWeight, NULL));
2328214e71cSJoe   PetscCall(PetscOptionsRealArray("-cosine_coefficients", "Amplitude and frequency of cosine equation used in initialization", "ex2.c", options->cosine_coefficients, &d, NULL));
2338214e71cSJoe   PetscCall(PetscOptionsRealArray("-charges", "Species charges", "ex2.c", options->charges, &maxSpecies, NULL));
2348214e71cSJoe   PetscCall(PetscOptionsEnum("-em_type", "Type of electrostatic solver", "ex2.c", EMTypes, (PetscEnum)options->em, (PetscEnum *)&options->em, NULL));
235d0609cedSBarry Smith   PetscOptionsEnd();
23684467f86SMatthew G. Knepley 
23784467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsX", TS_CLASSID, &options->RhsXEvent));
23884467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsV", TS_CLASSID, &options->RhsVEvent));
23984467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ESolve", TS_CLASSID, &options->ESolveEvent));
24084467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ETab", TS_CLASSID, &options->ETabEvent));
2413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
242b80bf5b1SJoe Pusztay }
243b80bf5b1SJoe Pusztay 
SetupContext(DM dm,DM sw,AppCtx * ctx)244*2a8381b2SBarry Smith static PetscErrorCode SetupContext(DM dm, DM sw, AppCtx *ctx)
2458214e71cSJoe {
246b02f317dSMatthew G. Knepley   MPI_Comm comm;
247b02f317dSMatthew G. Knepley 
2488214e71cSJoe   PetscFunctionBeginUser;
249b02f317dSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
250*2a8381b2SBarry Smith   if (ctx->efield_monitor) {
25175155f48SMatthew G. Knepley     PetscDraw     draw;
25275155f48SMatthew G. Knepley     PetscDrawAxis axis;
25375155f48SMatthew G. Knepley 
254b02f317dSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Max Electric Field", 0, 300, 400, 300, &draw));
255fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex2_Efield"));
25675155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
257*2a8381b2SBarry Smith     PetscCall(PetscDrawLGCreate(draw, 1, &ctx->drawlgE));
25875155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
259*2a8381b2SBarry Smith     PetscCall(PetscDrawLGGetAxis(ctx->drawlgE, &axis));
26075155f48SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Electron Electric Field", "time", "E_max"));
261*2a8381b2SBarry Smith     PetscCall(PetscDrawLGSetLimits(ctx->drawlgE, 0., ctx->steps * ctx->stepSize, ctx->drawlgEmin, 0.));
2628214e71cSJoe   }
263b02f317dSMatthew G. Knepley 
264*2a8381b2SBarry Smith   if (ctx->initial_monitor) {
265fd7102fcSMatthew G. Knepley     PetscDraw     drawic_x, drawic_v;
266b02f317dSMatthew G. Knepley     PetscDrawAxis axis1, axis2;
2678214e71cSJoe     PetscReal     dmboxlower[2], dmboxupper[2];
2688214e71cSJoe     PetscInt      dim, cStart, cEnd;
269b02f317dSMatthew G. Knepley 
2708214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
2718214e71cSJoe     PetscCall(DMGetBoundingBox(dm, dmboxlower, dmboxupper));
2728214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2738214e71cSJoe 
274fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_x", 0, 300, 400, 300, &drawic_x));
275fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawic_x, "ex2_ic_x"));
276fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawic_x));
277*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCreate(drawic_x, (int)dim, &ctx->drawhgic_x));
278*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCalcStats(ctx->drawhgic_x, PETSC_TRUE));
279*2a8381b2SBarry Smith     PetscCall(PetscDrawHGGetAxis(ctx->drawhgic_x, &axis1));
280*2a8381b2SBarry Smith     PetscCall(PetscDrawHGSetNumberBins(ctx->drawhgic_x, (int)(cEnd - cStart)));
281fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis1, "Initial X Distribution", "X", "weight"));
282b02f317dSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis1, dmboxlower[0], dmboxupper[0], 0, 0));
283fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawic_x));
2848214e71cSJoe 
285fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_v", 400, 300, 400, 300, &drawic_v));
286fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawic_v, "ex9_ic_v"));
287fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawic_v));
288*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCreate(drawic_v, (int)dim, &ctx->drawhgic_v));
289*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCalcStats(ctx->drawhgic_v, PETSC_TRUE));
290*2a8381b2SBarry Smith     PetscCall(PetscDrawHGGetAxis(ctx->drawhgic_v, &axis2));
291*2a8381b2SBarry Smith     PetscCall(PetscDrawHGSetNumberBins(ctx->drawhgic_v, 21));
292fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis2, "Initial V_x Distribution", "V", "weight"));
293b02f317dSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis2, -6, 6, 0, 0));
294fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawic_v));
295fd7102fcSMatthew G. Knepley   }
296fd7102fcSMatthew G. Knepley 
297*2a8381b2SBarry Smith   if (ctx->velocity_monitor >= 0) {
298fd7102fcSMatthew G. Knepley     DM            vdm;
299fd7102fcSMatthew G. Knepley     DMSwarmCellDM celldm;
300fd7102fcSMatthew G. Knepley     PetscDraw     drawcell_v;
301fd7102fcSMatthew G. Knepley     PetscDrawAxis axis;
302fd7102fcSMatthew G. Knepley     PetscReal     dmboxlower[2], dmboxupper[2];
303fd7102fcSMatthew G. Knepley     PetscInt      dim;
304fd7102fcSMatthew G. Knepley     char          title[PETSC_MAX_PATH_LEN];
305fd7102fcSMatthew G. Knepley 
306fd7102fcSMatthew G. Knepley     PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
307fd7102fcSMatthew G. Knepley     PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
308fd7102fcSMatthew G. Knepley     PetscCall(DMGetDimension(vdm, &dim));
309fd7102fcSMatthew G. Knepley     PetscCall(DMGetBoundingBox(vdm, dmboxlower, dmboxupper));
310fd7102fcSMatthew G. Knepley 
311*2a8381b2SBarry Smith     PetscCall(PetscSNPrintf(title, PETSC_MAX_PATH_LEN, "Cell %" PetscInt_FMT ": Velocity Distribution", ctx->velocity_monitor));
312fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, title, 400, 300, 400, 300, &drawcell_v));
313fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawcell_v, "ex2_cell_v"));
314fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawcell_v));
315*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCreate(drawcell_v, (int)dim, &ctx->drawhgcell_v));
316*2a8381b2SBarry Smith     PetscCall(PetscDrawHGCalcStats(ctx->drawhgcell_v, PETSC_TRUE));
317*2a8381b2SBarry Smith     PetscCall(PetscDrawHGGetAxis(ctx->drawhgcell_v, &axis));
318*2a8381b2SBarry Smith     PetscCall(PetscDrawHGSetNumberBins(ctx->drawhgcell_v, 21));
319fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "V_x Distribution", "V", "weight"));
320fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis, dmboxlower[0], dmboxupper[0], 0, 0));
321fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawcell_v));
3228214e71cSJoe   }
323b02f317dSMatthew G. Knepley 
324*2a8381b2SBarry Smith   if (ctx->positions_monitor) {
32575155f48SMatthew G. Knepley     PetscDraw     draw;
3268214e71cSJoe     PetscDrawAxis axis;
3278214e71cSJoe 
328b02f317dSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Particle Position", 0, 0, 400, 300, &draw));
32975155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_pos"));
33075155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
331*2a8381b2SBarry Smith     PetscCall(PetscDrawSPCreate(draw, 10, &ctx->drawspX));
33275155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
333*2a8381b2SBarry Smith     PetscCall(PetscDrawSPSetDimension(ctx->drawspX, 1));
334*2a8381b2SBarry Smith     PetscCall(PetscDrawSPGetAxis(ctx->drawspX, &axis));
3358214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "v"));
336*2a8381b2SBarry Smith     PetscCall(PetscDrawSPReset(ctx->drawspX));
3378214e71cSJoe   }
338*2a8381b2SBarry Smith   if (ctx->poisson_monitor) {
339b02f317dSMatthew G. Knepley     Vec           rho, rhohat, phi;
34075155f48SMatthew G. Knepley     PetscDraw     draw;
34175155f48SMatthew G. Knepley     PetscDrawAxis axis;
3428214e71cSJoe 
343b02f317dSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Electric_Field", 0, 0, 400, 300, &draw));
34475155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
34575155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_E_spatial"));
346*2a8381b2SBarry Smith     PetscCall(PetscDrawSPCreate(draw, 10, &ctx->drawspE));
34775155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
348*2a8381b2SBarry Smith     PetscCall(PetscDrawSPSetDimension(ctx->drawspE, 1));
349*2a8381b2SBarry Smith     PetscCall(PetscDrawSPGetAxis(ctx->drawspE, &axis));
35075155f48SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "E"));
351*2a8381b2SBarry Smith     PetscCall(PetscDrawSPReset(ctx->drawspE));
3528214e71cSJoe 
353*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "Charge Density", 0, 0, 400, 300, &ctx->viewerRho));
354*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerRho, "rho_"));
355*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerRho, 0, &draw));
35675155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_spatial"));
357*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerRho));
358*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rho", &rho));
35975155f48SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rho, "charge_density"));
360*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rho", &rho));
3618214e71cSJoe 
362b02f317dSMatthew G. Knepley     PetscInt dim, N;
363b02f317dSMatthew G. Knepley 
364*2a8381b2SBarry Smith     PetscCall(DMGetDimension(ctx->dmPot, &dim));
365b02f317dSMatthew G. Knepley     if (dim == 1) {
366*2a8381b2SBarry Smith       PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
367b02f317dSMatthew G. Knepley       PetscCall(VecGetSize(rhohat, &N));
368*2a8381b2SBarry Smith       PetscCall(MatCreateFFT(comm, dim, &N, MATFFTW, &ctx->fftPot));
369*2a8381b2SBarry Smith       PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
370*2a8381b2SBarry Smith       PetscCall(MatCreateVecs(ctx->fftPot, &ctx->fftX, &ctx->fftY));
371*2a8381b2SBarry Smith       PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &ctx->fftReal));
372b02f317dSMatthew G. Knepley     }
373b02f317dSMatthew G. Knepley 
374*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "rhohat: Charge Density FT", 0, 0, 400, 300, &ctx->viewerRhoHat));
375*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerRhoHat, "rhohat_"));
376*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerRhoHat, 0, &draw));
377b02f317dSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_ft"));
378*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerRhoHat));
379*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
380b02f317dSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rhohat, "charge_density_ft"));
381*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
382b02f317dSMatthew G. Knepley 
383*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawOpen(comm, NULL, "Potential", 400, 0, 400, 300, &ctx->viewerPhi));
384*2a8381b2SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->viewerPhi, "phi_"));
385*2a8381b2SBarry Smith     PetscCall(PetscViewerDrawGetDraw(ctx->viewerPhi, 0, &draw));
38675155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_phi_spatial"));
387*2a8381b2SBarry Smith     PetscCall(PetscViewerSetFromOptions(ctx->viewerPhi));
388*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
38975155f48SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)phi, "potential"));
390*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
3918214e71cSJoe   }
3928214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3938214e71cSJoe }
3948214e71cSJoe 
DestroyContext(AppCtx * ctx)395*2a8381b2SBarry Smith static PetscErrorCode DestroyContext(AppCtx *ctx)
3968214e71cSJoe {
3978214e71cSJoe   PetscFunctionBeginUser;
398*2a8381b2SBarry Smith   PetscCall(PetscDrawHGDestroy(&ctx->drawhgic_x));
399*2a8381b2SBarry Smith   PetscCall(PetscDrawHGDestroy(&ctx->drawhgic_v));
400*2a8381b2SBarry Smith   PetscCall(PetscDrawHGDestroy(&ctx->drawhgcell_v));
4018214e71cSJoe 
402*2a8381b2SBarry Smith   PetscCall(PetscDrawLGDestroy(&ctx->drawlgE));
403*2a8381b2SBarry Smith   PetscCall(PetscDrawSPDestroy(&ctx->drawspE));
404*2a8381b2SBarry Smith   PetscCall(PetscDrawSPDestroy(&ctx->drawspX));
405*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerRho));
406*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerRhoHat));
407*2a8381b2SBarry Smith   PetscCall(MatDestroy(&ctx->fftPot));
408*2a8381b2SBarry Smith   PetscCall(VecDestroy(&ctx->fftX));
409*2a8381b2SBarry Smith   PetscCall(VecDestroy(&ctx->fftY));
410*2a8381b2SBarry Smith   PetscCall(ISDestroy(&ctx->fftReal));
411*2a8381b2SBarry Smith   PetscCall(PetscViewerDestroy(&ctx->viewerPhi));
4128214e71cSJoe 
413*2a8381b2SBarry Smith   PetscCall(PetscBagDestroy(&ctx->bag));
4148214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
4158214e71cSJoe }
4168214e71cSJoe 
CheckNonNegativeWeights(DM sw,AppCtx * ctx)417*2a8381b2SBarry Smith static PetscErrorCode CheckNonNegativeWeights(DM sw, AppCtx *ctx)
4188214e71cSJoe {
4198214e71cSJoe   const PetscScalar *w;
4208214e71cSJoe   PetscInt           Np;
4218214e71cSJoe 
4228214e71cSJoe   PetscFunctionBeginUser;
423*2a8381b2SBarry Smith   if (!ctx->checkweights) PetscFunctionReturn(PETSC_SUCCESS);
4248214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w));
4258214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
4268214e71cSJoe   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]);
4278214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w));
4288214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
4298214e71cSJoe }
4308214e71cSJoe 
f0_Dirichlet(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])431f940b0e3Sdanofinn static void f0_Dirichlet(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
432f940b0e3Sdanofinn {
433f940b0e3Sdanofinn   for (PetscInt d = 0; d < dim; ++d) f0[0] += 0.5 * PetscSqr(u_x[d]);
434f940b0e3Sdanofinn }
435f940b0e3Sdanofinn 
computeFieldEnergy(DM dm,Vec u,PetscReal * En)436f940b0e3Sdanofinn static PetscErrorCode computeFieldEnergy(DM dm, Vec u, PetscReal *En)
437f940b0e3Sdanofinn {
438f940b0e3Sdanofinn   PetscDS        ds;
439f940b0e3Sdanofinn   const PetscInt field = 0;
440f940b0e3Sdanofinn   PetscInt       Nf;
441f940b0e3Sdanofinn   void          *ctx;
442f940b0e3Sdanofinn 
443f940b0e3Sdanofinn   PetscFunctionBegin;
444f940b0e3Sdanofinn   PetscCall(DMGetApplicationContext(dm, &ctx));
445f940b0e3Sdanofinn   PetscCall(DMGetDS(dm, &ds));
446f940b0e3Sdanofinn   PetscCall(PetscDSGetNumFields(ds, &Nf));
447f940b0e3Sdanofinn   PetscCheck(Nf == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "We currently only support 1 field, not %" PetscInt_FMT, Nf);
448f940b0e3Sdanofinn   PetscCall(PetscDSSetObjective(ds, field, &f0_Dirichlet));
449f940b0e3Sdanofinn   PetscCall(DMPlexComputeIntegralFEM(dm, u, En, ctx));
450f940b0e3Sdanofinn   PetscFunctionReturn(PETSC_SUCCESS);
451f940b0e3Sdanofinn }
452f940b0e3Sdanofinn 
computeVelocityFEMMoments(DM sw,PetscReal moments[],AppCtx * user)4539072cb8bSMatthew G. Knepley static PetscErrorCode computeVelocityFEMMoments(DM sw, PetscReal moments[], AppCtx *user)
4548214e71cSJoe {
4559072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
456f1e6e573SMatthew G. Knepley   DM            vdm;
457f1e6e573SMatthew G. Knepley   Vec           u[1];
458f1e6e573SMatthew G. Knepley   const char   *fields[1] = {"w_q"};
4598214e71cSJoe 
460f1e6e573SMatthew G. Knepley   PetscFunctionBegin;
4619072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "velocity"));
4629072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
4639072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
464f940b0e3Sdanofinn #if 0
465f940b0e3Sdanofinn   PetscReal  *v, pvmin[3] = {0., 0., 0.}, pvmax[3] = {0., 0., 0.}, vmin[3], vmax[3], fact = 1.;
466f940b0e3Sdanofinn   PetscInt    dim, Np;
467f940b0e3Sdanofinn 
468f940b0e3Sdanofinn   PetscCall(PetscObjectQuery((PetscObject)sw, "__vdm__", (PetscObject *)&vdm));
469f940b0e3Sdanofinn   // Check for particles outside the velocity grid
470f940b0e3Sdanofinn   PetscCall(DMGetDimension(sw, &dim));
471f940b0e3Sdanofinn   PetscCall(DMSwarmGetLocalSize(sw, &Np));
472f940b0e3Sdanofinn   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
473f940b0e3Sdanofinn   for (PetscInt p = 0; p < Np; ++p) {
474f940b0e3Sdanofinn     for (PetscInt d = 0; d < dim; ++d) {
475f940b0e3Sdanofinn       pvmin[d] = PetscMin(pvmax[d], v[p * dim + d]);
476f940b0e3Sdanofinn       pvmax[d] = PetscMax(pvmax[d], v[p * dim + d]);
477f940b0e3Sdanofinn     }
478f940b0e3Sdanofinn   }
479f940b0e3Sdanofinn   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
480f940b0e3Sdanofinn   PetscCall(DMGetBoundingBox(vdm, vmin, vmax));
481f940b0e3Sdanofinn   // To avoid particle loss, we enlarge the velocity grid if necessary
482f940b0e3Sdanofinn   for (PetscInt d = 0; d < dim; ++d) {
483f940b0e3Sdanofinn     fact = PetscMax(fact, pvmax[d] / vmax[d]);
484f940b0e3Sdanofinn     fact = PetscMax(fact, pvmin[d] / vmin[d]);
485f940b0e3Sdanofinn   }
486f940b0e3Sdanofinn   if (fact > 1.) {
487f940b0e3Sdanofinn     Vec coordinates, coordinatesLocal;
488f940b0e3Sdanofinn 
489f940b0e3Sdanofinn     fact *= 1.1;
490f940b0e3Sdanofinn     PetscCall(PetscPrintf(PETSC_COMM_SELF, "Expanding velocity grid by %g\n", fact));
491f940b0e3Sdanofinn     PetscCall(DMGetCoordinatesLocal(vdm, &coordinatesLocal));
492f940b0e3Sdanofinn     PetscCall(DMGetCoordinates(vdm, &coordinates));
493f940b0e3Sdanofinn     PetscCall(VecScale(coordinatesLocal, fact));
494f940b0e3Sdanofinn     PetscCall(VecScale(coordinates, fact));
495f940b0e3Sdanofinn     PetscCall(PetscGridHashDestroy(&((DM_Plex *)vdm->data)->lbox));
496f940b0e3Sdanofinn   }
497f940b0e3Sdanofinn #endif
498f1e6e573SMatthew G. Knepley   PetscCall(DMGetGlobalVector(vdm, &u[0]));
499f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmProjectFields(sw, vdm, 1, fields, u, SCATTER_FORWARD));
500f1e6e573SMatthew G. Knepley   PetscCall(DMPlexComputeMoments(vdm, u[0], moments));
501f1e6e573SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(vdm, &u[0]));
5029072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
5038214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5048214e71cSJoe }
5058214e71cSJoe 
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[])506fd7102fcSMatthew 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[])
507fd7102fcSMatthew G. Knepley {
508fd7102fcSMatthew G. Knepley   f0[0] = 0.;
509fd7102fcSMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f0[0] += PetscSqr(u_x[uOff_x[0] + d * dim + d]);
510fd7102fcSMatthew G. Knepley }
511fd7102fcSMatthew G. Knepley 
MonitorEField(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)512*2a8381b2SBarry Smith static PetscErrorCode MonitorEField(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
5138214e71cSJoe {
514*2a8381b2SBarry Smith   AppCtx     *ctx = (AppCtx *)Ctx;
515f1e6e573SMatthew G. Knepley   DM          sw;
516fd7102fcSMatthew G. Knepley   PetscScalar intESq;
517f1e6e573SMatthew G. Knepley   PetscReal  *E, *x, *weight;
518f1e6e573SMatthew G. Knepley   PetscReal   Enorm = 0., lgEnorm, lgEmax, sum = 0., Emax = 0., chargesum = 0.;
519f1e6e573SMatthew G. Knepley   PetscReal   pmoments[4]; /* \int f, \int v f, \int v^2 f */
520fd7102fcSMatthew G. Knepley   PetscInt   *species, dim, Np, gNp;
521fd7102fcSMatthew G. Knepley   MPI_Comm    comm;
5228214e71cSJoe 
5238214e71cSJoe   PetscFunctionBeginUser;
524*2a8381b2SBarry Smith   if (step < 0 || !ctx->validE) PetscFunctionReturn(PETSC_SUCCESS);
525fd7102fcSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
5268214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
5278214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
5288214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
529fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmGetSize(sw, &gNp));
5308214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
5318214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5328214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
5338214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
5348214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
5358214e71cSJoe 
536f1e6e573SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
537f1e6e573SMatthew G. Knepley     for (PetscInt d = 0; d < 1; ++d) {
538f1e6e573SMatthew G. Knepley       PetscReal temp = PetscAbsReal(E[p * dim + d]);
5398214e71cSJoe       if (temp > Emax) Emax = temp;
5408214e71cSJoe     }
5418214e71cSJoe     Enorm += PetscSqrtReal(E[p * dim] * E[p * dim]);
5428214e71cSJoe     sum += E[p * dim];
543*2a8381b2SBarry Smith     chargesum += ctx->charges[0] * weight[p];
5448214e71cSJoe   }
545fd7102fcSMatthew G. Knepley   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &Emax, 1, MPIU_REAL, MPIU_MAX, comm));
5468214e71cSJoe   lgEnorm = Enorm != 0 ? PetscLog10Real(Enorm) : -16.;
547*2a8381b2SBarry Smith   lgEmax  = Emax != 0 ? PetscLog10Real(Emax) : ctx->drawlgEmin;
5488214e71cSJoe 
549fd7102fcSMatthew G. Knepley   PetscDS ds;
550fd7102fcSMatthew G. Knepley   Vec     phi;
551fd7102fcSMatthew G. Knepley 
552*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
553*2a8381b2SBarry Smith   PetscCall(DMGetDS(ctx->dmPot, &ds));
554fd7102fcSMatthew G. Knepley   PetscCall(PetscDSSetObjective(ds, 0, &f0_grad_phi2));
555*2a8381b2SBarry Smith   PetscCall(DMPlexComputeIntegralFEM(ctx->dmPot, phi, &intESq, ctx));
556*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
557fd7102fcSMatthew G. Knepley 
5588214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5598214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
5608214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
5618214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
562*2a8381b2SBarry Smith   PetscCall(PetscDrawLGAddPoint(ctx->drawlgE, &t, &lgEmax));
563*2a8381b2SBarry Smith   PetscCall(PetscDrawLGDraw(ctx->drawlgE));
56475155f48SMatthew G. Knepley   PetscDraw draw;
565*2a8381b2SBarry Smith   PetscCall(PetscDrawLGGetDraw(ctx->drawlgE, &draw));
56675155f48SMatthew G. Knepley   PetscCall(PetscDrawSave(draw));
567f1e6e573SMatthew G. Knepley 
568f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
569fd7102fcSMatthew 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));
57075155f48SMatthew G. Knepley   PetscCall(DMViewFromOptions(sw, NULL, "-sw_efield_view"));
571f1e6e573SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
572f1e6e573SMatthew G. Knepley }
573f1e6e573SMatthew G. Knepley 
MonitorMoments(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)574*2a8381b2SBarry Smith static PetscErrorCode MonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
575f1e6e573SMatthew G. Knepley {
576*2a8381b2SBarry Smith   AppCtx   *ctx = (AppCtx *)Ctx;
577f1e6e573SMatthew G. Knepley   DM        sw;
578f1e6e573SMatthew G. Knepley   PetscReal pmoments[4], fmoments[4]; /* \int f, \int v f, \int v^2 f */
579f1e6e573SMatthew G. Knepley 
580f1e6e573SMatthew G. Knepley   PetscFunctionBeginUser;
581f1e6e573SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
582f1e6e573SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
583f1e6e573SMatthew G. Knepley 
584f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
585*2a8381b2SBarry Smith   PetscCall(computeVelocityFEMMoments(sw, fmoments, ctx));
586f1e6e573SMatthew G. Knepley 
587f1e6e573SMatthew 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]));
5888214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5898214e71cSJoe }
5908214e71cSJoe 
MonitorInitialConditions(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)591*2a8381b2SBarry Smith PetscErrorCode MonitorInitialConditions(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
5928214e71cSJoe {
593*2a8381b2SBarry Smith   AppCtx    *ctx = (AppCtx *)Ctx;
594b02f317dSMatthew G. Knepley   DM         sw;
595fd7102fcSMatthew G. Knepley   PetscDraw  drawic_x, drawic_v;
5968214e71cSJoe   PetscReal *weight, *pos, *vel;
597b02f317dSMatthew G. Knepley   PetscInt   dim, Np;
5988214e71cSJoe 
5998214e71cSJoe   PetscFunctionBegin;
6008214e71cSJoe   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
601b02f317dSMatthew G. Knepley   if (step == 0) {
6028214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
6038214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
6048214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
6058214e71cSJoe 
606*2a8381b2SBarry Smith     PetscCall(PetscDrawHGReset(ctx->drawhgic_x));
607*2a8381b2SBarry Smith     PetscCall(PetscDrawHGGetDraw(ctx->drawhgic_x, &drawic_x));
608fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawClear(drawic_x));
609fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawFlush(drawic_x));
6108214e71cSJoe 
611*2a8381b2SBarry Smith     PetscCall(PetscDrawHGReset(ctx->drawhgic_v));
612*2a8381b2SBarry Smith     PetscCall(PetscDrawHGGetDraw(ctx->drawhgic_v, &drawic_v));
613fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawClear(drawic_v));
614fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawFlush(drawic_v));
6158214e71cSJoe 
616b02f317dSMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
6178214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
6188214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
619b02f317dSMatthew G. Knepley     for (PetscInt p = 0; p < Np; ++p) {
620*2a8381b2SBarry Smith       PetscCall(PetscDrawHGAddWeightedValue(ctx->drawhgic_x, pos[p * dim], weight[p]));
621*2a8381b2SBarry Smith       PetscCall(PetscDrawHGAddWeightedValue(ctx->drawhgic_v, vel[p * dim], weight[p]));
6228214e71cSJoe     }
6238214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
6248214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
6258214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
626b02f317dSMatthew G. Knepley 
627*2a8381b2SBarry Smith     PetscCall(PetscDrawHGDraw(ctx->drawhgic_x));
628*2a8381b2SBarry Smith     PetscCall(PetscDrawHGSave(ctx->drawhgic_x));
629*2a8381b2SBarry Smith     PetscCall(PetscDrawHGDraw(ctx->drawhgic_v));
630*2a8381b2SBarry Smith     PetscCall(PetscDrawHGSave(ctx->drawhgic_v));
6318214e71cSJoe   }
6328214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
6338214e71cSJoe }
6348214e71cSJoe 
635bfe80ac4SPierre Jolivet // Right now, make the complete velocity histogram
MonitorVelocity(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)636*2a8381b2SBarry Smith PetscErrorCode MonitorVelocity(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
637fd7102fcSMatthew G. Knepley {
638*2a8381b2SBarry Smith   AppCtx      *ctx = (AppCtx *)Ctx;
639fd7102fcSMatthew G. Knepley   DM           sw, dm;
640fd7102fcSMatthew G. Knepley   Vec          ks;
641f8662bd6SBarry Smith   PetscProbFn *cdf;
642fd7102fcSMatthew G. Knepley   PetscDraw    drawcell_v;
643fd7102fcSMatthew G. Knepley   PetscScalar *ksa;
644fd7102fcSMatthew G. Knepley   PetscReal   *weight, *vel;
645fd7102fcSMatthew G. Knepley   PetscInt    *pidx;
646*2a8381b2SBarry Smith   PetscInt     dim, Npc, cStart, cEnd, cell = ctx->velocity_monitor;
647fd7102fcSMatthew G. Knepley 
648fd7102fcSMatthew G. Knepley   PetscFunctionBegin;
649fd7102fcSMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
650fd7102fcSMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
651fd7102fcSMatthew G. Knepley 
652fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &dm));
653fd7102fcSMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
654fd7102fcSMatthew G. Knepley   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &ks));
655fd7102fcSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)ks, "KS Statistic by Cell"));
656fd7102fcSMatthew G. Knepley   PetscCall(VecSetSizes(ks, cEnd - cStart, PETSC_DETERMINE));
657fd7102fcSMatthew G. Knepley   PetscCall(VecSetFromOptions(ks));
658fd7102fcSMatthew G. Knepley   switch (dim) {
659fd7102fcSMatthew G. Knepley   case 1:
660fd7102fcSMatthew G. Knepley     //cdf = PetscCDFMaxwellBoltzmann1D;
661fd7102fcSMatthew G. Knepley     cdf = PetscCDFGaussian1D;
662fd7102fcSMatthew G. Knepley     break;
663fd7102fcSMatthew G. Knepley   case 2:
664fd7102fcSMatthew G. Knepley     cdf = PetscCDFMaxwellBoltzmann2D;
665fd7102fcSMatthew G. Knepley     break;
666fd7102fcSMatthew G. Knepley   case 3:
667fd7102fcSMatthew G. Knepley     cdf = PetscCDFMaxwellBoltzmann3D;
668fd7102fcSMatthew G. Knepley     break;
669fd7102fcSMatthew G. Knepley   default:
670fd7102fcSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim);
671fd7102fcSMatthew G. Knepley   }
672fd7102fcSMatthew G. Knepley 
673*2a8381b2SBarry Smith   PetscCall(PetscDrawHGReset(ctx->drawhgcell_v));
674*2a8381b2SBarry Smith   PetscCall(PetscDrawHGGetDraw(ctx->drawhgcell_v, &drawcell_v));
675fd7102fcSMatthew G. Knepley   PetscCall(PetscDrawClear(drawcell_v));
676fd7102fcSMatthew G. Knepley   PetscCall(PetscDrawFlush(drawcell_v));
677fd7102fcSMatthew G. Knepley 
678fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
679fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
680fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
681fd7102fcSMatthew G. Knepley   PetscCall(VecGetArrayWrite(ks, &ksa));
682fd7102fcSMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
683fd7102fcSMatthew G. Knepley     Vec          cellv, cellw;
684fd7102fcSMatthew G. Knepley     PetscScalar *cella, *cellaw;
685fd7102fcSMatthew G. Knepley     PetscReal    totWgt = 0.;
686fd7102fcSMatthew G. Knepley 
687fd7102fcSMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
688fd7102fcSMatthew G. Knepley     PetscCall(VecCreate(PETSC_COMM_SELF, &cellv));
689fd7102fcSMatthew G. Knepley     PetscCall(VecSetBlockSize(cellv, dim));
690fd7102fcSMatthew G. Knepley     PetscCall(VecSetSizes(cellv, Npc * dim, Npc));
691fd7102fcSMatthew G. Knepley     PetscCall(VecSetFromOptions(cellv));
692fd7102fcSMatthew G. Knepley     PetscCall(VecCreate(PETSC_COMM_SELF, &cellw));
693fd7102fcSMatthew G. Knepley     PetscCall(VecSetSizes(cellw, Npc, Npc));
694fd7102fcSMatthew G. Knepley     PetscCall(VecSetFromOptions(cellw));
695fd7102fcSMatthew G. Knepley     PetscCall(VecGetArrayWrite(cellv, &cella));
696fd7102fcSMatthew G. Knepley     PetscCall(VecGetArrayWrite(cellw, &cellaw));
697fd7102fcSMatthew G. Knepley     for (PetscInt q = 0; q < Npc; ++q) {
698fd7102fcSMatthew G. Knepley       const PetscInt p = pidx[q];
699*2a8381b2SBarry Smith       if (c == cell) PetscCall(PetscDrawHGAddWeightedValue(ctx->drawhgcell_v, vel[p * dim], weight[p]));
700fd7102fcSMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) cella[q * dim + d] = vel[p * dim + d];
701fd7102fcSMatthew G. Knepley       cellaw[q] = weight[p];
702fd7102fcSMatthew G. Knepley       totWgt += weight[p];
703fd7102fcSMatthew G. Knepley     }
704fd7102fcSMatthew G. Knepley     PetscCall(VecRestoreArrayWrite(cellv, &cella));
705fd7102fcSMatthew G. Knepley     PetscCall(VecRestoreArrayWrite(cellw, &cellaw));
706fd7102fcSMatthew G. Knepley     PetscCall(VecScale(cellw, 1. / totWgt));
707fd7102fcSMatthew G. Knepley     PetscCall(PetscProbComputeKSStatisticWeighted(cellv, cellw, cdf, &ksa[c - cStart]));
708fd7102fcSMatthew G. Knepley     PetscCall(VecDestroy(&cellv));
709fd7102fcSMatthew G. Knepley     PetscCall(VecDestroy(&cellw));
710fd7102fcSMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
711fd7102fcSMatthew G. Knepley   }
712fd7102fcSMatthew G. Knepley   PetscCall(VecRestoreArrayWrite(ks, &ksa));
713fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
714fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
715fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
716fd7102fcSMatthew G. Knepley 
717fd7102fcSMatthew G. Knepley   PetscReal minalpha, maxalpha;
718fd7102fcSMatthew G. Knepley   PetscInt  mincell, maxcell;
719fd7102fcSMatthew G. Knepley 
720fd7102fcSMatthew G. Knepley   PetscCall(VecFilter(ks, PETSC_SMALL));
721fd7102fcSMatthew G. Knepley   PetscCall(VecMin(ks, &mincell, &minalpha));
722fd7102fcSMatthew G. Knepley   PetscCall(VecMax(ks, &maxcell, &maxalpha));
723fd7102fcSMatthew 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));
724fd7102fcSMatthew G. Knepley   PetscCall(VecViewFromOptions(ks, NULL, "-ks_view"));
725fd7102fcSMatthew G. Knepley   PetscCall(VecDestroy(&ks));
726fd7102fcSMatthew G. Knepley 
727*2a8381b2SBarry Smith   PetscCall(PetscDrawHGDraw(ctx->drawhgcell_v));
728*2a8381b2SBarry Smith   PetscCall(PetscDrawHGSave(ctx->drawhgcell_v));
729fd7102fcSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
730fd7102fcSMatthew G. Knepley }
731fd7102fcSMatthew G. Knepley 
MonitorPositions_2D(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)732*2a8381b2SBarry Smith static PetscErrorCode MonitorPositions_2D(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
7338214e71cSJoe {
734*2a8381b2SBarry Smith   AppCtx         *ctx = (AppCtx *)Ctx;
7358214e71cSJoe   DM              dm, sw;
736f940b0e3Sdanofinn   PetscDrawAxis   axis;
737f940b0e3Sdanofinn   char            title[1024];
7388214e71cSJoe   PetscScalar    *x, *v, *weight;
7398214e71cSJoe   PetscReal       lower[3], upper[3], speed;
7408214e71cSJoe   const PetscInt *s;
7418214e71cSJoe   PetscInt        dim, cStart, cEnd, c;
7428214e71cSJoe 
7438214e71cSJoe   PetscFunctionBeginUser;
744*2a8381b2SBarry Smith   if (step > 0 && step % ctx->ostep == 0) {
7458214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
7468214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
7478214e71cSJoe     PetscCall(DMGetDimension(dm, &dim));
7488214e71cSJoe     PetscCall(DMGetBoundingBox(dm, lower, upper));
7498214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
7508214e71cSJoe     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
7518214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
7528214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
7538214e71cSJoe     PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&s));
7548214e71cSJoe     PetscCall(DMSwarmSortGetAccess(sw));
755*2a8381b2SBarry Smith     PetscCall(PetscDrawSPReset(ctx->drawspX));
756*2a8381b2SBarry Smith     PetscCall(PetscDrawSPGetAxis(ctx->drawspX, &axis));
757f940b0e3Sdanofinn     PetscCall(PetscSNPrintf(title, 1024, "Step %" PetscInt_FMT " Time: %g", step, (double)t));
758f940b0e3Sdanofinn     PetscCall(PetscDrawAxisSetLabels(axis, title, "x", "v"));
759*2a8381b2SBarry Smith     PetscCall(PetscDrawSPSetLimits(ctx->drawspX, lower[0], upper[0], lower[1], upper[1]));
760*2a8381b2SBarry Smith     PetscCall(PetscDrawSPSetLimits(ctx->drawspX, lower[0], upper[0], -12, 12));
7618214e71cSJoe     for (c = 0; c < cEnd - cStart; ++c) {
7628214e71cSJoe       PetscInt *pidx, Npc, q;
7638214e71cSJoe       PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
7648214e71cSJoe       for (q = 0; q < Npc; ++q) {
7658214e71cSJoe         const PetscInt p = pidx[q];
7668214e71cSJoe         if (s[p] == 0) {
7679072cb8bSMatthew G. Knepley           speed = 0.;
7689072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) speed += PetscSqr(v[p * dim + d]);
7699072cb8bSMatthew G. Knepley           speed = PetscSqrtReal(speed);
770045208b8SMatthew G. Knepley           if (dim == 1) {
771*2a8381b2SBarry Smith             PetscCall(PetscDrawSPAddPointColorized(ctx->drawspX, &x[p * dim], &v[p * dim], &speed));
7728214e71cSJoe           } else {
773*2a8381b2SBarry Smith             PetscCall(PetscDrawSPAddPointColorized(ctx->drawspX, &x[p * dim], &x[p * dim + 1], &speed));
7748214e71cSJoe           }
7758214e71cSJoe         } else if (s[p] == 1) {
776*2a8381b2SBarry Smith           PetscCall(PetscDrawSPAddPoint(ctx->drawspX, &x[p * dim], &v[p * dim]));
7778214e71cSJoe         }
7788214e71cSJoe       }
77984467f86SMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
7808214e71cSJoe     }
781*2a8381b2SBarry Smith     PetscCall(PetscDrawSPDraw(ctx->drawspX, PETSC_TRUE));
78275155f48SMatthew G. Knepley     PetscDraw draw;
783*2a8381b2SBarry Smith     PetscCall(PetscDrawSPGetDraw(ctx->drawspX, &draw));
78475155f48SMatthew G. Knepley     PetscCall(PetscDrawSave(draw));
7858214e71cSJoe     PetscCall(DMSwarmSortRestoreAccess(sw));
7868214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
7878214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
7888214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
7898214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&s));
7908214e71cSJoe   }
7918214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
7928214e71cSJoe }
7938214e71cSJoe 
MonitorPoisson(TS ts,PetscInt step,PetscReal t,Vec U,void * Ctx)794*2a8381b2SBarry Smith static PetscErrorCode MonitorPoisson(TS ts, PetscInt step, PetscReal t, Vec U, void *Ctx)
7958214e71cSJoe {
796*2a8381b2SBarry Smith   AppCtx *ctx = (AppCtx *)Ctx;
7978214e71cSJoe   DM      dm, sw;
7988214e71cSJoe 
7998214e71cSJoe   PetscFunctionBeginUser;
800*2a8381b2SBarry Smith   if (step > 0 && step % ctx->ostep == 0) {
8018214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
8028214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
8039072cb8bSMatthew G. Knepley 
804*2a8381b2SBarry Smith     if (ctx->validE) {
8059072cb8bSMatthew G. Knepley       PetscScalar *x, *E, *weight;
8069072cb8bSMatthew G. Knepley       PetscReal    lower[3], upper[3], xval;
8079072cb8bSMatthew G. Knepley       PetscDraw    draw;
8089072cb8bSMatthew G. Knepley       PetscInt     dim, cStart, cEnd;
8099072cb8bSMatthew G. Knepley 
8108214e71cSJoe       PetscCall(DMGetDimension(dm, &dim));
8118214e71cSJoe       PetscCall(DMGetBoundingBox(dm, lower, upper));
8128214e71cSJoe       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
8138214e71cSJoe 
814*2a8381b2SBarry Smith       PetscCall(PetscDrawSPReset(ctx->drawspE));
8158214e71cSJoe       PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
8168214e71cSJoe       PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
8178214e71cSJoe       PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
8188214e71cSJoe 
8198214e71cSJoe       PetscCall(DMSwarmSortGetAccess(sw));
8209072cb8bSMatthew G. Knepley       for (PetscInt c = 0; c < cEnd - cStart; ++c) {
82175155f48SMatthew G. Knepley         PetscReal Eavg = 0.0;
8229072cb8bSMatthew G. Knepley         PetscInt *pidx, Npc;
8239072cb8bSMatthew G. Knepley 
8248214e71cSJoe         PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
8259072cb8bSMatthew G. Knepley         for (PetscInt q = 0; q < Npc; ++q) {
8268214e71cSJoe           const PetscInt p = pidx[q];
82775155f48SMatthew G. Knepley           Eavg += E[p * dim];
8288214e71cSJoe         }
82975155f48SMatthew G. Knepley         Eavg /= Npc;
8308214e71cSJoe         xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart));
831*2a8381b2SBarry Smith         PetscCall(PetscDrawSPAddPoint(ctx->drawspE, &xval, &Eavg));
83284467f86SMatthew G. Knepley         PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
8338214e71cSJoe       }
834*2a8381b2SBarry Smith       PetscCall(PetscDrawSPDraw(ctx->drawspE, PETSC_TRUE));
835*2a8381b2SBarry Smith       PetscCall(PetscDrawSPGetDraw(ctx->drawspE, &draw));
83675155f48SMatthew G. Knepley       PetscCall(PetscDrawSave(draw));
8378214e71cSJoe       PetscCall(DMSwarmSortRestoreAccess(sw));
8388214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
8398214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
8408214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
8419072cb8bSMatthew G. Knepley     }
84275155f48SMatthew G. Knepley 
843b02f317dSMatthew G. Knepley     Vec rho, rhohat, phi;
84475155f48SMatthew G. Knepley 
845*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rho", &rho));
846*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
847*2a8381b2SBarry Smith     PetscCall(VecView(rho, ctx->viewerRho));
848*2a8381b2SBarry Smith     PetscCall(VecISCopy(ctx->fftX, ctx->fftReal, SCATTER_FORWARD, rho));
849*2a8381b2SBarry Smith     PetscCall(MatMult(ctx->fftPot, ctx->fftX, ctx->fftY));
850*2a8381b2SBarry Smith     PetscCall(VecFilter(ctx->fftY, PETSC_SMALL));
851*2a8381b2SBarry Smith     PetscCall(VecViewFromOptions(ctx->fftX, NULL, "-real_view"));
852*2a8381b2SBarry Smith     PetscCall(VecViewFromOptions(ctx->fftY, NULL, "-fft_view"));
853*2a8381b2SBarry Smith     PetscCall(VecISCopy(ctx->fftY, ctx->fftReal, SCATTER_REVERSE, rhohat));
854fd7102fcSMatthew G. Knepley     PetscCall(VecSetValue(rhohat, 0, 0., INSERT_VALUES)); // Remove large DC component
855*2a8381b2SBarry Smith     PetscCall(VecView(rhohat, ctx->viewerRhoHat));
856*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rho", &rho));
857*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rhohat", &rhohat));
858b02f317dSMatthew G. Knepley 
859*2a8381b2SBarry Smith     PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
860*2a8381b2SBarry Smith     PetscCall(VecView(phi, ctx->viewerPhi));
861*2a8381b2SBarry Smith     PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
8628214e71cSJoe   }
8638214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
8648214e71cSJoe }
8658214e71cSJoe 
SetupParameters(MPI_Comm comm,AppCtx * ctx)8668214e71cSJoe static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx)
8678214e71cSJoe {
8688214e71cSJoe   PetscBag   bag;
8698214e71cSJoe   Parameter *p;
8708214e71cSJoe 
8718214e71cSJoe   PetscFunctionBeginUser;
8728214e71cSJoe   /* setup PETSc parameter bag */
873*2a8381b2SBarry Smith   PetscCall(PetscBagGetData(ctx->bag, &p));
8748214e71cSJoe   PetscCall(PetscBagSetName(ctx->bag, "par", "Vlasov-Poisson Parameters"));
8758214e71cSJoe   bag = ctx->bag;
8768214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "v0", "Velocity scale, m/s"));
8778214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->t0, 1.0, "t0", "Time scale, s"));
8788214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->x0, 1.0, "x0", "Space scale, m"));
8798214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "phi0", "Potential scale, kg*m^2/A*s^3"));
8808214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->q0, 1.0, "q0", "Charge Scale, A*s"));
8818214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->m0, 1.0, "m0", "Mass Scale, kg"));
8828214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->epsi0, 1.0, "epsi0", "Permittivity of Free Space, kg"));
8838214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->kb, 1.0, "kb", "Boltzmann Constant, m^2 kg/s^2 K^1"));
8848214e71cSJoe 
8858214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->sigma, 1.0, "sigma", "Charge per unit area, C/m^3"));
8868214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->poissonNumber, 1.0, "poissonNumber", "Non-Dimensional Poisson Number"));
8878214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->vlasovNumber, 1.0, "vlasovNumber", "Non-Dimensional Vlasov Number"));
8888214e71cSJoe   PetscCall(PetscBagSetFromOptions(bag));
8898214e71cSJoe   {
8908214e71cSJoe     PetscViewer       viewer;
8918214e71cSJoe     PetscViewerFormat format;
8928214e71cSJoe     PetscBool         flg;
8938214e71cSJoe 
894648c30bcSBarry Smith     PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg));
8958214e71cSJoe     if (flg) {
8968214e71cSJoe       PetscCall(PetscViewerPushFormat(viewer, format));
8978214e71cSJoe       PetscCall(PetscBagView(bag, viewer));
8988214e71cSJoe       PetscCall(PetscViewerFlush(viewer));
8998214e71cSJoe       PetscCall(PetscViewerPopFormat(viewer));
9008214e71cSJoe       PetscCall(PetscViewerDestroy(&viewer));
9018214e71cSJoe     }
9028214e71cSJoe   }
9038214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
9048214e71cSJoe }
9058214e71cSJoe 
CreateMesh(MPI_Comm comm,AppCtx * ctx,DM * dm)906*2a8381b2SBarry Smith static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *ctx, DM *dm)
907d71ae5a4SJacob Faibussowitsch {
908b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
9099566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
9109566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
9119566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*dm));
9129072cb8bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*dm, "space"));
9139566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
914f1e6e573SMatthew G. Knepley 
915f1e6e573SMatthew G. Knepley   // Cache the mesh geometry
916f1e6e573SMatthew G. Knepley   DMField         coordField;
917f1e6e573SMatthew G. Knepley   IS              cellIS;
918f1e6e573SMatthew G. Knepley   PetscQuadrature quad;
919f1e6e573SMatthew G. Knepley   PetscReal      *wt, *pt;
920f1e6e573SMatthew G. Knepley   PetscInt        cdim, cStart, cEnd;
921f1e6e573SMatthew G. Knepley 
922f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateField(*dm, &coordField));
923f1e6e573SMatthew G. Knepley   PetscCheck(coordField, comm, PETSC_ERR_USER, "DM must have a coordinate field");
924f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateDim(*dm, &cdim));
925f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd));
926f1e6e573SMatthew G. Knepley   PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cellIS));
927f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
928f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(1, &wt));
929f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(2, &pt));
930f1e6e573SMatthew G. Knepley   wt[0] = 1.;
931f1e6e573SMatthew G. Knepley   pt[0] = -1.;
932f1e6e573SMatthew G. Knepley   pt[1] = -1.;
933f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureSetData(quad, cdim, 1, 1, pt, wt));
934*2a8381b2SBarry Smith   PetscCall(DMFieldCreateFEGeom(coordField, cellIS, quad, PETSC_FEGEOM_BASIC, &ctx->fegeom));
935f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&quad));
936f1e6e573SMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
9373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
938b80bf5b1SJoe Pusztay }
939b80bf5b1SJoe Pusztay 
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[])9408214e71cSJoe 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[])
9418214e71cSJoe {
9428214e71cSJoe   f0[0] = -constants[SIGMA];
9438214e71cSJoe }
9448214e71cSJoe 
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[])945d71ae5a4SJacob Faibussowitsch 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[])
946d71ae5a4SJacob Faibussowitsch {
947b80bf5b1SJoe Pusztay   PetscInt d;
948ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) f1[d] = u_x[d];
949b80bf5b1SJoe Pusztay }
950b80bf5b1SJoe Pusztay 
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[])9518214e71cSJoe 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[])
952d71ae5a4SJacob Faibussowitsch {
953b80bf5b1SJoe Pusztay   PetscInt d;
954ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) g3[d * dim + d] = 1.0;
955b80bf5b1SJoe Pusztay }
956b80bf5b1SJoe Pusztay 
zero(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)957*2a8381b2SBarry Smith static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
958d71ae5a4SJacob Faibussowitsch {
9598214e71cSJoe   *u = 0.0;
9608214e71cSJoe   return PETSC_SUCCESS;
961b80bf5b1SJoe Pusztay }
962b80bf5b1SJoe Pusztay 
963b80bf5b1SJoe Pusztay /*
9648214e71cSJoe    /  I   -grad\ / q \ = /0\
9658214e71cSJoe    \-div    0  / \phi/   \f/
966b80bf5b1SJoe Pusztay */
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[])9678214e71cSJoe 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[])
968d71ae5a4SJacob Faibussowitsch {
9698214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[d] += u[uOff[0] + d];
9708214e71cSJoe }
9718214e71cSJoe 
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[])9728214e71cSJoe 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[])
9738214e71cSJoe {
9748214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f1[d * dim + d] = u[uOff[1]];
9758214e71cSJoe }
9768214e71cSJoe 
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[])9778214e71cSJoe 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[])
9788214e71cSJoe {
9798214e71cSJoe   f0[0] += constants[SIGMA];
9808214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[0] += u_x[uOff_x[0] + d * dim + d];
9818214e71cSJoe }
9828214e71cSJoe 
9838214e71cSJoe /* Boundary residual. Dirichlet boundary for u means u_bdy=p*n */
g0_qq(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g0[])9848214e71cSJoe 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[])
9858214e71cSJoe {
9868214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g0[d * dim + d] = 1.0;
9878214e71cSJoe }
9888214e71cSJoe 
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[])9898214e71cSJoe 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[])
9908214e71cSJoe {
9918214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g2[d * dim + d] = 1.0;
9928214e71cSJoe }
9938214e71cSJoe 
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[])9948214e71cSJoe 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[])
9958214e71cSJoe {
9968214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g1[d * dim + d] = 1.0;
9978214e71cSJoe }
9988214e71cSJoe 
CreateFEM(DM dm,AppCtx * ctx)999*2a8381b2SBarry Smith static PetscErrorCode CreateFEM(DM dm, AppCtx *ctx)
10008214e71cSJoe {
10018214e71cSJoe   PetscFE   fephi, feq;
10028214e71cSJoe   PetscDS   ds;
10038214e71cSJoe   PetscBool simplex;
10048214e71cSJoe   PetscInt  dim;
10058214e71cSJoe 
10068214e71cSJoe   PetscFunctionBeginUser;
10078214e71cSJoe   PetscCall(DMGetDimension(dm, &dim));
10088214e71cSJoe   PetscCall(DMPlexIsSimplex(dm, &simplex));
1009*2a8381b2SBarry Smith   if (ctx->em == EM_MIXED) {
10108214e71cSJoe     DMLabel        label;
10118214e71cSJoe     const PetscInt id = 1;
10128214e71cSJoe 
10138214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "field_", PETSC_DETERMINE, &feq));
10148214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)feq, "field"));
10158214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "potential_", PETSC_DETERMINE, &fephi));
10168214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
10178214e71cSJoe     PetscCall(PetscFECopyQuadrature(feq, fephi));
10188214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)feq));
10198214e71cSJoe     PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fephi));
10208214e71cSJoe     PetscCall(DMCreateDS(dm));
10218214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
10228214e71cSJoe     PetscCall(PetscFEDestroy(&feq));
10238214e71cSJoe 
10248214e71cSJoe     PetscCall(DMGetLabel(dm, "marker", &label));
10258214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
10268214e71cSJoe 
10278214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, f0_q, f1_q));
10288214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 1, f0_phi_backgroundCharge, NULL));
10298214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_qq, NULL, NULL, NULL));
10308214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_qphi, NULL));
10318214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_phiq, NULL, NULL));
10328214e71cSJoe 
103357d50842SBarry Smith     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)zero, NULL, NULL, NULL));
10348214e71cSJoe 
1035f1e6e573SMatthew G. Knepley   } else {
10368214e71cSJoe     MatNullSpace nullsp;
10378214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, PETSC_DETERMINE, &fephi));
10388214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
10398214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fephi));
10408214e71cSJoe     PetscCall(DMCreateDS(dm));
10418214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
10428214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, ion_f0, laplacian_f1));
10438214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, laplacian_g3));
10448214e71cSJoe     PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullsp));
10458214e71cSJoe     PetscCall(PetscObjectCompose((PetscObject)fephi, "nullspace", (PetscObject)nullsp));
10468214e71cSJoe     PetscCall(MatNullSpaceDestroy(&nullsp));
10478214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
10488214e71cSJoe   }
10498214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
10508214e71cSJoe }
10518214e71cSJoe 
CreatePoisson(DM dm,AppCtx * ctx)1052*2a8381b2SBarry Smith static PetscErrorCode CreatePoisson(DM dm, AppCtx *ctx)
10538214e71cSJoe {
10548214e71cSJoe   SNES         snes;
10558214e71cSJoe   Mat          J;
10568214e71cSJoe   MatNullSpace nullSpace;
10578214e71cSJoe 
10588214e71cSJoe   PetscFunctionBeginUser;
1059*2a8381b2SBarry Smith   PetscCall(CreateFEM(dm, ctx));
10608214e71cSJoe   PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes));
10618214e71cSJoe   PetscCall(SNESSetOptionsPrefix(snes, "em_"));
10628214e71cSJoe   PetscCall(SNESSetDM(snes, dm));
1063*2a8381b2SBarry Smith   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, ctx));
10648214e71cSJoe   PetscCall(SNESSetFromOptions(snes));
10658214e71cSJoe 
10668214e71cSJoe   PetscCall(DMCreateMatrix(dm, &J));
10678214e71cSJoe   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullSpace));
10688214e71cSJoe   PetscCall(MatSetNullSpace(J, nullSpace));
10698214e71cSJoe   PetscCall(MatNullSpaceDestroy(&nullSpace));
10708214e71cSJoe   PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL));
10718214e71cSJoe   PetscCall(MatDestroy(&J));
1072*2a8381b2SBarry Smith   if (ctx->em == EM_MIXED) {
10734a0cbf56SMatthew G. Knepley     const PetscInt potential = 1;
10744a0cbf56SMatthew G. Knepley 
1075*2a8381b2SBarry Smith     PetscCall(DMCreateSubDM(dm, 1, &potential, &ctx->isPot, &ctx->dmPot));
10764a0cbf56SMatthew G. Knepley   } else {
1077*2a8381b2SBarry Smith     ctx->dmPot = dm;
1078*2a8381b2SBarry Smith     PetscCall(PetscObjectReference((PetscObject)ctx->dmPot));
10794a0cbf56SMatthew G. Knepley   }
1080*2a8381b2SBarry Smith   PetscCall(DMCreateMassMatrix(ctx->dmPot, ctx->dmPot, &ctx->M));
1081f1e6e573SMatthew G. Knepley   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
1082*2a8381b2SBarry Smith   ctx->snes = snes;
10838214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
10848214e71cSJoe }
10858214e71cSJoe 
PetscPDFPertubedConstant2D(const PetscReal x[],const PetscReal dummy[],PetscReal p[])10868214e71cSJoe PetscErrorCode PetscPDFPertubedConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
10878214e71cSJoe {
10888214e71cSJoe   p[0] = (1 + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
10898214e71cSJoe   p[1] = (1 + 0.01 * PetscCosReal(0.5 * x[1])) / (2 * PETSC_PI);
10908214e71cSJoe   return PETSC_SUCCESS;
10918214e71cSJoe }
PetscPDFPertubedConstant1D(const PetscReal x[],const PetscReal dummy[],PetscReal p[])10928214e71cSJoe PetscErrorCode PetscPDFPertubedConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
10938214e71cSJoe {
10948214e71cSJoe   p[0] = (1. + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
10958214e71cSJoe   return PETSC_SUCCESS;
10968214e71cSJoe }
10978214e71cSJoe 
PetscPDFCosine1D(const PetscReal x[],const PetscReal scale[],PetscReal p[])10988214e71cSJoe PetscErrorCode PetscPDFCosine1D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
10998214e71cSJoe {
11008214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.0;
11018214e71cSJoe   const PetscReal k     = scale ? scale[1] : 1.;
11028214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * x[0]));
11038214e71cSJoe   return PETSC_SUCCESS;
11048214e71cSJoe }
11058214e71cSJoe 
PetscPDFCosine2D(const PetscReal x[],const PetscReal scale[],PetscReal p[])11068214e71cSJoe PetscErrorCode PetscPDFCosine2D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
11078214e71cSJoe {
11088214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.;
11098214e71cSJoe   const PetscReal k     = scale ? scale[0] : 1.;
11108214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * (x[0] + x[1])));
11118214e71cSJoe   return PETSC_SUCCESS;
11128214e71cSJoe }
11138214e71cSJoe 
CreateVelocityDM(DM sw,DM * vdm)111484467f86SMatthew G. Knepley static PetscErrorCode CreateVelocityDM(DM sw, DM *vdm)
11158214e71cSJoe {
1116f1e6e573SMatthew G. Knepley   PetscFE        fe;
1117f1e6e573SMatthew G. Knepley   DMPolytopeType ct;
1118f1e6e573SMatthew G. Knepley   PetscInt       dim, cStart;
1119f1e6e573SMatthew G. Knepley   const char    *prefix = "v";
1120f1e6e573SMatthew G. Knepley 
112184467f86SMatthew G. Knepley   PetscFunctionBegin;
112284467f86SMatthew G. Knepley   PetscCall(DMCreate(PETSC_COMM_SELF, vdm));
112384467f86SMatthew G. Knepley   PetscCall(DMSetType(*vdm, DMPLEX));
1124f1e6e573SMatthew G. Knepley   PetscCall(DMPlexSetOptionsPrefix(*vdm, prefix));
112584467f86SMatthew G. Knepley   PetscCall(DMSetFromOptions(*vdm));
11269072cb8bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*vdm, "velocity"));
112784467f86SMatthew G. Knepley   PetscCall(DMViewFromOptions(*vdm, NULL, "-dm_view"));
1128f1e6e573SMatthew G. Knepley 
1129f1e6e573SMatthew G. Knepley   PetscCall(DMGetDimension(*vdm, &dim));
1130f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*vdm, 0, &cStart, NULL));
1131f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetCellType(*vdm, cStart, &ct));
1132f1e6e573SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe));
1133f1e6e573SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "distribution"));
1134f1e6e573SMatthew G. Knepley   PetscCall(DMSetField(*vdm, 0, NULL, (PetscObject)fe));
1135f1e6e573SMatthew G. Knepley   PetscCall(DMCreateDS(*vdm));
1136f1e6e573SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
113784467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
11388214e71cSJoe }
11398214e71cSJoe 
11409072cb8bSMatthew G. Knepley /*
11419072cb8bSMatthew G. Knepley   InitializeParticles_Centroid - Initialize a regular grid of particles.
11429072cb8bSMatthew G. Knepley 
11439072cb8bSMatthew G. Knepley   Input Parameters:
11449072cb8bSMatthew G. Knepley + sw      - The `DMSWARM`
11459072cb8bSMatthew G. Knepley - force1D - Treat the spatial domain as 1D
11469072cb8bSMatthew G. Knepley 
11479072cb8bSMatthew G. Knepley   Notes:
11489072cb8bSMatthew G. Knepley   This functions sets the species, cellid, spatial coordinate, and velocity fields for all particles.
11499072cb8bSMatthew G. Knepley 
11509072cb8bSMatthew G. Knepley   It places one particle in the centroid of each cell in the implicit tensor product of the spatial
11519072cb8bSMatthew G. Knepley   and velocity meshes.
11529072cb8bSMatthew G. Knepley */
InitializeParticles_Centroid(DM sw)1153045208b8SMatthew G. Knepley static PetscErrorCode InitializeParticles_Centroid(DM sw)
11548214e71cSJoe {
115584467f86SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
11569072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
115784467f86SMatthew G. Knepley   DM            xdm, vdm;
115884467f86SMatthew G. Knepley   PetscReal     vmin[3], vmax[3];
115984467f86SMatthew G. Knepley   PetscReal    *x, *v;
116084467f86SMatthew G. Knepley   PetscInt     *species, *cellid;
116184467f86SMatthew G. Knepley   PetscInt      dim, xcStart, xcEnd, vcStart, vcEnd, Ns, Np, Npc, debug;
11628214e71cSJoe   PetscBool     flg;
116384467f86SMatthew G. Knepley   MPI_Comm      comm;
11649072cb8bSMatthew G. Knepley   const char   *cellidname;
11658214e71cSJoe 
11668214e71cSJoe   PetscFunctionBegin;
116784467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
116884467f86SMatthew G. Knepley 
116984467f86SMatthew G. Knepley   PetscOptionsBegin(comm, "", "DMSwarm Options", "DMSWARM");
11708214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
11718214e71cSJoe   PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg));
11728214e71cSJoe   if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns));
117384467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_coords", "Debug output level for particle coordinate computations", "InitializeParticles", 0, &swarm->printCoords, NULL, 0));
117484467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_weights", "Debug output level for particle weight computations", "InitializeWeights", 0, &swarm->printWeights, NULL, 0));
11758214e71cSJoe   PetscOptionsEnd();
117684467f86SMatthew G. Knepley   debug = swarm->printCoords;
11778214e71cSJoe 
11788214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
117984467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
118084467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
11818214e71cSJoe 
1182045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
1183045208b8SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
118484467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
11858214e71cSJoe 
118684467f86SMatthew G. Knepley   // One particle per centroid on the tensor product grid
118784467f86SMatthew G. Knepley   Npc = (vcEnd - vcStart) * Ns;
118884467f86SMatthew G. Knepley   Np  = (xcEnd - xcStart) * Npc;
11898214e71cSJoe   PetscCall(DMSwarmSetLocalSizes(sw, Np, 0));
119084467f86SMatthew G. Knepley   if (debug) {
1191fd7102fcSMatthew G. Knepley     PetscInt gNp, gNc, Nc = xcEnd - xcStart;
119284467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Np, &gNp, 1, MPIU_INT, MPIU_SUM, comm));
119384467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global Np = %" PetscInt_FMT "\n", gNp));
1194fd7102fcSMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Nc, &gNc, 1, MPIU_INT, MPIU_SUM, comm));
1195fd7102fcSMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global X-cells = %" PetscInt_FMT "\n", gNc));
1196fd7102fcSMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global V-cells = %" PetscInt_FMT "\n", vcEnd - vcStart));
11978214e71cSJoe   }
11988214e71cSJoe 
119984467f86SMatthew G. Knepley   // Set species and cellid
12009072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
12019072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCellID(celldm, &cellidname));
120284467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
12039072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, cellidname, NULL, NULL, (void **)&cellid));
120484467f86SMatthew G. Knepley   for (PetscInt c = 0, p = 0; c < xcEnd - xcStart; ++c) {
120584467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
120684467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q, ++p) {
120784467f86SMatthew G. Knepley         species[p] = s;
120884467f86SMatthew G. Knepley         cellid[p]  = c;
120984467f86SMatthew G. Knepley       }
121084467f86SMatthew G. Knepley     }
121184467f86SMatthew G. Knepley   }
121284467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
12139072cb8bSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, cellidname, NULL, NULL, (void **)&cellid));
121484467f86SMatthew G. Knepley 
121584467f86SMatthew G. Knepley   // Set particle coordinates
12168214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
12178214e71cSJoe   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
12188214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
121984467f86SMatthew G. Knepley   PetscCall(DMGetBoundingBox(vdm, vmin, vmax));
122084467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(xdm));
122184467f86SMatthew G. Knepley   for (PetscInt c = 0; c < xcEnd - xcStart; ++c) {
122284467f86SMatthew G. Knepley     const PetscInt cell = c + xcStart;
12238214e71cSJoe     PetscInt      *pidx, Npc;
12248214e71cSJoe     PetscReal      centroid[3], volume;
12258214e71cSJoe 
12268214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
122784467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFVM(xdm, cell, &volume, centroid, NULL));
122884467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
122984467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q) {
123084467f86SMatthew G. Knepley         const PetscInt p = pidx[q * Ns + s];
12318214e71cSJoe 
123284467f86SMatthew G. Knepley         for (PetscInt d = 0; d < dim; ++d) {
12338214e71cSJoe           x[p * dim + d] = centroid[d];
123484467f86SMatthew G. Knepley           v[p * dim + d] = vmin[0] + (q + 0.5) * ((vmax[0] - vmin[0]) / (Npc / Ns));
12358214e71cSJoe         }
12369072cb8bSMatthew G. Knepley         if (debug > 1) {
12379072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "Particle %4" PetscInt_FMT " ", p));
12389072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  x: ("));
12399072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
12409072cb8bSMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
12419072cb8bSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", x[p * dim + d]));
12429072cb8bSMatthew G. Knepley           }
12439072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ") v:("));
12449072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
12459072cb8bSMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
12469072cb8bSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", v[p * dim + d]));
12479072cb8bSMatthew G. Knepley           }
12489072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
12499072cb8bSMatthew G. Knepley         }
12508214e71cSJoe       }
12518214e71cSJoe     }
125284467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
12538214e71cSJoe   }
12548214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
12558214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
12568214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
125784467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
125884467f86SMatthew G. Knepley }
125984467f86SMatthew G. Knepley 
126084467f86SMatthew G. Knepley /*
126184467f86SMatthew G. Knepley   InitializeWeights - Compute weight for each local particle
126284467f86SMatthew G. Knepley 
126384467f86SMatthew G. Knepley   Input Parameters:
126484467f86SMatthew G. Knepley + sw          - The `DMSwarm`
126584467f86SMatthew G. Knepley . totalWeight - The sum of all particle weights
126684467f86SMatthew G. Knepley . func        - The PDF for the particle spatial distribution
126784467f86SMatthew G. Knepley - param       - The PDF parameters
126884467f86SMatthew G. Knepley 
126984467f86SMatthew G. Knepley   Notes:
127084467f86SMatthew G. Knepley   The PDF for velocity is assumed to be a Gaussian
127184467f86SMatthew G. Knepley 
127284467f86SMatthew G. Knepley   The particle weights are returned in the `w_q` field of `sw`.
127384467f86SMatthew G. Knepley */
InitializeWeights(DM sw,PetscReal totalWeight,PetscProbFn * func,const PetscReal param[])1274f8662bd6SBarry Smith static PetscErrorCode InitializeWeights(DM sw, PetscReal totalWeight, PetscProbFn *func, const PetscReal param[])
127584467f86SMatthew G. Knepley {
127684467f86SMatthew G. Knepley   DM               xdm, vdm;
1277045208b8SMatthew G. Knepley   DMSwarmCellDM    celldm;
127884467f86SMatthew G. Knepley   PetscScalar     *weight;
127984467f86SMatthew G. Knepley   PetscQuadrature  xquad;
128084467f86SMatthew G. Knepley   const PetscReal *xq, *xwq;
128184467f86SMatthew G. Knepley   const PetscInt   order = 5;
1282045208b8SMatthew G. Knepley   PetscReal        xi0[3];
128384467f86SMatthew G. Knepley   PetscReal        xwtot = 0., pwtot = 0.;
128484467f86SMatthew G. Knepley   PetscInt         xNq;
128584467f86SMatthew G. Knepley   PetscInt         dim, Ns, xcStart, xcEnd, vcStart, vcEnd, debug = ((DM_Swarm *)sw->data)->printWeights;
128684467f86SMatthew G. Knepley   MPI_Comm         comm;
128784467f86SMatthew G. Knepley   PetscMPIInt      rank;
128884467f86SMatthew G. Knepley 
128984467f86SMatthew G. Knepley   PetscFunctionBegin;
129084467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
129184467f86SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
129284467f86SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
129384467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
129484467f86SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
129584467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
1296045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
1297045208b8SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
129884467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
129984467f86SMatthew G. Knepley 
130084467f86SMatthew G. Knepley   // Setup Quadrature for spatial and velocity weight calculations
1301045208b8SMatthew G. Knepley   PetscCall(PetscDTGaussTensorQuadrature(dim, 1, order, -1.0, 1.0, &xquad));
130284467f86SMatthew G. Knepley   PetscCall(PetscQuadratureGetData(xquad, NULL, NULL, &xNq, &xq, &xwq));
130384467f86SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) xi0[d] = -1.0;
130484467f86SMatthew G. Knepley 
130584467f86SMatthew G. Knepley   // Integrate the density function to get the weights of particles in each cell
130684467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(vdm));
130784467f86SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
130884467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
130984467f86SMatthew G. Knepley   for (PetscInt c = xcStart; c < xcEnd; ++c) {
131084467f86SMatthew G. Knepley     PetscReal          xv0[3], xJ[9], xinvJ[9], xdetJ, xqr[3], xden, xw = 0.;
131184467f86SMatthew G. Knepley     PetscInt          *pidx, Npc;
131284467f86SMatthew G. Knepley     PetscInt           xNc;
131384467f86SMatthew G. Knepley     const PetscScalar *xarray;
131484467f86SMatthew G. Knepley     PetscScalar       *xcoords = NULL;
131584467f86SMatthew G. Knepley     PetscBool          xisDG;
131684467f86SMatthew G. Knepley 
131784467f86SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
131884467f86SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
131984467f86SMatthew 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);
132084467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFEM(xdm, c, NULL, xv0, xJ, xinvJ, &xdetJ));
132184467f86SMatthew G. Knepley     for (PetscInt q = 0; q < xNq; ++q) {
132284467f86SMatthew G. Knepley       // Transform quadrature points from ref space to real space
1323045208b8SMatthew G. Knepley       CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xq[q * dim], xqr);
132484467f86SMatthew G. Knepley       // Get probability density at quad point
132584467f86SMatthew G. Knepley       //   No need to scale xqr since PDF will be periodic
132684467f86SMatthew G. Knepley       PetscCall((*func)(xqr, param, &xden));
132784467f86SMatthew G. Knepley       xw += xden * (xwq[q] * xdetJ);
132884467f86SMatthew G. Knepley     }
132984467f86SMatthew G. Knepley     xwtot += xw;
133084467f86SMatthew G. Knepley     if (debug) {
133184467f86SMatthew G. Knepley       IS              globalOrdering;
133284467f86SMatthew G. Knepley       const PetscInt *ordering;
133384467f86SMatthew G. Knepley 
133484467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellNumbering(xdm, &globalOrdering));
133584467f86SMatthew G. Knepley       PetscCall(ISGetIndices(globalOrdering, &ordering));
133675155f48SMatthew 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));
133784467f86SMatthew G. Knepley       PetscCall(ISRestoreIndices(globalOrdering, &ordering));
133884467f86SMatthew G. Knepley     }
133984467f86SMatthew G. Knepley     // Set weights to be Gaussian in velocity cells
134084467f86SMatthew G. Knepley     for (PetscInt vc = vcStart; vc < vcEnd; ++vc) {
134184467f86SMatthew G. Knepley       const PetscInt     p  = pidx[vc * Ns + 0];
134284467f86SMatthew G. Knepley       PetscReal          vw = 0.;
134384467f86SMatthew G. Knepley       PetscInt           vNc;
134484467f86SMatthew G. Knepley       const PetscScalar *varray;
134584467f86SMatthew G. Knepley       PetscScalar       *vcoords = NULL;
134684467f86SMatthew G. Knepley       PetscBool          visDG;
134784467f86SMatthew G. Knepley 
134884467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
134984467f86SMatthew G. Knepley       // TODO: Fix 2 stream Ask Joe
135084467f86SMatthew G. Knepley       //   Two stream function from 1/2pi v^2 e^(-v^2/2)
135184467f86SMatthew 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.)));
135284467f86SMatthew G. Knepley       vw = 0.5 * (PetscErfReal(vcoords[1] / PetscSqrtReal(2.)) - PetscErfReal(vcoords[0] / PetscSqrtReal(2.)));
135384467f86SMatthew G. Knepley 
135484467f86SMatthew G. Knepley       weight[p] = totalWeight * vw * xw;
135584467f86SMatthew G. Knepley       pwtot += weight[p];
1356bfe80ac4SPierre Jolivet       PetscCheck(weight[p] <= 10., PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Particle %" PetscInt_FMT " weight exceeded 1: %g, %g, %g", p, xw, vw, totalWeight);
135784467f86SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
135884467f86SMatthew G. Knepley       if (debug > 1) PetscCall(PetscPrintf(comm, "particle %" PetscInt_FMT ": %g, vw: %g xw: %g\n", p, weight[p], vw, xw));
135984467f86SMatthew G. Knepley     }
136084467f86SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
136184467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
136284467f86SMatthew G. Knepley   }
136384467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
136484467f86SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
136584467f86SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&xquad));
136684467f86SMatthew G. Knepley 
136784467f86SMatthew G. Knepley   if (debug) {
136884467f86SMatthew G. Knepley     PetscReal wtot[2] = {pwtot, xwtot}, gwtot[2];
136984467f86SMatthew G. Knepley 
137084467f86SMatthew G. Knepley     PetscCall(PetscSynchronizedFlush(comm, NULL));
137184467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(wtot, gwtot, 2, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
137284467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "particle weight sum = %1.10f cell weight sum = %1.10f\n", (double)gwtot[0], (double)gwtot[1]));
137384467f86SMatthew G. Knepley   }
137484467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
137584467f86SMatthew G. Knepley }
137684467f86SMatthew G. Knepley 
InitializeParticles_PerturbedWeights(DM sw,AppCtx * ctx)1377*2a8381b2SBarry Smith static PetscErrorCode InitializeParticles_PerturbedWeights(DM sw, AppCtx *ctx)
137884467f86SMatthew G. Knepley {
1379*2a8381b2SBarry Smith   PetscReal scale[2] = {ctx->cosine_coefficients[0], ctx->cosine_coefficients[1]};
138075155f48SMatthew G. Knepley   PetscInt  dim;
138184467f86SMatthew G. Knepley 
138284467f86SMatthew G. Knepley   PetscFunctionBegin;
138375155f48SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1384045208b8SMatthew G. Knepley   PetscCall(InitializeParticles_Centroid(sw));
1385*2a8381b2SBarry Smith   PetscCall(InitializeWeights(sw, ctx->totalWeight, dim == 1 ? PetscPDFCosine1D : PetscPDFCosine2D, scale));
13868214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
13878214e71cSJoe }
13888214e71cSJoe 
InitializeConstants(DM sw,AppCtx * ctx)1389*2a8381b2SBarry Smith static PetscErrorCode InitializeConstants(DM sw, AppCtx *ctx)
13908214e71cSJoe {
13918214e71cSJoe   DM         dm;
13928214e71cSJoe   PetscInt  *species;
13938214e71cSJoe   PetscReal *weight, totalCharge = 0., totalWeight = 0., gmin[3], gmax[3], global_charge, global_weight;
13948214e71cSJoe   PetscInt   Np, dim;
13958214e71cSJoe 
13968214e71cSJoe   PetscFunctionBegin;
13978214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &dm));
13988214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
13998214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
14008214e71cSJoe   PetscCall(DMGetBoundingBox(dm, gmin, gmax));
14018214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
14028214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
14038214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
14048214e71cSJoe     totalWeight += weight[p];
1405*2a8381b2SBarry Smith     totalCharge += ctx->charges[species[p]] * weight[p];
14068214e71cSJoe   }
14078214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
14088214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
14098214e71cSJoe   {
14108214e71cSJoe     Parameter *param;
14118214e71cSJoe     PetscReal  Area;
14128214e71cSJoe 
1413*2a8381b2SBarry Smith     PetscCall(PetscBagGetData(ctx->bag, &param));
14148214e71cSJoe     switch (dim) {
14158214e71cSJoe     case 1:
14168214e71cSJoe       Area = (gmax[0] - gmin[0]);
14178214e71cSJoe       break;
14188214e71cSJoe     case 2:
14198214e71cSJoe       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]);
14208214e71cSJoe       break;
14218214e71cSJoe     case 3:
14228214e71cSJoe       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]) * (gmax[2] - gmin[2]);
14238214e71cSJoe       break;
14248214e71cSJoe     default:
14258214e71cSJoe       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", dim);
14268214e71cSJoe     }
1427462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalWeight, &global_weight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
1428462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalCharge, &global_charge, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
1429*2a8381b2SBarry Smith     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "dim = %" PetscInt_FMT "\ttotalWeight = %f, ctx->charges[species[0]] = %f\ttotalCharge = %f, Total Area = %f\n", dim, (double)global_weight, (double)ctx->charges[0], (double)global_charge, (double)Area));
14308214e71cSJoe     param->sigma = PetscAbsReal(global_charge / (Area));
14318214e71cSJoe 
14328214e71cSJoe     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "sigma: %g\n", (double)param->sigma));
14338214e71cSJoe     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,
14348214e71cSJoe                           (double)param->vlasovNumber));
14358214e71cSJoe   }
14368214e71cSJoe   /* Setup Constants */
14378214e71cSJoe   {
14388214e71cSJoe     PetscDS    ds;
14398214e71cSJoe     Parameter *param;
1440*2a8381b2SBarry Smith     PetscCall(PetscBagGetData(ctx->bag, &param));
14418214e71cSJoe     PetscScalar constants[NUM_CONSTANTS];
14428214e71cSJoe     constants[SIGMA]   = param->sigma;
14438214e71cSJoe     constants[V0]      = param->v0;
14448214e71cSJoe     constants[T0]      = param->t0;
14458214e71cSJoe     constants[X0]      = param->x0;
14468214e71cSJoe     constants[M0]      = param->m0;
14478214e71cSJoe     constants[Q0]      = param->q0;
14488214e71cSJoe     constants[PHI0]    = param->phi0;
14498214e71cSJoe     constants[POISSON] = param->poissonNumber;
14508214e71cSJoe     constants[VLASOV]  = param->vlasovNumber;
14518214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
14528214e71cSJoe     PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants));
14538214e71cSJoe   }
14548214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
14558214e71cSJoe }
14568214e71cSJoe 
CreateSwarm(DM dm,AppCtx * ctx,DM * sw)1457*2a8381b2SBarry Smith static PetscErrorCode CreateSwarm(DM dm, AppCtx *ctx, DM *sw)
14588214e71cSJoe {
14599072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
14609072cb8bSMatthew G. Knepley   DM            vdm;
14618214e71cSJoe   PetscReal     v0[2] = {1., 0.};
14628214e71cSJoe   PetscInt      dim;
1463b80bf5b1SJoe Pusztay 
1464b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
14659566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
14669566063dSJacob Faibussowitsch   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw));
14679566063dSJacob Faibussowitsch   PetscCall(DMSetType(*sw, DMSWARM));
14689566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*sw, dim));
14699566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC));
1470*2a8381b2SBarry Smith   PetscCall(DMSetApplicationContext(*sw, ctx));
14719072cb8bSMatthew G. Knepley 
14729566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR));
14738214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL));
14748214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "species", 1, PETSC_INT));
14758214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "E_field", dim, PETSC_REAL));
14769072cb8bSMatthew G. Knepley 
14779072cb8bSMatthew G. Knepley   const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"};
14789072cb8bSMatthew G. Knepley 
14799072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(dm, 2, fieldnames, 1, fieldnames, &celldm));
14809072cb8bSMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
14819072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
14829072cb8bSMatthew G. Knepley 
14839072cb8bSMatthew G. Knepley   const char *vfieldnames[1] = {"w_q"};
14849072cb8bSMatthew G. Knepley 
14859072cb8bSMatthew G. Knepley   PetscCall(CreateVelocityDM(*sw, &vdm));
14869072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(vdm, 1, vfieldnames, 1, &fieldnames[1], &celldm));
14879072cb8bSMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
14889072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
14899072cb8bSMatthew G. Knepley   PetscCall(DMDestroy(&vdm));
14909072cb8bSMatthew G. Knepley 
14914a0cbf56SMatthew G. Knepley   DM mdm;
14924a0cbf56SMatthew G. Knepley 
14934a0cbf56SMatthew G. Knepley   PetscCall(DMClone(dm, &mdm));
14944a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)mdm, "moments"));
14954a0cbf56SMatthew G. Knepley   PetscCall(DMCopyDisc(dm, mdm));
14964a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(mdm, 1, vfieldnames, 1, fieldnames, &celldm));
14974a0cbf56SMatthew G. Knepley   PetscCall(DMDestroy(&mdm));
14984a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
14994a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
15004a0cbf56SMatthew G. Knepley 
15019566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*sw));
1502045208b8SMatthew G. Knepley   PetscCall(DMSetUp(*sw));
1503045208b8SMatthew G. Knepley 
15049072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(*sw, "space"));
1505*2a8381b2SBarry Smith   ctx->swarm = *sw;
1506045208b8SMatthew G. Knepley   // TODO: This is redundant init since it is done in InitializeSolveAndSwarm, however DMSetUp() requires the local size be set
1507*2a8381b2SBarry Smith   if (ctx->perturbed_weights) {
1508*2a8381b2SBarry Smith     PetscCall(InitializeParticles_PerturbedWeights(*sw, ctx));
1509b80bf5b1SJoe Pusztay   } else {
15108214e71cSJoe     PetscCall(DMSwarmComputeLocalSizeFromOptions(*sw));
15118214e71cSJoe     PetscCall(DMSwarmInitializeCoordinates(*sw));
15128214e71cSJoe     PetscCall(DMSwarmInitializeVelocitiesFromOptions(*sw, v0));
1513b80bf5b1SJoe Pusztay   }
15149566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles"));
15159566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view"));
15163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1517b80bf5b1SJoe Pusztay }
1518b80bf5b1SJoe Pusztay 
ComputeFieldAtParticles_Coulomb(SNES snes,DM sw,PetscReal E[])15198214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Coulomb(SNES snes, DM sw, PetscReal E[])
1520d71ae5a4SJacob Faibussowitsch {
1521*2a8381b2SBarry Smith   AppCtx     *ctx;
15228214e71cSJoe   PetscReal  *coords;
15238214e71cSJoe   PetscInt   *species, dim, Np, Ns;
15248214e71cSJoe   PetscMPIInt size;
15258214e71cSJoe 
15268214e71cSJoe   PetscFunctionBegin;
15278214e71cSJoe   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)snes), &size));
15288214e71cSJoe   PetscCheck(size == 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Coulomb code only works in serial");
15298214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
15308214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
15318214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
1532*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
15338214e71cSJoe 
15348214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
15358214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
15368214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
15378214e71cSJoe     PetscReal *pcoord = &coords[p * dim];
15388214e71cSJoe     PetscReal  pE[3]  = {0., 0., 0.};
15398214e71cSJoe 
15408214e71cSJoe     /* Calculate field at particle p due to particle q */
15418214e71cSJoe     for (PetscInt q = 0; q < Np; ++q) {
15428214e71cSJoe       PetscReal *qcoord = &coords[q * dim];
15438214e71cSJoe       PetscReal  rpq[3], r, r3, q_q;
15448214e71cSJoe 
15458214e71cSJoe       if (p == q) continue;
1546*2a8381b2SBarry Smith       q_q = ctx->charges[species[q]] * 1.;
15478214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) rpq[d] = pcoord[d] - qcoord[d];
15488214e71cSJoe       r = DMPlex_NormD_Internal(dim, rpq);
15498214e71cSJoe       if (r < PETSC_SQRT_MACHINE_EPSILON) continue;
15508214e71cSJoe       r3 = PetscPowRealInt(r, 3);
15518214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pE[d] += q_q * rpq[d] / r3;
15528214e71cSJoe     }
15538214e71cSJoe     for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = pE[d];
15548214e71cSJoe   }
15558214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
15568214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
15578214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
15588214e71cSJoe }
15598214e71cSJoe 
ComputeFieldAtParticles_Primal(SNES snes,DM sw,Mat M_p,PetscReal E[])15604a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Primal(SNES snes, DM sw, Mat M_p, PetscReal E[])
15618214e71cSJoe {
1562b80bf5b1SJoe Pusztay   DM         dm;
1563*2a8381b2SBarry Smith   AppCtx    *ctx;
15648214e71cSJoe   PetscDS    ds;
15658214e71cSJoe   PetscFE    fe;
15664a0cbf56SMatthew G. Knepley   KSP        ksp;
156775155f48SMatthew G. Knepley   Vec        rhoRhs;      // Weak charge density, \int phi_i rho
156875155f48SMatthew G. Knepley   Vec        rho;         // Charge density, M^{-1} rhoRhs
156975155f48SMatthew G. Knepley   Vec        phi, locPhi; // Potential
157075155f48SMatthew G. Knepley   Vec        f;           // Particle weights
15718214e71cSJoe   PetscReal *coords;
15728214e71cSJoe   PetscInt   dim, cStart, cEnd, Np;
15738214e71cSJoe 
15748214e71cSJoe   PetscFunctionBegin;
1575*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
1576*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->ESolveEvent, snes, sw, 0, 0));
15778214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
15788214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
15798214e71cSJoe 
15808214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
158175155f48SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhs));
158275155f48SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
1583*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rho", &rho));
15848214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
15858214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
158675155f48SMatthew G. Knepley 
15878214e71cSJoe   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
1588*2a8381b2SBarry Smith   PetscCall(MatViewFromOptions(ctx->M, NULL, "-m_view"));
15898214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
159075155f48SMatthew G. Knepley 
159175155f48SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
15928214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
15938214e71cSJoe 
1594fd7102fcSMatthew G. Knepley   // Low-pass filter rhoRhs
1595fd7102fcSMatthew G. Knepley   PetscInt window = 0;
1596fd7102fcSMatthew G. Knepley   PetscCall(PetscOptionsGetInt(NULL, NULL, "-rho_average", &window, NULL));
1597fd7102fcSMatthew G. Knepley   if (window) {
1598fd7102fcSMatthew G. Knepley     PetscScalar *a;
1599fd7102fcSMatthew G. Knepley     PetscInt     n;
1600fd7102fcSMatthew G. Knepley     PetscReal    width = 2. * window + 1.;
1601fd7102fcSMatthew G. Knepley 
1602fd7102fcSMatthew G. Knepley     // This will only work for P_1
1603fd7102fcSMatthew G. Knepley     //   This works because integration against a test function is linear
1604fd7102fcSMatthew G. Knepley     //   This only works in serial since I need the periodic values (maybe use FFT)
1605fd7102fcSMatthew G. Knepley     //   Do a real integral against weight function for higher order
1606fd7102fcSMatthew G. Knepley     PetscCall(VecGetLocalSize(rhoRhs, &n));
1607fd7102fcSMatthew G. Knepley     PetscCall(VecGetArrayWrite(rhoRhs, &a));
1608fd7102fcSMatthew G. Knepley     for (PetscInt i = 0; i < n; ++i) {
1609fd7102fcSMatthew G. Knepley       PetscScalar avg = a[i];
1610fd7102fcSMatthew G. Knepley       for (PetscInt j = 1; j <= window; ++j) avg += a[(i - j + n) % n] + a[(i + j) % n];
1611fd7102fcSMatthew G. Knepley       a[i] = avg / width;
1612fd7102fcSMatthew G. Knepley       //a[i] = (a[(i - 1 + n) % n] + a[i] + a[(i + 1) % n]) / 3.;
1613fd7102fcSMatthew G. Knepley     }
1614fd7102fcSMatthew G. Knepley     PetscCall(VecRestoreArrayWrite(rhoRhs, &a));
1615fd7102fcSMatthew G. Knepley   }
1616fd7102fcSMatthew G. Knepley 
16178214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
16188214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj_"));
1619*2a8381b2SBarry Smith   PetscCall(KSPSetOperators(ksp, ctx->M, ctx->M));
16208214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
162175155f48SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
16228214e71cSJoe 
162375155f48SMatthew G. Knepley   PetscCall(VecScale(rhoRhs, -1.0));
16248214e71cSJoe 
162575155f48SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
1626*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rho", &rho));
16278214e71cSJoe   PetscCall(KSPDestroy(&ksp));
16288214e71cSJoe 
1629*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
16308214e71cSJoe   PetscCall(VecSet(phi, 0.0));
163175155f48SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhs, phi));
163275155f48SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhs));
16338214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
16348214e71cSJoe 
16358214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
16368214e71cSJoe   PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi));
16378214e71cSJoe   PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi));
1638*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
1639*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->ESolveEvent, snes, sw, 0, 0));
16408214e71cSJoe 
16418214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
16428214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
16438214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
16448214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
16458214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
16468214e71cSJoe 
1647*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->ETabEvent, snes, sw, 0, 0));
16488214e71cSJoe   PetscTabulation tab;
16498214e71cSJoe   PetscReal      *pcoord, *refcoord;
1650045208b8SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
1651045208b8SMatthew G. Knepley   PetscInt        maxNcp    = 0;
1652045208b8SMatthew G. Knepley 
1653045208b8SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1654045208b8SMatthew G. Knepley     PetscInt Ncp;
1655045208b8SMatthew G. Knepley 
1656045208b8SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
1657045208b8SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
1658045208b8SMatthew G. Knepley   }
1659045208b8SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1660045208b8SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1661045208b8SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
1662045208b8SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1663045208b8SMatthew G. Knepley     PetscScalar *clPhi = NULL;
16648214e71cSJoe     PetscInt    *points;
16658214e71cSJoe     PetscInt     Ncp;
16668214e71cSJoe 
16678214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
16688214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
16698214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1670f1e6e573SMatthew G. Knepley     {
1671*2a8381b2SBarry Smith       PetscCall(PetscFEGeomGetChunk(ctx->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1672f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1673f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1674f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1675f1e6e573SMatthew G. Knepley       }
1676f1e6e573SMatthew G. Knepley     }
1677045208b8SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
16788214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
16798214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
16808214e71cSJoe       const PetscReal *basisDer = tab->T[1];
16818214e71cSJoe       const PetscInt   p        = points[cp];
16828214e71cSJoe 
16838214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1684f1e6e573SMatthew G. Knepley       PetscCall(PetscFEFreeInterpolateGradient_Static(fe, basisDer, clPhi, dim, chunkgeom->invJ, NULL, cp, &E[p * dim]));
1685045208b8SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
16868214e71cSJoe     }
16878214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
168884467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
16898214e71cSJoe   }
1690045208b8SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1691045208b8SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1692045208b8SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
16938214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
16948214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
16958214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1696*2a8381b2SBarry Smith   PetscCall(PetscFEGeomRestoreChunk(ctx->fegeom, 0, 1, &chunkgeom));
1697*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->ETabEvent, snes, sw, 0, 0));
16988214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16998214e71cSJoe }
17008214e71cSJoe 
ComputeFieldAtParticles_Mixed(SNES snes,DM sw,Mat M_p,PetscReal E[])17014a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Mixed(SNES snes, DM sw, Mat M_p, PetscReal E[])
17028214e71cSJoe {
17034a0cbf56SMatthew G. Knepley   DM         dm;
1704*2a8381b2SBarry Smith   AppCtx    *ctx;
17058214e71cSJoe   PetscDS    ds;
17068214e71cSJoe   PetscFE    fe;
17074a0cbf56SMatthew G. Knepley   KSP        ksp;
17084a0cbf56SMatthew G. Knepley   Vec        rhoRhs, rhoRhsFull;   // Weak charge density, \int phi_i rho, and embedding in mixed problem
17094a0cbf56SMatthew G. Knepley   Vec        rho;                  // Charge density, M^{-1} rhoRhs
17104a0cbf56SMatthew G. Knepley   Vec        phi, locPhi, phiFull; // Potential and embedding in mixed problem
17114a0cbf56SMatthew G. Knepley   Vec        f;                    // Particle weights
171275155f48SMatthew G. Knepley   PetscReal *coords;
17134a0cbf56SMatthew G. Knepley   PetscInt   dim, cStart, cEnd, Np;
17148214e71cSJoe 
17158214e71cSJoe   PetscFunctionBegin;
1716*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
1717*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->ESolveEvent, snes, sw, 0, 0));
17188214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
17198214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
17208214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
1721*2a8381b2SBarry Smith   PetscCall(DMGetGlobalVector(ctx->dmPot, &rhoRhs));
17224a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
17234a0cbf56SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhsFull));
17244a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhsFull, "Weak charge density"));
1725*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "rho", &rho));
17268214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
17278214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
17284a0cbf56SMatthew G. Knepley 
17294a0cbf56SMatthew G. Knepley   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
1730*2a8381b2SBarry Smith   PetscCall(MatViewFromOptions(ctx->M, NULL, "-m_view"));
17318214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
17324a0cbf56SMatthew G. Knepley 
17334a0cbf56SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
17348214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
17358214e71cSJoe 
17368214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
17378214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj"));
1738*2a8381b2SBarry Smith   PetscCall(KSPSetOperators(ksp, ctx->M, ctx->M));
17398214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
17404a0cbf56SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
17418214e71cSJoe 
1742*2a8381b2SBarry Smith   PetscCall(VecISCopy(rhoRhsFull, ctx->isPot, SCATTER_FORWARD, rhoRhs));
17434a0cbf56SMatthew G. Knepley   //PetscCall(VecScale(rhoRhsFull, -1.0));
17448214e71cSJoe 
17454a0cbf56SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
17464a0cbf56SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhsFull, NULL, "-rho_full_view"));
1747*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "rho", &rho));
1748*2a8381b2SBarry Smith   PetscCall(DMRestoreGlobalVector(ctx->dmPot, &rhoRhs));
17498214e71cSJoe   PetscCall(KSPDestroy(&ksp));
17508214e71cSJoe 
17514a0cbf56SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &phiFull));
1752*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
17534a0cbf56SMatthew G. Knepley   PetscCall(VecSet(phiFull, 0.0));
17544a0cbf56SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhsFull, phiFull));
17554a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhsFull));
17568214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
17578214e71cSJoe 
1758*2a8381b2SBarry Smith   PetscCall(VecISCopy(phiFull, ctx->isPot, SCATTER_REVERSE, phi));
1759*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
17604a0cbf56SMatthew G. Knepley 
17618214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
17624a0cbf56SMatthew G. Knepley   PetscCall(DMGlobalToLocalBegin(dm, phiFull, INSERT_VALUES, locPhi));
17634a0cbf56SMatthew G. Knepley   PetscCall(DMGlobalToLocalEnd(dm, phiFull, INSERT_VALUES, locPhi));
17644a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &phiFull));
1765*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->ESolveEvent, snes, sw, 0, 0));
17668214e71cSJoe 
17678214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
17688214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
17698214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
17708214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
17718214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
17724a0cbf56SMatthew G. Knepley 
1773*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->ETabEvent, snes, sw, 0, 0));
17748214e71cSJoe   PetscTabulation tab;
17758214e71cSJoe   PetscReal      *pcoord, *refcoord;
17764a0cbf56SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
17774a0cbf56SMatthew G. Knepley   PetscInt        maxNcp    = 0;
17784a0cbf56SMatthew G. Knepley 
17794a0cbf56SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
17804a0cbf56SMatthew G. Knepley     PetscInt Ncp;
17814a0cbf56SMatthew G. Knepley 
17824a0cbf56SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
17834a0cbf56SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
17844a0cbf56SMatthew G. Knepley   }
17854a0cbf56SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
17864a0cbf56SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
17874a0cbf56SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
17884a0cbf56SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
17894a0cbf56SMatthew G. Knepley     PetscScalar *clPhi = NULL;
17908214e71cSJoe     PetscInt    *points;
17918214e71cSJoe     PetscInt     Ncp;
17928214e71cSJoe 
17938214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
17948214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
17958214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1796f1e6e573SMatthew G. Knepley     {
1797*2a8381b2SBarry Smith       PetscCall(PetscFEGeomGetChunk(ctx->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1798f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1799f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1800f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1801f1e6e573SMatthew G. Knepley       }
1802f1e6e573SMatthew G. Knepley     }
18034a0cbf56SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
18048214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
18058214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
18068214e71cSJoe       const PetscInt p = points[cp];
18078214e71cSJoe 
18088214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1809f1e6e573SMatthew G. Knepley       PetscCall(PetscFEInterpolateAtPoints_Static(fe, tab, clPhi, chunkgeom, cp, &E[p * dim]));
1810f1e6e573SMatthew G. Knepley       PetscCall(PetscFEPushforward(fe, chunkgeom, 1, &E[p * dim]));
18114a0cbf56SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
18128214e71cSJoe     }
18138214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
181484467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
18158214e71cSJoe   }
18164a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
18174a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
18184a0cbf56SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
18198214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
18208214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
18218214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1822*2a8381b2SBarry Smith   PetscCall(PetscFEGeomRestoreChunk(ctx->fegeom, 0, 1, &chunkgeom));
1823*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->ETabEvent, snes, sw, 0, 0));
18248214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18258214e71cSJoe }
18268214e71cSJoe 
ComputeFieldAtParticles(SNES snes,DM sw)18274a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles(SNES snes, DM sw)
18288214e71cSJoe {
1829*2a8381b2SBarry Smith   AppCtx    *ctx;
18304a0cbf56SMatthew G. Knepley   Mat        M_p;
18314a0cbf56SMatthew G. Knepley   PetscReal *E;
18328214e71cSJoe   PetscInt   dim, Np;
18338214e71cSJoe 
18348214e71cSJoe   PetscFunctionBegin;
18358214e71cSJoe   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
18368214e71cSJoe   PetscValidHeaderSpecific(sw, DM_CLASSID, 2);
18378214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
18388214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
1839*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
18408214e71cSJoe 
18414a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "moments"));
18424a0cbf56SMatthew G. Knepley   // TODO: Could share sort context with space cellDM
18434a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmMigrate(sw, PETSC_FALSE));
1844*2a8381b2SBarry Smith   PetscCall(DMCreateMassMatrix(sw, ctx->dmPot, &M_p));
18454a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
18464a0cbf56SMatthew G. Knepley 
18474a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
18484a0cbf56SMatthew G. Knepley   PetscCall(PetscArrayzero(E, Np * dim));
1849*2a8381b2SBarry Smith   ctx->validE = PETSC_TRUE;
18504a0cbf56SMatthew G. Knepley 
1851*2a8381b2SBarry Smith   switch (ctx->em) {
18528214e71cSJoe   case EM_COULOMB:
18538214e71cSJoe     PetscCall(ComputeFieldAtParticles_Coulomb(snes, sw, E));
18548214e71cSJoe     break;
18554a0cbf56SMatthew G. Knepley   case EM_PRIMAL:
18564a0cbf56SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Primal(snes, sw, M_p, E));
18574a0cbf56SMatthew G. Knepley     break;
18588214e71cSJoe   case EM_MIXED:
18594a0cbf56SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Mixed(snes, sw, M_p, E));
18608214e71cSJoe     break;
18618214e71cSJoe   case EM_NONE:
18628214e71cSJoe     break;
18638214e71cSJoe   default:
1864*2a8381b2SBarry Smith     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No solver for electrostatic model %s", EMTypes[ctx->em]);
18658214e71cSJoe   }
18664a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
18674a0cbf56SMatthew G. Knepley   PetscCall(MatDestroy(&M_p));
18688214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18698214e71cSJoe }
18708214e71cSJoe 
RHSFunction(TS ts,PetscReal t,Vec U,Vec G,PetscCtx ctx)1871*2a8381b2SBarry Smith static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec G, PetscCtx ctx)
18728214e71cSJoe {
18738214e71cSJoe   DM                 sw;
18748214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
18758214e71cSJoe   const PetscScalar *u;
18768214e71cSJoe   PetscScalar       *g;
18778214e71cSJoe   PetscReal         *E, m_p = 1., q_p = -1.;
18788214e71cSJoe   PetscInt           dim, d, Np, p;
1879b80bf5b1SJoe Pusztay 
1880b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
18818214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
18824a0cbf56SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
18834a0cbf56SMatthew G. Knepley 
18848214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
18858214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
18864a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
18878214e71cSJoe   PetscCall(VecGetArrayRead(U, &u));
18888214e71cSJoe   PetscCall(VecGetArray(G, &g));
18898214e71cSJoe   Np /= 2 * dim;
18908214e71cSJoe   for (p = 0; p < Np; ++p) {
18918214e71cSJoe     for (d = 0; d < dim; ++d) {
18928214e71cSJoe       g[(p * 2 + 0) * dim + d] = u[(p * 2 + 1) * dim + d];
18938214e71cSJoe       g[(p * 2 + 1) * dim + d] = q_p * E[p * dim + d] / m_p;
18948214e71cSJoe     }
18958214e71cSJoe   }
18968214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
18978214e71cSJoe   PetscCall(VecRestoreArrayRead(U, &u));
18988214e71cSJoe   PetscCall(VecRestoreArray(G, &g));
18998214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
19008214e71cSJoe }
19018214e71cSJoe 
19028214e71cSJoe /* J_{ij} = dF_i/dx_j
19038214e71cSJoe    J_p = (  0   1)
19048214e71cSJoe          (-w^2  0)
19058214e71cSJoe    TODO Now there is another term with w^2 from the electric field. I think we will need to invert the operator.
19068214e71cSJoe         Perhaps we can approximate the Jacobian using only the cellwise P-P gradient from Coulomb
19078214e71cSJoe */
RHSJacobian(TS ts,PetscReal t,Vec U,Mat J,Mat P,PetscCtx ctx)1908*2a8381b2SBarry Smith static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat P, PetscCtx ctx)
19098214e71cSJoe {
19108214e71cSJoe   DM               sw;
19118214e71cSJoe   const PetscReal *coords, *vel;
19128214e71cSJoe   PetscInt         dim, d, Np, p, rStart;
19138214e71cSJoe 
19148214e71cSJoe   PetscFunctionBeginUser;
19158214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19168214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
19178214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
19188214e71cSJoe   PetscCall(MatGetOwnershipRange(J, &rStart, NULL));
1919045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1920045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
19218214e71cSJoe   Np /= 2 * dim;
19228214e71cSJoe   for (p = 0; p < Np; ++p) {
1923f940b0e3Sdanofinn     // TODO This is not right because dv/dx has the electric field in it
1924f940b0e3Sdanofinn     PetscScalar vals[4] = {0., 1., -1, 0.};
19258214e71cSJoe 
19268214e71cSJoe     for (d = 0; d < dim; ++d) {
19278214e71cSJoe       const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart};
19288214e71cSJoe       PetscCall(MatSetValues(J, 2, rows, 2, rows, vals, INSERT_VALUES));
19298214e71cSJoe     }
19308214e71cSJoe   }
1931045208b8SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1932045208b8SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
19338214e71cSJoe   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
19348214e71cSJoe   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
19358214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
19368214e71cSJoe }
19378214e71cSJoe 
RHSFunctionX(TS ts,PetscReal t,Vec V,Vec Xres,void * Ctx)1938*2a8381b2SBarry Smith static PetscErrorCode RHSFunctionX(TS ts, PetscReal t, Vec V, Vec Xres, void *Ctx)
19398214e71cSJoe {
1940*2a8381b2SBarry Smith   AppCtx            *ctx = (AppCtx *)Ctx;
19418214e71cSJoe   DM                 sw;
19428214e71cSJoe   const PetscScalar *v;
19438214e71cSJoe   PetscScalar       *xres;
19448214e71cSJoe   PetscInt           Np, p, d, dim;
19458214e71cSJoe 
19468214e71cSJoe   PetscFunctionBeginUser;
1947*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->RhsXEvent, ts, 0, 0, 0));
19488214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19498214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
19508214e71cSJoe   PetscCall(VecGetLocalSize(Xres, &Np));
19519566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(V, &v));
19528214e71cSJoe   PetscCall(VecGetArray(Xres, &xres));
1953b80bf5b1SJoe Pusztay   Np /= dim;
1954b80bf5b1SJoe Pusztay   for (p = 0; p < Np; ++p) {
1955045208b8SMatthew G. Knepley     for (d = 0; d < dim; ++d) xres[p * dim + d] = v[p * dim + d];
1956b80bf5b1SJoe Pusztay   }
19579566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(V, &v));
19588214e71cSJoe   PetscCall(VecRestoreArray(Xres, &xres));
1959*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->RhsXEvent, ts, 0, 0, 0));
19603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1961b80bf5b1SJoe Pusztay }
1962b80bf5b1SJoe Pusztay 
RHSFunctionV(TS ts,PetscReal t,Vec X,Vec Vres,void * Ctx)1963*2a8381b2SBarry Smith static PetscErrorCode RHSFunctionV(TS ts, PetscReal t, Vec X, Vec Vres, void *Ctx)
19648214e71cSJoe {
19658214e71cSJoe   DM                 sw;
1966*2a8381b2SBarry Smith   AppCtx            *ctx  = (AppCtx *)Ctx;
19678214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
19688214e71cSJoe   const PetscScalar *x;
19698214e71cSJoe   PetscScalar       *vres;
19704a0cbf56SMatthew G. Knepley   PetscReal         *E, m_p, q_p;
19718214e71cSJoe   PetscInt           Np, p, dim, d;
19728214e71cSJoe   Parameter         *param;
19738214e71cSJoe 
19748214e71cSJoe   PetscFunctionBeginUser;
1975*2a8381b2SBarry Smith   PetscCall(PetscLogEventBegin(ctx->RhsVEvent, ts, 0, 0, 0));
19768214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19774a0cbf56SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
19784a0cbf56SMatthew G. Knepley 
19798214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
19808214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
1981*2a8381b2SBarry Smith   PetscCall(PetscBagGetData(ctx->bag, (void **)&param));
1982*2a8381b2SBarry Smith   m_p = ctx->masses[0] * param->m0;
1983*2a8381b2SBarry Smith   q_p = ctx->charges[0] * param->q0;
19848214e71cSJoe   PetscCall(VecGetLocalSize(Vres, &Np));
19858214e71cSJoe   PetscCall(VecGetArrayRead(X, &x));
19868214e71cSJoe   PetscCall(VecGetArray(Vres, &vres));
19878214e71cSJoe   Np /= dim;
19888214e71cSJoe   for (p = 0; p < Np; ++p) {
1989045208b8SMatthew G. Knepley     for (d = 0; d < dim; ++d) vres[p * dim + d] = q_p * E[p * dim + d] / m_p;
19908214e71cSJoe   }
19918214e71cSJoe   PetscCall(VecRestoreArrayRead(X, &x));
19928214e71cSJoe   /*
1993d7c1f440SPierre Jolivet     Synchronized, ordered output for parallel/sequential test cases.
19948214e71cSJoe     In the 1D (on the 2D mesh) case, every y component should be zero.
19958214e71cSJoe   */
1996*2a8381b2SBarry Smith   if (ctx->checkVRes) {
1997*2a8381b2SBarry Smith     PetscBool pr = ctx->checkVRes > 1 ? PETSC_TRUE : PETSC_FALSE;
19988214e71cSJoe     PetscInt  step;
19998214e71cSJoe 
20008214e71cSJoe     PetscCall(TSGetStepNumber(ts, &step));
20018214e71cSJoe     if (pr) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step: %" PetscInt_FMT "\n", step));
20028214e71cSJoe     for (PetscInt p = 0; p < Np; ++p) {
20038214e71cSJoe       if (pr) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Residual: %.12g %.12g\n", (double)PetscRealPart(vres[p * dim + 0]), (double)PetscRealPart(vres[p * dim + 1])));
20048214e71cSJoe       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]));
20058214e71cSJoe     }
20068214e71cSJoe     if (pr) PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
20078214e71cSJoe   }
20088214e71cSJoe   PetscCall(VecRestoreArray(Vres, &vres));
20098214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
2010*2a8381b2SBarry Smith   PetscCall(PetscLogEventEnd(ctx->RhsVEvent, ts, 0, 0, 0));
20118214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
20128214e71cSJoe }
20138214e71cSJoe 
2014f940b0e3Sdanofinn /* Discrete Gradients Formulation: S, F, gradF (G) */
RHSJacobianS(TS ts,PetscReal t,Vec U,Mat S,PetscCtx ctx)2015*2a8381b2SBarry Smith PetscErrorCode RHSJacobianS(TS ts, PetscReal t, Vec U, Mat S, PetscCtx ctx)
2016f940b0e3Sdanofinn {
2017f940b0e3Sdanofinn   PetscScalar vals[4] = {0., 1., -1., 0.};
2018f940b0e3Sdanofinn   DM          sw;
2019f940b0e3Sdanofinn   PetscInt    dim, d, Np, p, rStart;
2020f940b0e3Sdanofinn 
2021f940b0e3Sdanofinn   PetscFunctionBeginUser;
2022f940b0e3Sdanofinn   PetscCall(TSGetDM(ts, &sw));
2023f940b0e3Sdanofinn   PetscCall(DMGetDimension(sw, &dim));
2024f940b0e3Sdanofinn   PetscCall(VecGetLocalSize(U, &Np));
2025f940b0e3Sdanofinn   PetscCall(MatGetOwnershipRange(S, &rStart, NULL));
2026f940b0e3Sdanofinn   Np /= 2 * dim;
2027f940b0e3Sdanofinn   for (p = 0; p < Np; ++p) {
2028f940b0e3Sdanofinn     for (d = 0; d < dim; ++d) {
2029f940b0e3Sdanofinn       const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart};
2030f940b0e3Sdanofinn       PetscCall(MatSetValues(S, 2, rows, 2, rows, vals, INSERT_VALUES));
2031f940b0e3Sdanofinn     }
2032f940b0e3Sdanofinn   }
2033f940b0e3Sdanofinn   PetscCall(MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY));
2034f940b0e3Sdanofinn   PetscCall(MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY));
2035f940b0e3Sdanofinn   PetscFunctionReturn(PETSC_SUCCESS);
2036f940b0e3Sdanofinn }
2037f940b0e3Sdanofinn 
RHSObjectiveF(TS ts,PetscReal t,Vec U,PetscScalar * F,void * Ctx)2038*2a8381b2SBarry Smith PetscErrorCode RHSObjectiveF(TS ts, PetscReal t, Vec U, PetscScalar *F, void *Ctx)
2039f940b0e3Sdanofinn {
2040*2a8381b2SBarry Smith   AppCtx            *ctx = (AppCtx *)Ctx;
2041f940b0e3Sdanofinn   DM                 sw;
2042f940b0e3Sdanofinn   Vec                phi;
2043f940b0e3Sdanofinn   const PetscScalar *u;
2044f940b0e3Sdanofinn   PetscInt           dim, Np, cStart, cEnd;
2045f940b0e3Sdanofinn   PetscReal         *vel, *coords, m_p = 1.;
2046f940b0e3Sdanofinn 
2047f940b0e3Sdanofinn   PetscFunctionBeginUser;
2048f940b0e3Sdanofinn   PetscCall(TSGetDM(ts, &sw));
2049f940b0e3Sdanofinn   PetscCall(DMGetDimension(sw, &dim));
2050*2a8381b2SBarry Smith   PetscCall(DMPlexGetHeightStratum(ctx->dmPot, 0, &cStart, &cEnd));
2051f940b0e3Sdanofinn 
2052*2a8381b2SBarry Smith   PetscCall(DMGetNamedGlobalVector(ctx->dmPot, "phi", &phi));
2053f940b0e3Sdanofinn   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view_dg"));
2054*2a8381b2SBarry Smith   PetscCall(computeFieldEnergy(ctx->dmPot, phi, F));
2055*2a8381b2SBarry Smith   PetscCall(DMRestoreNamedGlobalVector(ctx->dmPot, "phi", &phi));
2056f940b0e3Sdanofinn 
2057f940b0e3Sdanofinn   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2058f940b0e3Sdanofinn   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
2059f940b0e3Sdanofinn   PetscCall(DMSwarmSortGetAccess(sw));
2060f940b0e3Sdanofinn   PetscCall(VecGetArrayRead(U, &u));
2061f940b0e3Sdanofinn   PetscCall(VecGetLocalSize(U, &Np));
2062f940b0e3Sdanofinn   Np /= 2 * dim;
2063f940b0e3Sdanofinn   for (PetscInt c = cStart; c < cEnd; ++c) {
2064f940b0e3Sdanofinn     PetscInt *points;
2065f940b0e3Sdanofinn     PetscInt  Ncp;
2066f940b0e3Sdanofinn 
2067f940b0e3Sdanofinn     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
2068f940b0e3Sdanofinn     for (PetscInt cp = 0; cp < Ncp; ++cp) {
2069f940b0e3Sdanofinn       const PetscInt  p  = points[cp];
2070f940b0e3Sdanofinn       const PetscReal v2 = DMPlex_DotRealD_Internal(dim, &u[(p * 2 + 1) * dim], &u[(p * 2 + 1) * dim]);
2071f940b0e3Sdanofinn 
2072f940b0e3Sdanofinn       *F += 0.5 * m_p * v2;
2073f940b0e3Sdanofinn     }
2074f940b0e3Sdanofinn     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
2075f940b0e3Sdanofinn   }
2076f940b0e3Sdanofinn   PetscCall(VecRestoreArrayRead(U, &u));
2077f940b0e3Sdanofinn   PetscCall(DMSwarmSortRestoreAccess(sw));
2078f940b0e3Sdanofinn   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2079f940b0e3Sdanofinn   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
2080f940b0e3Sdanofinn   PetscFunctionReturn(PETSC_SUCCESS);
2081f940b0e3Sdanofinn }
2082f940b0e3Sdanofinn 
2083f940b0e3Sdanofinn /* dF/dx = q E   dF/dv = v */
RHSFunctionG(TS ts,PetscReal t,Vec U,Vec G,PetscCtx ctx)2084*2a8381b2SBarry Smith PetscErrorCode RHSFunctionG(TS ts, PetscReal t, Vec U, Vec G, PetscCtx ctx)
2085f940b0e3Sdanofinn {
2086f940b0e3Sdanofinn   DM                 sw;
2087f940b0e3Sdanofinn   SNES               snes = ((AppCtx *)ctx)->snes;
2088f940b0e3Sdanofinn   const PetscReal   *coords, *vel, *E;
2089f940b0e3Sdanofinn   const PetscScalar *u;
2090f940b0e3Sdanofinn   PetscScalar       *g;
2091f940b0e3Sdanofinn   PetscReal          m_p = 1., q_p = -1.;
2092f940b0e3Sdanofinn   PetscInt           dim, d, Np, p;
2093f940b0e3Sdanofinn 
2094f940b0e3Sdanofinn   PetscFunctionBeginUser;
2095f940b0e3Sdanofinn   PetscCall(TSGetDM(ts, &sw));
2096f940b0e3Sdanofinn   PetscCall(DMGetDimension(sw, &dim));
2097f940b0e3Sdanofinn   PetscCall(DMSwarmGetLocalSize(sw, &Np));
2098f940b0e3Sdanofinn   PetscCall(VecGetArrayRead(U, &u));
2099f940b0e3Sdanofinn   PetscCall(VecGetArray(G, &g));
2100f940b0e3Sdanofinn 
2101f940b0e3Sdanofinn   PetscLogEvent COMPUTEFIELD;
2102f940b0e3Sdanofinn   PetscCall(PetscLogEventRegister("COMPFIELDATPART", TS_CLASSID, &COMPUTEFIELD));
2103f940b0e3Sdanofinn   PetscCall(PetscLogEventBegin(COMPUTEFIELD, 0, 0, 0, 0));
2104f940b0e3Sdanofinn   PetscCall(ComputeFieldAtParticles(snes, sw));
2105f940b0e3Sdanofinn   PetscCall(PetscLogEventEnd(COMPUTEFIELD, 0, 0, 0, 0));
2106f940b0e3Sdanofinn   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2107f940b0e3Sdanofinn   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
2108f940b0e3Sdanofinn   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
2109f940b0e3Sdanofinn   for (p = 0; p < Np; ++p) {
2110f940b0e3Sdanofinn     for (d = 0; d < dim; ++d) {
2111f940b0e3Sdanofinn       g[(p * 2 + 0) * dim + d] = -(q_p / m_p) * E[p * dim + d];
2112f940b0e3Sdanofinn       g[(p * 2 + 1) * dim + d] = u[(p * 2 + 1) * dim + d];
2113f940b0e3Sdanofinn     }
2114f940b0e3Sdanofinn   }
2115f940b0e3Sdanofinn   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
2116f940b0e3Sdanofinn   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2117f940b0e3Sdanofinn   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
2118f940b0e3Sdanofinn   PetscCall(VecRestoreArrayRead(U, &u));
2119f940b0e3Sdanofinn   PetscCall(VecRestoreArray(G, &g));
2120f940b0e3Sdanofinn   PetscFunctionReturn(PETSC_SUCCESS);
2121f940b0e3Sdanofinn }
2122f940b0e3Sdanofinn 
CreateSolution(TS ts)21238214e71cSJoe static PetscErrorCode CreateSolution(TS ts)
21248214e71cSJoe {
21258214e71cSJoe   DM       sw;
21268214e71cSJoe   Vec      u;
21278214e71cSJoe   PetscInt dim, Np;
21288214e71cSJoe 
21298214e71cSJoe   PetscFunctionBegin;
21308214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
21318214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
21328214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
21338214e71cSJoe   PetscCall(VecCreate(PETSC_COMM_WORLD, &u));
21348214e71cSJoe   PetscCall(VecSetBlockSize(u, dim));
21358214e71cSJoe   PetscCall(VecSetSizes(u, 2 * Np * dim, PETSC_DECIDE));
21368214e71cSJoe   PetscCall(VecSetUp(u));
21378214e71cSJoe   PetscCall(TSSetSolution(ts, u));
21388214e71cSJoe   PetscCall(VecDestroy(&u));
21398214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
21408214e71cSJoe }
21418214e71cSJoe 
SetProblem(TS ts)21428214e71cSJoe static PetscErrorCode SetProblem(TS ts)
21438214e71cSJoe {
2144*2a8381b2SBarry Smith   AppCtx *ctx;
21458214e71cSJoe   DM      sw;
21468214e71cSJoe 
21478214e71cSJoe   PetscFunctionBegin;
21488214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
2149*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
21508214e71cSJoe   // Define unified system for (X, V)
21518214e71cSJoe   {
21528214e71cSJoe     Mat      J;
21538214e71cSJoe     PetscInt dim, Np;
21548214e71cSJoe 
21558214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
21568214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
21578214e71cSJoe     PetscCall(MatCreate(PETSC_COMM_WORLD, &J));
21588214e71cSJoe     PetscCall(MatSetSizes(J, 2 * Np * dim, 2 * Np * dim, PETSC_DECIDE, PETSC_DECIDE));
21598214e71cSJoe     PetscCall(MatSetBlockSize(J, 2 * dim));
21608214e71cSJoe     PetscCall(MatSetFromOptions(J));
21618214e71cSJoe     PetscCall(MatSetUp(J));
2162*2a8381b2SBarry Smith     PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, ctx));
2163*2a8381b2SBarry Smith     PetscCall(TSSetRHSJacobian(ts, J, J, RHSJacobian, ctx));
21648214e71cSJoe     PetscCall(MatDestroy(&J));
21658214e71cSJoe   }
21668214e71cSJoe   /* Define split system for X and V */
21678214e71cSJoe   {
21688214e71cSJoe     Vec             u;
21698214e71cSJoe     IS              isx, isv, istmp;
21708214e71cSJoe     const PetscInt *idx;
21718214e71cSJoe     PetscInt        dim, Np, rstart;
21728214e71cSJoe 
21738214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
21748214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
21758214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
21768214e71cSJoe     PetscCall(VecGetOwnershipRange(u, &rstart, NULL));
21778214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 0, 2, &istmp));
21788214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
21798214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isx));
21808214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
21818214e71cSJoe     PetscCall(ISDestroy(&istmp));
21828214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 1, 2, &istmp));
21838214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
21848214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isv));
21858214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
21868214e71cSJoe     PetscCall(ISDestroy(&istmp));
21878214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "position", isx));
21888214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "momentum", isv));
21898214e71cSJoe     PetscCall(ISDestroy(&isx));
21908214e71cSJoe     PetscCall(ISDestroy(&isv));
2191*2a8381b2SBarry Smith     PetscCall(TSRHSSplitSetRHSFunction(ts, "position", NULL, RHSFunctionX, ctx));
2192*2a8381b2SBarry Smith     PetscCall(TSRHSSplitSetRHSFunction(ts, "momentum", NULL, RHSFunctionV, ctx));
21938214e71cSJoe   }
2194f940b0e3Sdanofinn   // Define symplectic formulation U_t = S . G, where G = grad F
2195f940b0e3Sdanofinn   {
2196*2a8381b2SBarry Smith     PetscCall(TSDiscGradSetFormulation(ts, RHSJacobianS, RHSObjectiveF, RHSFunctionG, ctx));
2197f940b0e3Sdanofinn   }
21988214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
21998214e71cSJoe }
22008214e71cSJoe 
DMSwarmTSRedistribute(TS ts)22018214e71cSJoe static PetscErrorCode DMSwarmTSRedistribute(TS ts)
22028214e71cSJoe {
22038214e71cSJoe   DM        sw;
22048214e71cSJoe   Vec       u;
22058214e71cSJoe   PetscReal t, maxt, dt;
22068214e71cSJoe   PetscInt  n, maxn;
22078214e71cSJoe 
22088214e71cSJoe   PetscFunctionBegin;
22098214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
22108214e71cSJoe   PetscCall(TSGetTime(ts, &t));
22118214e71cSJoe   PetscCall(TSGetMaxTime(ts, &maxt));
22128214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
22138214e71cSJoe   PetscCall(TSGetStepNumber(ts, &n));
22148214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
22158214e71cSJoe 
22168214e71cSJoe   PetscCall(TSReset(ts));
22178214e71cSJoe   PetscCall(TSSetDM(ts, sw));
22188214e71cSJoe   PetscCall(TSSetFromOptions(ts));
22198214e71cSJoe   PetscCall(TSSetTime(ts, t));
22208214e71cSJoe   PetscCall(TSSetMaxTime(ts, maxt));
22218214e71cSJoe   PetscCall(TSSetTimeStep(ts, dt));
22228214e71cSJoe   PetscCall(TSSetStepNumber(ts, n));
22238214e71cSJoe   PetscCall(TSSetMaxSteps(ts, maxn));
22248214e71cSJoe 
22258214e71cSJoe   PetscCall(CreateSolution(ts));
22268214e71cSJoe   PetscCall(SetProblem(ts));
22278214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
22288214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
22298214e71cSJoe }
22308214e71cSJoe 
line(PetscInt dim,PetscReal time,const PetscReal dummy[],PetscInt p,PetscScalar x[],void * Ctx)2231*2a8381b2SBarry Smith PetscErrorCode line(PetscInt dim, PetscReal time, const PetscReal dummy[], PetscInt p, PetscScalar x[], void *Ctx)
22328214e71cSJoe {
22338214e71cSJoe   DM        sw, cdm;
22348214e71cSJoe   PetscInt  Np;
22358214e71cSJoe   PetscReal low[2], high[2];
2236*2a8381b2SBarry Smith   AppCtx   *ctx = (AppCtx *)Ctx;
22378214e71cSJoe 
2238*2a8381b2SBarry Smith   sw = ctx->swarm;
22398214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &cdm));
22408214e71cSJoe   // Get the bounding box so we can equally space the particles
22418214e71cSJoe   PetscCall(DMGetLocalBoundingBox(cdm, low, high));
22428214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
22438214e71cSJoe   // shift it by h/2 so nothing is initialized directly on a boundary
22448214e71cSJoe   x[0] = ((high[0] - low[0]) / Np) * (p + 0.5);
22458214e71cSJoe   x[1] = 0.;
22468214e71cSJoe   return PETSC_SUCCESS;
22478214e71cSJoe }
22488214e71cSJoe 
2249b80bf5b1SJoe Pusztay /*
22508214e71cSJoe   InitializeSolveAndSwarm - Set the solution values to the swarm coordinates and velocities, and also possibly set the initial values.
22518214e71cSJoe 
22528214e71cSJoe   Input Parameters:
22538214e71cSJoe + ts         - The TS
2254d7c1f440SPierre Jolivet - useInitial - Flag to also set the initial conditions to the current coordinates and velocities and setup the problem
22558214e71cSJoe 
22568214e71cSJoe   Output Parameters:
22578214e71cSJoe . u - The initialized solution vector
22588214e71cSJoe 
22598214e71cSJoe   Level: advanced
22608214e71cSJoe 
22618214e71cSJoe .seealso: InitializeSolve()
2262b80bf5b1SJoe Pusztay */
InitializeSolveAndSwarm(TS ts,PetscBool useInitial)22638214e71cSJoe static PetscErrorCode InitializeSolveAndSwarm(TS ts, PetscBool useInitial)
2264d71ae5a4SJacob Faibussowitsch {
22658214e71cSJoe   DM       sw;
2266045208b8SMatthew G. Knepley   Vec      u, gc, gv;
22678214e71cSJoe   IS       isx, isv;
22688214e71cSJoe   PetscInt dim;
2269*2a8381b2SBarry Smith   AppCtx  *ctx;
2270b80bf5b1SJoe Pusztay 
2271b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
22728214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
2273*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(sw, &ctx));
22748214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
22758214e71cSJoe   if (useInitial) {
22768214e71cSJoe     PetscReal v0[2] = {1., 0.};
2277*2a8381b2SBarry Smith     if (ctx->perturbed_weights) {
2278*2a8381b2SBarry Smith       PetscCall(InitializeParticles_PerturbedWeights(sw, ctx));
22798214e71cSJoe     } else {
22808214e71cSJoe       PetscCall(DMSwarmComputeLocalSizeFromOptions(sw));
22818214e71cSJoe       PetscCall(DMSwarmInitializeCoordinates(sw));
22828214e71cSJoe       PetscCall(DMSwarmInitializeVelocitiesFromOptions(sw, v0));
22838214e71cSJoe     }
22848214e71cSJoe     PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
22858214e71cSJoe     PetscCall(DMSwarmTSRedistribute(ts));
22868214e71cSJoe   }
2287045208b8SMatthew G. Knepley   PetscCall(DMSetUp(sw));
22888214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
22898214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
22908214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
22918214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
22928214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
22938214e71cSJoe   PetscCall(VecISCopy(u, isx, SCATTER_FORWARD, gc));
22948214e71cSJoe   PetscCall(VecISCopy(u, isv, SCATTER_FORWARD, gv));
22958214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
22968214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
22978214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
22988214e71cSJoe }
22998214e71cSJoe 
InitializeSolve(TS ts,Vec u)23008214e71cSJoe static PetscErrorCode InitializeSolve(TS ts, Vec u)
2301b80bf5b1SJoe Pusztay {
23028214e71cSJoe   PetscFunctionBegin;
23038214e71cSJoe   PetscCall(TSSetSolution(ts, u));
23048214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_TRUE));
23058214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
2306b80bf5b1SJoe Pusztay }
2307b80bf5b1SJoe Pusztay 
MigrateParticles(TS ts)23088214e71cSJoe static PetscErrorCode MigrateParticles(TS ts)
23098214e71cSJoe {
23108214e71cSJoe   DM               sw, cdm;
23118214e71cSJoe   const PetscReal *L;
23129072cb8bSMatthew G. Knepley   AppCtx          *ctx;
23138214e71cSJoe 
23148214e71cSJoe   PetscFunctionBeginUser;
23158214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
23169072cb8bSMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &ctx));
23178214e71cSJoe   PetscCall(DMViewFromOptions(sw, NULL, "-migrate_view_pre"));
23188214e71cSJoe   {
23198214e71cSJoe     Vec        u, gc, gv, position, momentum;
23208214e71cSJoe     IS         isx, isv;
23218214e71cSJoe     PetscReal *pos, *mom;
23228214e71cSJoe 
23238214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
23248214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
23258214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
23268214e71cSJoe     PetscCall(VecGetSubVector(u, isx, &position));
23278214e71cSJoe     PetscCall(VecGetSubVector(u, isv, &momentum));
23288214e71cSJoe     PetscCall(VecGetArray(position, &pos));
23298214e71cSJoe     PetscCall(VecGetArray(momentum, &mom));
23308214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
23318214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
23328214e71cSJoe     PetscCall(VecISCopy(u, isx, SCATTER_REVERSE, gc));
23338214e71cSJoe     PetscCall(VecISCopy(u, isv, SCATTER_REVERSE, gv));
23348214e71cSJoe 
23358214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &cdm));
23368214e71cSJoe     PetscCall(DMGetPeriodicity(cdm, NULL, NULL, &L));
23378214e71cSJoe     if ((L[0] || L[1]) >= 0.) {
23388214e71cSJoe       PetscReal *x, *v, upper[3], lower[3];
23398214e71cSJoe       PetscInt   Np, dim;
23408214e71cSJoe 
23418214e71cSJoe       PetscCall(DMSwarmGetLocalSize(sw, &Np));
23428214e71cSJoe       PetscCall(DMGetDimension(cdm, &dim));
23438214e71cSJoe       PetscCall(DMGetBoundingBox(cdm, lower, upper));
23448214e71cSJoe       PetscCall(VecGetArray(gc, &x));
23458214e71cSJoe       PetscCall(VecGetArray(gv, &v));
23468214e71cSJoe       for (PetscInt p = 0; p < Np; ++p) {
23478214e71cSJoe         for (PetscInt d = 0; d < dim; ++d) {
23488214e71cSJoe           if (pos[p * dim + d] < lower[d]) {
23498214e71cSJoe             x[p * dim + d] = pos[p * dim + d] + (upper[d] - lower[d]);
23508214e71cSJoe           } else if (pos[p * dim + d] > upper[d]) {
23518214e71cSJoe             x[p * dim + d] = pos[p * dim + d] - (upper[d] - lower[d]);
23528214e71cSJoe           } else {
23538214e71cSJoe             x[p * dim + d] = pos[p * dim + d];
23548214e71cSJoe           }
23558214e71cSJoe           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]);
23568214e71cSJoe           v[p * dim + d] = mom[p * dim + d];
23578214e71cSJoe         }
23588214e71cSJoe       }
23598214e71cSJoe       PetscCall(VecRestoreArray(gc, &x));
23608214e71cSJoe       PetscCall(VecRestoreArray(gv, &v));
23618214e71cSJoe     }
23628214e71cSJoe     PetscCall(VecRestoreArray(position, &pos));
23638214e71cSJoe     PetscCall(VecRestoreArray(momentum, &mom));
23648214e71cSJoe     PetscCall(VecRestoreSubVector(u, isx, &position));
23658214e71cSJoe     PetscCall(VecRestoreSubVector(u, isv, &momentum));
23668214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
23678214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
23688214e71cSJoe   }
23698214e71cSJoe   PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
23709072cb8bSMatthew G. Knepley   PetscInt step;
23719072cb8bSMatthew G. Knepley 
23729072cb8bSMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &step));
2373045208b8SMatthew G. Knepley   if (!(step % ctx->remapFreq)) {
23749072cb8bSMatthew G. Knepley     // Monitor electric field before we destroy it
23759072cb8bSMatthew G. Knepley     PetscReal ptime;
23769072cb8bSMatthew G. Knepley     PetscInt  step;
23779072cb8bSMatthew G. Knepley 
23789072cb8bSMatthew G. Knepley     PetscCall(TSGetStepNumber(ts, &step));
23799072cb8bSMatthew G. Knepley     PetscCall(TSGetTime(ts, &ptime));
23809072cb8bSMatthew G. Knepley     if (ctx->efield_monitor) PetscCall(MonitorEField(ts, step, ptime, NULL, ctx));
23819072cb8bSMatthew G. Knepley     if (ctx->poisson_monitor) PetscCall(MonitorPoisson(ts, step, ptime, NULL, ctx));
23829072cb8bSMatthew G. Knepley     PetscCall(DMSwarmRemap(sw));
23839072cb8bSMatthew G. Knepley     ctx->validE = PETSC_FALSE;
23849072cb8bSMatthew G. Knepley   }
23859072cb8bSMatthew G. Knepley   // This MUST come last, since it recreates the subswarms and they must DMClone() the new swarm
23868214e71cSJoe   PetscCall(DMSwarmTSRedistribute(ts));
23878214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_FALSE));
2388f940b0e3Sdanofinn   {
2389f940b0e3Sdanofinn     const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"};
2390f940b0e3Sdanofinn     PetscCall(DMSwarmVectorDefineFields(sw, 2, fieldnames));
2391f940b0e3Sdanofinn   }
23923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2393b80bf5b1SJoe Pusztay }
2394b80bf5b1SJoe Pusztay 
main(int argc,char ** argv)2395d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
2396d71ae5a4SJacob Faibussowitsch {
2397b80bf5b1SJoe Pusztay   DM        dm, sw;
23988214e71cSJoe   TS        ts;
23998214e71cSJoe   Vec       u;
24008214e71cSJoe   PetscReal dt;
24018214e71cSJoe   PetscInt  maxn;
2402*2a8381b2SBarry Smith   AppCtx    ctx;
2403b80bf5b1SJoe Pusztay 
24049566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
2405*2a8381b2SBarry Smith   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &ctx));
2406*2a8381b2SBarry Smith   PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &ctx.bag));
2407*2a8381b2SBarry Smith   PetscCall(CreateMesh(PETSC_COMM_WORLD, &ctx, &dm));
2408*2a8381b2SBarry Smith   PetscCall(CreatePoisson(dm, &ctx));
2409*2a8381b2SBarry Smith   PetscCall(CreateSwarm(dm, &ctx, &sw));
2410*2a8381b2SBarry Smith   PetscCall(SetupParameters(PETSC_COMM_WORLD, &ctx));
2411*2a8381b2SBarry Smith   PetscCall(InitializeConstants(sw, &ctx));
2412*2a8381b2SBarry Smith   PetscCall(DMSetApplicationContext(sw, &ctx));
2413b80bf5b1SJoe Pusztay 
24148214e71cSJoe   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
24158214e71cSJoe   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
24169566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts, sw));
24178214e71cSJoe   PetscCall(TSSetMaxTime(ts, 0.1));
24188214e71cSJoe   PetscCall(TSSetTimeStep(ts, 0.00001));
24198214e71cSJoe   PetscCall(TSSetMaxSteps(ts, 100));
24208214e71cSJoe   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
24218214e71cSJoe 
2422*2a8381b2SBarry Smith   if (ctx.efield_monitor) PetscCall(TSMonitorSet(ts, MonitorEField, &ctx, NULL));
2423*2a8381b2SBarry Smith   if (ctx.moment_monitor) PetscCall(TSMonitorSet(ts, MonitorMoments, &ctx, NULL));
2424*2a8381b2SBarry Smith   if (ctx.initial_monitor) PetscCall(TSMonitorSet(ts, MonitorInitialConditions, &ctx, NULL));
2425*2a8381b2SBarry Smith   if (ctx.positions_monitor) PetscCall(TSMonitorSet(ts, MonitorPositions_2D, &ctx, NULL));
2426*2a8381b2SBarry Smith   if (ctx.poisson_monitor) PetscCall(TSMonitorSet(ts, MonitorPoisson, &ctx, NULL));
2427*2a8381b2SBarry Smith   if (ctx.velocity_monitor >= 0) PetscCall(TSMonitorSet(ts, MonitorVelocity, &ctx, NULL));
24288214e71cSJoe 
24298214e71cSJoe   PetscCall(TSSetFromOptions(ts));
24308214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
24318214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
2432*2a8381b2SBarry Smith   ctx.steps    = maxn;
2433*2a8381b2SBarry Smith   ctx.stepSize = dt;
2434*2a8381b2SBarry Smith   PetscCall(SetupContext(dm, sw, &ctx));
24358214e71cSJoe   PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve));
24368214e71cSJoe   PetscCall(TSSetPostStep(ts, MigrateParticles));
24378214e71cSJoe   PetscCall(CreateSolution(ts));
24388214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
24398214e71cSJoe   PetscCall(TSComputeInitialCondition(ts, u));
2440*2a8381b2SBarry Smith   PetscCall(CheckNonNegativeWeights(sw, &ctx));
24418214e71cSJoe   PetscCall(TSSolve(ts, NULL));
24428214e71cSJoe 
2443*2a8381b2SBarry Smith   PetscCall(SNESDestroy(&ctx.snes));
2444*2a8381b2SBarry Smith   PetscCall(DMDestroy(&ctx.dmPot));
2445*2a8381b2SBarry Smith   PetscCall(ISDestroy(&ctx.isPot));
2446*2a8381b2SBarry Smith   PetscCall(MatDestroy(&ctx.M));
2447*2a8381b2SBarry Smith   PetscCall(PetscFEGeomDestroy(&ctx.fegeom));
24489566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
24499566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sw));
24509566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
2451*2a8381b2SBarry Smith   PetscCall(DestroyContext(&ctx));
24529566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
2453b122ec5aSJacob Faibussowitsch   return 0;
2454b80bf5b1SJoe Pusztay }
2455b80bf5b1SJoe Pusztay 
2456b80bf5b1SJoe Pusztay /*TEST
2457b80bf5b1SJoe Pusztay 
2458b80bf5b1SJoe Pusztay    build:
24598214e71cSJoe     requires: !complex double
24608214e71cSJoe 
24618214e71cSJoe   # This tests that we can put particles in a box and compute the Coulomb force
24628214e71cSJoe   # Recommend -draw_size 500,500
24638214e71cSJoe    testset:
24648214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2465045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 20 \
2466045208b8SMatthew G. Knepley              -dm_plex_box_lower 0 -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
24679072cb8bSMatthew G. Knepley            -vdm_plex_simplex 0 \
24688214e71cSJoe            -dm_swarm_coordinate_density constant -dm_swarm_num_particles 100 \
24698214e71cSJoe            -sigma 1.0e-8 -timeScale 2.0e-14 \
24708214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
24718214e71cSJoe            -output_step 50 -check_vel_res
24728214e71cSJoe      test:
24738214e71cSJoe        suffix: none_1d
24749072cb8bSMatthew G. Knepley        requires:
24758214e71cSJoe        args: -em_type none -error
24768214e71cSJoe      test:
24778214e71cSJoe        suffix: coulomb_1d
24788214e71cSJoe        args: -em_type coulomb
24798214e71cSJoe 
24808214e71cSJoe    # for viewers
24818214e71cSJoe    #-ts_monitor_sp_swarm_phase -ts_monitor_sp_swarm -em_snes_monitor -ts_monitor_sp_swarm_multi_species 0 -ts_monitor_sp_swarm_retain 0
24828214e71cSJoe    testset:
24838214e71cSJoe      nsize: {{1 2}}
24848214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2485045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 36 \
2486045208b8SMatthew G. Knepley              -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
24878214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
24888214e71cSJoe              -vdm_plex_box_lower -3 -vdm_plex_box_upper 3 \
248984467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -twostream -charges -1.,1. -sigma 1.0e-8 \
24908214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
24918214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 2 \
2492188af4bfSBarry Smith              -ts_time_step 0.01 -ts_max_time 5 -ts_max_steps 10 \
24938214e71cSJoe            -em_snes_atol 1.e-15 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
249484467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
24958214e71cSJoe      test:
24968214e71cSJoe        suffix: two_stream_c0
24978214e71cSJoe        args: -em_type primal -petscfe_default_quadrature_order 2 -petscspace_degree 2 -em_pc_type svd
24988214e71cSJoe      test:
24998214e71cSJoe        suffix: two_stream_rt
25008214e71cSJoe        requires: superlu_dist
25018214e71cSJoe        args: -em_type mixed \
25028214e71cSJoe                -potential_petscspace_degree 0 \
25038214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
25048214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
2505045208b8SMatthew G. Knepley                -field_petscspace_degree 1 -field_petscfe_default_quadrature_order 1 \
25068214e71cSJoe              -em_snes_error_if_not_converged \
25078214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
25088214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
25098214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
25108214e71cSJoe                -em_fieldsplit_field_pc_type lu \
25118214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
25128214e71cSJoe                -em_fieldsplit_potential_pc_type svd
25138214e71cSJoe 
251484467f86SMatthew G. Knepley    # For an eyeball check, we use
25159072cb8bSMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 10,1 -vdm_plex_box_faces 2000 -efield_monitor
25168214e71cSJoe    # For verification, we use
251784467f86SMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 100,1 -vdm_plex_box_faces 8000 -dm_swarm_num_particles 800000 -monitor_efield
25188214e71cSJoe    # -ts_monitor_sp_swarm_multi_species 0 -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500
25198214e71cSJoe    testset:
25208214e71cSJoe      nsize: {{1 2}}
2521045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 10 \
2522045208b8SMatthew G. Knepley              -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
25238214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
25248214e71cSJoe              -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \
2525f1e6e573SMatthew G. Knepley              -vpetscspace_degree 2 -vdm_plex_hash_location \
252684467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -charges -1.,1. \
25278214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
25288214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
2529188af4bfSBarry Smith              -ts_time_step 0.03 -ts_max_time 500 -ts_max_steps 1 \
25308214e71cSJoe            -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
253184467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
25328214e71cSJoe 
25338214e71cSJoe      test:
25348214e71cSJoe        suffix: uniform_equilibrium_1d
25358214e71cSJoe        args: -cosine_coefficients 0.0,0.5 -em_type primal -petscspace_degree 1 -em_pc_type svd
25368214e71cSJoe      test:
253775155f48SMatthew G. Knepley        suffix: uniform_equilibrium_1d_real
2538045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
253975155f48SMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
254075155f48SMatthew G. Knepley              -cosine_coefficients 0.0 -em_type primal -petscspace_degree 1 -em_pc_type svd
254175155f48SMatthew G. Knepley      test:
2542f940b0e3Sdanofinn        suffix: landau_damping_1d_c0
25438214e71cSJoe        args: -em_type primal -petscspace_degree 1 -em_pc_type svd
25448214e71cSJoe      test:
254575155f48SMatthew G. Knepley        suffix: uniform_primal_1d_real
2546045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
254775155f48SMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
254875155f48SMatthew G. Knepley              -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd
25499072cb8bSMatthew G. Knepley      # NOT WORKING -ftop_pc_type bjacobi -ftop_sub_pc_type lu -ftop_sub_pc_factor_shift_type nonzero
25509072cb8bSMatthew G. Knepley      test:
25519072cb8bSMatthew G. Knepley        suffix: uniform_primal_1d_real_pfak
25529072cb8bSMatthew G. Knepley        nsize: 1
2553045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
25549072cb8bSMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
25559072cb8bSMatthew G. Knepley              -remap_dm_plex_dim 2 -remap_dm_plex_simplex 0 -remap_dm_plex_box_faces 10,10 -remap_dm_plex_box_bd periodic,none \
25569072cb8bSMatthew G. Knepley                -remap_dm_plex_box_lower 0.,-10. -remap_dm_plex_box_upper 12.5664,10. \
25579072cb8bSMatthew G. Knepley                -remap_petscspace_degree 2 -remap_dm_plex_hash_location \
2558045208b8SMatthew G. Knepley              -remap_freq 1 -dm_swarm_remap_type pfak \
25599072cb8bSMatthew G. Knepley                -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 \
25609072cb8bSMatthew G. Knepley                -ptof_pc_type lu \
25619072cb8bSMatthew G. Knepley              -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd -em_proj_pc_type lu
256275155f48SMatthew G. Knepley      test:
25638214e71cSJoe        requires: superlu_dist
2564f940b0e3Sdanofinn        suffix: landau_damping_1d_mixed
25658214e71cSJoe        args: -em_type mixed \
25668214e71cSJoe                -potential_petscspace_degree 0 \
25678214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
25688214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
2569045208b8SMatthew G. Knepley                -field_petscspace_degree 1 \
25708214e71cSJoe              -em_snes_error_if_not_converged \
25718214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
25728214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
25738214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
25748214e71cSJoe                -em_fieldsplit_field_pc_type lu \
25758214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
25768214e71cSJoe                -em_fieldsplit_potential_pc_type svd
25778214e71cSJoe 
2578f940b0e3Sdanofinn    # Same as above, with different timestepping
2579f940b0e3Sdanofinn    testset:
2580f940b0e3Sdanofinn      nsize: {{1 2}}
2581f940b0e3Sdanofinn      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 10 \
2582f940b0e3Sdanofinn              -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
2583f940b0e3Sdanofinn            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
2584f940b0e3Sdanofinn              -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \
2585f940b0e3Sdanofinn              -vpetscspace_degree 2 -vdm_plex_hash_location \
2586f940b0e3Sdanofinn            -dm_swarm_num_species 1 -charges -1.,1. \
2587f940b0e3Sdanofinn              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
2588f940b0e3Sdanofinn            -ts_type discgrad -ts_discgrad_type average \
2589188af4bfSBarry Smith              -ts_time_step 0.03 -ts_max_time 500 -ts_max_steps 1 \
2590f940b0e3Sdanofinn            -snes_type qn \
2591f940b0e3Sdanofinn            -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
2592f940b0e3Sdanofinn            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
2593f940b0e3Sdanofinn 
2594f940b0e3Sdanofinn      test:
2595f940b0e3Sdanofinn        suffix: landau_damping_1d_dg
2596f940b0e3Sdanofinn        args: -em_type primal -petscspace_degree 1 -em_pc_type svd
2597f940b0e3Sdanofinn 
2598b80bf5b1SJoe Pusztay TEST*/
2599