xref: /petsc/src/ts/tutorials/hamiltonian/ex2.c (revision ac9d17c75cb5e991458e9675ca6ec07d361dad47)
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
56045208b8SMatthew G. Knepley   -ts_type basicsymplectic -ts_basicsymplectic_type 1 -ts_dt 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
1219072cb8bSMatthew G. Knepley   PetscBool    perturbed_weights; // Uniformly sample x,v space with gaussian weights
1229072cb8bSMatthew G. Knepley   PetscInt     ostep;             // Print the energy at each ostep time steps
1238214e71cSJoe   PetscInt     numParticles;
1248214e71cSJoe   PetscReal    timeScale;              /* Nondimensionalizing time scale */
1258214e71cSJoe   PetscReal    charges[2];             /* The charges of each species */
1268214e71cSJoe   PetscReal    masses[2];              /* The masses of each species */
1278214e71cSJoe   PetscReal    thermal_energy[2];      /* Thermal Energy (used to get other constants)*/
1288214e71cSJoe   PetscReal    cosine_coefficients[2]; /*(alpha, k)*/
1298214e71cSJoe   PetscReal    totalWeight;
1308214e71cSJoe   PetscReal    stepSize;
1318214e71cSJoe   PetscInt     steps;
1328214e71cSJoe   PetscReal    initVel;
133f1e6e573SMatthew G. Knepley   EMType       em;           // Type of electrostatic model
134f1e6e573SMatthew G. Knepley   SNES         snes;         // EM solver
1354a0cbf56SMatthew G. Knepley   DM           dmPot;        // The DM for potential
136b02f317dSMatthew G. Knepley   Mat          fftPot;       // Fourier Transform operator for the potential
1374a0cbf56SMatthew G. Knepley   IS           isPot;        // The IS for potential, or NULL in primal
1384a0cbf56SMatthew G. Knepley   Mat          M;            // The finite element mass matrix for potential
139f1e6e573SMatthew G. Knepley   PetscFEGeom *fegeom;       // Geometric information for the DM cells
140b02f317dSMatthew G. Knepley   PetscDrawHG  drawhgic_x;   // Histogram of the particle weight in each X cell
141b02f317dSMatthew G. Knepley   PetscDraw    drawic_x;     //   Draw context for histogram
142b02f317dSMatthew G. Knepley   PetscDrawHG  drawhgic_v;   // Histogram of the particle weight in each X cell
143b02f317dSMatthew G. Knepley   PetscDraw    drawic_v;     //   Draw context for histogram
1449072cb8bSMatthew G. Knepley   PetscBool    validE;       // Flag to indicate E-field in swarm is valid
14575155f48SMatthew G. Knepley   PetscReal    drawlgEmin;   // The minimum lg(E) to plot
14675155f48SMatthew G. Knepley   PetscDrawLG  drawlgE;      // Logarithm of maximum electric field
14775155f48SMatthew G. Knepley   PetscDrawSP  drawspE;      // Electric field at particle positions
14875155f48SMatthew G. Knepley   PetscDrawSP  drawspX;      // Particle positions
14975155f48SMatthew G. Knepley   PetscViewer  viewerRho;    // Charge density viewer
150b02f317dSMatthew G. Knepley   PetscViewer  viewerRhoHat; // Charge density Fourier Transform viewer
15175155f48SMatthew G. Knepley   PetscViewer  viewerPhi;    // Potential viewer
1528214e71cSJoe   DM           swarm;
1538214e71cSJoe   PetscRandom  random;
1548214e71cSJoe   PetscBool    twostream;
1558214e71cSJoe   PetscBool    checkweights;
156b02f317dSMatthew G. Knepley   PetscInt     checkVRes; // Flag to check/output velocity residuals for nightly tests
15784467f86SMatthew G. Knepley 
15884467f86SMatthew G. Knepley   PetscLogEvent RhsXEvent, RhsVEvent, ESolveEvent, ETabEvent;
159b80bf5b1SJoe Pusztay } AppCtx;
160b80bf5b1SJoe Pusztay 
161d71ae5a4SJacob Faibussowitsch static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
162d71ae5a4SJacob Faibussowitsch {
163b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
1648214e71cSJoe   PetscInt d                      = 2;
1658214e71cSJoe   PetscInt maxSpecies             = 2;
1668214e71cSJoe   options->error                  = PETSC_FALSE;
1679072cb8bSMatthew G. Knepley   options->remapFreq              = 1;
1688214e71cSJoe   options->efield_monitor         = PETSC_FALSE;
169f1e6e573SMatthew G. Knepley   options->moment_monitor         = PETSC_FALSE;
1708214e71cSJoe   options->initial_monitor        = PETSC_FALSE;
1718214e71cSJoe   options->perturbed_weights      = PETSC_FALSE;
1728214e71cSJoe   options->poisson_monitor        = PETSC_FALSE;
1739072cb8bSMatthew G. Knepley   options->positions_monitor      = PETSC_FALSE;
1748214e71cSJoe   options->ostep                  = 100;
1758214e71cSJoe   options->timeScale              = 2.0e-14;
1768214e71cSJoe   options->charges[0]             = -1.0;
1778214e71cSJoe   options->charges[1]             = 1.0;
1788214e71cSJoe   options->masses[0]              = 1.0;
1798214e71cSJoe   options->masses[1]              = 1000.0;
1808214e71cSJoe   options->thermal_energy[0]      = 1.0;
1818214e71cSJoe   options->thermal_energy[1]      = 1.0;
1828214e71cSJoe   options->cosine_coefficients[0] = 0.01;
1838214e71cSJoe   options->cosine_coefficients[1] = 0.5;
1848214e71cSJoe   options->initVel                = 1;
1858214e71cSJoe   options->totalWeight            = 1.0;
1868214e71cSJoe   options->drawic_x               = NULL;
1878214e71cSJoe   options->drawhgic_x             = NULL;
188b02f317dSMatthew G. Knepley   options->drawic_v               = NULL;
1898214e71cSJoe   options->drawhgic_v             = NULL;
19075155f48SMatthew G. Knepley   options->drawlgEmin             = -6;
19175155f48SMatthew G. Knepley   options->drawlgE                = NULL;
19275155f48SMatthew G. Knepley   options->drawspE                = NULL;
19375155f48SMatthew G. Knepley   options->drawspX                = NULL;
19475155f48SMatthew G. Knepley   options->viewerRho              = NULL;
195b02f317dSMatthew G. Knepley   options->viewerRhoHat           = NULL;
19675155f48SMatthew G. Knepley   options->viewerPhi              = NULL;
1978214e71cSJoe   options->em                     = EM_COULOMB;
1984a0cbf56SMatthew G. Knepley   options->snes                   = NULL;
1994a0cbf56SMatthew G. Knepley   options->dmPot                  = NULL;
200b02f317dSMatthew G. Knepley   options->fftPot                 = NULL;
2014a0cbf56SMatthew G. Knepley   options->isPot                  = NULL;
2024a0cbf56SMatthew G. Knepley   options->M                      = NULL;
2038214e71cSJoe   options->numParticles           = 32768;
2048214e71cSJoe   options->twostream              = PETSC_FALSE;
2058214e71cSJoe   options->checkweights           = PETSC_FALSE;
2068214e71cSJoe   options->checkVRes              = 0;
207b80bf5b1SJoe Pusztay 
2088214e71cSJoe   PetscOptionsBegin(comm, "", "Landau Damping and Two Stream options", "DMSWARM");
2098214e71cSJoe   PetscCall(PetscOptionsBool("-error", "Flag to print the error", "ex2.c", options->error, &options->error, NULL));
2109072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsInt("-remap_freq", "Number", "ex2.c", options->remapFreq, &options->remapFreq, NULL));
2119072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-efield_monitor", "Flag to plot log(max E) over time", "ex2.c", options->efield_monitor, &options->efield_monitor, NULL));
2129072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsReal("-efield_min_monitor", "Minimum E field to plot", "ex2.c", options->drawlgEmin, &options->drawlgEmin, NULL));
2139072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-moments_monitor", "Flag to show moments table", "ex2.c", options->moment_monitor, &options->moment_monitor, NULL));
2149072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-ics_monitor", "Flag to show initial condition histograms", "ex2.c", options->initial_monitor, &options->initial_monitor, NULL));
2159072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-positions_monitor", "The flag to show particle positions", "ex2.c", options->positions_monitor, &options->positions_monitor, NULL));
2169072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-poisson_monitor", "The flag to show charges, Efield and potential solve", "ex2.c", options->poisson_monitor, &options->poisson_monitor, NULL));
2178214e71cSJoe   PetscCall(PetscOptionsBool("-twostream", "Run two stream instability", "ex2.c", options->twostream, &options->twostream, NULL));
2188214e71cSJoe   PetscCall(PetscOptionsBool("-perturbed_weights", "Flag to run uniform sampling with perturbed weights", "ex2.c", options->perturbed_weights, &options->perturbed_weights, NULL));
2198214e71cSJoe   PetscCall(PetscOptionsBool("-check_weights", "Ensure all particle weights are positive", "ex2.c", options->checkweights, &options->checkweights, NULL));
2208214e71cSJoe   PetscCall(PetscOptionsInt("-check_vel_res", "Check particle velocity residuals for nightly tests", "ex2.c", options->checkVRes, &options->checkVRes, NULL));
2218214e71cSJoe   PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", "ex2.c", options->ostep, &options->ostep, NULL));
2228214e71cSJoe   PetscCall(PetscOptionsReal("-timeScale", "Nondimensionalizing time scale", "ex2.c", options->timeScale, &options->timeScale, NULL));
2238214e71cSJoe   PetscCall(PetscOptionsReal("-initial_velocity", "Initial velocity of perturbed particle", "ex2.c", options->initVel, &options->initVel, NULL));
2248214e71cSJoe   PetscCall(PetscOptionsReal("-total_weight", "Total weight of all particles", "ex2.c", options->totalWeight, &options->totalWeight, NULL));
2258214e71cSJoe   PetscCall(PetscOptionsRealArray("-cosine_coefficients", "Amplitude and frequency of cosine equation used in initialization", "ex2.c", options->cosine_coefficients, &d, NULL));
2268214e71cSJoe   PetscCall(PetscOptionsRealArray("-charges", "Species charges", "ex2.c", options->charges, &maxSpecies, NULL));
2278214e71cSJoe   PetscCall(PetscOptionsEnum("-em_type", "Type of electrostatic solver", "ex2.c", EMTypes, (PetscEnum)options->em, (PetscEnum *)&options->em, NULL));
228d0609cedSBarry Smith   PetscOptionsEnd();
22984467f86SMatthew G. Knepley 
23084467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsX", TS_CLASSID, &options->RhsXEvent));
23184467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsV", TS_CLASSID, &options->RhsVEvent));
23284467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ESolve", TS_CLASSID, &options->ESolveEvent));
23384467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ETab", TS_CLASSID, &options->ETabEvent));
2343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
235b80bf5b1SJoe Pusztay }
236b80bf5b1SJoe Pusztay 
2378214e71cSJoe static PetscErrorCode SetupContext(DM dm, DM sw, AppCtx *user)
2388214e71cSJoe {
239b02f317dSMatthew G. Knepley   MPI_Comm comm;
240b02f317dSMatthew G. Knepley 
2418214e71cSJoe   PetscFunctionBeginUser;
242b02f317dSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2438214e71cSJoe   if (user->efield_monitor) {
24475155f48SMatthew G. Knepley     PetscDraw     draw;
24575155f48SMatthew G. Knepley     PetscDrawAxis axis;
24675155f48SMatthew G. Knepley 
247b02f317dSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Max Electric Field", 0, 300, 400, 300, &draw));
24875155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_Efield"));
24975155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
25075155f48SMatthew G. Knepley     PetscCall(PetscDrawLGCreate(draw, 1, &user->drawlgE));
25175155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
25275155f48SMatthew G. Knepley     PetscCall(PetscDrawLGGetAxis(user->drawlgE, &axis));
25375155f48SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Electron Electric Field", "time", "E_max"));
25475155f48SMatthew G. Knepley     PetscCall(PetscDrawLGSetLimits(user->drawlgE, 0., user->steps * user->stepSize, user->drawlgEmin, 0.));
2558214e71cSJoe   }
256b02f317dSMatthew G. Knepley 
2578214e71cSJoe   if (user->initial_monitor) {
258b02f317dSMatthew G. Knepley     PetscDrawAxis axis1, axis2;
2598214e71cSJoe     PetscReal     dmboxlower[2], dmboxupper[2];
2608214e71cSJoe     PetscInt      dim, cStart, cEnd;
261b02f317dSMatthew G. Knepley 
2628214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
2638214e71cSJoe     PetscCall(DMGetBoundingBox(dm, dmboxlower, dmboxupper));
2648214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2658214e71cSJoe 
266b02f317dSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_x", 0, 300, 400, 300, &user->drawic_x));
26775155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(user->drawic_x, "ex9_ic_x"));
2688214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawic_x));
2696497c311SBarry Smith     PetscCall(PetscDrawHGCreate(user->drawic_x, (int)dim, &user->drawhgic_x));
270b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGCalcStats(user->drawhgic_x, PETSC_TRUE));
2718214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_x, &axis1));
2726497c311SBarry Smith     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_x, (int)(cEnd - cStart)));
2738214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis1, "Initial X Distribution", "X", "counts"));
274b02f317dSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis1, dmboxlower[0], dmboxupper[0], 0, 0));
2758214e71cSJoe 
276b02f317dSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_v", 400, 300, 400, 300, &user->drawic_v));
27775155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(user->drawic_v, "ex9_ic_v"));
2788214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawic_v));
2796497c311SBarry Smith     PetscCall(PetscDrawHGCreate(user->drawic_v, (int)dim, &user->drawhgic_v));
280b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGCalcStats(user->drawhgic_v, PETSC_TRUE));
2818214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_v, &axis2));
282b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_v, 21));
2838214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis2, "Initial V_x Distribution", "V", "counts"));
284b02f317dSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis2, -6, 6, 0, 0));
2858214e71cSJoe   }
286b02f317dSMatthew G. Knepley 
2879072cb8bSMatthew G. Knepley   if (user->positions_monitor) {
28875155f48SMatthew G. Knepley     PetscDraw     draw;
2898214e71cSJoe     PetscDrawAxis axis;
2908214e71cSJoe 
291b02f317dSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Particle Position", 0, 0, 400, 300, &draw));
29275155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_pos"));
29375155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
29475155f48SMatthew G. Knepley     PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspX));
29575155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
29675155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetDimension(user->drawspX, 1));
29775155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetAxis(user->drawspX, &axis));
2988214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "v"));
29975155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspX));
3008214e71cSJoe   }
3018214e71cSJoe   if (user->poisson_monitor) {
302b02f317dSMatthew G. Knepley     Vec           rho, rhohat, phi;
30375155f48SMatthew G. Knepley     PetscDraw     draw;
30475155f48SMatthew G. Knepley     PetscDrawAxis axis;
3058214e71cSJoe 
306b02f317dSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Electric_Field", 0, 0, 400, 300, &draw));
30775155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
30875155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_E_spatial"));
30975155f48SMatthew G. Knepley     PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspE));
31075155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
31175155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetDimension(user->drawspE, 1));
31275155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetAxis(user->drawspE, &axis));
31375155f48SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "E"));
31475155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspE));
3158214e71cSJoe 
316b02f317dSMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "Charge Density", 0, 0, 400, 300, &user->viewerRho));
31775155f48SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerRho, "rho_"));
31875155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerRho, 0, &draw));
31975155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_spatial"));
32075155f48SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerRho));
3214a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
32275155f48SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rho, "charge_density"));
3234a0cbf56SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
3248214e71cSJoe 
325b02f317dSMatthew G. Knepley     PetscInt dim, N;
326b02f317dSMatthew G. Knepley 
327b02f317dSMatthew G. Knepley     PetscCall(DMGetDimension(user->dmPot, &dim));
328b02f317dSMatthew G. Knepley     if (dim == 1) {
329b02f317dSMatthew G. Knepley       PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
330b02f317dSMatthew G. Knepley       PetscCall(VecGetSize(rhohat, &N));
331b02f317dSMatthew G. Knepley       PetscCall(MatCreateFFT(comm, dim, &N, MATFFTW, &user->fftPot));
332b02f317dSMatthew G. Knepley       PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
333b02f317dSMatthew G. Knepley     }
334b02f317dSMatthew G. Knepley 
335b02f317dSMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "Charge Density FT", 0, 0, 400, 300, &user->viewerRhoHat));
336b02f317dSMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerRhoHat, "rhohat_"));
337b02f317dSMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerRhoHat, 0, &draw));
338b02f317dSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_ft"));
339b02f317dSMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerRhoHat));
340b02f317dSMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
341b02f317dSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rhohat, "charge_density_ft"));
342b02f317dSMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
343b02f317dSMatthew G. Knepley 
344b02f317dSMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "Potential", 400, 0, 400, 300, &user->viewerPhi));
34575155f48SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerPhi, "phi_"));
34675155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerPhi, 0, &draw));
34775155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_phi_spatial"));
34875155f48SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerPhi));
3494a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
35075155f48SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)phi, "potential"));
3514a0cbf56SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
3528214e71cSJoe   }
3538214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3548214e71cSJoe }
3558214e71cSJoe 
3568214e71cSJoe static PetscErrorCode DestroyContext(AppCtx *user)
3578214e71cSJoe {
3588214e71cSJoe   PetscFunctionBeginUser;
3598214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_x));
3608214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawic_x));
3618214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_v));
3628214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawic_v));
3638214e71cSJoe 
36475155f48SMatthew G. Knepley   PetscCall(PetscDrawLGDestroy(&user->drawlgE));
36575155f48SMatthew G. Knepley   PetscCall(PetscDrawSPDestroy(&user->drawspE));
36675155f48SMatthew G. Knepley   PetscCall(PetscDrawSPDestroy(&user->drawspX));
36775155f48SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerRho));
368b02f317dSMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerRhoHat));
369b02f317dSMatthew G. Knepley   PetscCall(MatDestroy(&user->fftPot));
37075155f48SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerPhi));
3718214e71cSJoe 
3728214e71cSJoe   PetscCall(PetscBagDestroy(&user->bag));
3738214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3748214e71cSJoe }
3758214e71cSJoe 
3768214e71cSJoe static PetscErrorCode CheckNonNegativeWeights(DM sw, AppCtx *user)
3778214e71cSJoe {
3788214e71cSJoe   const PetscScalar *w;
3798214e71cSJoe   PetscInt           Np;
3808214e71cSJoe 
3818214e71cSJoe   PetscFunctionBeginUser;
3828214e71cSJoe   if (!user->checkweights) PetscFunctionReturn(PETSC_SUCCESS);
3838214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w));
3848214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
3858214e71cSJoe   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]);
3868214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w));
3878214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3888214e71cSJoe }
3898214e71cSJoe 
3909072cb8bSMatthew G. Knepley static PetscErrorCode computeVelocityFEMMoments(DM sw, PetscReal moments[], AppCtx *user)
3918214e71cSJoe {
3929072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
393f1e6e573SMatthew G. Knepley   DM            vdm;
394f1e6e573SMatthew G. Knepley   Vec           u[1];
395f1e6e573SMatthew G. Knepley   const char   *fields[1] = {"w_q"};
3968214e71cSJoe 
397f1e6e573SMatthew G. Knepley   PetscFunctionBegin;
3989072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "velocity"));
3999072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
4009072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
401f1e6e573SMatthew G. Knepley   PetscCall(DMGetGlobalVector(vdm, &u[0]));
402f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmProjectFields(sw, vdm, 1, fields, u, SCATTER_FORWARD));
403f1e6e573SMatthew G. Knepley   PetscCall(DMPlexComputeMoments(vdm, u[0], moments));
404f1e6e573SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(vdm, &u[0]));
4059072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
4068214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
4078214e71cSJoe }
4088214e71cSJoe 
4098214e71cSJoe static PetscErrorCode MonitorEField(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
4108214e71cSJoe {
4118214e71cSJoe   AppCtx    *user = (AppCtx *)ctx;
412f1e6e573SMatthew G. Knepley   DM         sw;
413f1e6e573SMatthew G. Knepley   PetscReal *E, *x, *weight;
414f1e6e573SMatthew G. Knepley   PetscReal  Enorm = 0., lgEnorm, lgEmax, sum = 0., Emax = 0., chargesum = 0.;
415f1e6e573SMatthew G. Knepley   PetscReal  pmoments[4]; /* \int f, \int v f, \int v^2 f */
416f1e6e573SMatthew G. Knepley   PetscInt  *species, dim, Np;
4178214e71cSJoe 
4188214e71cSJoe   PetscFunctionBeginUser;
4199072cb8bSMatthew G. Knepley   if (step < 0 || !user->validE) PetscFunctionReturn(PETSC_SUCCESS);
4208214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
4218214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
4228214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
4238214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
4248214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
4258214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
4268214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
4278214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
4288214e71cSJoe 
429f1e6e573SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
430f1e6e573SMatthew G. Knepley     for (PetscInt d = 0; d < 1; ++d) {
431f1e6e573SMatthew G. Knepley       PetscReal temp = PetscAbsReal(E[p * dim + d]);
4328214e71cSJoe       if (temp > Emax) Emax = temp;
4338214e71cSJoe     }
4348214e71cSJoe     Enorm += PetscSqrtReal(E[p * dim] * E[p * dim]);
4358214e71cSJoe     sum += E[p * dim];
4368214e71cSJoe     chargesum += user->charges[0] * weight[p];
4378214e71cSJoe   }
4388214e71cSJoe   lgEnorm = Enorm != 0 ? PetscLog10Real(Enorm) : -16.;
43975155f48SMatthew G. Knepley   lgEmax  = Emax != 0 ? PetscLog10Real(Emax) : user->drawlgEmin;
4408214e71cSJoe 
4418214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
4428214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
4438214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
4448214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
44575155f48SMatthew G. Knepley   PetscCall(PetscDrawLGAddPoint(user->drawlgE, &t, &lgEmax));
44675155f48SMatthew G. Knepley   PetscCall(PetscDrawLGDraw(user->drawlgE));
44775155f48SMatthew G. Knepley   PetscDraw draw;
44875155f48SMatthew G. Knepley   PetscCall(PetscDrawLGGetDraw(user->drawlgE, &draw));
44975155f48SMatthew G. Knepley   PetscCall(PetscDrawSave(draw));
450f1e6e573SMatthew G. Knepley 
451f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
45275155f48SMatthew G. Knepley   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%f\t%+e\t%e\t%f\t%f\t%f\t%f\t%f\t%f\t%f\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]));
45375155f48SMatthew G. Knepley   PetscCall(DMViewFromOptions(sw, NULL, "-sw_efield_view"));
454f1e6e573SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
455f1e6e573SMatthew G. Knepley }
456f1e6e573SMatthew G. Knepley 
457f1e6e573SMatthew G. Knepley static PetscErrorCode MonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
458f1e6e573SMatthew G. Knepley {
459f1e6e573SMatthew G. Knepley   AppCtx   *user = (AppCtx *)ctx;
460f1e6e573SMatthew G. Knepley   DM        sw;
461f1e6e573SMatthew G. Knepley   PetscReal pmoments[4], fmoments[4]; /* \int f, \int v f, \int v^2 f */
462f1e6e573SMatthew G. Knepley 
463f1e6e573SMatthew G. Knepley   PetscFunctionBeginUser;
464f1e6e573SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
465f1e6e573SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
466f1e6e573SMatthew G. Knepley 
467f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
468f1e6e573SMatthew G. Knepley   PetscCall(computeVelocityFEMMoments(sw, fmoments, user));
469f1e6e573SMatthew G. Knepley 
470f1e6e573SMatthew 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]));
4718214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
4728214e71cSJoe }
4738214e71cSJoe 
4748214e71cSJoe PetscErrorCode MonitorInitialConditions(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
4758214e71cSJoe {
4768214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
477b02f317dSMatthew G. Knepley   DM                 sw;
4788214e71cSJoe   const PetscScalar *u;
4798214e71cSJoe   PetscReal         *weight, *pos, *vel;
480b02f317dSMatthew G. Knepley   PetscInt           dim, Np;
4818214e71cSJoe 
4828214e71cSJoe   PetscFunctionBegin;
4838214e71cSJoe   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
484b02f317dSMatthew G. Knepley   if (step == 0) {
4858214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
4868214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
4878214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
4888214e71cSJoe 
4898214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_x));
4908214e71cSJoe     PetscCall(PetscDrawHGGetDraw(user->drawhgic_x, &user->drawic_x));
4918214e71cSJoe     PetscCall(PetscDrawClear(user->drawic_x));
4928214e71cSJoe     PetscCall(PetscDrawFlush(user->drawic_x));
4938214e71cSJoe 
4948214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_v));
4958214e71cSJoe     PetscCall(PetscDrawHGGetDraw(user->drawhgic_v, &user->drawic_v));
4968214e71cSJoe     PetscCall(PetscDrawClear(user->drawic_v));
4978214e71cSJoe     PetscCall(PetscDrawFlush(user->drawic_v));
4988214e71cSJoe 
4998214e71cSJoe     PetscCall(VecGetArrayRead(U, &u));
500b02f317dSMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
5018214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
5028214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
503b02f317dSMatthew G. Knepley     for (PetscInt p = 0; p < Np; ++p) {
504b02f317dSMatthew G. Knepley       PetscCall(PetscDrawHGAddWeightedValue(user->drawhgic_x, pos[p * dim], weight[p]));
505b02f317dSMatthew G. Knepley       PetscCall(PetscDrawHGAddWeightedValue(user->drawhgic_v, vel[p * dim], weight[p]));
5068214e71cSJoe     }
5078214e71cSJoe     PetscCall(VecRestoreArrayRead(U, &u));
5088214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
5098214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
5108214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
511b02f317dSMatthew G. Knepley 
512b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGDraw(user->drawhgic_x));
513b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGSave(user->drawhgic_x));
514b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGDraw(user->drawhgic_v));
515b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGSave(user->drawhgic_v));
5168214e71cSJoe   }
5178214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5188214e71cSJoe }
5198214e71cSJoe 
5208214e71cSJoe static PetscErrorCode MonitorPositions_2D(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
5218214e71cSJoe {
5228214e71cSJoe   AppCtx         *user = (AppCtx *)ctx;
5238214e71cSJoe   DM              dm, sw;
5248214e71cSJoe   PetscScalar    *x, *v, *weight;
5258214e71cSJoe   PetscReal       lower[3], upper[3], speed;
5268214e71cSJoe   const PetscInt *s;
5278214e71cSJoe   PetscInt        dim, cStart, cEnd, c;
5288214e71cSJoe 
5298214e71cSJoe   PetscFunctionBeginUser;
5308214e71cSJoe   if (step > 0 && step % user->ostep == 0) {
5318214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
5328214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
5338214e71cSJoe     PetscCall(DMGetDimension(dm, &dim));
5348214e71cSJoe     PetscCall(DMGetBoundingBox(dm, lower, upper));
5358214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
5368214e71cSJoe     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5378214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
5388214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
5398214e71cSJoe     PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&s));
5408214e71cSJoe     PetscCall(DMSwarmSortGetAccess(sw));
54175155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspX));
54275155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], lower[1], upper[1]));
54375155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], -12, 12));
5448214e71cSJoe     for (c = 0; c < cEnd - cStart; ++c) {
5458214e71cSJoe       PetscInt *pidx, Npc, q;
5468214e71cSJoe       PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
5478214e71cSJoe       for (q = 0; q < Npc; ++q) {
5488214e71cSJoe         const PetscInt p = pidx[q];
5498214e71cSJoe         if (s[p] == 0) {
5509072cb8bSMatthew G. Knepley           speed = 0.;
5519072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) speed += PetscSqr(v[p * dim + d]);
5529072cb8bSMatthew G. Knepley           speed = PetscSqrtReal(speed);
553045208b8SMatthew G. Knepley           if (dim == 1) {
55475155f48SMatthew G. Knepley             PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &v[p * dim], &speed));
5558214e71cSJoe           } else {
55675155f48SMatthew G. Knepley             PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &x[p * dim + 1], &speed));
5578214e71cSJoe           }
5588214e71cSJoe         } else if (s[p] == 1) {
55975155f48SMatthew G. Knepley           PetscCall(PetscDrawSPAddPoint(user->drawspX, &x[p * dim], &v[p * dim]));
5608214e71cSJoe         }
5618214e71cSJoe       }
56284467f86SMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
5638214e71cSJoe     }
56475155f48SMatthew G. Knepley     PetscCall(PetscDrawSPDraw(user->drawspX, PETSC_TRUE));
56575155f48SMatthew G. Knepley     PetscDraw draw;
56675155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetDraw(user->drawspX, &draw));
56775155f48SMatthew G. Knepley     PetscCall(PetscDrawSave(draw));
5688214e71cSJoe     PetscCall(DMSwarmSortRestoreAccess(sw));
5698214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5708214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
5718214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
5728214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&s));
5738214e71cSJoe   }
5748214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5758214e71cSJoe }
5768214e71cSJoe 
5778214e71cSJoe static PetscErrorCode MonitorPoisson(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
5788214e71cSJoe {
5798214e71cSJoe   AppCtx *user = (AppCtx *)ctx;
5808214e71cSJoe   DM      dm, sw;
5818214e71cSJoe 
5828214e71cSJoe   PetscFunctionBeginUser;
5838214e71cSJoe   if (step > 0 && step % user->ostep == 0) {
5848214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
5858214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
5869072cb8bSMatthew G. Knepley 
5879072cb8bSMatthew G. Knepley     if (user->validE) {
5889072cb8bSMatthew G. Knepley       PetscScalar *x, *E, *weight;
5899072cb8bSMatthew G. Knepley       PetscReal    lower[3], upper[3], xval;
5909072cb8bSMatthew G. Knepley       PetscDraw    draw;
5919072cb8bSMatthew G. Knepley       PetscInt     dim, cStart, cEnd;
5929072cb8bSMatthew G. Knepley 
5938214e71cSJoe       PetscCall(DMGetDimension(dm, &dim));
5948214e71cSJoe       PetscCall(DMGetBoundingBox(dm, lower, upper));
5958214e71cSJoe       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
5968214e71cSJoe 
59775155f48SMatthew G. Knepley       PetscCall(PetscDrawSPReset(user->drawspE));
5988214e71cSJoe       PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5998214e71cSJoe       PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
6008214e71cSJoe       PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
6018214e71cSJoe 
6028214e71cSJoe       PetscCall(DMSwarmSortGetAccess(sw));
6039072cb8bSMatthew G. Knepley       for (PetscInt c = 0; c < cEnd - cStart; ++c) {
60475155f48SMatthew G. Knepley         PetscReal Eavg = 0.0;
6059072cb8bSMatthew G. Knepley         PetscInt *pidx, Npc;
6069072cb8bSMatthew G. Knepley 
6078214e71cSJoe         PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
6089072cb8bSMatthew G. Knepley         for (PetscInt q = 0; q < Npc; ++q) {
6098214e71cSJoe           const PetscInt p = pidx[q];
61075155f48SMatthew G. Knepley           Eavg += E[p * dim];
6118214e71cSJoe         }
61275155f48SMatthew G. Knepley         Eavg /= Npc;
6138214e71cSJoe         xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart));
61475155f48SMatthew G. Knepley         PetscCall(PetscDrawSPAddPoint(user->drawspE, &xval, &Eavg));
61584467f86SMatthew G. Knepley         PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
6168214e71cSJoe       }
61775155f48SMatthew G. Knepley       PetscCall(PetscDrawSPDraw(user->drawspE, PETSC_TRUE));
61875155f48SMatthew G. Knepley       PetscCall(PetscDrawSPGetDraw(user->drawspE, &draw));
61975155f48SMatthew G. Knepley       PetscCall(PetscDrawSave(draw));
6208214e71cSJoe       PetscCall(DMSwarmSortRestoreAccess(sw));
6218214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
6228214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
6238214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
6249072cb8bSMatthew G. Knepley     }
62575155f48SMatthew G. Knepley 
626b02f317dSMatthew G. Knepley     Vec rho, rhohat, phi;
62775155f48SMatthew G. Knepley 
6284a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
62975155f48SMatthew G. Knepley     PetscCall(VecView(rho, user->viewerRho));
6304a0cbf56SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
63175155f48SMatthew G. Knepley 
632b02f317dSMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
633b02f317dSMatthew G. Knepley     PetscCall(MatMult(user->fftPot, rho, rhohat));
634b02f317dSMatthew G. Knepley     PetscCall(VecView(rhohat, user->viewerRhoHat));
635b02f317dSMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
636b02f317dSMatthew G. Knepley 
6374a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
63875155f48SMatthew G. Knepley     PetscCall(VecView(phi, user->viewerPhi));
6394a0cbf56SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
6408214e71cSJoe   }
6418214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
6428214e71cSJoe }
6438214e71cSJoe 
6448214e71cSJoe static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx)
6458214e71cSJoe {
6468214e71cSJoe   PetscBag   bag;
6478214e71cSJoe   Parameter *p;
6488214e71cSJoe 
6498214e71cSJoe   PetscFunctionBeginUser;
6508214e71cSJoe   /* setup PETSc parameter bag */
6518214e71cSJoe   PetscCall(PetscBagGetData(ctx->bag, (void **)&p));
6528214e71cSJoe   PetscCall(PetscBagSetName(ctx->bag, "par", "Vlasov-Poisson Parameters"));
6538214e71cSJoe   bag = ctx->bag;
6548214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "v0", "Velocity scale, m/s"));
6558214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->t0, 1.0, "t0", "Time scale, s"));
6568214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->x0, 1.0, "x0", "Space scale, m"));
6578214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "phi0", "Potential scale, kg*m^2/A*s^3"));
6588214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->q0, 1.0, "q0", "Charge Scale, A*s"));
6598214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->m0, 1.0, "m0", "Mass Scale, kg"));
6608214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->epsi0, 1.0, "epsi0", "Permittivity of Free Space, kg"));
6618214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->kb, 1.0, "kb", "Boltzmann Constant, m^2 kg/s^2 K^1"));
6628214e71cSJoe 
6638214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->sigma, 1.0, "sigma", "Charge per unit area, C/m^3"));
6648214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->poissonNumber, 1.0, "poissonNumber", "Non-Dimensional Poisson Number"));
6658214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->vlasovNumber, 1.0, "vlasovNumber", "Non-Dimensional Vlasov Number"));
6668214e71cSJoe   PetscCall(PetscBagSetFromOptions(bag));
6678214e71cSJoe   {
6688214e71cSJoe     PetscViewer       viewer;
6698214e71cSJoe     PetscViewerFormat format;
6708214e71cSJoe     PetscBool         flg;
6718214e71cSJoe 
672648c30bcSBarry Smith     PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg));
6738214e71cSJoe     if (flg) {
6748214e71cSJoe       PetscCall(PetscViewerPushFormat(viewer, format));
6758214e71cSJoe       PetscCall(PetscBagView(bag, viewer));
6768214e71cSJoe       PetscCall(PetscViewerFlush(viewer));
6778214e71cSJoe       PetscCall(PetscViewerPopFormat(viewer));
6788214e71cSJoe       PetscCall(PetscViewerDestroy(&viewer));
6798214e71cSJoe     }
6808214e71cSJoe   }
6818214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
6828214e71cSJoe }
6838214e71cSJoe 
6848214e71cSJoe static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
685d71ae5a4SJacob Faibussowitsch {
686b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
6879566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
6889566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
6899566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*dm));
6909072cb8bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*dm, "space"));
6919566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
692f1e6e573SMatthew G. Knepley 
693f1e6e573SMatthew G. Knepley   // Cache the mesh geometry
694f1e6e573SMatthew G. Knepley   DMField         coordField;
695f1e6e573SMatthew G. Knepley   IS              cellIS;
696f1e6e573SMatthew G. Knepley   PetscQuadrature quad;
697f1e6e573SMatthew G. Knepley   PetscReal      *wt, *pt;
698f1e6e573SMatthew G. Knepley   PetscInt        cdim, cStart, cEnd;
699f1e6e573SMatthew G. Knepley 
700f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateField(*dm, &coordField));
701f1e6e573SMatthew G. Knepley   PetscCheck(coordField, comm, PETSC_ERR_USER, "DM must have a coordinate field");
702f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateDim(*dm, &cdim));
703f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd));
704f1e6e573SMatthew G. Knepley   PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cellIS));
705f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
706f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(1, &wt));
707f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(2, &pt));
708f1e6e573SMatthew G. Knepley   wt[0] = 1.;
709f1e6e573SMatthew G. Knepley   pt[0] = -1.;
710f1e6e573SMatthew G. Knepley   pt[1] = -1.;
711f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureSetData(quad, cdim, 1, 1, pt, wt));
712*ac9d17c7SMatthew G. Knepley   PetscCall(DMFieldCreateFEGeom(coordField, cellIS, quad, PETSC_FEGEOM_BASIC, &user->fegeom));
713f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&quad));
714f1e6e573SMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
7153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
716b80bf5b1SJoe Pusztay }
717b80bf5b1SJoe Pusztay 
7188214e71cSJoe 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[])
7198214e71cSJoe {
7208214e71cSJoe   f0[0] = -constants[SIGMA];
7218214e71cSJoe }
7228214e71cSJoe 
723d71ae5a4SJacob 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[])
724d71ae5a4SJacob Faibussowitsch {
725b80bf5b1SJoe Pusztay   PetscInt d;
726ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) f1[d] = u_x[d];
727b80bf5b1SJoe Pusztay }
728b80bf5b1SJoe Pusztay 
7298214e71cSJoe 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[])
730d71ae5a4SJacob Faibussowitsch {
731b80bf5b1SJoe Pusztay   PetscInt d;
732ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) g3[d * dim + d] = 1.0;
733b80bf5b1SJoe Pusztay }
734b80bf5b1SJoe Pusztay 
7358214e71cSJoe static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
736d71ae5a4SJacob Faibussowitsch {
7378214e71cSJoe   *u = 0.0;
7388214e71cSJoe   return PETSC_SUCCESS;
739b80bf5b1SJoe Pusztay }
740b80bf5b1SJoe Pusztay 
741b80bf5b1SJoe Pusztay /*
7428214e71cSJoe    /  I   -grad\ / q \ = /0\
7438214e71cSJoe    \-div    0  / \phi/   \f/
744b80bf5b1SJoe Pusztay */
7458214e71cSJoe 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[])
746d71ae5a4SJacob Faibussowitsch {
7478214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[d] += u[uOff[0] + d];
7488214e71cSJoe }
7498214e71cSJoe 
7508214e71cSJoe 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[])
7518214e71cSJoe {
7528214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f1[d * dim + d] = u[uOff[1]];
7538214e71cSJoe }
7548214e71cSJoe 
7558214e71cSJoe 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[])
7568214e71cSJoe {
7578214e71cSJoe   f0[0] += constants[SIGMA];
7588214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[0] += u_x[uOff_x[0] + d * dim + d];
7598214e71cSJoe }
7608214e71cSJoe 
7618214e71cSJoe /* Boundary residual. Dirichlet boundary for u means u_bdy=p*n */
7628214e71cSJoe 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[])
7638214e71cSJoe {
7648214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g0[d * dim + d] = 1.0;
7658214e71cSJoe }
7668214e71cSJoe 
7678214e71cSJoe 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[])
7688214e71cSJoe {
7698214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g2[d * dim + d] = 1.0;
7708214e71cSJoe }
7718214e71cSJoe 
7728214e71cSJoe 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[])
7738214e71cSJoe {
7748214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g1[d * dim + d] = 1.0;
7758214e71cSJoe }
7768214e71cSJoe 
7778214e71cSJoe static PetscErrorCode CreateFEM(DM dm, AppCtx *user)
7788214e71cSJoe {
7798214e71cSJoe   PetscFE   fephi, feq;
7808214e71cSJoe   PetscDS   ds;
7818214e71cSJoe   PetscBool simplex;
7828214e71cSJoe   PetscInt  dim;
7838214e71cSJoe 
7848214e71cSJoe   PetscFunctionBeginUser;
7858214e71cSJoe   PetscCall(DMGetDimension(dm, &dim));
7868214e71cSJoe   PetscCall(DMPlexIsSimplex(dm, &simplex));
7878214e71cSJoe   if (user->em == EM_MIXED) {
7888214e71cSJoe     DMLabel        label;
7898214e71cSJoe     const PetscInt id = 1;
7908214e71cSJoe 
7918214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "field_", PETSC_DETERMINE, &feq));
7928214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)feq, "field"));
7938214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "potential_", PETSC_DETERMINE, &fephi));
7948214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
7958214e71cSJoe     PetscCall(PetscFECopyQuadrature(feq, fephi));
7968214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)feq));
7978214e71cSJoe     PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fephi));
7988214e71cSJoe     PetscCall(DMCreateDS(dm));
7998214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
8008214e71cSJoe     PetscCall(PetscFEDestroy(&feq));
8018214e71cSJoe 
8028214e71cSJoe     PetscCall(DMGetLabel(dm, "marker", &label));
8038214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
8048214e71cSJoe 
8058214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, f0_q, f1_q));
8068214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 1, f0_phi_backgroundCharge, NULL));
8078214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_qq, NULL, NULL, NULL));
8088214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_qphi, NULL));
8098214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_phiq, NULL, NULL));
8108214e71cSJoe 
8118214e71cSJoe     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void))zero, NULL, NULL, NULL));
8128214e71cSJoe 
813f1e6e573SMatthew G. Knepley   } else {
8148214e71cSJoe     MatNullSpace nullsp;
8158214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, PETSC_DETERMINE, &fephi));
8168214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
8178214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fephi));
8188214e71cSJoe     PetscCall(DMCreateDS(dm));
8198214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
8208214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, ion_f0, laplacian_f1));
8218214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, laplacian_g3));
8228214e71cSJoe     PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullsp));
8238214e71cSJoe     PetscCall(PetscObjectCompose((PetscObject)fephi, "nullspace", (PetscObject)nullsp));
8248214e71cSJoe     PetscCall(MatNullSpaceDestroy(&nullsp));
8258214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
8268214e71cSJoe   }
8278214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
8288214e71cSJoe }
8298214e71cSJoe 
8308214e71cSJoe static PetscErrorCode CreatePoisson(DM dm, AppCtx *user)
8318214e71cSJoe {
8328214e71cSJoe   SNES         snes;
8338214e71cSJoe   Mat          J;
8348214e71cSJoe   MatNullSpace nullSpace;
8358214e71cSJoe 
8368214e71cSJoe   PetscFunctionBeginUser;
8378214e71cSJoe   PetscCall(CreateFEM(dm, user));
8388214e71cSJoe   PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes));
8398214e71cSJoe   PetscCall(SNESSetOptionsPrefix(snes, "em_"));
8408214e71cSJoe   PetscCall(SNESSetDM(snes, dm));
8418214e71cSJoe   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, user));
8428214e71cSJoe   PetscCall(SNESSetFromOptions(snes));
8438214e71cSJoe 
8448214e71cSJoe   PetscCall(DMCreateMatrix(dm, &J));
8458214e71cSJoe   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullSpace));
8468214e71cSJoe   PetscCall(MatSetNullSpace(J, nullSpace));
8478214e71cSJoe   PetscCall(MatNullSpaceDestroy(&nullSpace));
8488214e71cSJoe   PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL));
8498214e71cSJoe   PetscCall(MatDestroy(&J));
8504a0cbf56SMatthew G. Knepley   if (user->em == EM_MIXED) {
8514a0cbf56SMatthew G. Knepley     const PetscInt potential = 1;
8524a0cbf56SMatthew G. Knepley 
8534a0cbf56SMatthew G. Knepley     PetscCall(DMCreateSubDM(dm, 1, &potential, &user->isPot, &user->dmPot));
8544a0cbf56SMatthew G. Knepley   } else {
8554a0cbf56SMatthew G. Knepley     user->dmPot = dm;
8564a0cbf56SMatthew G. Knepley     PetscCall(PetscObjectReference((PetscObject)user->dmPot));
8574a0cbf56SMatthew G. Knepley   }
8584a0cbf56SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(user->dmPot, user->dmPot, &user->M));
859f1e6e573SMatthew G. Knepley   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
8608214e71cSJoe   user->snes = snes;
8618214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
8628214e71cSJoe }
8638214e71cSJoe 
8648214e71cSJoe PetscErrorCode PetscPDFPertubedConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
8658214e71cSJoe {
8668214e71cSJoe   p[0] = (1 + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
8678214e71cSJoe   p[1] = (1 + 0.01 * PetscCosReal(0.5 * x[1])) / (2 * PETSC_PI);
8688214e71cSJoe   return PETSC_SUCCESS;
8698214e71cSJoe }
8708214e71cSJoe PetscErrorCode PetscPDFPertubedConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
8718214e71cSJoe {
8728214e71cSJoe   p[0] = (1. + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
8738214e71cSJoe   return PETSC_SUCCESS;
8748214e71cSJoe }
8758214e71cSJoe 
8768214e71cSJoe PetscErrorCode PetscPDFCosine1D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
8778214e71cSJoe {
8788214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.0;
8798214e71cSJoe   const PetscReal k     = scale ? scale[1] : 1.;
8808214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * x[0]));
8818214e71cSJoe   return PETSC_SUCCESS;
8828214e71cSJoe }
8838214e71cSJoe 
8848214e71cSJoe PetscErrorCode PetscPDFCosine2D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
8858214e71cSJoe {
8868214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.;
8878214e71cSJoe   const PetscReal k     = scale ? scale[0] : 1.;
8888214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * (x[0] + x[1])));
8898214e71cSJoe   return PETSC_SUCCESS;
8908214e71cSJoe }
8918214e71cSJoe 
89284467f86SMatthew G. Knepley static PetscErrorCode CreateVelocityDM(DM sw, DM *vdm)
8938214e71cSJoe {
894f1e6e573SMatthew G. Knepley   PetscFE        fe;
895f1e6e573SMatthew G. Knepley   DMPolytopeType ct;
896f1e6e573SMatthew G. Knepley   PetscInt       dim, cStart;
897f1e6e573SMatthew G. Knepley   const char    *prefix = "v";
898f1e6e573SMatthew G. Knepley 
89984467f86SMatthew G. Knepley   PetscFunctionBegin;
90084467f86SMatthew G. Knepley   PetscCall(DMCreate(PETSC_COMM_SELF, vdm));
90184467f86SMatthew G. Knepley   PetscCall(DMSetType(*vdm, DMPLEX));
902f1e6e573SMatthew G. Knepley   PetscCall(DMPlexSetOptionsPrefix(*vdm, prefix));
90384467f86SMatthew G. Knepley   PetscCall(DMSetFromOptions(*vdm));
9049072cb8bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*vdm, "velocity"));
90584467f86SMatthew G. Knepley   PetscCall(DMViewFromOptions(*vdm, NULL, "-dm_view"));
906f1e6e573SMatthew G. Knepley 
907f1e6e573SMatthew G. Knepley   PetscCall(DMGetDimension(*vdm, &dim));
908f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*vdm, 0, &cStart, NULL));
909f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetCellType(*vdm, cStart, &ct));
910f1e6e573SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe));
911f1e6e573SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "distribution"));
912f1e6e573SMatthew G. Knepley   PetscCall(DMSetField(*vdm, 0, NULL, (PetscObject)fe));
913f1e6e573SMatthew G. Knepley   PetscCall(DMCreateDS(*vdm));
914f1e6e573SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
91584467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
9168214e71cSJoe }
9178214e71cSJoe 
9189072cb8bSMatthew G. Knepley /*
9199072cb8bSMatthew G. Knepley   InitializeParticles_Centroid - Initialize a regular grid of particles.
9209072cb8bSMatthew G. Knepley 
9219072cb8bSMatthew G. Knepley   Input Parameters:
9229072cb8bSMatthew G. Knepley + sw      - The `DMSWARM`
9239072cb8bSMatthew G. Knepley - force1D - Treat the spatial domain as 1D
9249072cb8bSMatthew G. Knepley 
9259072cb8bSMatthew G. Knepley   Notes:
9269072cb8bSMatthew G. Knepley   This functions sets the species, cellid, spatial coordinate, and velocity fields for all particles.
9279072cb8bSMatthew G. Knepley 
9289072cb8bSMatthew G. Knepley   It places one particle in the centroid of each cell in the implicit tensor product of the spatial
9299072cb8bSMatthew G. Knepley   and velocity meshes.
9309072cb8bSMatthew G. Knepley */
931045208b8SMatthew G. Knepley static PetscErrorCode InitializeParticles_Centroid(DM sw)
9328214e71cSJoe {
93384467f86SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
9349072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
93584467f86SMatthew G. Knepley   DM            xdm, vdm;
93684467f86SMatthew G. Knepley   PetscReal     vmin[3], vmax[3];
93784467f86SMatthew G. Knepley   PetscReal    *x, *v;
93884467f86SMatthew G. Knepley   PetscInt     *species, *cellid;
93984467f86SMatthew G. Knepley   PetscInt      dim, xcStart, xcEnd, vcStart, vcEnd, Ns, Np, Npc, debug;
9408214e71cSJoe   PetscBool     flg;
94184467f86SMatthew G. Knepley   MPI_Comm      comm;
9429072cb8bSMatthew G. Knepley   const char   *cellidname;
9438214e71cSJoe 
9448214e71cSJoe   PetscFunctionBegin;
94584467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
94684467f86SMatthew G. Knepley 
94784467f86SMatthew G. Knepley   PetscOptionsBegin(comm, "", "DMSwarm Options", "DMSWARM");
9488214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
9498214e71cSJoe   PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg));
9508214e71cSJoe   if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns));
95184467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_coords", "Debug output level for particle coordinate computations", "InitializeParticles", 0, &swarm->printCoords, NULL, 0));
95284467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_weights", "Debug output level for particle weight computations", "InitializeWeights", 0, &swarm->printWeights, NULL, 0));
9538214e71cSJoe   PetscOptionsEnd();
95484467f86SMatthew G. Knepley   debug = swarm->printCoords;
9558214e71cSJoe 
9568214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
95784467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
95884467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
9598214e71cSJoe 
960045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
961045208b8SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
96284467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
9638214e71cSJoe 
96484467f86SMatthew G. Knepley   // One particle per centroid on the tensor product grid
96584467f86SMatthew G. Knepley   Npc = (vcEnd - vcStart) * Ns;
96684467f86SMatthew G. Knepley   Np  = (xcEnd - xcStart) * Npc;
9678214e71cSJoe   PetscCall(DMSwarmSetLocalSizes(sw, Np, 0));
96884467f86SMatthew G. Knepley   if (debug) {
96984467f86SMatthew G. Knepley     PetscInt gNp;
97084467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Np, &gNp, 1, MPIU_INT, MPIU_SUM, comm));
97184467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global Np = %" PetscInt_FMT "\n", gNp));
9728214e71cSJoe   }
9738214e71cSJoe 
97484467f86SMatthew G. Knepley   // Set species and cellid
9759072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
9769072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCellID(celldm, &cellidname));
97784467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
9789072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, cellidname, NULL, NULL, (void **)&cellid));
97984467f86SMatthew G. Knepley   for (PetscInt c = 0, p = 0; c < xcEnd - xcStart; ++c) {
98084467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
98184467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q, ++p) {
98284467f86SMatthew G. Knepley         species[p] = s;
98384467f86SMatthew G. Knepley         cellid[p]  = c;
98484467f86SMatthew G. Knepley       }
98584467f86SMatthew G. Knepley     }
98684467f86SMatthew G. Knepley   }
98784467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
9889072cb8bSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, cellidname, NULL, NULL, (void **)&cellid));
98984467f86SMatthew G. Knepley 
99084467f86SMatthew G. Knepley   // Set particle coordinates
9918214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
9928214e71cSJoe   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
9938214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
99484467f86SMatthew G. Knepley   PetscCall(DMGetBoundingBox(vdm, vmin, vmax));
99584467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(xdm));
99684467f86SMatthew G. Knepley   for (PetscInt c = 0; c < xcEnd - xcStart; ++c) {
99784467f86SMatthew G. Knepley     const PetscInt cell = c + xcStart;
9988214e71cSJoe     PetscInt      *pidx, Npc;
9998214e71cSJoe     PetscReal      centroid[3], volume;
10008214e71cSJoe 
10018214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
100284467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFVM(xdm, cell, &volume, centroid, NULL));
100384467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
100484467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q) {
100584467f86SMatthew G. Knepley         const PetscInt p = pidx[q * Ns + s];
10068214e71cSJoe 
100784467f86SMatthew G. Knepley         for (PetscInt d = 0; d < dim; ++d) {
10088214e71cSJoe           x[p * dim + d] = centroid[d];
100984467f86SMatthew G. Knepley           v[p * dim + d] = vmin[0] + (q + 0.5) * ((vmax[0] - vmin[0]) / (Npc / Ns));
10108214e71cSJoe         }
10119072cb8bSMatthew G. Knepley         if (debug > 1) {
10129072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "Particle %4" PetscInt_FMT " ", p));
10139072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  x: ("));
10149072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
10159072cb8bSMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
10169072cb8bSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", x[p * dim + d]));
10179072cb8bSMatthew G. Knepley           }
10189072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ") v:("));
10199072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
10209072cb8bSMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
10219072cb8bSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", v[p * dim + d]));
10229072cb8bSMatthew G. Knepley           }
10239072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
10249072cb8bSMatthew G. Knepley         }
10258214e71cSJoe       }
10268214e71cSJoe     }
102784467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
10288214e71cSJoe   }
10298214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
10308214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
10318214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
103284467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
103384467f86SMatthew G. Knepley }
103484467f86SMatthew G. Knepley 
103584467f86SMatthew G. Knepley /*
103684467f86SMatthew G. Knepley   InitializeWeights - Compute weight for each local particle
103784467f86SMatthew G. Knepley 
103884467f86SMatthew G. Knepley   Input Parameters:
103984467f86SMatthew G. Knepley + sw          - The `DMSwarm`
104084467f86SMatthew G. Knepley . totalWeight - The sum of all particle weights
104184467f86SMatthew G. Knepley . func        - The PDF for the particle spatial distribution
104284467f86SMatthew G. Knepley - param       - The PDF parameters
104384467f86SMatthew G. Knepley 
104484467f86SMatthew G. Knepley   Notes:
104584467f86SMatthew G. Knepley   The PDF for velocity is assumed to be a Gaussian
104684467f86SMatthew G. Knepley 
104784467f86SMatthew G. Knepley   The particle weights are returned in the `w_q` field of `sw`.
104884467f86SMatthew G. Knepley */
1049045208b8SMatthew G. Knepley static PetscErrorCode InitializeWeights(DM sw, PetscReal totalWeight, PetscProbFunc func, const PetscReal param[])
105084467f86SMatthew G. Knepley {
105184467f86SMatthew G. Knepley   DM               xdm, vdm;
1052045208b8SMatthew G. Knepley   DMSwarmCellDM    celldm;
105384467f86SMatthew G. Knepley   PetscScalar     *weight;
105484467f86SMatthew G. Knepley   PetscQuadrature  xquad;
105584467f86SMatthew G. Knepley   const PetscReal *xq, *xwq;
105684467f86SMatthew G. Knepley   const PetscInt   order = 5;
1057045208b8SMatthew G. Knepley   PetscReal        xi0[3];
105884467f86SMatthew G. Knepley   PetscReal        xwtot = 0., pwtot = 0.;
105984467f86SMatthew G. Knepley   PetscInt         xNq;
106084467f86SMatthew G. Knepley   PetscInt         dim, Ns, xcStart, xcEnd, vcStart, vcEnd, debug = ((DM_Swarm *)sw->data)->printWeights;
106184467f86SMatthew G. Knepley   MPI_Comm         comm;
106284467f86SMatthew G. Knepley   PetscMPIInt      rank;
106384467f86SMatthew G. Knepley 
106484467f86SMatthew G. Knepley   PetscFunctionBegin;
106584467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
106684467f86SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
106784467f86SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
106884467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
106984467f86SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
107084467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
1071045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
1072045208b8SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
107384467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
107484467f86SMatthew G. Knepley 
107584467f86SMatthew G. Knepley   // Setup Quadrature for spatial and velocity weight calculations
1076045208b8SMatthew G. Knepley   PetscCall(PetscDTGaussTensorQuadrature(dim, 1, order, -1.0, 1.0, &xquad));
107784467f86SMatthew G. Knepley   PetscCall(PetscQuadratureGetData(xquad, NULL, NULL, &xNq, &xq, &xwq));
107884467f86SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) xi0[d] = -1.0;
107984467f86SMatthew G. Knepley 
108084467f86SMatthew G. Knepley   // Integrate the density function to get the weights of particles in each cell
108184467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(vdm));
108284467f86SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
108384467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
108484467f86SMatthew G. Knepley   for (PetscInt c = xcStart; c < xcEnd; ++c) {
108584467f86SMatthew G. Knepley     PetscReal          xv0[3], xJ[9], xinvJ[9], xdetJ, xqr[3], xden, xw = 0.;
108684467f86SMatthew G. Knepley     PetscInt          *pidx, Npc;
108784467f86SMatthew G. Knepley     PetscInt           xNc;
108884467f86SMatthew G. Knepley     const PetscScalar *xarray;
108984467f86SMatthew G. Knepley     PetscScalar       *xcoords = NULL;
109084467f86SMatthew G. Knepley     PetscBool          xisDG;
109184467f86SMatthew G. Knepley 
109284467f86SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
109384467f86SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
109484467f86SMatthew 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);
109584467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFEM(xdm, c, NULL, xv0, xJ, xinvJ, &xdetJ));
109684467f86SMatthew G. Knepley     for (PetscInt q = 0; q < xNq; ++q) {
109784467f86SMatthew G. Knepley       // Transform quadrature points from ref space to real space
1098045208b8SMatthew G. Knepley       CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xq[q * dim], xqr);
109984467f86SMatthew G. Knepley       // Get probability density at quad point
110084467f86SMatthew G. Knepley       //   No need to scale xqr since PDF will be periodic
110184467f86SMatthew G. Knepley       PetscCall((*func)(xqr, param, &xden));
110284467f86SMatthew G. Knepley       xw += xden * (xwq[q] * xdetJ);
110384467f86SMatthew G. Knepley     }
110484467f86SMatthew G. Knepley     xwtot += xw;
110584467f86SMatthew G. Knepley     if (debug) {
110684467f86SMatthew G. Knepley       IS              globalOrdering;
110784467f86SMatthew G. Knepley       const PetscInt *ordering;
110884467f86SMatthew G. Knepley 
110984467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellNumbering(xdm, &globalOrdering));
111084467f86SMatthew G. Knepley       PetscCall(ISGetIndices(globalOrdering, &ordering));
111175155f48SMatthew 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));
111284467f86SMatthew G. Knepley       PetscCall(ISRestoreIndices(globalOrdering, &ordering));
111384467f86SMatthew G. Knepley     }
111484467f86SMatthew G. Knepley     // Set weights to be Gaussian in velocity cells
111584467f86SMatthew G. Knepley     for (PetscInt vc = vcStart; vc < vcEnd; ++vc) {
111684467f86SMatthew G. Knepley       const PetscInt     p  = pidx[vc * Ns + 0];
111784467f86SMatthew G. Knepley       PetscReal          vw = 0.;
111884467f86SMatthew G. Knepley       PetscInt           vNc;
111984467f86SMatthew G. Knepley       const PetscScalar *varray;
112084467f86SMatthew G. Knepley       PetscScalar       *vcoords = NULL;
112184467f86SMatthew G. Knepley       PetscBool          visDG;
112284467f86SMatthew G. Knepley 
112384467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
112484467f86SMatthew G. Knepley       // TODO: Fix 2 stream Ask Joe
112584467f86SMatthew G. Knepley       //   Two stream function from 1/2pi v^2 e^(-v^2/2)
112684467f86SMatthew 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.)));
112784467f86SMatthew G. Knepley       vw = 0.5 * (PetscErfReal(vcoords[1] / PetscSqrtReal(2.)) - PetscErfReal(vcoords[0] / PetscSqrtReal(2.)));
112884467f86SMatthew G. Knepley 
112984467f86SMatthew G. Knepley       weight[p] = totalWeight * vw * xw;
113084467f86SMatthew G. Knepley       pwtot += weight[p];
11319072cb8bSMatthew G. Knepley       PetscCheck(weight[p] <= 10., PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Particle %" PetscInt_FMT " weight exceeeded 1: %g, %g, %g", p, xw, vw, totalWeight);
113284467f86SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
113384467f86SMatthew G. Knepley       if (debug > 1) PetscCall(PetscPrintf(comm, "particle %" PetscInt_FMT ": %g, vw: %g xw: %g\n", p, weight[p], vw, xw));
113484467f86SMatthew G. Knepley     }
113584467f86SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
113684467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
113784467f86SMatthew G. Knepley   }
113884467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
113984467f86SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
114084467f86SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&xquad));
114184467f86SMatthew G. Knepley 
114284467f86SMatthew G. Knepley   if (debug) {
114384467f86SMatthew G. Knepley     PetscReal wtot[2] = {pwtot, xwtot}, gwtot[2];
114484467f86SMatthew G. Knepley 
114584467f86SMatthew G. Knepley     PetscCall(PetscSynchronizedFlush(comm, NULL));
114684467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(wtot, gwtot, 2, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
114784467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "particle weight sum = %1.10f cell weight sum = %1.10f\n", (double)gwtot[0], (double)gwtot[1]));
114884467f86SMatthew G. Knepley   }
114984467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
115084467f86SMatthew G. Knepley }
115184467f86SMatthew G. Knepley 
115284467f86SMatthew G. Knepley static PetscErrorCode InitializeParticles_PerturbedWeights(DM sw, AppCtx *user)
115384467f86SMatthew G. Knepley {
115484467f86SMatthew G. Knepley   PetscReal scale[2] = {user->cosine_coefficients[0], user->cosine_coefficients[1]};
115575155f48SMatthew G. Knepley   PetscInt  dim;
115684467f86SMatthew G. Knepley 
115784467f86SMatthew G. Knepley   PetscFunctionBegin;
115875155f48SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1159045208b8SMatthew G. Knepley   PetscCall(InitializeParticles_Centroid(sw));
1160045208b8SMatthew G. Knepley   PetscCall(InitializeWeights(sw, user->totalWeight, dim == 1 ? PetscPDFCosine1D : PetscPDFCosine2D, scale));
11618214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
11628214e71cSJoe }
11638214e71cSJoe 
11648214e71cSJoe static PetscErrorCode InitializeConstants(DM sw, AppCtx *user)
11658214e71cSJoe {
11668214e71cSJoe   DM         dm;
11678214e71cSJoe   PetscInt  *species;
11688214e71cSJoe   PetscReal *weight, totalCharge = 0., totalWeight = 0., gmin[3], gmax[3], global_charge, global_weight;
11698214e71cSJoe   PetscInt   Np, dim;
11708214e71cSJoe 
11718214e71cSJoe   PetscFunctionBegin;
11728214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &dm));
11738214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
11748214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
11758214e71cSJoe   PetscCall(DMGetBoundingBox(dm, gmin, gmax));
11768214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
11778214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
11788214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
11798214e71cSJoe     totalWeight += weight[p];
11808214e71cSJoe     totalCharge += user->charges[species[p]] * weight[p];
11818214e71cSJoe   }
11828214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
11838214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
11848214e71cSJoe   {
11858214e71cSJoe     Parameter *param;
11868214e71cSJoe     PetscReal  Area;
11878214e71cSJoe 
11888214e71cSJoe     PetscCall(PetscBagGetData(user->bag, (void **)&param));
11898214e71cSJoe     switch (dim) {
11908214e71cSJoe     case 1:
11918214e71cSJoe       Area = (gmax[0] - gmin[0]);
11928214e71cSJoe       break;
11938214e71cSJoe     case 2:
11948214e71cSJoe       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]);
11958214e71cSJoe       break;
11968214e71cSJoe     case 3:
11978214e71cSJoe       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]) * (gmax[2] - gmin[2]);
11988214e71cSJoe       break;
11998214e71cSJoe     default:
12008214e71cSJoe       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", dim);
12018214e71cSJoe     }
1202462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalWeight, &global_weight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
1203462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalCharge, &global_charge, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
12048214e71cSJoe     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "dim = %" PetscInt_FMT "\ttotalWeight = %f, user->charges[species[0]] = %f\ttotalCharge = %f, Total Area = %f\n", dim, (double)global_weight, (double)user->charges[0], (double)global_charge, (double)Area));
12058214e71cSJoe     param->sigma = PetscAbsReal(global_charge / (Area));
12068214e71cSJoe 
12078214e71cSJoe     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "sigma: %g\n", (double)param->sigma));
12088214e71cSJoe     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,
12098214e71cSJoe                           (double)param->vlasovNumber));
12108214e71cSJoe   }
12118214e71cSJoe   /* Setup Constants */
12128214e71cSJoe   {
12138214e71cSJoe     PetscDS    ds;
12148214e71cSJoe     Parameter *param;
12158214e71cSJoe     PetscCall(PetscBagGetData(user->bag, (void **)&param));
12168214e71cSJoe     PetscScalar constants[NUM_CONSTANTS];
12178214e71cSJoe     constants[SIGMA]   = param->sigma;
12188214e71cSJoe     constants[V0]      = param->v0;
12198214e71cSJoe     constants[T0]      = param->t0;
12208214e71cSJoe     constants[X0]      = param->x0;
12218214e71cSJoe     constants[M0]      = param->m0;
12228214e71cSJoe     constants[Q0]      = param->q0;
12238214e71cSJoe     constants[PHI0]    = param->phi0;
12248214e71cSJoe     constants[POISSON] = param->poissonNumber;
12258214e71cSJoe     constants[VLASOV]  = param->vlasovNumber;
12268214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
12278214e71cSJoe     PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants));
12288214e71cSJoe   }
12298214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
12308214e71cSJoe }
12318214e71cSJoe 
12328214e71cSJoe static PetscErrorCode CreateSwarm(DM dm, AppCtx *user, DM *sw)
12338214e71cSJoe {
12349072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
12359072cb8bSMatthew G. Knepley   DM            vdm;
12368214e71cSJoe   PetscReal     v0[2] = {1., 0.};
12378214e71cSJoe   PetscInt      dim;
1238b80bf5b1SJoe Pusztay 
1239b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
12409566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
12419566063dSJacob Faibussowitsch   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw));
12429566063dSJacob Faibussowitsch   PetscCall(DMSetType(*sw, DMSWARM));
12439566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*sw, dim));
12449566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC));
1245045208b8SMatthew G. Knepley   PetscCall(DMSetApplicationContext(*sw, user));
12469072cb8bSMatthew G. Knepley 
12479566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR));
12488214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL));
12498214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "species", 1, PETSC_INT));
12508214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "E_field", dim, PETSC_REAL));
12519072cb8bSMatthew G. Knepley 
12529072cb8bSMatthew G. Knepley   const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"};
12539072cb8bSMatthew G. Knepley 
12549072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(dm, 2, fieldnames, 1, fieldnames, &celldm));
12559072cb8bSMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
12569072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
12579072cb8bSMatthew G. Knepley 
12589072cb8bSMatthew G. Knepley   const char *vfieldnames[1] = {"w_q"};
12599072cb8bSMatthew G. Knepley 
12609072cb8bSMatthew G. Knepley   PetscCall(CreateVelocityDM(*sw, &vdm));
12619072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(vdm, 1, vfieldnames, 1, &fieldnames[1], &celldm));
12629072cb8bSMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
12639072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
12649072cb8bSMatthew G. Knepley   PetscCall(DMDestroy(&vdm));
12659072cb8bSMatthew G. Knepley 
12664a0cbf56SMatthew G. Knepley   DM mdm;
12674a0cbf56SMatthew G. Knepley 
12684a0cbf56SMatthew G. Knepley   PetscCall(DMClone(dm, &mdm));
12694a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)mdm, "moments"));
12704a0cbf56SMatthew G. Knepley   PetscCall(DMCopyDisc(dm, mdm));
12714a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(mdm, 1, vfieldnames, 1, fieldnames, &celldm));
12724a0cbf56SMatthew G. Knepley   PetscCall(DMDestroy(&mdm));
12734a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
12744a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
12754a0cbf56SMatthew G. Knepley 
12769566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*sw));
1277045208b8SMatthew G. Knepley   PetscCall(DMSetUp(*sw));
1278045208b8SMatthew G. Knepley 
12799072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(*sw, "space"));
12808214e71cSJoe   user->swarm = *sw;
1281045208b8SMatthew G. Knepley   // TODO: This is redundant init since it is done in InitializeSolveAndSwarm, however DMSetUp() requires the local size be set
12828214e71cSJoe   if (user->perturbed_weights) {
12838214e71cSJoe     PetscCall(InitializeParticles_PerturbedWeights(*sw, user));
1284b80bf5b1SJoe Pusztay   } else {
12858214e71cSJoe     PetscCall(DMSwarmComputeLocalSizeFromOptions(*sw));
12868214e71cSJoe     PetscCall(DMSwarmInitializeCoordinates(*sw));
12878214e71cSJoe     PetscCall(DMSwarmInitializeVelocitiesFromOptions(*sw, v0));
1288b80bf5b1SJoe Pusztay   }
12899566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles"));
12909566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view"));
12913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1292b80bf5b1SJoe Pusztay }
1293b80bf5b1SJoe Pusztay 
12948214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Coulomb(SNES snes, DM sw, PetscReal E[])
1295d71ae5a4SJacob Faibussowitsch {
12968214e71cSJoe   AppCtx     *user;
12978214e71cSJoe   PetscReal  *coords;
12988214e71cSJoe   PetscInt   *species, dim, Np, Ns;
12998214e71cSJoe   PetscMPIInt size;
13008214e71cSJoe 
13018214e71cSJoe   PetscFunctionBegin;
13028214e71cSJoe   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)snes), &size));
13038214e71cSJoe   PetscCheck(size == 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Coulomb code only works in serial");
13048214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
13058214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
13068214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
13078214e71cSJoe   PetscCall(DMGetApplicationContext(sw, (void *)&user));
13088214e71cSJoe 
13098214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
13108214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
13118214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
13128214e71cSJoe     PetscReal *pcoord = &coords[p * dim];
13138214e71cSJoe     PetscReal  pE[3]  = {0., 0., 0.};
13148214e71cSJoe 
13158214e71cSJoe     /* Calculate field at particle p due to particle q */
13168214e71cSJoe     for (PetscInt q = 0; q < Np; ++q) {
13178214e71cSJoe       PetscReal *qcoord = &coords[q * dim];
13188214e71cSJoe       PetscReal  rpq[3], r, r3, q_q;
13198214e71cSJoe 
13208214e71cSJoe       if (p == q) continue;
13218214e71cSJoe       q_q = user->charges[species[q]] * 1.;
13228214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) rpq[d] = pcoord[d] - qcoord[d];
13238214e71cSJoe       r = DMPlex_NormD_Internal(dim, rpq);
13248214e71cSJoe       if (r < PETSC_SQRT_MACHINE_EPSILON) continue;
13258214e71cSJoe       r3 = PetscPowRealInt(r, 3);
13268214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pE[d] += q_q * rpq[d] / r3;
13278214e71cSJoe     }
13288214e71cSJoe     for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = pE[d];
13298214e71cSJoe   }
13308214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
13318214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
13328214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
13338214e71cSJoe }
13348214e71cSJoe 
13354a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Primal(SNES snes, DM sw, Mat M_p, PetscReal E[])
13368214e71cSJoe {
1337b80bf5b1SJoe Pusztay   DM         dm;
13388214e71cSJoe   AppCtx    *user;
13398214e71cSJoe   PetscDS    ds;
13408214e71cSJoe   PetscFE    fe;
13414a0cbf56SMatthew G. Knepley   KSP        ksp;
134275155f48SMatthew G. Knepley   Vec        rhoRhs;      // Weak charge density, \int phi_i rho
134375155f48SMatthew G. Knepley   Vec        rho;         // Charge density, M^{-1} rhoRhs
134475155f48SMatthew G. Knepley   Vec        phi, locPhi; // Potential
134575155f48SMatthew G. Knepley   Vec        f;           // Particle weights
13468214e71cSJoe   PetscReal *coords;
13478214e71cSJoe   PetscInt   dim, cStart, cEnd, Np;
13488214e71cSJoe 
13498214e71cSJoe   PetscFunctionBegin;
135084467f86SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, (void *)&user));
135184467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
13528214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
13538214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
13548214e71cSJoe 
13558214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
135675155f48SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhs));
135775155f48SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
13584a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
13598214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
13608214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
136175155f48SMatthew G. Knepley 
13628214e71cSJoe   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
1363f1e6e573SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->M, NULL, "-m_view"));
13648214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
136575155f48SMatthew G. Knepley 
136675155f48SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
13678214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
13688214e71cSJoe 
13698214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
13708214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj_"));
1371f1e6e573SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->M, user->M));
13728214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
137375155f48SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
13748214e71cSJoe 
137575155f48SMatthew G. Knepley   PetscCall(VecScale(rhoRhs, -1.0));
13768214e71cSJoe 
137775155f48SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
13784a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
13798214e71cSJoe   PetscCall(KSPDestroy(&ksp));
13808214e71cSJoe 
13814a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
13828214e71cSJoe   PetscCall(VecSet(phi, 0.0));
138375155f48SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhs, phi));
138475155f48SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhs));
13858214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
13868214e71cSJoe 
13878214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
13888214e71cSJoe   PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi));
13898214e71cSJoe   PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi));
13904a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
139184467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
13928214e71cSJoe 
13938214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
13948214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
13958214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
13968214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
13978214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
13988214e71cSJoe 
139984467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
14008214e71cSJoe   PetscTabulation tab;
14018214e71cSJoe   PetscReal      *pcoord, *refcoord;
1402045208b8SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
1403045208b8SMatthew G. Knepley   PetscInt        maxNcp    = 0;
1404045208b8SMatthew G. Knepley 
1405045208b8SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1406045208b8SMatthew G. Knepley     PetscInt Ncp;
1407045208b8SMatthew G. Knepley 
1408045208b8SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
1409045208b8SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
1410045208b8SMatthew G. Knepley   }
1411045208b8SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1412045208b8SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1413045208b8SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
1414045208b8SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1415045208b8SMatthew G. Knepley     PetscScalar *clPhi = NULL;
14168214e71cSJoe     PetscInt    *points;
14178214e71cSJoe     PetscInt     Ncp;
14188214e71cSJoe 
14198214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
14208214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
14218214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1422f1e6e573SMatthew G. Knepley     {
1423f1e6e573SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1424f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1425f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1426f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1427f1e6e573SMatthew G. Knepley       }
1428f1e6e573SMatthew G. Knepley     }
1429045208b8SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
14308214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
14318214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
14328214e71cSJoe       const PetscReal *basisDer = tab->T[1];
14338214e71cSJoe       const PetscInt   p        = points[cp];
14348214e71cSJoe 
14358214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1436f1e6e573SMatthew G. Knepley       PetscCall(PetscFEFreeInterpolateGradient_Static(fe, basisDer, clPhi, dim, chunkgeom->invJ, NULL, cp, &E[p * dim]));
1437045208b8SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
14388214e71cSJoe     }
14398214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
144084467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
14418214e71cSJoe   }
1442045208b8SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1443045208b8SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1444045208b8SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
14458214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
14468214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
14478214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1448f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
144984467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
14508214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
14518214e71cSJoe }
14528214e71cSJoe 
14534a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Mixed(SNES snes, DM sw, Mat M_p, PetscReal E[])
14548214e71cSJoe {
14554a0cbf56SMatthew G. Knepley   DM         dm;
14568214e71cSJoe   AppCtx    *user;
14578214e71cSJoe   PetscDS    ds;
14588214e71cSJoe   PetscFE    fe;
14594a0cbf56SMatthew G. Knepley   KSP        ksp;
14604a0cbf56SMatthew G. Knepley   Vec        rhoRhs, rhoRhsFull;   // Weak charge density, \int phi_i rho, and embedding in mixed problem
14614a0cbf56SMatthew G. Knepley   Vec        rho;                  // Charge density, M^{-1} rhoRhs
14624a0cbf56SMatthew G. Knepley   Vec        phi, locPhi, phiFull; // Potential and embedding in mixed problem
14634a0cbf56SMatthew G. Knepley   Vec        f;                    // Particle weights
146475155f48SMatthew G. Knepley   PetscReal *coords;
14654a0cbf56SMatthew G. Knepley   PetscInt   dim, cStart, cEnd, Np;
14668214e71cSJoe 
14678214e71cSJoe   PetscFunctionBegin;
146884467f86SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &user));
146984467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
14708214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
14718214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
14728214e71cSJoe 
14738214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
14744a0cbf56SMatthew G. Knepley   PetscCall(DMGetGlobalVector(user->dmPot, &rhoRhs));
14754a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
14764a0cbf56SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhsFull));
14774a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhsFull, "Weak charge density"));
14784a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
14798214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
14808214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
14814a0cbf56SMatthew G. Knepley 
14824a0cbf56SMatthew G. Knepley   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
14834a0cbf56SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->M, NULL, "-m_view"));
14848214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
14854a0cbf56SMatthew G. Knepley 
14864a0cbf56SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
14878214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
14888214e71cSJoe 
14898214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
14908214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj"));
14914a0cbf56SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->M, user->M));
14928214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
14934a0cbf56SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
14948214e71cSJoe 
14954a0cbf56SMatthew G. Knepley   PetscCall(VecISCopy(rhoRhsFull, user->isPot, SCATTER_FORWARD, rhoRhs));
14964a0cbf56SMatthew G. Knepley   //PetscCall(VecScale(rhoRhsFull, -1.0));
14978214e71cSJoe 
14984a0cbf56SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
14994a0cbf56SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhsFull, NULL, "-rho_full_view"));
15004a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
15014a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(user->dmPot, &rhoRhs));
15028214e71cSJoe   PetscCall(KSPDestroy(&ksp));
15038214e71cSJoe 
15044a0cbf56SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &phiFull));
15054a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
15064a0cbf56SMatthew G. Knepley   PetscCall(VecSet(phiFull, 0.0));
15074a0cbf56SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhsFull, phiFull));
15084a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhsFull));
15098214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
15108214e71cSJoe 
15114a0cbf56SMatthew G. Knepley   PetscCall(VecISCopy(phiFull, user->isPot, SCATTER_REVERSE, phi));
15124a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
15134a0cbf56SMatthew G. Knepley 
15148214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
15154a0cbf56SMatthew G. Knepley   PetscCall(DMGlobalToLocalBegin(dm, phiFull, INSERT_VALUES, locPhi));
15164a0cbf56SMatthew G. Knepley   PetscCall(DMGlobalToLocalEnd(dm, phiFull, INSERT_VALUES, locPhi));
15174a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &phiFull));
151884467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
15198214e71cSJoe 
15208214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
15218214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
15228214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
15238214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
15248214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
15254a0cbf56SMatthew G. Knepley 
15264a0cbf56SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
15278214e71cSJoe   PetscTabulation tab;
15288214e71cSJoe   PetscReal      *pcoord, *refcoord;
15294a0cbf56SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
15304a0cbf56SMatthew G. Knepley   PetscInt        maxNcp    = 0;
15314a0cbf56SMatthew G. Knepley 
15324a0cbf56SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
15334a0cbf56SMatthew G. Knepley     PetscInt Ncp;
15344a0cbf56SMatthew G. Knepley 
15354a0cbf56SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
15364a0cbf56SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
15374a0cbf56SMatthew G. Knepley   }
15384a0cbf56SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
15394a0cbf56SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
15404a0cbf56SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
15414a0cbf56SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
15424a0cbf56SMatthew G. Knepley     PetscScalar *clPhi = NULL;
15438214e71cSJoe     PetscInt    *points;
15448214e71cSJoe     PetscInt     Ncp;
15458214e71cSJoe 
15468214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
15478214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
15488214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1549f1e6e573SMatthew G. Knepley     {
1550f1e6e573SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1551f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1552f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1553f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1554f1e6e573SMatthew G. Knepley       }
1555f1e6e573SMatthew G. Knepley     }
15564a0cbf56SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
15578214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
15588214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
15598214e71cSJoe       const PetscInt p = points[cp];
15608214e71cSJoe 
15618214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1562f1e6e573SMatthew G. Knepley       PetscCall(PetscFEInterpolateAtPoints_Static(fe, tab, clPhi, chunkgeom, cp, &E[p * dim]));
1563f1e6e573SMatthew G. Knepley       PetscCall(PetscFEPushforward(fe, chunkgeom, 1, &E[p * dim]));
15644a0cbf56SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
15658214e71cSJoe     }
15668214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
156784467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
15688214e71cSJoe   }
15694a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
15704a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
15714a0cbf56SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
15728214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
15738214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
15748214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1575f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
157684467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
15778214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
15788214e71cSJoe }
15798214e71cSJoe 
15804a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles(SNES snes, DM sw)
15818214e71cSJoe {
15824a0cbf56SMatthew G. Knepley   AppCtx    *user;
15834a0cbf56SMatthew G. Knepley   Mat        M_p;
15844a0cbf56SMatthew G. Knepley   PetscReal *E;
15858214e71cSJoe   PetscInt   dim, Np;
15868214e71cSJoe 
15878214e71cSJoe   PetscFunctionBegin;
15888214e71cSJoe   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
15898214e71cSJoe   PetscValidHeaderSpecific(sw, DM_CLASSID, 2);
15908214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
15918214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
15924a0cbf56SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &user));
15938214e71cSJoe 
15944a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "moments"));
15954a0cbf56SMatthew G. Knepley   // TODO: Could share sort context with space cellDM
15964a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmMigrate(sw, PETSC_FALSE));
15974a0cbf56SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(sw, user->dmPot, &M_p));
15984a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
15994a0cbf56SMatthew G. Knepley 
16004a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
16014a0cbf56SMatthew G. Knepley   PetscCall(PetscArrayzero(E, Np * dim));
16024a0cbf56SMatthew G. Knepley   user->validE = PETSC_TRUE;
16034a0cbf56SMatthew G. Knepley 
16044a0cbf56SMatthew G. Knepley   switch (user->em) {
16058214e71cSJoe   case EM_COULOMB:
16068214e71cSJoe     PetscCall(ComputeFieldAtParticles_Coulomb(snes, sw, E));
16078214e71cSJoe     break;
16084a0cbf56SMatthew G. Knepley   case EM_PRIMAL:
16094a0cbf56SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Primal(snes, sw, M_p, E));
16104a0cbf56SMatthew G. Knepley     break;
16118214e71cSJoe   case EM_MIXED:
16124a0cbf56SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Mixed(snes, sw, M_p, E));
16138214e71cSJoe     break;
16148214e71cSJoe   case EM_NONE:
16158214e71cSJoe     break;
16168214e71cSJoe   default:
16174a0cbf56SMatthew G. Knepley     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No solver for electrostatic model %s", EMTypes[user->em]);
16188214e71cSJoe   }
16194a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
16204a0cbf56SMatthew G. Knepley   PetscCall(MatDestroy(&M_p));
16218214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16228214e71cSJoe }
16238214e71cSJoe 
16248214e71cSJoe static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec G, void *ctx)
16258214e71cSJoe {
16268214e71cSJoe   DM                 sw;
16278214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
16288214e71cSJoe   const PetscScalar *u;
16298214e71cSJoe   PetscScalar       *g;
16308214e71cSJoe   PetscReal         *E, m_p = 1., q_p = -1.;
16318214e71cSJoe   PetscInt           dim, d, Np, p;
1632b80bf5b1SJoe Pusztay 
1633b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
16348214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
16354a0cbf56SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
16364a0cbf56SMatthew G. Knepley 
16378214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16388214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
16394a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
16408214e71cSJoe   PetscCall(VecGetArrayRead(U, &u));
16418214e71cSJoe   PetscCall(VecGetArray(G, &g));
16428214e71cSJoe   Np /= 2 * dim;
16438214e71cSJoe   for (p = 0; p < Np; ++p) {
16448214e71cSJoe     for (d = 0; d < dim; ++d) {
16458214e71cSJoe       g[(p * 2 + 0) * dim + d] = u[(p * 2 + 1) * dim + d];
16468214e71cSJoe       g[(p * 2 + 1) * dim + d] = q_p * E[p * dim + d] / m_p;
16478214e71cSJoe     }
16488214e71cSJoe   }
16498214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
16508214e71cSJoe   PetscCall(VecRestoreArrayRead(U, &u));
16518214e71cSJoe   PetscCall(VecRestoreArray(G, &g));
16528214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16538214e71cSJoe }
16548214e71cSJoe 
16558214e71cSJoe /* J_{ij} = dF_i/dx_j
16568214e71cSJoe    J_p = (  0   1)
16578214e71cSJoe          (-w^2  0)
16588214e71cSJoe    TODO Now there is another term with w^2 from the electric field. I think we will need to invert the operator.
16598214e71cSJoe         Perhaps we can approximate the Jacobian using only the cellwise P-P gradient from Coulomb
16608214e71cSJoe */
16618214e71cSJoe static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat P, void *ctx)
16628214e71cSJoe {
16638214e71cSJoe   DM               sw;
16648214e71cSJoe   const PetscReal *coords, *vel;
16658214e71cSJoe   PetscInt         dim, d, Np, p, rStart;
16668214e71cSJoe 
16678214e71cSJoe   PetscFunctionBeginUser;
16688214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
16698214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16708214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
16718214e71cSJoe   PetscCall(MatGetOwnershipRange(J, &rStart, NULL));
1672045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1673045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
16748214e71cSJoe   Np /= 2 * dim;
16758214e71cSJoe   for (p = 0; p < Np; ++p) {
16768214e71cSJoe     const PetscReal x0      = coords[p * dim + 0];
16778214e71cSJoe     const PetscReal vy0     = vel[p * dim + 1];
16788214e71cSJoe     const PetscReal omega   = vy0 / x0;
16798214e71cSJoe     PetscScalar     vals[4] = {0., 1., -PetscSqr(omega), 0.};
16808214e71cSJoe 
16818214e71cSJoe     for (d = 0; d < dim; ++d) {
16828214e71cSJoe       const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart};
16838214e71cSJoe       PetscCall(MatSetValues(J, 2, rows, 2, rows, vals, INSERT_VALUES));
16848214e71cSJoe     }
16858214e71cSJoe   }
1686045208b8SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1687045208b8SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
16888214e71cSJoe   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
16898214e71cSJoe   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
16908214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16918214e71cSJoe }
16928214e71cSJoe 
16938214e71cSJoe static PetscErrorCode RHSFunctionX(TS ts, PetscReal t, Vec V, Vec Xres, void *ctx)
16948214e71cSJoe {
16958214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
16968214e71cSJoe   DM                 sw;
16978214e71cSJoe   const PetscScalar *v;
16988214e71cSJoe   PetscScalar       *xres;
16998214e71cSJoe   PetscInt           Np, p, d, dim;
17008214e71cSJoe 
17018214e71cSJoe   PetscFunctionBeginUser;
170284467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsXEvent, ts, 0, 0, 0));
17038214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
17048214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
17058214e71cSJoe   PetscCall(VecGetLocalSize(Xres, &Np));
17069566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(V, &v));
17078214e71cSJoe   PetscCall(VecGetArray(Xres, &xres));
1708b80bf5b1SJoe Pusztay   Np /= dim;
1709b80bf5b1SJoe Pusztay   for (p = 0; p < Np; ++p) {
1710045208b8SMatthew G. Knepley     for (d = 0; d < dim; ++d) xres[p * dim + d] = v[p * dim + d];
1711b80bf5b1SJoe Pusztay   }
17129566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(V, &v));
17138214e71cSJoe   PetscCall(VecRestoreArray(Xres, &xres));
171484467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsXEvent, ts, 0, 0, 0));
17153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1716b80bf5b1SJoe Pusztay }
1717b80bf5b1SJoe Pusztay 
17188214e71cSJoe static PetscErrorCode RHSFunctionV(TS ts, PetscReal t, Vec X, Vec Vres, void *ctx)
17198214e71cSJoe {
17208214e71cSJoe   DM                 sw;
17218214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
17228214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
17238214e71cSJoe   const PetscScalar *x;
17248214e71cSJoe   PetscScalar       *vres;
17254a0cbf56SMatthew G. Knepley   PetscReal         *E, m_p, q_p;
17268214e71cSJoe   PetscInt           Np, p, dim, d;
17278214e71cSJoe   Parameter         *param;
17288214e71cSJoe 
17298214e71cSJoe   PetscFunctionBeginUser;
173084467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsVEvent, ts, 0, 0, 0));
17318214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
17324a0cbf56SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
17334a0cbf56SMatthew G. Knepley 
17348214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
17358214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
17368214e71cSJoe   PetscCall(PetscBagGetData(user->bag, (void **)&param));
17378214e71cSJoe   m_p = user->masses[0] * param->m0;
17388214e71cSJoe   q_p = user->charges[0] * param->q0;
17398214e71cSJoe   PetscCall(VecGetLocalSize(Vres, &Np));
17408214e71cSJoe   PetscCall(VecGetArrayRead(X, &x));
17418214e71cSJoe   PetscCall(VecGetArray(Vres, &vres));
17428214e71cSJoe   Np /= dim;
17438214e71cSJoe   for (p = 0; p < Np; ++p) {
1744045208b8SMatthew G. Knepley     for (d = 0; d < dim; ++d) vres[p * dim + d] = q_p * E[p * dim + d] / m_p;
17458214e71cSJoe   }
17468214e71cSJoe   PetscCall(VecRestoreArrayRead(X, &x));
17478214e71cSJoe   /*
1748d7c1f440SPierre Jolivet     Synchronized, ordered output for parallel/sequential test cases.
17498214e71cSJoe     In the 1D (on the 2D mesh) case, every y component should be zero.
17508214e71cSJoe   */
17518214e71cSJoe   if (user->checkVRes) {
17528214e71cSJoe     PetscBool pr = user->checkVRes > 1 ? PETSC_TRUE : PETSC_FALSE;
17538214e71cSJoe     PetscInt  step;
17548214e71cSJoe 
17558214e71cSJoe     PetscCall(TSGetStepNumber(ts, &step));
17568214e71cSJoe     if (pr) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step: %" PetscInt_FMT "\n", step));
17578214e71cSJoe     for (PetscInt p = 0; p < Np; ++p) {
17588214e71cSJoe       if (pr) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Residual: %.12g %.12g\n", (double)PetscRealPart(vres[p * dim + 0]), (double)PetscRealPart(vres[p * dim + 1])));
17598214e71cSJoe       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]));
17608214e71cSJoe     }
17618214e71cSJoe     if (pr) PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
17628214e71cSJoe   }
17638214e71cSJoe   PetscCall(VecRestoreArray(Vres, &vres));
17648214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
176584467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsVEvent, ts, 0, 0, 0));
17668214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
17678214e71cSJoe }
17688214e71cSJoe 
17698214e71cSJoe static PetscErrorCode CreateSolution(TS ts)
17708214e71cSJoe {
17718214e71cSJoe   DM       sw;
17728214e71cSJoe   Vec      u;
17738214e71cSJoe   PetscInt dim, Np;
17748214e71cSJoe 
17758214e71cSJoe   PetscFunctionBegin;
17768214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
17778214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
17788214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
17798214e71cSJoe   PetscCall(VecCreate(PETSC_COMM_WORLD, &u));
17808214e71cSJoe   PetscCall(VecSetBlockSize(u, dim));
17818214e71cSJoe   PetscCall(VecSetSizes(u, 2 * Np * dim, PETSC_DECIDE));
17828214e71cSJoe   PetscCall(VecSetUp(u));
17838214e71cSJoe   PetscCall(TSSetSolution(ts, u));
17848214e71cSJoe   PetscCall(VecDestroy(&u));
17858214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
17868214e71cSJoe }
17878214e71cSJoe 
17888214e71cSJoe static PetscErrorCode SetProblem(TS ts)
17898214e71cSJoe {
17908214e71cSJoe   AppCtx *user;
17918214e71cSJoe   DM      sw;
17928214e71cSJoe 
17938214e71cSJoe   PetscFunctionBegin;
17948214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
17958214e71cSJoe   PetscCall(DMGetApplicationContext(sw, (void **)&user));
17968214e71cSJoe   // Define unified system for (X, V)
17978214e71cSJoe   {
17988214e71cSJoe     Mat      J;
17998214e71cSJoe     PetscInt dim, Np;
18008214e71cSJoe 
18018214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
18028214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
18038214e71cSJoe     PetscCall(MatCreate(PETSC_COMM_WORLD, &J));
18048214e71cSJoe     PetscCall(MatSetSizes(J, 2 * Np * dim, 2 * Np * dim, PETSC_DECIDE, PETSC_DECIDE));
18058214e71cSJoe     PetscCall(MatSetBlockSize(J, 2 * dim));
18068214e71cSJoe     PetscCall(MatSetFromOptions(J));
18078214e71cSJoe     PetscCall(MatSetUp(J));
18088214e71cSJoe     PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, user));
18098214e71cSJoe     PetscCall(TSSetRHSJacobian(ts, J, J, RHSJacobian, user));
18108214e71cSJoe     PetscCall(MatDestroy(&J));
18118214e71cSJoe   }
18128214e71cSJoe   /* Define split system for X and V */
18138214e71cSJoe   {
18148214e71cSJoe     Vec             u;
18158214e71cSJoe     IS              isx, isv, istmp;
18168214e71cSJoe     const PetscInt *idx;
18178214e71cSJoe     PetscInt        dim, Np, rstart;
18188214e71cSJoe 
18198214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
18208214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
18218214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
18228214e71cSJoe     PetscCall(VecGetOwnershipRange(u, &rstart, NULL));
18238214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 0, 2, &istmp));
18248214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
18258214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isx));
18268214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
18278214e71cSJoe     PetscCall(ISDestroy(&istmp));
18288214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 1, 2, &istmp));
18298214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
18308214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isv));
18318214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
18328214e71cSJoe     PetscCall(ISDestroy(&istmp));
18338214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "position", isx));
18348214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "momentum", isv));
18358214e71cSJoe     PetscCall(ISDestroy(&isx));
18368214e71cSJoe     PetscCall(ISDestroy(&isv));
18378214e71cSJoe     PetscCall(TSRHSSplitSetRHSFunction(ts, "position", NULL, RHSFunctionX, user));
18388214e71cSJoe     PetscCall(TSRHSSplitSetRHSFunction(ts, "momentum", NULL, RHSFunctionV, user));
18398214e71cSJoe   }
18408214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18418214e71cSJoe }
18428214e71cSJoe 
18438214e71cSJoe static PetscErrorCode DMSwarmTSRedistribute(TS ts)
18448214e71cSJoe {
18458214e71cSJoe   DM        sw;
18468214e71cSJoe   Vec       u;
18478214e71cSJoe   PetscReal t, maxt, dt;
18488214e71cSJoe   PetscInt  n, maxn;
18498214e71cSJoe 
18508214e71cSJoe   PetscFunctionBegin;
18518214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
18528214e71cSJoe   PetscCall(TSGetTime(ts, &t));
18538214e71cSJoe   PetscCall(TSGetMaxTime(ts, &maxt));
18548214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
18558214e71cSJoe   PetscCall(TSGetStepNumber(ts, &n));
18568214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
18578214e71cSJoe 
18588214e71cSJoe   PetscCall(TSReset(ts));
18598214e71cSJoe   PetscCall(TSSetDM(ts, sw));
18608214e71cSJoe   PetscCall(TSSetFromOptions(ts));
18618214e71cSJoe   PetscCall(TSSetTime(ts, t));
18628214e71cSJoe   PetscCall(TSSetMaxTime(ts, maxt));
18638214e71cSJoe   PetscCall(TSSetTimeStep(ts, dt));
18648214e71cSJoe   PetscCall(TSSetStepNumber(ts, n));
18658214e71cSJoe   PetscCall(TSSetMaxSteps(ts, maxn));
18668214e71cSJoe 
18678214e71cSJoe   PetscCall(CreateSolution(ts));
18688214e71cSJoe   PetscCall(SetProblem(ts));
18698214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
18708214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18718214e71cSJoe }
18728214e71cSJoe 
18738214e71cSJoe PetscErrorCode line(PetscInt dim, PetscReal time, const PetscReal dummy[], PetscInt p, PetscScalar x[], void *ctx)
18748214e71cSJoe {
18758214e71cSJoe   DM        sw, cdm;
18768214e71cSJoe   PetscInt  Np;
18778214e71cSJoe   PetscReal low[2], high[2];
18788214e71cSJoe   AppCtx   *user = (AppCtx *)ctx;
18798214e71cSJoe 
18808214e71cSJoe   sw = user->swarm;
18818214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &cdm));
18828214e71cSJoe   // Get the bounding box so we can equally space the particles
18838214e71cSJoe   PetscCall(DMGetLocalBoundingBox(cdm, low, high));
18848214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
18858214e71cSJoe   // shift it by h/2 so nothing is initialized directly on a boundary
18868214e71cSJoe   x[0] = ((high[0] - low[0]) / Np) * (p + 0.5);
18878214e71cSJoe   x[1] = 0.;
18888214e71cSJoe   return PETSC_SUCCESS;
18898214e71cSJoe }
18908214e71cSJoe 
1891b80bf5b1SJoe Pusztay /*
18928214e71cSJoe   InitializeSolveAndSwarm - Set the solution values to the swarm coordinates and velocities, and also possibly set the initial values.
18938214e71cSJoe 
18948214e71cSJoe   Input Parameters:
18958214e71cSJoe + ts         - The TS
1896d7c1f440SPierre Jolivet - useInitial - Flag to also set the initial conditions to the current coordinates and velocities and setup the problem
18978214e71cSJoe 
18988214e71cSJoe   Output Parameters:
18998214e71cSJoe . u - The initialized solution vector
19008214e71cSJoe 
19018214e71cSJoe   Level: advanced
19028214e71cSJoe 
19038214e71cSJoe .seealso: InitializeSolve()
1904b80bf5b1SJoe Pusztay */
19058214e71cSJoe static PetscErrorCode InitializeSolveAndSwarm(TS ts, PetscBool useInitial)
1906d71ae5a4SJacob Faibussowitsch {
19078214e71cSJoe   DM       sw;
1908045208b8SMatthew G. Knepley   Vec      u, gc, gv;
19098214e71cSJoe   IS       isx, isv;
19108214e71cSJoe   PetscInt dim;
19118214e71cSJoe   AppCtx  *user;
1912b80bf5b1SJoe Pusztay 
1913b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
19148214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19158214e71cSJoe   PetscCall(DMGetApplicationContext(sw, &user));
19168214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
19178214e71cSJoe   if (useInitial) {
19188214e71cSJoe     PetscReal v0[2] = {1., 0.};
19198214e71cSJoe     if (user->perturbed_weights) {
19208214e71cSJoe       PetscCall(InitializeParticles_PerturbedWeights(sw, user));
19218214e71cSJoe     } else {
19228214e71cSJoe       PetscCall(DMSwarmComputeLocalSizeFromOptions(sw));
19238214e71cSJoe       PetscCall(DMSwarmInitializeCoordinates(sw));
19248214e71cSJoe       PetscCall(DMSwarmInitializeVelocitiesFromOptions(sw, v0));
19258214e71cSJoe     }
19268214e71cSJoe     PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
19278214e71cSJoe     PetscCall(DMSwarmTSRedistribute(ts));
19288214e71cSJoe   }
1929045208b8SMatthew G. Knepley   PetscCall(DMSetUp(sw));
19308214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
19318214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
19328214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
19338214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19348214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
19358214e71cSJoe   PetscCall(VecISCopy(u, isx, SCATTER_FORWARD, gc));
19368214e71cSJoe   PetscCall(VecISCopy(u, isv, SCATTER_FORWARD, gv));
19378214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19388214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
19398214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
19408214e71cSJoe }
19418214e71cSJoe 
19428214e71cSJoe static PetscErrorCode InitializeSolve(TS ts, Vec u)
1943b80bf5b1SJoe Pusztay {
19448214e71cSJoe   PetscFunctionBegin;
19458214e71cSJoe   PetscCall(TSSetSolution(ts, u));
19468214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_TRUE));
19478214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
1948b80bf5b1SJoe Pusztay }
1949b80bf5b1SJoe Pusztay 
19508214e71cSJoe static PetscErrorCode MigrateParticles(TS ts)
19518214e71cSJoe {
19528214e71cSJoe   DM               sw, cdm;
19538214e71cSJoe   const PetscReal *L;
19549072cb8bSMatthew G. Knepley   AppCtx          *ctx;
19558214e71cSJoe 
19568214e71cSJoe   PetscFunctionBeginUser;
19578214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19589072cb8bSMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &ctx));
19598214e71cSJoe   PetscCall(DMViewFromOptions(sw, NULL, "-migrate_view_pre"));
19608214e71cSJoe   {
19618214e71cSJoe     Vec        u, gc, gv, position, momentum;
19628214e71cSJoe     IS         isx, isv;
19638214e71cSJoe     PetscReal *pos, *mom;
19648214e71cSJoe 
19658214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
19668214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
19678214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
19688214e71cSJoe     PetscCall(VecGetSubVector(u, isx, &position));
19698214e71cSJoe     PetscCall(VecGetSubVector(u, isv, &momentum));
19708214e71cSJoe     PetscCall(VecGetArray(position, &pos));
19718214e71cSJoe     PetscCall(VecGetArray(momentum, &mom));
19728214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19738214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
19748214e71cSJoe     PetscCall(VecISCopy(u, isx, SCATTER_REVERSE, gc));
19758214e71cSJoe     PetscCall(VecISCopy(u, isv, SCATTER_REVERSE, gv));
19768214e71cSJoe 
19778214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &cdm));
19788214e71cSJoe     PetscCall(DMGetPeriodicity(cdm, NULL, NULL, &L));
19798214e71cSJoe     if ((L[0] || L[1]) >= 0.) {
19808214e71cSJoe       PetscReal *x, *v, upper[3], lower[3];
19818214e71cSJoe       PetscInt   Np, dim;
19828214e71cSJoe 
19838214e71cSJoe       PetscCall(DMSwarmGetLocalSize(sw, &Np));
19848214e71cSJoe       PetscCall(DMGetDimension(cdm, &dim));
19858214e71cSJoe       PetscCall(DMGetBoundingBox(cdm, lower, upper));
19868214e71cSJoe       PetscCall(VecGetArray(gc, &x));
19878214e71cSJoe       PetscCall(VecGetArray(gv, &v));
19888214e71cSJoe       for (PetscInt p = 0; p < Np; ++p) {
19898214e71cSJoe         for (PetscInt d = 0; d < dim; ++d) {
19908214e71cSJoe           if (pos[p * dim + d] < lower[d]) {
19918214e71cSJoe             x[p * dim + d] = pos[p * dim + d] + (upper[d] - lower[d]);
19928214e71cSJoe           } else if (pos[p * dim + d] > upper[d]) {
19938214e71cSJoe             x[p * dim + d] = pos[p * dim + d] - (upper[d] - lower[d]);
19948214e71cSJoe           } else {
19958214e71cSJoe             x[p * dim + d] = pos[p * dim + d];
19968214e71cSJoe           }
19978214e71cSJoe           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]);
19988214e71cSJoe           v[p * dim + d] = mom[p * dim + d];
19998214e71cSJoe         }
20008214e71cSJoe       }
20018214e71cSJoe       PetscCall(VecRestoreArray(gc, &x));
20028214e71cSJoe       PetscCall(VecRestoreArray(gv, &v));
20038214e71cSJoe     }
20048214e71cSJoe     PetscCall(VecRestoreArray(position, &pos));
20058214e71cSJoe     PetscCall(VecRestoreArray(momentum, &mom));
20068214e71cSJoe     PetscCall(VecRestoreSubVector(u, isx, &position));
20078214e71cSJoe     PetscCall(VecRestoreSubVector(u, isv, &momentum));
20088214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
20098214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
20108214e71cSJoe   }
20118214e71cSJoe   PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
20129072cb8bSMatthew G. Knepley   PetscInt step;
20139072cb8bSMatthew G. Knepley 
20149072cb8bSMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &step));
2015045208b8SMatthew G. Knepley   if (!(step % ctx->remapFreq)) {
20169072cb8bSMatthew G. Knepley     // Monitor electric field before we destroy it
20179072cb8bSMatthew G. Knepley     PetscReal ptime;
20189072cb8bSMatthew G. Knepley     PetscInt  step;
20199072cb8bSMatthew G. Knepley 
20209072cb8bSMatthew G. Knepley     PetscCall(TSGetStepNumber(ts, &step));
20219072cb8bSMatthew G. Knepley     PetscCall(TSGetTime(ts, &ptime));
20229072cb8bSMatthew G. Knepley     if (ctx->efield_monitor) PetscCall(MonitorEField(ts, step, ptime, NULL, ctx));
20239072cb8bSMatthew G. Knepley     if (ctx->poisson_monitor) PetscCall(MonitorPoisson(ts, step, ptime, NULL, ctx));
20249072cb8bSMatthew G. Knepley     PetscCall(DMSwarmRemap(sw));
20259072cb8bSMatthew G. Knepley     ctx->validE = PETSC_FALSE;
20269072cb8bSMatthew G. Knepley   }
20279072cb8bSMatthew G. Knepley   // This MUST come last, since it recreates the subswarms and they must DMClone() the new swarm
20288214e71cSJoe   PetscCall(DMSwarmTSRedistribute(ts));
20298214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_FALSE));
20303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2031b80bf5b1SJoe Pusztay }
2032b80bf5b1SJoe Pusztay 
2033d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
2034d71ae5a4SJacob Faibussowitsch {
2035b80bf5b1SJoe Pusztay   DM        dm, sw;
20368214e71cSJoe   TS        ts;
20378214e71cSJoe   Vec       u;
20388214e71cSJoe   PetscReal dt;
20398214e71cSJoe   PetscInt  maxn;
2040b80bf5b1SJoe Pusztay   AppCtx    user;
2041b80bf5b1SJoe Pusztay 
20429566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
20438214e71cSJoe   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
20448214e71cSJoe   PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &user.bag));
20458214e71cSJoe   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
20468214e71cSJoe   PetscCall(CreatePoisson(dm, &user));
20478214e71cSJoe   PetscCall(CreateSwarm(dm, &user, &sw));
20488214e71cSJoe   PetscCall(SetupParameters(PETSC_COMM_WORLD, &user));
20498214e71cSJoe   PetscCall(InitializeConstants(sw, &user));
20508214e71cSJoe   PetscCall(DMSetApplicationContext(sw, &user));
2051b80bf5b1SJoe Pusztay 
20528214e71cSJoe   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
20538214e71cSJoe   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
20549566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts, sw));
20558214e71cSJoe   PetscCall(TSSetMaxTime(ts, 0.1));
20568214e71cSJoe   PetscCall(TSSetTimeStep(ts, 0.00001));
20578214e71cSJoe   PetscCall(TSSetMaxSteps(ts, 100));
20588214e71cSJoe   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
20598214e71cSJoe 
20608214e71cSJoe   if (user.efield_monitor) PetscCall(TSMonitorSet(ts, MonitorEField, &user, NULL));
2061f1e6e573SMatthew G. Knepley   if (user.moment_monitor) PetscCall(TSMonitorSet(ts, MonitorMoments, &user, NULL));
20628214e71cSJoe   if (user.initial_monitor) PetscCall(TSMonitorSet(ts, MonitorInitialConditions, &user, NULL));
20639072cb8bSMatthew G. Knepley   if (user.positions_monitor) PetscCall(TSMonitorSet(ts, MonitorPositions_2D, &user, NULL));
20648214e71cSJoe   if (user.poisson_monitor) PetscCall(TSMonitorSet(ts, MonitorPoisson, &user, NULL));
20658214e71cSJoe 
20668214e71cSJoe   PetscCall(TSSetFromOptions(ts));
20678214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
20688214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
20698214e71cSJoe   user.steps    = maxn;
20708214e71cSJoe   user.stepSize = dt;
20718214e71cSJoe   PetscCall(SetupContext(dm, sw, &user));
20728214e71cSJoe   PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve));
20738214e71cSJoe   PetscCall(TSSetPostStep(ts, MigrateParticles));
20748214e71cSJoe   PetscCall(CreateSolution(ts));
20758214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
20768214e71cSJoe   PetscCall(TSComputeInitialCondition(ts, u));
20778214e71cSJoe   PetscCall(CheckNonNegativeWeights(sw, &user));
20788214e71cSJoe   PetscCall(TSSolve(ts, NULL));
20798214e71cSJoe 
20809566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&user.snes));
20814a0cbf56SMatthew G. Knepley   PetscCall(DMDestroy(&user.dmPot));
20824a0cbf56SMatthew G. Knepley   PetscCall(ISDestroy(&user.isPot));
2083f1e6e573SMatthew G. Knepley   PetscCall(MatDestroy(&user.M));
2084f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomDestroy(&user.fegeom));
20859566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
20869566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sw));
20879566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
20888214e71cSJoe   PetscCall(DestroyContext(&user));
20899566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
2090b122ec5aSJacob Faibussowitsch   return 0;
2091b80bf5b1SJoe Pusztay }
2092b80bf5b1SJoe Pusztay 
2093b80bf5b1SJoe Pusztay /*TEST
2094b80bf5b1SJoe Pusztay 
2095b80bf5b1SJoe Pusztay    build:
20968214e71cSJoe     requires: !complex double
20978214e71cSJoe 
20988214e71cSJoe   # This tests that we can put particles in a box and compute the Coulomb force
20998214e71cSJoe   # Recommend -draw_size 500,500
21008214e71cSJoe    testset:
21018214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2102045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 20 \
2103045208b8SMatthew G. Knepley              -dm_plex_box_lower 0 -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
21049072cb8bSMatthew G. Knepley            -vdm_plex_simplex 0 \
21058214e71cSJoe            -dm_swarm_coordinate_density constant -dm_swarm_num_particles 100 \
21068214e71cSJoe            -sigma 1.0e-8 -timeScale 2.0e-14 \
21078214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
21088214e71cSJoe            -output_step 50 -check_vel_res
21098214e71cSJoe      test:
21108214e71cSJoe        suffix: none_1d
21119072cb8bSMatthew G. Knepley        requires:
21128214e71cSJoe        args: -em_type none -error
21138214e71cSJoe      test:
21148214e71cSJoe        suffix: coulomb_1d
21158214e71cSJoe        args: -em_type coulomb
21168214e71cSJoe 
21178214e71cSJoe    # for viewers
21188214e71cSJoe    #-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
21198214e71cSJoe    testset:
21208214e71cSJoe      nsize: {{1 2}}
21218214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2122045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 36 \
2123045208b8SMatthew G. Knepley              -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
21248214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
21258214e71cSJoe              -vdm_plex_box_lower -3 -vdm_plex_box_upper 3 \
212684467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -twostream -charges -1.,1. -sigma 1.0e-8 \
21278214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
21288214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 2 \
21298214e71cSJoe              -ts_dt 0.01 -ts_max_time 5 -ts_max_steps 10 \
21308214e71cSJoe            -em_snes_atol 1.e-15 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
213184467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
21328214e71cSJoe      test:
21338214e71cSJoe        suffix: two_stream_c0
21348214e71cSJoe        args: -em_type primal -petscfe_default_quadrature_order 2 -petscspace_degree 2 -em_pc_type svd
21358214e71cSJoe      test:
21368214e71cSJoe        suffix: two_stream_rt
21378214e71cSJoe        requires: superlu_dist
21388214e71cSJoe        args: -em_type mixed \
21398214e71cSJoe                -potential_petscspace_degree 0 \
21408214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
21418214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
2142045208b8SMatthew G. Knepley                -field_petscspace_degree 1 -field_petscfe_default_quadrature_order 1 \
21438214e71cSJoe              -em_snes_error_if_not_converged \
21448214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
21458214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
21468214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
21478214e71cSJoe                -em_fieldsplit_field_pc_type lu \
21488214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
21498214e71cSJoe                -em_fieldsplit_potential_pc_type svd
21508214e71cSJoe 
215184467f86SMatthew G. Knepley    # For an eyeball check, we use
21529072cb8bSMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 10,1 -vdm_plex_box_faces 2000 -efield_monitor
21538214e71cSJoe    # For verification, we use
215484467f86SMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 100,1 -vdm_plex_box_faces 8000 -dm_swarm_num_particles 800000 -monitor_efield
21558214e71cSJoe    # -ts_monitor_sp_swarm_multi_species 0 -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500
21568214e71cSJoe    testset:
21578214e71cSJoe      nsize: {{1 2}}
21588214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2159045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 10 \
2160045208b8SMatthew G. Knepley              -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
21618214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
21628214e71cSJoe              -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \
2163f1e6e573SMatthew G. Knepley              -vpetscspace_degree 2 -vdm_plex_hash_location \
216484467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -charges -1.,1. \
21658214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
21668214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
21678214e71cSJoe              -ts_dt 0.03 -ts_max_time 500 -ts_max_steps 1 \
21688214e71cSJoe            -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
216984467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
21708214e71cSJoe 
21718214e71cSJoe      test:
21728214e71cSJoe        suffix: uniform_equilibrium_1d
21738214e71cSJoe        args: -cosine_coefficients 0.0,0.5 -em_type primal -petscspace_degree 1 -em_pc_type svd
21748214e71cSJoe      test:
217575155f48SMatthew G. Knepley        suffix: uniform_equilibrium_1d_real
2176045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
217775155f48SMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
217875155f48SMatthew G. Knepley              -cosine_coefficients 0.0 -em_type primal -petscspace_degree 1 -em_pc_type svd
217975155f48SMatthew G. Knepley      test:
21808214e71cSJoe        suffix: uniform_primal_1d
21818214e71cSJoe        args: -em_type primal -petscspace_degree 1 -em_pc_type svd
21828214e71cSJoe      test:
218375155f48SMatthew G. Knepley        suffix: uniform_primal_1d_real
2184045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
218575155f48SMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
218675155f48SMatthew G. Knepley              -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd
21879072cb8bSMatthew G. Knepley      # NOT WORKING -ftop_pc_type bjacobi -ftop_sub_pc_type lu -ftop_sub_pc_factor_shift_type nonzero
21889072cb8bSMatthew G. Knepley      test:
21899072cb8bSMatthew G. Knepley        suffix: uniform_primal_1d_real_pfak
21909072cb8bSMatthew G. Knepley        nsize: 1
2191045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
21929072cb8bSMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
21939072cb8bSMatthew 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 \
21949072cb8bSMatthew G. Knepley                -remap_dm_plex_box_lower 0.,-10. -remap_dm_plex_box_upper 12.5664,10. \
21959072cb8bSMatthew G. Knepley                -remap_petscspace_degree 2 -remap_dm_plex_hash_location \
2196045208b8SMatthew G. Knepley              -remap_freq 1 -dm_swarm_remap_type pfak \
21979072cb8bSMatthew G. Knepley                -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 \
21989072cb8bSMatthew G. Knepley                -ptof_pc_type lu \
21999072cb8bSMatthew G. Knepley              -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd -em_proj_pc_type lu
220075155f48SMatthew G. Knepley      test:
22018214e71cSJoe        requires: superlu_dist
22028214e71cSJoe        suffix: uniform_mixed_1d
22038214e71cSJoe        args: -em_type mixed \
22048214e71cSJoe                -potential_petscspace_degree 0 \
22058214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
22068214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
2207045208b8SMatthew G. Knepley                -field_petscspace_degree 1 \
22088214e71cSJoe              -em_snes_error_if_not_converged \
22098214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
22108214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
22118214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
22128214e71cSJoe                -em_fieldsplit_field_pc_type lu \
22138214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
22148214e71cSJoe                -em_fieldsplit_potential_pc_type svd
22158214e71cSJoe 
2216b80bf5b1SJoe Pusztay TEST*/
2217