xref: /petsc/src/ts/tutorials/hamiltonian/ex2.c (revision bfe80ac4a46d58cb7760074b25f5e81b2f541d8a)
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
121fd7102fcSMatthew G. Knepley   PetscInt     velocity_monitor;  // Cell to monitor the velocity distribution for
1229072cb8bSMatthew G. Knepley   PetscBool    perturbed_weights; // Uniformly sample x,v space with gaussian weights
1239072cb8bSMatthew G. Knepley   PetscInt     ostep;             // Print the energy at each ostep time steps
1248214e71cSJoe   PetscInt     numParticles;
1258214e71cSJoe   PetscReal    timeScale;              /* Nondimensionalizing time scale */
1268214e71cSJoe   PetscReal    charges[2];             /* The charges of each species */
1278214e71cSJoe   PetscReal    masses[2];              /* The masses of each species */
1288214e71cSJoe   PetscReal    thermal_energy[2];      /* Thermal Energy (used to get other constants)*/
1298214e71cSJoe   PetscReal    cosine_coefficients[2]; /*(alpha, k)*/
1308214e71cSJoe   PetscReal    totalWeight;
1318214e71cSJoe   PetscReal    stepSize;
1328214e71cSJoe   PetscInt     steps;
1338214e71cSJoe   PetscReal    initVel;
134f1e6e573SMatthew G. Knepley   EMType       em;           // Type of electrostatic model
135f1e6e573SMatthew G. Knepley   SNES         snes;         // EM solver
1364a0cbf56SMatthew G. Knepley   DM           dmPot;        // The DM for potential
137b02f317dSMatthew G. Knepley   Mat          fftPot;       // Fourier Transform operator for the potential
138fd7102fcSMatthew G. Knepley   Vec          fftX, fftY;   //   FFT vectors with phases added (complex parts)
139fd7102fcSMatthew G. Knepley   IS           fftReal;      //   The indices for real parts
1404a0cbf56SMatthew G. Knepley   IS           isPot;        // The IS for potential, or NULL in primal
1414a0cbf56SMatthew G. Knepley   Mat          M;            // The finite element mass matrix for potential
142f1e6e573SMatthew G. Knepley   PetscFEGeom *fegeom;       // Geometric information for the DM cells
143b02f317dSMatthew G. Knepley   PetscDrawHG  drawhgic_x;   // Histogram of the particle weight in each X cell
144b02f317dSMatthew G. Knepley   PetscDrawHG  drawhgic_v;   // Histogram of the particle weight in each X cell
145fd7102fcSMatthew G. Knepley   PetscDrawHG  drawhgcell_v; // Histogram of the particle weight in a given cell
1469072cb8bSMatthew G. Knepley   PetscBool    validE;       // Flag to indicate E-field in swarm is valid
14775155f48SMatthew G. Knepley   PetscReal    drawlgEmin;   // The minimum lg(E) to plot
14875155f48SMatthew G. Knepley   PetscDrawLG  drawlgE;      // Logarithm of maximum electric field
14975155f48SMatthew G. Knepley   PetscDrawSP  drawspE;      // Electric field at particle positions
15075155f48SMatthew G. Knepley   PetscDrawSP  drawspX;      // Particle positions
15175155f48SMatthew G. Knepley   PetscViewer  viewerRho;    // Charge density viewer
152b02f317dSMatthew G. Knepley   PetscViewer  viewerRhoHat; // Charge density Fourier Transform viewer
15375155f48SMatthew G. Knepley   PetscViewer  viewerPhi;    // Potential viewer
1548214e71cSJoe   DM           swarm;
1558214e71cSJoe   PetscRandom  random;
1568214e71cSJoe   PetscBool    twostream;
1578214e71cSJoe   PetscBool    checkweights;
158b02f317dSMatthew G. Knepley   PetscInt     checkVRes; // Flag to check/output velocity residuals for nightly tests
15984467f86SMatthew G. Knepley 
16084467f86SMatthew G. Knepley   PetscLogEvent RhsXEvent, RhsVEvent, ESolveEvent, ETabEvent;
161b80bf5b1SJoe Pusztay } AppCtx;
162b80bf5b1SJoe Pusztay 
163d71ae5a4SJacob Faibussowitsch static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
164d71ae5a4SJacob Faibussowitsch {
165b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
1668214e71cSJoe   PetscInt d                      = 2;
1678214e71cSJoe   PetscInt maxSpecies             = 2;
1688214e71cSJoe   options->error                  = PETSC_FALSE;
1699072cb8bSMatthew G. Knepley   options->remapFreq              = 1;
1708214e71cSJoe   options->efield_monitor         = PETSC_FALSE;
171f1e6e573SMatthew G. Knepley   options->moment_monitor         = PETSC_FALSE;
1728214e71cSJoe   options->initial_monitor        = PETSC_FALSE;
1738214e71cSJoe   options->perturbed_weights      = PETSC_FALSE;
1748214e71cSJoe   options->poisson_monitor        = PETSC_FALSE;
1759072cb8bSMatthew G. Knepley   options->positions_monitor      = PETSC_FALSE;
176fd7102fcSMatthew G. Knepley   options->velocity_monitor       = -1;
1778214e71cSJoe   options->ostep                  = 100;
1788214e71cSJoe   options->timeScale              = 2.0e-14;
1798214e71cSJoe   options->charges[0]             = -1.0;
1808214e71cSJoe   options->charges[1]             = 1.0;
1818214e71cSJoe   options->masses[0]              = 1.0;
1828214e71cSJoe   options->masses[1]              = 1000.0;
1838214e71cSJoe   options->thermal_energy[0]      = 1.0;
1848214e71cSJoe   options->thermal_energy[1]      = 1.0;
1858214e71cSJoe   options->cosine_coefficients[0] = 0.01;
1868214e71cSJoe   options->cosine_coefficients[1] = 0.5;
1878214e71cSJoe   options->initVel                = 1;
1888214e71cSJoe   options->totalWeight            = 1.0;
1898214e71cSJoe   options->drawhgic_x             = NULL;
1908214e71cSJoe   options->drawhgic_v             = NULL;
191fd7102fcSMatthew G. Knepley   options->drawhgcell_v           = NULL;
19275155f48SMatthew G. Knepley   options->drawlgEmin             = -6;
19375155f48SMatthew G. Knepley   options->drawlgE                = NULL;
19475155f48SMatthew G. Knepley   options->drawspE                = NULL;
19575155f48SMatthew G. Knepley   options->drawspX                = NULL;
19675155f48SMatthew G. Knepley   options->viewerRho              = NULL;
197b02f317dSMatthew G. Knepley   options->viewerRhoHat           = NULL;
19875155f48SMatthew G. Knepley   options->viewerPhi              = NULL;
1998214e71cSJoe   options->em                     = EM_COULOMB;
2004a0cbf56SMatthew G. Knepley   options->snes                   = NULL;
2014a0cbf56SMatthew G. Knepley   options->dmPot                  = NULL;
202b02f317dSMatthew G. Knepley   options->fftPot                 = NULL;
203fd7102fcSMatthew G. Knepley   options->fftX                   = NULL;
204fd7102fcSMatthew G. Knepley   options->fftY                   = NULL;
205fd7102fcSMatthew G. Knepley   options->fftReal                = NULL;
2064a0cbf56SMatthew G. Knepley   options->isPot                  = NULL;
2074a0cbf56SMatthew G. Knepley   options->M                      = NULL;
2088214e71cSJoe   options->numParticles           = 32768;
2098214e71cSJoe   options->twostream              = PETSC_FALSE;
2108214e71cSJoe   options->checkweights           = PETSC_FALSE;
2118214e71cSJoe   options->checkVRes              = 0;
212b80bf5b1SJoe Pusztay 
2138214e71cSJoe   PetscOptionsBegin(comm, "", "Landau Damping and Two Stream options", "DMSWARM");
2148214e71cSJoe   PetscCall(PetscOptionsBool("-error", "Flag to print the error", "ex2.c", options->error, &options->error, NULL));
2159072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsInt("-remap_freq", "Number", "ex2.c", options->remapFreq, &options->remapFreq, NULL));
2169072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-efield_monitor", "Flag to plot log(max E) over time", "ex2.c", options->efield_monitor, &options->efield_monitor, NULL));
2179072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsReal("-efield_min_monitor", "Minimum E field to plot", "ex2.c", options->drawlgEmin, &options->drawlgEmin, NULL));
2189072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-moments_monitor", "Flag to show moments table", "ex2.c", options->moment_monitor, &options->moment_monitor, NULL));
2199072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-ics_monitor", "Flag to show initial condition histograms", "ex2.c", options->initial_monitor, &options->initial_monitor, NULL));
2209072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-positions_monitor", "The flag to show particle positions", "ex2.c", options->positions_monitor, &options->positions_monitor, NULL));
2219072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-poisson_monitor", "The flag to show charges, Efield and potential solve", "ex2.c", options->poisson_monitor, &options->poisson_monitor, NULL));
222fd7102fcSMatthew G. Knepley   PetscCall(PetscOptionsInt("-velocity_monitor", "Cell to show velocity histograms", "ex2.c", options->velocity_monitor, &options->velocity_monitor, NULL));
2238214e71cSJoe   PetscCall(PetscOptionsBool("-twostream", "Run two stream instability", "ex2.c", options->twostream, &options->twostream, NULL));
2248214e71cSJoe   PetscCall(PetscOptionsBool("-perturbed_weights", "Flag to run uniform sampling with perturbed weights", "ex2.c", options->perturbed_weights, &options->perturbed_weights, NULL));
2258214e71cSJoe   PetscCall(PetscOptionsBool("-check_weights", "Ensure all particle weights are positive", "ex2.c", options->checkweights, &options->checkweights, NULL));
2268214e71cSJoe   PetscCall(PetscOptionsInt("-check_vel_res", "Check particle velocity residuals for nightly tests", "ex2.c", options->checkVRes, &options->checkVRes, NULL));
2278214e71cSJoe   PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", "ex2.c", options->ostep, &options->ostep, NULL));
2288214e71cSJoe   PetscCall(PetscOptionsReal("-timeScale", "Nondimensionalizing time scale", "ex2.c", options->timeScale, &options->timeScale, NULL));
2298214e71cSJoe   PetscCall(PetscOptionsReal("-initial_velocity", "Initial velocity of perturbed particle", "ex2.c", options->initVel, &options->initVel, NULL));
2308214e71cSJoe   PetscCall(PetscOptionsReal("-total_weight", "Total weight of all particles", "ex2.c", options->totalWeight, &options->totalWeight, NULL));
2318214e71cSJoe   PetscCall(PetscOptionsRealArray("-cosine_coefficients", "Amplitude and frequency of cosine equation used in initialization", "ex2.c", options->cosine_coefficients, &d, NULL));
2328214e71cSJoe   PetscCall(PetscOptionsRealArray("-charges", "Species charges", "ex2.c", options->charges, &maxSpecies, NULL));
2338214e71cSJoe   PetscCall(PetscOptionsEnum("-em_type", "Type of electrostatic solver", "ex2.c", EMTypes, (PetscEnum)options->em, (PetscEnum *)&options->em, NULL));
234d0609cedSBarry Smith   PetscOptionsEnd();
23584467f86SMatthew G. Knepley 
23684467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsX", TS_CLASSID, &options->RhsXEvent));
23784467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsV", TS_CLASSID, &options->RhsVEvent));
23884467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ESolve", TS_CLASSID, &options->ESolveEvent));
23984467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ETab", TS_CLASSID, &options->ETabEvent));
2403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
241b80bf5b1SJoe Pusztay }
242b80bf5b1SJoe Pusztay 
2438214e71cSJoe static PetscErrorCode SetupContext(DM dm, DM sw, AppCtx *user)
2448214e71cSJoe {
245b02f317dSMatthew G. Knepley   MPI_Comm comm;
246b02f317dSMatthew G. Knepley 
2478214e71cSJoe   PetscFunctionBeginUser;
248b02f317dSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2498214e71cSJoe   if (user->efield_monitor) {
25075155f48SMatthew G. Knepley     PetscDraw     draw;
25175155f48SMatthew G. Knepley     PetscDrawAxis axis;
25275155f48SMatthew G. Knepley 
253b02f317dSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Max Electric Field", 0, 300, 400, 300, &draw));
254fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex2_Efield"));
25575155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
25675155f48SMatthew G. Knepley     PetscCall(PetscDrawLGCreate(draw, 1, &user->drawlgE));
25775155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
25875155f48SMatthew G. Knepley     PetscCall(PetscDrawLGGetAxis(user->drawlgE, &axis));
25975155f48SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Electron Electric Field", "time", "E_max"));
26075155f48SMatthew G. Knepley     PetscCall(PetscDrawLGSetLimits(user->drawlgE, 0., user->steps * user->stepSize, user->drawlgEmin, 0.));
2618214e71cSJoe   }
262b02f317dSMatthew G. Knepley 
2638214e71cSJoe   if (user->initial_monitor) {
264fd7102fcSMatthew G. Knepley     PetscDraw     drawic_x, drawic_v;
265b02f317dSMatthew G. Knepley     PetscDrawAxis axis1, axis2;
2668214e71cSJoe     PetscReal     dmboxlower[2], dmboxupper[2];
2678214e71cSJoe     PetscInt      dim, cStart, cEnd;
268b02f317dSMatthew G. Knepley 
2698214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
2708214e71cSJoe     PetscCall(DMGetBoundingBox(dm, dmboxlower, dmboxupper));
2718214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2728214e71cSJoe 
273fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_x", 0, 300, 400, 300, &drawic_x));
274fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawic_x, "ex2_ic_x"));
275fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawic_x));
276fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawHGCreate(drawic_x, (int)dim, &user->drawhgic_x));
277b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGCalcStats(user->drawhgic_x, PETSC_TRUE));
2788214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_x, &axis1));
2796497c311SBarry Smith     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_x, (int)(cEnd - cStart)));
280fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis1, "Initial X Distribution", "X", "weight"));
281b02f317dSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis1, dmboxlower[0], dmboxupper[0], 0, 0));
282fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawic_x));
2838214e71cSJoe 
284fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_v", 400, 300, 400, 300, &drawic_v));
285fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawic_v, "ex9_ic_v"));
286fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawic_v));
287fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawHGCreate(drawic_v, (int)dim, &user->drawhgic_v));
288b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGCalcStats(user->drawhgic_v, PETSC_TRUE));
2898214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_v, &axis2));
290b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_v, 21));
291fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis2, "Initial V_x Distribution", "V", "weight"));
292b02f317dSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis2, -6, 6, 0, 0));
293fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawic_v));
294fd7102fcSMatthew G. Knepley   }
295fd7102fcSMatthew G. Knepley 
296fd7102fcSMatthew G. Knepley   if (user->velocity_monitor >= 0) {
297fd7102fcSMatthew G. Knepley     DM            vdm;
298fd7102fcSMatthew G. Knepley     DMSwarmCellDM celldm;
299fd7102fcSMatthew G. Knepley     PetscDraw     drawcell_v;
300fd7102fcSMatthew G. Knepley     PetscDrawAxis axis;
301fd7102fcSMatthew G. Knepley     PetscReal     dmboxlower[2], dmboxupper[2];
302fd7102fcSMatthew G. Knepley     PetscInt      dim;
303fd7102fcSMatthew G. Knepley     char          title[PETSC_MAX_PATH_LEN];
304fd7102fcSMatthew G. Knepley 
305fd7102fcSMatthew G. Knepley     PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
306fd7102fcSMatthew G. Knepley     PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
307fd7102fcSMatthew G. Knepley     PetscCall(DMGetDimension(vdm, &dim));
308fd7102fcSMatthew G. Knepley     PetscCall(DMGetBoundingBox(vdm, dmboxlower, dmboxupper));
309fd7102fcSMatthew G. Knepley 
310fd7102fcSMatthew G. Knepley     PetscCall(PetscSNPrintf(title, PETSC_MAX_PATH_LEN, "Cell %" PetscInt_FMT ": Velocity Distribution", user->velocity_monitor));
311fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, title, 400, 300, 400, 300, &drawcell_v));
312fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetSave(drawcell_v, "ex2_cell_v"));
313fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(drawcell_v));
314fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawHGCreate(drawcell_v, (int)dim, &user->drawhgcell_v));
315fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawHGCalcStats(user->drawhgcell_v, PETSC_TRUE));
316fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawHGGetAxis(user->drawhgcell_v, &axis));
317fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawHGSetNumberBins(user->drawhgcell_v, 21));
318fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "V_x Distribution", "V", "weight"));
319fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawAxisSetLimits(axis, dmboxlower[0], dmboxupper[0], 0, 0));
320fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawDestroy(&drawcell_v));
3218214e71cSJoe   }
322b02f317dSMatthew G. Knepley 
3239072cb8bSMatthew G. Knepley   if (user->positions_monitor) {
32475155f48SMatthew G. Knepley     PetscDraw     draw;
3258214e71cSJoe     PetscDrawAxis axis;
3268214e71cSJoe 
327b02f317dSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Particle Position", 0, 0, 400, 300, &draw));
32875155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_pos"));
32975155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
33075155f48SMatthew G. Knepley     PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspX));
33175155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
33275155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetDimension(user->drawspX, 1));
33375155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetAxis(user->drawspX, &axis));
3348214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "v"));
33575155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspX));
3368214e71cSJoe   }
3378214e71cSJoe   if (user->poisson_monitor) {
338b02f317dSMatthew G. Knepley     Vec           rho, rhohat, phi;
33975155f48SMatthew G. Knepley     PetscDraw     draw;
34075155f48SMatthew G. Knepley     PetscDrawAxis axis;
3418214e71cSJoe 
342b02f317dSMatthew G. Knepley     PetscCall(PetscDrawCreate(comm, NULL, "Electric_Field", 0, 0, 400, 300, &draw));
34375155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
34475155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_E_spatial"));
34575155f48SMatthew G. Knepley     PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspE));
34675155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
34775155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetDimension(user->drawspE, 1));
34875155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetAxis(user->drawspE, &axis));
34975155f48SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "E"));
35075155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspE));
3518214e71cSJoe 
352b02f317dSMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "Charge Density", 0, 0, 400, 300, &user->viewerRho));
35375155f48SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerRho, "rho_"));
35475155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerRho, 0, &draw));
35575155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_spatial"));
35675155f48SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerRho));
3574a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
35875155f48SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rho, "charge_density"));
3594a0cbf56SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
3608214e71cSJoe 
361b02f317dSMatthew G. Knepley     PetscInt dim, N;
362b02f317dSMatthew G. Knepley 
363b02f317dSMatthew G. Knepley     PetscCall(DMGetDimension(user->dmPot, &dim));
364b02f317dSMatthew G. Knepley     if (dim == 1) {
365b02f317dSMatthew G. Knepley       PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
366b02f317dSMatthew G. Knepley       PetscCall(VecGetSize(rhohat, &N));
367b02f317dSMatthew G. Knepley       PetscCall(MatCreateFFT(comm, dim, &N, MATFFTW, &user->fftPot));
368b02f317dSMatthew G. Knepley       PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
369fd7102fcSMatthew G. Knepley       PetscCall(MatCreateVecs(user->fftPot, &user->fftX, &user->fftY));
370fd7102fcSMatthew G. Knepley       PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &user->fftReal));
371b02f317dSMatthew G. Knepley     }
372b02f317dSMatthew G. Knepley 
373fd7102fcSMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "rhohat: Charge Density FT", 0, 0, 400, 300, &user->viewerRhoHat));
374b02f317dSMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerRhoHat, "rhohat_"));
375b02f317dSMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerRhoHat, 0, &draw));
376b02f317dSMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_ft"));
377b02f317dSMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerRhoHat));
378b02f317dSMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
379b02f317dSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rhohat, "charge_density_ft"));
380b02f317dSMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
381b02f317dSMatthew G. Knepley 
382b02f317dSMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(comm, NULL, "Potential", 400, 0, 400, 300, &user->viewerPhi));
38375155f48SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerPhi, "phi_"));
38475155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerPhi, 0, &draw));
38575155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_phi_spatial"));
38675155f48SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerPhi));
3874a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
38875155f48SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)phi, "potential"));
3894a0cbf56SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
3908214e71cSJoe   }
3918214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3928214e71cSJoe }
3938214e71cSJoe 
3948214e71cSJoe static PetscErrorCode DestroyContext(AppCtx *user)
3958214e71cSJoe {
3968214e71cSJoe   PetscFunctionBeginUser;
3978214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_x));
3988214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_v));
399fd7102fcSMatthew G. Knepley   PetscCall(PetscDrawHGDestroy(&user->drawhgcell_v));
4008214e71cSJoe 
40175155f48SMatthew G. Knepley   PetscCall(PetscDrawLGDestroy(&user->drawlgE));
40275155f48SMatthew G. Knepley   PetscCall(PetscDrawSPDestroy(&user->drawspE));
40375155f48SMatthew G. Knepley   PetscCall(PetscDrawSPDestroy(&user->drawspX));
40475155f48SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerRho));
405b02f317dSMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerRhoHat));
406b02f317dSMatthew G. Knepley   PetscCall(MatDestroy(&user->fftPot));
407fd7102fcSMatthew G. Knepley   PetscCall(VecDestroy(&user->fftX));
408fd7102fcSMatthew G. Knepley   PetscCall(VecDestroy(&user->fftY));
409fd7102fcSMatthew G. Knepley   PetscCall(ISDestroy(&user->fftReal));
41075155f48SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerPhi));
4118214e71cSJoe 
4128214e71cSJoe   PetscCall(PetscBagDestroy(&user->bag));
4138214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
4148214e71cSJoe }
4158214e71cSJoe 
4168214e71cSJoe static PetscErrorCode CheckNonNegativeWeights(DM sw, AppCtx *user)
4178214e71cSJoe {
4188214e71cSJoe   const PetscScalar *w;
4198214e71cSJoe   PetscInt           Np;
4208214e71cSJoe 
4218214e71cSJoe   PetscFunctionBeginUser;
4228214e71cSJoe   if (!user->checkweights) PetscFunctionReturn(PETSC_SUCCESS);
4238214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w));
4248214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
4258214e71cSJoe   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]);
4268214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w));
4278214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
4288214e71cSJoe }
4298214e71cSJoe 
4309072cb8bSMatthew G. Knepley static PetscErrorCode computeVelocityFEMMoments(DM sw, PetscReal moments[], AppCtx *user)
4318214e71cSJoe {
4329072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
433f1e6e573SMatthew G. Knepley   DM            vdm;
434f1e6e573SMatthew G. Knepley   Vec           u[1];
435f1e6e573SMatthew G. Knepley   const char   *fields[1] = {"w_q"};
4368214e71cSJoe 
437f1e6e573SMatthew G. Knepley   PetscFunctionBegin;
4389072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "velocity"));
4399072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
4409072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
441f1e6e573SMatthew G. Knepley   PetscCall(DMGetGlobalVector(vdm, &u[0]));
442f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmProjectFields(sw, vdm, 1, fields, u, SCATTER_FORWARD));
443f1e6e573SMatthew G. Knepley   PetscCall(DMPlexComputeMoments(vdm, u[0], moments));
444f1e6e573SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(vdm, &u[0]));
4459072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
4468214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
4478214e71cSJoe }
4488214e71cSJoe 
449fd7102fcSMatthew G. Knepley static void f0_grad_phi2(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
450fd7102fcSMatthew G. Knepley {
451fd7102fcSMatthew G. Knepley   f0[0] = 0.;
452fd7102fcSMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) f0[0] += PetscSqr(u_x[uOff_x[0] + d * dim + d]);
453fd7102fcSMatthew G. Knepley }
454fd7102fcSMatthew G. Knepley 
4558214e71cSJoe static PetscErrorCode MonitorEField(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
4568214e71cSJoe {
4578214e71cSJoe   AppCtx     *user = (AppCtx *)ctx;
458f1e6e573SMatthew G. Knepley   DM          sw;
459fd7102fcSMatthew G. Knepley   PetscScalar intESq;
460f1e6e573SMatthew G. Knepley   PetscReal  *E, *x, *weight;
461f1e6e573SMatthew G. Knepley   PetscReal   Enorm = 0., lgEnorm, lgEmax, sum = 0., Emax = 0., chargesum = 0.;
462f1e6e573SMatthew G. Knepley   PetscReal   pmoments[4]; /* \int f, \int v f, \int v^2 f */
463fd7102fcSMatthew G. Knepley   PetscInt   *species, dim, Np, gNp;
464fd7102fcSMatthew G. Knepley   MPI_Comm    comm;
4658214e71cSJoe 
4668214e71cSJoe   PetscFunctionBeginUser;
4679072cb8bSMatthew G. Knepley   if (step < 0 || !user->validE) PetscFunctionReturn(PETSC_SUCCESS);
468fd7102fcSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
4698214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
4708214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
4718214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
472fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmGetSize(sw, &gNp));
4738214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
4748214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
4758214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
4768214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
4778214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
4788214e71cSJoe 
479f1e6e573SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
480f1e6e573SMatthew G. Knepley     for (PetscInt d = 0; d < 1; ++d) {
481f1e6e573SMatthew G. Knepley       PetscReal temp = PetscAbsReal(E[p * dim + d]);
4828214e71cSJoe       if (temp > Emax) Emax = temp;
4838214e71cSJoe     }
4848214e71cSJoe     Enorm += PetscSqrtReal(E[p * dim] * E[p * dim]);
4858214e71cSJoe     sum += E[p * dim];
4868214e71cSJoe     chargesum += user->charges[0] * weight[p];
4878214e71cSJoe   }
488fd7102fcSMatthew G. Knepley   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &Emax, 1, MPIU_REAL, MPIU_MAX, comm));
4898214e71cSJoe   lgEnorm = Enorm != 0 ? PetscLog10Real(Enorm) : -16.;
49075155f48SMatthew G. Knepley   lgEmax  = Emax != 0 ? PetscLog10Real(Emax) : user->drawlgEmin;
4918214e71cSJoe 
492fd7102fcSMatthew G. Knepley   PetscDS ds;
493fd7102fcSMatthew G. Knepley   Vec     phi;
494fd7102fcSMatthew G. Knepley 
495fd7102fcSMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
496fd7102fcSMatthew G. Knepley   PetscCall(DMGetDS(user->dmPot, &ds));
497fd7102fcSMatthew G. Knepley   PetscCall(PetscDSSetObjective(ds, 0, &f0_grad_phi2));
498fd7102fcSMatthew G. Knepley   PetscCall(DMPlexComputeIntegralFEM(user->dmPot, phi, &intESq, user));
499fd7102fcSMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
500fd7102fcSMatthew G. Knepley 
5018214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5028214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
5038214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
5048214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
50575155f48SMatthew G. Knepley   PetscCall(PetscDrawLGAddPoint(user->drawlgE, &t, &lgEmax));
50675155f48SMatthew G. Knepley   PetscCall(PetscDrawLGDraw(user->drawlgE));
50775155f48SMatthew G. Knepley   PetscDraw draw;
50875155f48SMatthew G. Knepley   PetscCall(PetscDrawLGGetDraw(user->drawlgE, &draw));
50975155f48SMatthew G. Knepley   PetscCall(PetscDrawSave(draw));
510f1e6e573SMatthew G. Knepley 
511f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
512fd7102fcSMatthew G. Knepley   PetscCall(PetscPrintf(comm, "E: %f\t%+e\t%e\t%f\t%20.15e\t%f\t%f\t%f\t%20.15e\t%20.15e\t%20.15e\t%" PetscInt_FMT "\t(%" PetscInt_FMT ")\n", (double)t, (double)sum, (double)Enorm, (double)lgEnorm, (double)Emax, (double)lgEmax, (double)chargesum, (double)pmoments[0], (double)pmoments[1], (double)pmoments[1 + dim], (double)PetscSqrtReal(intESq), gNp, step));
51375155f48SMatthew G. Knepley   PetscCall(DMViewFromOptions(sw, NULL, "-sw_efield_view"));
514f1e6e573SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
515f1e6e573SMatthew G. Knepley }
516f1e6e573SMatthew G. Knepley 
517f1e6e573SMatthew G. Knepley static PetscErrorCode MonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
518f1e6e573SMatthew G. Knepley {
519f1e6e573SMatthew G. Knepley   AppCtx   *user = (AppCtx *)ctx;
520f1e6e573SMatthew G. Knepley   DM        sw;
521f1e6e573SMatthew G. Knepley   PetscReal pmoments[4], fmoments[4]; /* \int f, \int v f, \int v^2 f */
522f1e6e573SMatthew G. Knepley 
523f1e6e573SMatthew G. Knepley   PetscFunctionBeginUser;
524f1e6e573SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
525f1e6e573SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
526f1e6e573SMatthew G. Knepley 
527f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
528f1e6e573SMatthew G. Knepley   PetscCall(computeVelocityFEMMoments(sw, fmoments, user));
529f1e6e573SMatthew G. Knepley 
530f1e6e573SMatthew 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]));
5318214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5328214e71cSJoe }
5338214e71cSJoe 
5348214e71cSJoe PetscErrorCode MonitorInitialConditions(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
5358214e71cSJoe {
5368214e71cSJoe   AppCtx    *user = (AppCtx *)ctx;
537b02f317dSMatthew G. Knepley   DM         sw;
538fd7102fcSMatthew G. Knepley   PetscDraw  drawic_x, drawic_v;
5398214e71cSJoe   PetscReal *weight, *pos, *vel;
540b02f317dSMatthew G. Knepley   PetscInt   dim, Np;
5418214e71cSJoe 
5428214e71cSJoe   PetscFunctionBegin;
5438214e71cSJoe   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
544b02f317dSMatthew G. Knepley   if (step == 0) {
5458214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
5468214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
5478214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
5488214e71cSJoe 
5498214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_x));
550fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawHGGetDraw(user->drawhgic_x, &drawic_x));
551fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawClear(drawic_x));
552fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawFlush(drawic_x));
5538214e71cSJoe 
5548214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_v));
555fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawHGGetDraw(user->drawhgic_v, &drawic_v));
556fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawClear(drawic_v));
557fd7102fcSMatthew G. Knepley     PetscCall(PetscDrawFlush(drawic_v));
5588214e71cSJoe 
559b02f317dSMatthew G. Knepley     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
5608214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
5618214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
562b02f317dSMatthew G. Knepley     for (PetscInt p = 0; p < Np; ++p) {
563b02f317dSMatthew G. Knepley       PetscCall(PetscDrawHGAddWeightedValue(user->drawhgic_x, pos[p * dim], weight[p]));
564b02f317dSMatthew G. Knepley       PetscCall(PetscDrawHGAddWeightedValue(user->drawhgic_v, vel[p * dim], weight[p]));
5658214e71cSJoe     }
5668214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
5678214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
5688214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
569b02f317dSMatthew G. Knepley 
570b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGDraw(user->drawhgic_x));
571b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGSave(user->drawhgic_x));
572b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGDraw(user->drawhgic_v));
573b02f317dSMatthew G. Knepley     PetscCall(PetscDrawHGSave(user->drawhgic_v));
5748214e71cSJoe   }
5758214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5768214e71cSJoe }
5778214e71cSJoe 
578*bfe80ac4SPierre Jolivet // Right now, make the complete velocity histogram
579fd7102fcSMatthew G. Knepley PetscErrorCode MonitorVelocity(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
580fd7102fcSMatthew G. Knepley {
581fd7102fcSMatthew G. Knepley   AppCtx       *user = (AppCtx *)ctx;
582fd7102fcSMatthew G. Knepley   DM            sw, dm;
583fd7102fcSMatthew G. Knepley   Vec           ks;
584fd7102fcSMatthew G. Knepley   PetscProbFunc cdf;
585fd7102fcSMatthew G. Knepley   PetscDraw     drawcell_v;
586fd7102fcSMatthew G. Knepley   PetscScalar  *ksa;
587fd7102fcSMatthew G. Knepley   PetscReal    *weight, *vel;
588fd7102fcSMatthew G. Knepley   PetscInt     *pidx;
589fd7102fcSMatthew G. Knepley   PetscInt      dim, Npc, cStart, cEnd, cell = user->velocity_monitor;
590fd7102fcSMatthew G. Knepley 
591fd7102fcSMatthew G. Knepley   PetscFunctionBegin;
592fd7102fcSMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
593fd7102fcSMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
594fd7102fcSMatthew G. Knepley 
595fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &dm));
596fd7102fcSMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
597fd7102fcSMatthew G. Knepley   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &ks));
598fd7102fcSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)ks, "KS Statistic by Cell"));
599fd7102fcSMatthew G. Knepley   PetscCall(VecSetSizes(ks, cEnd - cStart, PETSC_DETERMINE));
600fd7102fcSMatthew G. Knepley   PetscCall(VecSetFromOptions(ks));
601fd7102fcSMatthew G. Knepley   switch (dim) {
602fd7102fcSMatthew G. Knepley   case 1:
603fd7102fcSMatthew G. Knepley     //cdf = PetscCDFMaxwellBoltzmann1D;
604fd7102fcSMatthew G. Knepley     cdf = PetscCDFGaussian1D;
605fd7102fcSMatthew G. Knepley     break;
606fd7102fcSMatthew G. Knepley   case 2:
607fd7102fcSMatthew G. Knepley     cdf = PetscCDFMaxwellBoltzmann2D;
608fd7102fcSMatthew G. Knepley     break;
609fd7102fcSMatthew G. Knepley   case 3:
610fd7102fcSMatthew G. Knepley     cdf = PetscCDFMaxwellBoltzmann3D;
611fd7102fcSMatthew G. Knepley     break;
612fd7102fcSMatthew G. Knepley   default:
613fd7102fcSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim);
614fd7102fcSMatthew G. Knepley   }
615fd7102fcSMatthew G. Knepley 
616fd7102fcSMatthew G. Knepley   PetscCall(PetscDrawHGReset(user->drawhgcell_v));
617fd7102fcSMatthew G. Knepley   PetscCall(PetscDrawHGGetDraw(user->drawhgcell_v, &drawcell_v));
618fd7102fcSMatthew G. Knepley   PetscCall(PetscDrawClear(drawcell_v));
619fd7102fcSMatthew G. Knepley   PetscCall(PetscDrawFlush(drawcell_v));
620fd7102fcSMatthew G. Knepley 
621fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
622fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
623fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
624fd7102fcSMatthew G. Knepley   PetscCall(VecGetArrayWrite(ks, &ksa));
625fd7102fcSMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
626fd7102fcSMatthew G. Knepley     Vec          cellv, cellw;
627fd7102fcSMatthew G. Knepley     PetscScalar *cella, *cellaw;
628fd7102fcSMatthew G. Knepley     PetscReal    totWgt = 0.;
629fd7102fcSMatthew G. Knepley 
630fd7102fcSMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
631fd7102fcSMatthew G. Knepley     PetscCall(VecCreate(PETSC_COMM_SELF, &cellv));
632fd7102fcSMatthew G. Knepley     PetscCall(VecSetBlockSize(cellv, dim));
633fd7102fcSMatthew G. Knepley     PetscCall(VecSetSizes(cellv, Npc * dim, Npc));
634fd7102fcSMatthew G. Knepley     PetscCall(VecSetFromOptions(cellv));
635fd7102fcSMatthew G. Knepley     PetscCall(VecCreate(PETSC_COMM_SELF, &cellw));
636fd7102fcSMatthew G. Knepley     PetscCall(VecSetSizes(cellw, Npc, Npc));
637fd7102fcSMatthew G. Knepley     PetscCall(VecSetFromOptions(cellw));
638fd7102fcSMatthew G. Knepley     PetscCall(VecGetArrayWrite(cellv, &cella));
639fd7102fcSMatthew G. Knepley     PetscCall(VecGetArrayWrite(cellw, &cellaw));
640fd7102fcSMatthew G. Knepley     for (PetscInt q = 0; q < Npc; ++q) {
641fd7102fcSMatthew G. Knepley       const PetscInt p = pidx[q];
642fd7102fcSMatthew G. Knepley       if (c == cell) PetscCall(PetscDrawHGAddWeightedValue(user->drawhgcell_v, vel[p * dim], weight[p]));
643fd7102fcSMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) cella[q * dim + d] = vel[p * dim + d];
644fd7102fcSMatthew G. Knepley       cellaw[q] = weight[p];
645fd7102fcSMatthew G. Knepley       totWgt += weight[p];
646fd7102fcSMatthew G. Knepley     }
647fd7102fcSMatthew G. Knepley     PetscCall(VecRestoreArrayWrite(cellv, &cella));
648fd7102fcSMatthew G. Knepley     PetscCall(VecRestoreArrayWrite(cellw, &cellaw));
649fd7102fcSMatthew G. Knepley     PetscCall(VecScale(cellw, 1. / totWgt));
650fd7102fcSMatthew G. Knepley     PetscCall(PetscProbComputeKSStatisticWeighted(cellv, cellw, cdf, &ksa[c - cStart]));
651fd7102fcSMatthew G. Knepley     PetscCall(VecDestroy(&cellv));
652fd7102fcSMatthew G. Knepley     PetscCall(VecDestroy(&cellw));
653fd7102fcSMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
654fd7102fcSMatthew G. Knepley   }
655fd7102fcSMatthew G. Knepley   PetscCall(VecRestoreArrayWrite(ks, &ksa));
656fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
657fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
658fd7102fcSMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
659fd7102fcSMatthew G. Knepley 
660fd7102fcSMatthew G. Knepley   PetscReal minalpha, maxalpha;
661fd7102fcSMatthew G. Knepley   PetscInt  mincell, maxcell;
662fd7102fcSMatthew G. Knepley 
663fd7102fcSMatthew G. Knepley   PetscCall(VecFilter(ks, PETSC_SMALL));
664fd7102fcSMatthew G. Knepley   PetscCall(VecMin(ks, &mincell, &minalpha));
665fd7102fcSMatthew G. Knepley   PetscCall(VecMax(ks, &maxcell, &maxalpha));
666fd7102fcSMatthew G. Knepley   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Step %" PetscInt_FMT ": Min/Max KS statistic %g/%g in cell %" PetscInt_FMT "/%" PetscInt_FMT "\n", step, minalpha, maxalpha, mincell, maxcell));
667fd7102fcSMatthew G. Knepley   PetscCall(VecViewFromOptions(ks, NULL, "-ks_view"));
668fd7102fcSMatthew G. Knepley   PetscCall(VecDestroy(&ks));
669fd7102fcSMatthew G. Knepley 
670fd7102fcSMatthew G. Knepley   PetscCall(PetscDrawHGDraw(user->drawhgcell_v));
671fd7102fcSMatthew G. Knepley   PetscCall(PetscDrawHGSave(user->drawhgcell_v));
672fd7102fcSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
673fd7102fcSMatthew G. Knepley }
674fd7102fcSMatthew G. Knepley 
6758214e71cSJoe static PetscErrorCode MonitorPositions_2D(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
6768214e71cSJoe {
6778214e71cSJoe   AppCtx         *user = (AppCtx *)ctx;
6788214e71cSJoe   DM              dm, sw;
6798214e71cSJoe   PetscScalar    *x, *v, *weight;
6808214e71cSJoe   PetscReal       lower[3], upper[3], speed;
6818214e71cSJoe   const PetscInt *s;
6828214e71cSJoe   PetscInt        dim, cStart, cEnd, c;
6838214e71cSJoe 
6848214e71cSJoe   PetscFunctionBeginUser;
6858214e71cSJoe   if (step > 0 && step % user->ostep == 0) {
6868214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
6878214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
6888214e71cSJoe     PetscCall(DMGetDimension(dm, &dim));
6898214e71cSJoe     PetscCall(DMGetBoundingBox(dm, lower, upper));
6908214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
6918214e71cSJoe     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
6928214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
6938214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
6948214e71cSJoe     PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&s));
6958214e71cSJoe     PetscCall(DMSwarmSortGetAccess(sw));
69675155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspX));
69775155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], lower[1], upper[1]));
69875155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], -12, 12));
6998214e71cSJoe     for (c = 0; c < cEnd - cStart; ++c) {
7008214e71cSJoe       PetscInt *pidx, Npc, q;
7018214e71cSJoe       PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
7028214e71cSJoe       for (q = 0; q < Npc; ++q) {
7038214e71cSJoe         const PetscInt p = pidx[q];
7048214e71cSJoe         if (s[p] == 0) {
7059072cb8bSMatthew G. Knepley           speed = 0.;
7069072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) speed += PetscSqr(v[p * dim + d]);
7079072cb8bSMatthew G. Knepley           speed = PetscSqrtReal(speed);
708045208b8SMatthew G. Knepley           if (dim == 1) {
70975155f48SMatthew G. Knepley             PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &v[p * dim], &speed));
7108214e71cSJoe           } else {
71175155f48SMatthew G. Knepley             PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &x[p * dim + 1], &speed));
7128214e71cSJoe           }
7138214e71cSJoe         } else if (s[p] == 1) {
71475155f48SMatthew G. Knepley           PetscCall(PetscDrawSPAddPoint(user->drawspX, &x[p * dim], &v[p * dim]));
7158214e71cSJoe         }
7168214e71cSJoe       }
71784467f86SMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
7188214e71cSJoe     }
71975155f48SMatthew G. Knepley     PetscCall(PetscDrawSPDraw(user->drawspX, PETSC_TRUE));
72075155f48SMatthew G. Knepley     PetscDraw draw;
72175155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetDraw(user->drawspX, &draw));
72275155f48SMatthew G. Knepley     PetscCall(PetscDrawSave(draw));
7238214e71cSJoe     PetscCall(DMSwarmSortRestoreAccess(sw));
7248214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
7258214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
7268214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
7278214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&s));
7288214e71cSJoe   }
7298214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
7308214e71cSJoe }
7318214e71cSJoe 
7328214e71cSJoe static PetscErrorCode MonitorPoisson(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
7338214e71cSJoe {
7348214e71cSJoe   AppCtx *user = (AppCtx *)ctx;
7358214e71cSJoe   DM      dm, sw;
7368214e71cSJoe 
7378214e71cSJoe   PetscFunctionBeginUser;
7388214e71cSJoe   if (step > 0 && step % user->ostep == 0) {
7398214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
7408214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
7419072cb8bSMatthew G. Knepley 
7429072cb8bSMatthew G. Knepley     if (user->validE) {
7439072cb8bSMatthew G. Knepley       PetscScalar *x, *E, *weight;
7449072cb8bSMatthew G. Knepley       PetscReal    lower[3], upper[3], xval;
7459072cb8bSMatthew G. Knepley       PetscDraw    draw;
7469072cb8bSMatthew G. Knepley       PetscInt     dim, cStart, cEnd;
7479072cb8bSMatthew G. Knepley 
7488214e71cSJoe       PetscCall(DMGetDimension(dm, &dim));
7498214e71cSJoe       PetscCall(DMGetBoundingBox(dm, lower, upper));
7508214e71cSJoe       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
7518214e71cSJoe 
75275155f48SMatthew G. Knepley       PetscCall(PetscDrawSPReset(user->drawspE));
7538214e71cSJoe       PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
7548214e71cSJoe       PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
7558214e71cSJoe       PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
7568214e71cSJoe 
7578214e71cSJoe       PetscCall(DMSwarmSortGetAccess(sw));
7589072cb8bSMatthew G. Knepley       for (PetscInt c = 0; c < cEnd - cStart; ++c) {
75975155f48SMatthew G. Knepley         PetscReal Eavg = 0.0;
7609072cb8bSMatthew G. Knepley         PetscInt *pidx, Npc;
7619072cb8bSMatthew G. Knepley 
7628214e71cSJoe         PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
7639072cb8bSMatthew G. Knepley         for (PetscInt q = 0; q < Npc; ++q) {
7648214e71cSJoe           const PetscInt p = pidx[q];
76575155f48SMatthew G. Knepley           Eavg += E[p * dim];
7668214e71cSJoe         }
76775155f48SMatthew G. Knepley         Eavg /= Npc;
7688214e71cSJoe         xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart));
76975155f48SMatthew G. Knepley         PetscCall(PetscDrawSPAddPoint(user->drawspE, &xval, &Eavg));
77084467f86SMatthew G. Knepley         PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
7718214e71cSJoe       }
77275155f48SMatthew G. Knepley       PetscCall(PetscDrawSPDraw(user->drawspE, PETSC_TRUE));
77375155f48SMatthew G. Knepley       PetscCall(PetscDrawSPGetDraw(user->drawspE, &draw));
77475155f48SMatthew G. Knepley       PetscCall(PetscDrawSave(draw));
7758214e71cSJoe       PetscCall(DMSwarmSortRestoreAccess(sw));
7768214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
7778214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
7788214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
7799072cb8bSMatthew G. Knepley     }
78075155f48SMatthew G. Knepley 
781b02f317dSMatthew G. Knepley     Vec rho, rhohat, phi;
78275155f48SMatthew G. Knepley 
7834a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
784b02f317dSMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
785fd7102fcSMatthew G. Knepley     PetscCall(VecView(rho, user->viewerRho));
786fd7102fcSMatthew G. Knepley     PetscCall(VecISCopy(user->fftX, user->fftReal, SCATTER_FORWARD, rho));
787fd7102fcSMatthew G. Knepley     PetscCall(MatMult(user->fftPot, user->fftX, user->fftY));
788fd7102fcSMatthew G. Knepley     PetscCall(VecFilter(user->fftY, PETSC_SMALL));
789fd7102fcSMatthew G. Knepley     PetscCall(VecViewFromOptions(user->fftX, NULL, "-real_view"));
790fd7102fcSMatthew G. Knepley     PetscCall(VecViewFromOptions(user->fftY, NULL, "-fft_view"));
791fd7102fcSMatthew G. Knepley     PetscCall(VecISCopy(user->fftY, user->fftReal, SCATTER_REVERSE, rhohat));
792fd7102fcSMatthew G. Knepley     PetscCall(VecSetValue(rhohat, 0, 0., INSERT_VALUES)); // Remove large DC component
793b02f317dSMatthew G. Knepley     PetscCall(VecView(rhohat, user->viewerRhoHat));
794fd7102fcSMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
795b02f317dSMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat));
796b02f317dSMatthew G. Knepley 
7974a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
79875155f48SMatthew G. Knepley     PetscCall(VecView(phi, user->viewerPhi));
7994a0cbf56SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
8008214e71cSJoe   }
8018214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
8028214e71cSJoe }
8038214e71cSJoe 
8048214e71cSJoe static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx)
8058214e71cSJoe {
8068214e71cSJoe   PetscBag   bag;
8078214e71cSJoe   Parameter *p;
8088214e71cSJoe 
8098214e71cSJoe   PetscFunctionBeginUser;
8108214e71cSJoe   /* setup PETSc parameter bag */
8118214e71cSJoe   PetscCall(PetscBagGetData(ctx->bag, (void **)&p));
8128214e71cSJoe   PetscCall(PetscBagSetName(ctx->bag, "par", "Vlasov-Poisson Parameters"));
8138214e71cSJoe   bag = ctx->bag;
8148214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "v0", "Velocity scale, m/s"));
8158214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->t0, 1.0, "t0", "Time scale, s"));
8168214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->x0, 1.0, "x0", "Space scale, m"));
8178214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "phi0", "Potential scale, kg*m^2/A*s^3"));
8188214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->q0, 1.0, "q0", "Charge Scale, A*s"));
8198214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->m0, 1.0, "m0", "Mass Scale, kg"));
8208214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->epsi0, 1.0, "epsi0", "Permittivity of Free Space, kg"));
8218214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->kb, 1.0, "kb", "Boltzmann Constant, m^2 kg/s^2 K^1"));
8228214e71cSJoe 
8238214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->sigma, 1.0, "sigma", "Charge per unit area, C/m^3"));
8248214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->poissonNumber, 1.0, "poissonNumber", "Non-Dimensional Poisson Number"));
8258214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->vlasovNumber, 1.0, "vlasovNumber", "Non-Dimensional Vlasov Number"));
8268214e71cSJoe   PetscCall(PetscBagSetFromOptions(bag));
8278214e71cSJoe   {
8288214e71cSJoe     PetscViewer       viewer;
8298214e71cSJoe     PetscViewerFormat format;
8308214e71cSJoe     PetscBool         flg;
8318214e71cSJoe 
832648c30bcSBarry Smith     PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg));
8338214e71cSJoe     if (flg) {
8348214e71cSJoe       PetscCall(PetscViewerPushFormat(viewer, format));
8358214e71cSJoe       PetscCall(PetscBagView(bag, viewer));
8368214e71cSJoe       PetscCall(PetscViewerFlush(viewer));
8378214e71cSJoe       PetscCall(PetscViewerPopFormat(viewer));
8388214e71cSJoe       PetscCall(PetscViewerDestroy(&viewer));
8398214e71cSJoe     }
8408214e71cSJoe   }
8418214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
8428214e71cSJoe }
8438214e71cSJoe 
8448214e71cSJoe static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
845d71ae5a4SJacob Faibussowitsch {
846b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
8479566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
8489566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
8499566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*dm));
8509072cb8bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*dm, "space"));
8519566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
852f1e6e573SMatthew G. Knepley 
853f1e6e573SMatthew G. Knepley   // Cache the mesh geometry
854f1e6e573SMatthew G. Knepley   DMField         coordField;
855f1e6e573SMatthew G. Knepley   IS              cellIS;
856f1e6e573SMatthew G. Knepley   PetscQuadrature quad;
857f1e6e573SMatthew G. Knepley   PetscReal      *wt, *pt;
858f1e6e573SMatthew G. Knepley   PetscInt        cdim, cStart, cEnd;
859f1e6e573SMatthew G. Knepley 
860f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateField(*dm, &coordField));
861f1e6e573SMatthew G. Knepley   PetscCheck(coordField, comm, PETSC_ERR_USER, "DM must have a coordinate field");
862f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateDim(*dm, &cdim));
863f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd));
864f1e6e573SMatthew G. Knepley   PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cellIS));
865f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
866f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(1, &wt));
867f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(2, &pt));
868f1e6e573SMatthew G. Knepley   wt[0] = 1.;
869f1e6e573SMatthew G. Knepley   pt[0] = -1.;
870f1e6e573SMatthew G. Knepley   pt[1] = -1.;
871f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureSetData(quad, cdim, 1, 1, pt, wt));
872ac9d17c7SMatthew G. Knepley   PetscCall(DMFieldCreateFEGeom(coordField, cellIS, quad, PETSC_FEGEOM_BASIC, &user->fegeom));
873f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&quad));
874f1e6e573SMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
8753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
876b80bf5b1SJoe Pusztay }
877b80bf5b1SJoe Pusztay 
8788214e71cSJoe 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[])
8798214e71cSJoe {
8808214e71cSJoe   f0[0] = -constants[SIGMA];
8818214e71cSJoe }
8828214e71cSJoe 
883d71ae5a4SJacob 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[])
884d71ae5a4SJacob Faibussowitsch {
885b80bf5b1SJoe Pusztay   PetscInt d;
886ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) f1[d] = u_x[d];
887b80bf5b1SJoe Pusztay }
888b80bf5b1SJoe Pusztay 
8898214e71cSJoe 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[])
890d71ae5a4SJacob Faibussowitsch {
891b80bf5b1SJoe Pusztay   PetscInt d;
892ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) g3[d * dim + d] = 1.0;
893b80bf5b1SJoe Pusztay }
894b80bf5b1SJoe Pusztay 
8958214e71cSJoe static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
896d71ae5a4SJacob Faibussowitsch {
8978214e71cSJoe   *u = 0.0;
8988214e71cSJoe   return PETSC_SUCCESS;
899b80bf5b1SJoe Pusztay }
900b80bf5b1SJoe Pusztay 
901b80bf5b1SJoe Pusztay /*
9028214e71cSJoe    /  I   -grad\ / q \ = /0\
9038214e71cSJoe    \-div    0  / \phi/   \f/
904b80bf5b1SJoe Pusztay */
9058214e71cSJoe 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[])
906d71ae5a4SJacob Faibussowitsch {
9078214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[d] += u[uOff[0] + d];
9088214e71cSJoe }
9098214e71cSJoe 
9108214e71cSJoe 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[])
9118214e71cSJoe {
9128214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f1[d * dim + d] = u[uOff[1]];
9138214e71cSJoe }
9148214e71cSJoe 
9158214e71cSJoe 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[])
9168214e71cSJoe {
9178214e71cSJoe   f0[0] += constants[SIGMA];
9188214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[0] += u_x[uOff_x[0] + d * dim + d];
9198214e71cSJoe }
9208214e71cSJoe 
9218214e71cSJoe /* Boundary residual. Dirichlet boundary for u means u_bdy=p*n */
9228214e71cSJoe 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[])
9238214e71cSJoe {
9248214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g0[d * dim + d] = 1.0;
9258214e71cSJoe }
9268214e71cSJoe 
9278214e71cSJoe 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[])
9288214e71cSJoe {
9298214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g2[d * dim + d] = 1.0;
9308214e71cSJoe }
9318214e71cSJoe 
9328214e71cSJoe 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[])
9338214e71cSJoe {
9348214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g1[d * dim + d] = 1.0;
9358214e71cSJoe }
9368214e71cSJoe 
9378214e71cSJoe static PetscErrorCode CreateFEM(DM dm, AppCtx *user)
9388214e71cSJoe {
9398214e71cSJoe   PetscFE   fephi, feq;
9408214e71cSJoe   PetscDS   ds;
9418214e71cSJoe   PetscBool simplex;
9428214e71cSJoe   PetscInt  dim;
9438214e71cSJoe 
9448214e71cSJoe   PetscFunctionBeginUser;
9458214e71cSJoe   PetscCall(DMGetDimension(dm, &dim));
9468214e71cSJoe   PetscCall(DMPlexIsSimplex(dm, &simplex));
9478214e71cSJoe   if (user->em == EM_MIXED) {
9488214e71cSJoe     DMLabel        label;
9498214e71cSJoe     const PetscInt id = 1;
9508214e71cSJoe 
9518214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "field_", PETSC_DETERMINE, &feq));
9528214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)feq, "field"));
9538214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "potential_", PETSC_DETERMINE, &fephi));
9548214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
9558214e71cSJoe     PetscCall(PetscFECopyQuadrature(feq, fephi));
9568214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)feq));
9578214e71cSJoe     PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fephi));
9588214e71cSJoe     PetscCall(DMCreateDS(dm));
9598214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
9608214e71cSJoe     PetscCall(PetscFEDestroy(&feq));
9618214e71cSJoe 
9628214e71cSJoe     PetscCall(DMGetLabel(dm, "marker", &label));
9638214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
9648214e71cSJoe 
9658214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, f0_q, f1_q));
9668214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 1, f0_phi_backgroundCharge, NULL));
9678214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_qq, NULL, NULL, NULL));
9688214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_qphi, NULL));
9698214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_phiq, NULL, NULL));
9708214e71cSJoe 
9718214e71cSJoe     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void))zero, NULL, NULL, NULL));
9728214e71cSJoe 
973f1e6e573SMatthew G. Knepley   } else {
9748214e71cSJoe     MatNullSpace nullsp;
9758214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, PETSC_DETERMINE, &fephi));
9768214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
9778214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fephi));
9788214e71cSJoe     PetscCall(DMCreateDS(dm));
9798214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
9808214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, ion_f0, laplacian_f1));
9818214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, laplacian_g3));
9828214e71cSJoe     PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullsp));
9838214e71cSJoe     PetscCall(PetscObjectCompose((PetscObject)fephi, "nullspace", (PetscObject)nullsp));
9848214e71cSJoe     PetscCall(MatNullSpaceDestroy(&nullsp));
9858214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
9868214e71cSJoe   }
9878214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
9888214e71cSJoe }
9898214e71cSJoe 
9908214e71cSJoe static PetscErrorCode CreatePoisson(DM dm, AppCtx *user)
9918214e71cSJoe {
9928214e71cSJoe   SNES         snes;
9938214e71cSJoe   Mat          J;
9948214e71cSJoe   MatNullSpace nullSpace;
9958214e71cSJoe 
9968214e71cSJoe   PetscFunctionBeginUser;
9978214e71cSJoe   PetscCall(CreateFEM(dm, user));
9988214e71cSJoe   PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes));
9998214e71cSJoe   PetscCall(SNESSetOptionsPrefix(snes, "em_"));
10008214e71cSJoe   PetscCall(SNESSetDM(snes, dm));
10018214e71cSJoe   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, user));
10028214e71cSJoe   PetscCall(SNESSetFromOptions(snes));
10038214e71cSJoe 
10048214e71cSJoe   PetscCall(DMCreateMatrix(dm, &J));
10058214e71cSJoe   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullSpace));
10068214e71cSJoe   PetscCall(MatSetNullSpace(J, nullSpace));
10078214e71cSJoe   PetscCall(MatNullSpaceDestroy(&nullSpace));
10088214e71cSJoe   PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL));
10098214e71cSJoe   PetscCall(MatDestroy(&J));
10104a0cbf56SMatthew G. Knepley   if (user->em == EM_MIXED) {
10114a0cbf56SMatthew G. Knepley     const PetscInt potential = 1;
10124a0cbf56SMatthew G. Knepley 
10134a0cbf56SMatthew G. Knepley     PetscCall(DMCreateSubDM(dm, 1, &potential, &user->isPot, &user->dmPot));
10144a0cbf56SMatthew G. Knepley   } else {
10154a0cbf56SMatthew G. Knepley     user->dmPot = dm;
10164a0cbf56SMatthew G. Knepley     PetscCall(PetscObjectReference((PetscObject)user->dmPot));
10174a0cbf56SMatthew G. Knepley   }
10184a0cbf56SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(user->dmPot, user->dmPot, &user->M));
1019f1e6e573SMatthew G. Knepley   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
10208214e71cSJoe   user->snes = snes;
10218214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
10228214e71cSJoe }
10238214e71cSJoe 
10248214e71cSJoe PetscErrorCode PetscPDFPertubedConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
10258214e71cSJoe {
10268214e71cSJoe   p[0] = (1 + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
10278214e71cSJoe   p[1] = (1 + 0.01 * PetscCosReal(0.5 * x[1])) / (2 * PETSC_PI);
10288214e71cSJoe   return PETSC_SUCCESS;
10298214e71cSJoe }
10308214e71cSJoe PetscErrorCode PetscPDFPertubedConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
10318214e71cSJoe {
10328214e71cSJoe   p[0] = (1. + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
10338214e71cSJoe   return PETSC_SUCCESS;
10348214e71cSJoe }
10358214e71cSJoe 
10368214e71cSJoe PetscErrorCode PetscPDFCosine1D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
10378214e71cSJoe {
10388214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.0;
10398214e71cSJoe   const PetscReal k     = scale ? scale[1] : 1.;
10408214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * x[0]));
10418214e71cSJoe   return PETSC_SUCCESS;
10428214e71cSJoe }
10438214e71cSJoe 
10448214e71cSJoe PetscErrorCode PetscPDFCosine2D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
10458214e71cSJoe {
10468214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.;
10478214e71cSJoe   const PetscReal k     = scale ? scale[0] : 1.;
10488214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * (x[0] + x[1])));
10498214e71cSJoe   return PETSC_SUCCESS;
10508214e71cSJoe }
10518214e71cSJoe 
105284467f86SMatthew G. Knepley static PetscErrorCode CreateVelocityDM(DM sw, DM *vdm)
10538214e71cSJoe {
1054f1e6e573SMatthew G. Knepley   PetscFE        fe;
1055f1e6e573SMatthew G. Knepley   DMPolytopeType ct;
1056f1e6e573SMatthew G. Knepley   PetscInt       dim, cStart;
1057f1e6e573SMatthew G. Knepley   const char    *prefix = "v";
1058f1e6e573SMatthew G. Knepley 
105984467f86SMatthew G. Knepley   PetscFunctionBegin;
106084467f86SMatthew G. Knepley   PetscCall(DMCreate(PETSC_COMM_SELF, vdm));
106184467f86SMatthew G. Knepley   PetscCall(DMSetType(*vdm, DMPLEX));
1062f1e6e573SMatthew G. Knepley   PetscCall(DMPlexSetOptionsPrefix(*vdm, prefix));
106384467f86SMatthew G. Knepley   PetscCall(DMSetFromOptions(*vdm));
10649072cb8bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*vdm, "velocity"));
106584467f86SMatthew G. Knepley   PetscCall(DMViewFromOptions(*vdm, NULL, "-dm_view"));
1066f1e6e573SMatthew G. Knepley 
1067f1e6e573SMatthew G. Knepley   PetscCall(DMGetDimension(*vdm, &dim));
1068f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*vdm, 0, &cStart, NULL));
1069f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetCellType(*vdm, cStart, &ct));
1070f1e6e573SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe));
1071f1e6e573SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "distribution"));
1072f1e6e573SMatthew G. Knepley   PetscCall(DMSetField(*vdm, 0, NULL, (PetscObject)fe));
1073f1e6e573SMatthew G. Knepley   PetscCall(DMCreateDS(*vdm));
1074f1e6e573SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
107584467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
10768214e71cSJoe }
10778214e71cSJoe 
10789072cb8bSMatthew G. Knepley /*
10799072cb8bSMatthew G. Knepley   InitializeParticles_Centroid - Initialize a regular grid of particles.
10809072cb8bSMatthew G. Knepley 
10819072cb8bSMatthew G. Knepley   Input Parameters:
10829072cb8bSMatthew G. Knepley + sw      - The `DMSWARM`
10839072cb8bSMatthew G. Knepley - force1D - Treat the spatial domain as 1D
10849072cb8bSMatthew G. Knepley 
10859072cb8bSMatthew G. Knepley   Notes:
10869072cb8bSMatthew G. Knepley   This functions sets the species, cellid, spatial coordinate, and velocity fields for all particles.
10879072cb8bSMatthew G. Knepley 
10889072cb8bSMatthew G. Knepley   It places one particle in the centroid of each cell in the implicit tensor product of the spatial
10899072cb8bSMatthew G. Knepley   and velocity meshes.
10909072cb8bSMatthew G. Knepley */
1091045208b8SMatthew G. Knepley static PetscErrorCode InitializeParticles_Centroid(DM sw)
10928214e71cSJoe {
109384467f86SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
10949072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
109584467f86SMatthew G. Knepley   DM            xdm, vdm;
109684467f86SMatthew G. Knepley   PetscReal     vmin[3], vmax[3];
109784467f86SMatthew G. Knepley   PetscReal    *x, *v;
109884467f86SMatthew G. Knepley   PetscInt     *species, *cellid;
109984467f86SMatthew G. Knepley   PetscInt      dim, xcStart, xcEnd, vcStart, vcEnd, Ns, Np, Npc, debug;
11008214e71cSJoe   PetscBool     flg;
110184467f86SMatthew G. Knepley   MPI_Comm      comm;
11029072cb8bSMatthew G. Knepley   const char   *cellidname;
11038214e71cSJoe 
11048214e71cSJoe   PetscFunctionBegin;
110584467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
110684467f86SMatthew G. Knepley 
110784467f86SMatthew G. Knepley   PetscOptionsBegin(comm, "", "DMSwarm Options", "DMSWARM");
11088214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
11098214e71cSJoe   PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg));
11108214e71cSJoe   if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns));
111184467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_coords", "Debug output level for particle coordinate computations", "InitializeParticles", 0, &swarm->printCoords, NULL, 0));
111284467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_weights", "Debug output level for particle weight computations", "InitializeWeights", 0, &swarm->printWeights, NULL, 0));
11138214e71cSJoe   PetscOptionsEnd();
111484467f86SMatthew G. Knepley   debug = swarm->printCoords;
11158214e71cSJoe 
11168214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
111784467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
111884467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
11198214e71cSJoe 
1120045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
1121045208b8SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
112284467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
11238214e71cSJoe 
112484467f86SMatthew G. Knepley   // One particle per centroid on the tensor product grid
112584467f86SMatthew G. Knepley   Npc = (vcEnd - vcStart) * Ns;
112684467f86SMatthew G. Knepley   Np  = (xcEnd - xcStart) * Npc;
11278214e71cSJoe   PetscCall(DMSwarmSetLocalSizes(sw, Np, 0));
112884467f86SMatthew G. Knepley   if (debug) {
1129fd7102fcSMatthew G. Knepley     PetscInt gNp, gNc, Nc = xcEnd - xcStart;
113084467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Np, &gNp, 1, MPIU_INT, MPIU_SUM, comm));
113184467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global Np = %" PetscInt_FMT "\n", gNp));
1132fd7102fcSMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Nc, &gNc, 1, MPIU_INT, MPIU_SUM, comm));
1133fd7102fcSMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global X-cells = %" PetscInt_FMT "\n", gNc));
1134fd7102fcSMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global V-cells = %" PetscInt_FMT "\n", vcEnd - vcStart));
11358214e71cSJoe   }
11368214e71cSJoe 
113784467f86SMatthew G. Knepley   // Set species and cellid
11389072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
11399072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCellID(celldm, &cellidname));
114084467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
11419072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, cellidname, NULL, NULL, (void **)&cellid));
114284467f86SMatthew G. Knepley   for (PetscInt c = 0, p = 0; c < xcEnd - xcStart; ++c) {
114384467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
114484467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q, ++p) {
114584467f86SMatthew G. Knepley         species[p] = s;
114684467f86SMatthew G. Knepley         cellid[p]  = c;
114784467f86SMatthew G. Knepley       }
114884467f86SMatthew G. Knepley     }
114984467f86SMatthew G. Knepley   }
115084467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
11519072cb8bSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, cellidname, NULL, NULL, (void **)&cellid));
115284467f86SMatthew G. Knepley 
115384467f86SMatthew G. Knepley   // Set particle coordinates
11548214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
11558214e71cSJoe   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
11568214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
115784467f86SMatthew G. Knepley   PetscCall(DMGetBoundingBox(vdm, vmin, vmax));
115884467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(xdm));
115984467f86SMatthew G. Knepley   for (PetscInt c = 0; c < xcEnd - xcStart; ++c) {
116084467f86SMatthew G. Knepley     const PetscInt cell = c + xcStart;
11618214e71cSJoe     PetscInt      *pidx, Npc;
11628214e71cSJoe     PetscReal      centroid[3], volume;
11638214e71cSJoe 
11648214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
116584467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFVM(xdm, cell, &volume, centroid, NULL));
116684467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
116784467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q) {
116884467f86SMatthew G. Knepley         const PetscInt p = pidx[q * Ns + s];
11698214e71cSJoe 
117084467f86SMatthew G. Knepley         for (PetscInt d = 0; d < dim; ++d) {
11718214e71cSJoe           x[p * dim + d] = centroid[d];
117284467f86SMatthew G. Knepley           v[p * dim + d] = vmin[0] + (q + 0.5) * ((vmax[0] - vmin[0]) / (Npc / Ns));
11738214e71cSJoe         }
11749072cb8bSMatthew G. Knepley         if (debug > 1) {
11759072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "Particle %4" PetscInt_FMT " ", p));
11769072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  x: ("));
11779072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
11789072cb8bSMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
11799072cb8bSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", x[p * dim + d]));
11809072cb8bSMatthew G. Knepley           }
11819072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ") v:("));
11829072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
11839072cb8bSMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
11849072cb8bSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", v[p * dim + d]));
11859072cb8bSMatthew G. Knepley           }
11869072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
11879072cb8bSMatthew G. Knepley         }
11888214e71cSJoe       }
11898214e71cSJoe     }
119084467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
11918214e71cSJoe   }
11928214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
11938214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
11948214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
119584467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
119684467f86SMatthew G. Knepley }
119784467f86SMatthew G. Knepley 
119884467f86SMatthew G. Knepley /*
119984467f86SMatthew G. Knepley   InitializeWeights - Compute weight for each local particle
120084467f86SMatthew G. Knepley 
120184467f86SMatthew G. Knepley   Input Parameters:
120284467f86SMatthew G. Knepley + sw          - The `DMSwarm`
120384467f86SMatthew G. Knepley . totalWeight - The sum of all particle weights
120484467f86SMatthew G. Knepley . func        - The PDF for the particle spatial distribution
120584467f86SMatthew G. Knepley - param       - The PDF parameters
120684467f86SMatthew G. Knepley 
120784467f86SMatthew G. Knepley   Notes:
120884467f86SMatthew G. Knepley   The PDF for velocity is assumed to be a Gaussian
120984467f86SMatthew G. Knepley 
121084467f86SMatthew G. Knepley   The particle weights are returned in the `w_q` field of `sw`.
121184467f86SMatthew G. Knepley */
1212045208b8SMatthew G. Knepley static PetscErrorCode InitializeWeights(DM sw, PetscReal totalWeight, PetscProbFunc func, const PetscReal param[])
121384467f86SMatthew G. Knepley {
121484467f86SMatthew G. Knepley   DM               xdm, vdm;
1215045208b8SMatthew G. Knepley   DMSwarmCellDM    celldm;
121684467f86SMatthew G. Knepley   PetscScalar     *weight;
121784467f86SMatthew G. Knepley   PetscQuadrature  xquad;
121884467f86SMatthew G. Knepley   const PetscReal *xq, *xwq;
121984467f86SMatthew G. Knepley   const PetscInt   order = 5;
1220045208b8SMatthew G. Knepley   PetscReal        xi0[3];
122184467f86SMatthew G. Knepley   PetscReal        xwtot = 0., pwtot = 0.;
122284467f86SMatthew G. Knepley   PetscInt         xNq;
122384467f86SMatthew G. Knepley   PetscInt         dim, Ns, xcStart, xcEnd, vcStart, vcEnd, debug = ((DM_Swarm *)sw->data)->printWeights;
122484467f86SMatthew G. Knepley   MPI_Comm         comm;
122584467f86SMatthew G. Knepley   PetscMPIInt      rank;
122684467f86SMatthew G. Knepley 
122784467f86SMatthew G. Knepley   PetscFunctionBegin;
122884467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
122984467f86SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
123084467f86SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
123184467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
123284467f86SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
123384467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
1234045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
1235045208b8SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
123684467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
123784467f86SMatthew G. Knepley 
123884467f86SMatthew G. Knepley   // Setup Quadrature for spatial and velocity weight calculations
1239045208b8SMatthew G. Knepley   PetscCall(PetscDTGaussTensorQuadrature(dim, 1, order, -1.0, 1.0, &xquad));
124084467f86SMatthew G. Knepley   PetscCall(PetscQuadratureGetData(xquad, NULL, NULL, &xNq, &xq, &xwq));
124184467f86SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) xi0[d] = -1.0;
124284467f86SMatthew G. Knepley 
124384467f86SMatthew G. Knepley   // Integrate the density function to get the weights of particles in each cell
124484467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(vdm));
124584467f86SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
124684467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
124784467f86SMatthew G. Knepley   for (PetscInt c = xcStart; c < xcEnd; ++c) {
124884467f86SMatthew G. Knepley     PetscReal          xv0[3], xJ[9], xinvJ[9], xdetJ, xqr[3], xden, xw = 0.;
124984467f86SMatthew G. Knepley     PetscInt          *pidx, Npc;
125084467f86SMatthew G. Knepley     PetscInt           xNc;
125184467f86SMatthew G. Knepley     const PetscScalar *xarray;
125284467f86SMatthew G. Knepley     PetscScalar       *xcoords = NULL;
125384467f86SMatthew G. Knepley     PetscBool          xisDG;
125484467f86SMatthew G. Knepley 
125584467f86SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
125684467f86SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
125784467f86SMatthew 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);
125884467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFEM(xdm, c, NULL, xv0, xJ, xinvJ, &xdetJ));
125984467f86SMatthew G. Knepley     for (PetscInt q = 0; q < xNq; ++q) {
126084467f86SMatthew G. Knepley       // Transform quadrature points from ref space to real space
1261045208b8SMatthew G. Knepley       CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xq[q * dim], xqr);
126284467f86SMatthew G. Knepley       // Get probability density at quad point
126384467f86SMatthew G. Knepley       //   No need to scale xqr since PDF will be periodic
126484467f86SMatthew G. Knepley       PetscCall((*func)(xqr, param, &xden));
126584467f86SMatthew G. Knepley       xw += xden * (xwq[q] * xdetJ);
126684467f86SMatthew G. Knepley     }
126784467f86SMatthew G. Knepley     xwtot += xw;
126884467f86SMatthew G. Knepley     if (debug) {
126984467f86SMatthew G. Knepley       IS              globalOrdering;
127084467f86SMatthew G. Knepley       const PetscInt *ordering;
127184467f86SMatthew G. Knepley 
127284467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellNumbering(xdm, &globalOrdering));
127384467f86SMatthew G. Knepley       PetscCall(ISGetIndices(globalOrdering, &ordering));
127475155f48SMatthew 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));
127584467f86SMatthew G. Knepley       PetscCall(ISRestoreIndices(globalOrdering, &ordering));
127684467f86SMatthew G. Knepley     }
127784467f86SMatthew G. Knepley     // Set weights to be Gaussian in velocity cells
127884467f86SMatthew G. Knepley     for (PetscInt vc = vcStart; vc < vcEnd; ++vc) {
127984467f86SMatthew G. Knepley       const PetscInt     p  = pidx[vc * Ns + 0];
128084467f86SMatthew G. Knepley       PetscReal          vw = 0.;
128184467f86SMatthew G. Knepley       PetscInt           vNc;
128284467f86SMatthew G. Knepley       const PetscScalar *varray;
128384467f86SMatthew G. Knepley       PetscScalar       *vcoords = NULL;
128484467f86SMatthew G. Knepley       PetscBool          visDG;
128584467f86SMatthew G. Knepley 
128684467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
128784467f86SMatthew G. Knepley       // TODO: Fix 2 stream Ask Joe
128884467f86SMatthew G. Knepley       //   Two stream function from 1/2pi v^2 e^(-v^2/2)
128984467f86SMatthew 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.)));
129084467f86SMatthew G. Knepley       vw = 0.5 * (PetscErfReal(vcoords[1] / PetscSqrtReal(2.)) - PetscErfReal(vcoords[0] / PetscSqrtReal(2.)));
129184467f86SMatthew G. Knepley 
129284467f86SMatthew G. Knepley       weight[p] = totalWeight * vw * xw;
129384467f86SMatthew G. Knepley       pwtot += weight[p];
1294*bfe80ac4SPierre Jolivet       PetscCheck(weight[p] <= 10., PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Particle %" PetscInt_FMT " weight exceeded 1: %g, %g, %g", p, xw, vw, totalWeight);
129584467f86SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
129684467f86SMatthew G. Knepley       if (debug > 1) PetscCall(PetscPrintf(comm, "particle %" PetscInt_FMT ": %g, vw: %g xw: %g\n", p, weight[p], vw, xw));
129784467f86SMatthew G. Knepley     }
129884467f86SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
129984467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
130084467f86SMatthew G. Knepley   }
130184467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
130284467f86SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
130384467f86SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&xquad));
130484467f86SMatthew G. Knepley 
130584467f86SMatthew G. Knepley   if (debug) {
130684467f86SMatthew G. Knepley     PetscReal wtot[2] = {pwtot, xwtot}, gwtot[2];
130784467f86SMatthew G. Knepley 
130884467f86SMatthew G. Knepley     PetscCall(PetscSynchronizedFlush(comm, NULL));
130984467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(wtot, gwtot, 2, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
131084467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "particle weight sum = %1.10f cell weight sum = %1.10f\n", (double)gwtot[0], (double)gwtot[1]));
131184467f86SMatthew G. Knepley   }
131284467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
131384467f86SMatthew G. Knepley }
131484467f86SMatthew G. Knepley 
131584467f86SMatthew G. Knepley static PetscErrorCode InitializeParticles_PerturbedWeights(DM sw, AppCtx *user)
131684467f86SMatthew G. Knepley {
131784467f86SMatthew G. Knepley   PetscReal scale[2] = {user->cosine_coefficients[0], user->cosine_coefficients[1]};
131875155f48SMatthew G. Knepley   PetscInt  dim;
131984467f86SMatthew G. Knepley 
132084467f86SMatthew G. Knepley   PetscFunctionBegin;
132175155f48SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1322045208b8SMatthew G. Knepley   PetscCall(InitializeParticles_Centroid(sw));
1323045208b8SMatthew G. Knepley   PetscCall(InitializeWeights(sw, user->totalWeight, dim == 1 ? PetscPDFCosine1D : PetscPDFCosine2D, scale));
13248214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
13258214e71cSJoe }
13268214e71cSJoe 
13278214e71cSJoe static PetscErrorCode InitializeConstants(DM sw, AppCtx *user)
13288214e71cSJoe {
13298214e71cSJoe   DM         dm;
13308214e71cSJoe   PetscInt  *species;
13318214e71cSJoe   PetscReal *weight, totalCharge = 0., totalWeight = 0., gmin[3], gmax[3], global_charge, global_weight;
13328214e71cSJoe   PetscInt   Np, dim;
13338214e71cSJoe 
13348214e71cSJoe   PetscFunctionBegin;
13358214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &dm));
13368214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
13378214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
13388214e71cSJoe   PetscCall(DMGetBoundingBox(dm, gmin, gmax));
13398214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
13408214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
13418214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
13428214e71cSJoe     totalWeight += weight[p];
13438214e71cSJoe     totalCharge += user->charges[species[p]] * weight[p];
13448214e71cSJoe   }
13458214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
13468214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
13478214e71cSJoe   {
13488214e71cSJoe     Parameter *param;
13498214e71cSJoe     PetscReal  Area;
13508214e71cSJoe 
13518214e71cSJoe     PetscCall(PetscBagGetData(user->bag, (void **)&param));
13528214e71cSJoe     switch (dim) {
13538214e71cSJoe     case 1:
13548214e71cSJoe       Area = (gmax[0] - gmin[0]);
13558214e71cSJoe       break;
13568214e71cSJoe     case 2:
13578214e71cSJoe       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]);
13588214e71cSJoe       break;
13598214e71cSJoe     case 3:
13608214e71cSJoe       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]) * (gmax[2] - gmin[2]);
13618214e71cSJoe       break;
13628214e71cSJoe     default:
13638214e71cSJoe       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", dim);
13648214e71cSJoe     }
1365462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalWeight, &global_weight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
1366462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalCharge, &global_charge, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
13678214e71cSJoe     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));
13688214e71cSJoe     param->sigma = PetscAbsReal(global_charge / (Area));
13698214e71cSJoe 
13708214e71cSJoe     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "sigma: %g\n", (double)param->sigma));
13718214e71cSJoe     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,
13728214e71cSJoe                           (double)param->vlasovNumber));
13738214e71cSJoe   }
13748214e71cSJoe   /* Setup Constants */
13758214e71cSJoe   {
13768214e71cSJoe     PetscDS    ds;
13778214e71cSJoe     Parameter *param;
13788214e71cSJoe     PetscCall(PetscBagGetData(user->bag, (void **)&param));
13798214e71cSJoe     PetscScalar constants[NUM_CONSTANTS];
13808214e71cSJoe     constants[SIGMA]   = param->sigma;
13818214e71cSJoe     constants[V0]      = param->v0;
13828214e71cSJoe     constants[T0]      = param->t0;
13838214e71cSJoe     constants[X0]      = param->x0;
13848214e71cSJoe     constants[M0]      = param->m0;
13858214e71cSJoe     constants[Q0]      = param->q0;
13868214e71cSJoe     constants[PHI0]    = param->phi0;
13878214e71cSJoe     constants[POISSON] = param->poissonNumber;
13888214e71cSJoe     constants[VLASOV]  = param->vlasovNumber;
13898214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
13908214e71cSJoe     PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants));
13918214e71cSJoe   }
13928214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
13938214e71cSJoe }
13948214e71cSJoe 
13958214e71cSJoe static PetscErrorCode CreateSwarm(DM dm, AppCtx *user, DM *sw)
13968214e71cSJoe {
13979072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
13989072cb8bSMatthew G. Knepley   DM            vdm;
13998214e71cSJoe   PetscReal     v0[2] = {1., 0.};
14008214e71cSJoe   PetscInt      dim;
1401b80bf5b1SJoe Pusztay 
1402b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
14039566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
14049566063dSJacob Faibussowitsch   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw));
14059566063dSJacob Faibussowitsch   PetscCall(DMSetType(*sw, DMSWARM));
14069566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*sw, dim));
14079566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC));
1408045208b8SMatthew G. Knepley   PetscCall(DMSetApplicationContext(*sw, user));
14099072cb8bSMatthew G. Knepley 
14109566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR));
14118214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL));
14128214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "species", 1, PETSC_INT));
14138214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "E_field", dim, PETSC_REAL));
14149072cb8bSMatthew G. Knepley 
14159072cb8bSMatthew G. Knepley   const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"};
14169072cb8bSMatthew G. Knepley 
14179072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(dm, 2, fieldnames, 1, fieldnames, &celldm));
14189072cb8bSMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
14199072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
14209072cb8bSMatthew G. Knepley 
14219072cb8bSMatthew G. Knepley   const char *vfieldnames[1] = {"w_q"};
14229072cb8bSMatthew G. Knepley 
14239072cb8bSMatthew G. Knepley   PetscCall(CreateVelocityDM(*sw, &vdm));
14249072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(vdm, 1, vfieldnames, 1, &fieldnames[1], &celldm));
14259072cb8bSMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
14269072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
14279072cb8bSMatthew G. Knepley   PetscCall(DMDestroy(&vdm));
14289072cb8bSMatthew G. Knepley 
14294a0cbf56SMatthew G. Knepley   DM mdm;
14304a0cbf56SMatthew G. Knepley 
14314a0cbf56SMatthew G. Knepley   PetscCall(DMClone(dm, &mdm));
14324a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)mdm, "moments"));
14334a0cbf56SMatthew G. Knepley   PetscCall(DMCopyDisc(dm, mdm));
14344a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(mdm, 1, vfieldnames, 1, fieldnames, &celldm));
14354a0cbf56SMatthew G. Knepley   PetscCall(DMDestroy(&mdm));
14364a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
14374a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
14384a0cbf56SMatthew G. Knepley 
14399566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*sw));
1440045208b8SMatthew G. Knepley   PetscCall(DMSetUp(*sw));
1441045208b8SMatthew G. Knepley 
14429072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(*sw, "space"));
14438214e71cSJoe   user->swarm = *sw;
1444045208b8SMatthew G. Knepley   // TODO: This is redundant init since it is done in InitializeSolveAndSwarm, however DMSetUp() requires the local size be set
14458214e71cSJoe   if (user->perturbed_weights) {
14468214e71cSJoe     PetscCall(InitializeParticles_PerturbedWeights(*sw, user));
1447b80bf5b1SJoe Pusztay   } else {
14488214e71cSJoe     PetscCall(DMSwarmComputeLocalSizeFromOptions(*sw));
14498214e71cSJoe     PetscCall(DMSwarmInitializeCoordinates(*sw));
14508214e71cSJoe     PetscCall(DMSwarmInitializeVelocitiesFromOptions(*sw, v0));
1451b80bf5b1SJoe Pusztay   }
14529566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles"));
14539566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view"));
14543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1455b80bf5b1SJoe Pusztay }
1456b80bf5b1SJoe Pusztay 
14578214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Coulomb(SNES snes, DM sw, PetscReal E[])
1458d71ae5a4SJacob Faibussowitsch {
14598214e71cSJoe   AppCtx     *user;
14608214e71cSJoe   PetscReal  *coords;
14618214e71cSJoe   PetscInt   *species, dim, Np, Ns;
14628214e71cSJoe   PetscMPIInt size;
14638214e71cSJoe 
14648214e71cSJoe   PetscFunctionBegin;
14658214e71cSJoe   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)snes), &size));
14668214e71cSJoe   PetscCheck(size == 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Coulomb code only works in serial");
14678214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
14688214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
14698214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
14708214e71cSJoe   PetscCall(DMGetApplicationContext(sw, (void *)&user));
14718214e71cSJoe 
14728214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
14738214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
14748214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
14758214e71cSJoe     PetscReal *pcoord = &coords[p * dim];
14768214e71cSJoe     PetscReal  pE[3]  = {0., 0., 0.};
14778214e71cSJoe 
14788214e71cSJoe     /* Calculate field at particle p due to particle q */
14798214e71cSJoe     for (PetscInt q = 0; q < Np; ++q) {
14808214e71cSJoe       PetscReal *qcoord = &coords[q * dim];
14818214e71cSJoe       PetscReal  rpq[3], r, r3, q_q;
14828214e71cSJoe 
14838214e71cSJoe       if (p == q) continue;
14848214e71cSJoe       q_q = user->charges[species[q]] * 1.;
14858214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) rpq[d] = pcoord[d] - qcoord[d];
14868214e71cSJoe       r = DMPlex_NormD_Internal(dim, rpq);
14878214e71cSJoe       if (r < PETSC_SQRT_MACHINE_EPSILON) continue;
14888214e71cSJoe       r3 = PetscPowRealInt(r, 3);
14898214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pE[d] += q_q * rpq[d] / r3;
14908214e71cSJoe     }
14918214e71cSJoe     for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = pE[d];
14928214e71cSJoe   }
14938214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
14948214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
14958214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
14968214e71cSJoe }
14978214e71cSJoe 
14984a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Primal(SNES snes, DM sw, Mat M_p, PetscReal E[])
14998214e71cSJoe {
1500b80bf5b1SJoe Pusztay   DM         dm;
15018214e71cSJoe   AppCtx    *user;
15028214e71cSJoe   PetscDS    ds;
15038214e71cSJoe   PetscFE    fe;
15044a0cbf56SMatthew G. Knepley   KSP        ksp;
150575155f48SMatthew G. Knepley   Vec        rhoRhs;      // Weak charge density, \int phi_i rho
150675155f48SMatthew G. Knepley   Vec        rho;         // Charge density, M^{-1} rhoRhs
150775155f48SMatthew G. Knepley   Vec        phi, locPhi; // Potential
150875155f48SMatthew G. Knepley   Vec        f;           // Particle weights
15098214e71cSJoe   PetscReal *coords;
15108214e71cSJoe   PetscInt   dim, cStart, cEnd, Np;
15118214e71cSJoe 
15128214e71cSJoe   PetscFunctionBegin;
151384467f86SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, (void *)&user));
151484467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
15158214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
15168214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
15178214e71cSJoe 
15188214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
151975155f48SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhs));
152075155f48SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
15214a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
15228214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
15238214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
152475155f48SMatthew G. Knepley 
15258214e71cSJoe   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
1526f1e6e573SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->M, NULL, "-m_view"));
15278214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
152875155f48SMatthew G. Knepley 
152975155f48SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
15308214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
15318214e71cSJoe 
1532fd7102fcSMatthew G. Knepley   // Low-pass filter rhoRhs
1533fd7102fcSMatthew G. Knepley   PetscInt window = 0;
1534fd7102fcSMatthew G. Knepley   PetscCall(PetscOptionsGetInt(NULL, NULL, "-rho_average", &window, NULL));
1535fd7102fcSMatthew G. Knepley   if (window) {
1536fd7102fcSMatthew G. Knepley     PetscScalar *a;
1537fd7102fcSMatthew G. Knepley     PetscInt     n;
1538fd7102fcSMatthew G. Knepley     PetscReal    width = 2. * window + 1.;
1539fd7102fcSMatthew G. Knepley 
1540fd7102fcSMatthew G. Knepley     // This will only work for P_1
1541fd7102fcSMatthew G. Knepley     //   This works because integration against a test function is linear
1542fd7102fcSMatthew G. Knepley     //   This only works in serial since I need the periodic values (maybe use FFT)
1543fd7102fcSMatthew G. Knepley     //   Do a real integral against weight function for higher order
1544fd7102fcSMatthew G. Knepley     PetscCall(VecGetLocalSize(rhoRhs, &n));
1545fd7102fcSMatthew G. Knepley     PetscCall(VecGetArrayWrite(rhoRhs, &a));
1546fd7102fcSMatthew G. Knepley     for (PetscInt i = 0; i < n; ++i) {
1547fd7102fcSMatthew G. Knepley       PetscScalar avg = a[i];
1548fd7102fcSMatthew G. Knepley       for (PetscInt j = 1; j <= window; ++j) avg += a[(i - j + n) % n] + a[(i + j) % n];
1549fd7102fcSMatthew G. Knepley       a[i] = avg / width;
1550fd7102fcSMatthew G. Knepley       //a[i] = (a[(i - 1 + n) % n] + a[i] + a[(i + 1) % n]) / 3.;
1551fd7102fcSMatthew G. Knepley     }
1552fd7102fcSMatthew G. Knepley     PetscCall(VecRestoreArrayWrite(rhoRhs, &a));
1553fd7102fcSMatthew G. Knepley   }
1554fd7102fcSMatthew G. Knepley 
15558214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
15568214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj_"));
1557f1e6e573SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->M, user->M));
15588214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
155975155f48SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
15608214e71cSJoe 
156175155f48SMatthew G. Knepley   PetscCall(VecScale(rhoRhs, -1.0));
15628214e71cSJoe 
156375155f48SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
15644a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
15658214e71cSJoe   PetscCall(KSPDestroy(&ksp));
15668214e71cSJoe 
15674a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
15688214e71cSJoe   PetscCall(VecSet(phi, 0.0));
156975155f48SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhs, phi));
157075155f48SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhs));
15718214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
15728214e71cSJoe 
15738214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
15748214e71cSJoe   PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi));
15758214e71cSJoe   PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi));
15764a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
157784467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
15788214e71cSJoe 
15798214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
15808214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
15818214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
15828214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
15838214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
15848214e71cSJoe 
158584467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
15868214e71cSJoe   PetscTabulation tab;
15878214e71cSJoe   PetscReal      *pcoord, *refcoord;
1588045208b8SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
1589045208b8SMatthew G. Knepley   PetscInt        maxNcp    = 0;
1590045208b8SMatthew G. Knepley 
1591045208b8SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1592045208b8SMatthew G. Knepley     PetscInt Ncp;
1593045208b8SMatthew G. Knepley 
1594045208b8SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
1595045208b8SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
1596045208b8SMatthew G. Knepley   }
1597045208b8SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1598045208b8SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1599045208b8SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
1600045208b8SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1601045208b8SMatthew G. Knepley     PetscScalar *clPhi = NULL;
16028214e71cSJoe     PetscInt    *points;
16038214e71cSJoe     PetscInt     Ncp;
16048214e71cSJoe 
16058214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
16068214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
16078214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1608f1e6e573SMatthew G. Knepley     {
1609f1e6e573SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1610f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1611f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1612f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1613f1e6e573SMatthew G. Knepley       }
1614f1e6e573SMatthew G. Knepley     }
1615045208b8SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
16168214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
16178214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
16188214e71cSJoe       const PetscReal *basisDer = tab->T[1];
16198214e71cSJoe       const PetscInt   p        = points[cp];
16208214e71cSJoe 
16218214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1622f1e6e573SMatthew G. Knepley       PetscCall(PetscFEFreeInterpolateGradient_Static(fe, basisDer, clPhi, dim, chunkgeom->invJ, NULL, cp, &E[p * dim]));
1623045208b8SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
16248214e71cSJoe     }
16258214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
162684467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
16278214e71cSJoe   }
1628045208b8SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1629045208b8SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1630045208b8SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
16318214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
16328214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
16338214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1634f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
163584467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
16368214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16378214e71cSJoe }
16388214e71cSJoe 
16394a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Mixed(SNES snes, DM sw, Mat M_p, PetscReal E[])
16408214e71cSJoe {
16414a0cbf56SMatthew G. Knepley   DM         dm;
16428214e71cSJoe   AppCtx    *user;
16438214e71cSJoe   PetscDS    ds;
16448214e71cSJoe   PetscFE    fe;
16454a0cbf56SMatthew G. Knepley   KSP        ksp;
16464a0cbf56SMatthew G. Knepley   Vec        rhoRhs, rhoRhsFull;   // Weak charge density, \int phi_i rho, and embedding in mixed problem
16474a0cbf56SMatthew G. Knepley   Vec        rho;                  // Charge density, M^{-1} rhoRhs
16484a0cbf56SMatthew G. Knepley   Vec        phi, locPhi, phiFull; // Potential and embedding in mixed problem
16494a0cbf56SMatthew G. Knepley   Vec        f;                    // Particle weights
165075155f48SMatthew G. Knepley   PetscReal *coords;
16514a0cbf56SMatthew G. Knepley   PetscInt   dim, cStart, cEnd, Np;
16528214e71cSJoe 
16538214e71cSJoe   PetscFunctionBegin;
165484467f86SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &user));
165584467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
16568214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16578214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
16588214e71cSJoe 
16598214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
16604a0cbf56SMatthew G. Knepley   PetscCall(DMGetGlobalVector(user->dmPot, &rhoRhs));
16614a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
16624a0cbf56SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhsFull));
16634a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhsFull, "Weak charge density"));
16644a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
16658214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
16668214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
16674a0cbf56SMatthew G. Knepley 
16684a0cbf56SMatthew G. Knepley   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
16694a0cbf56SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->M, NULL, "-m_view"));
16708214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
16714a0cbf56SMatthew G. Knepley 
16724a0cbf56SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
16738214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
16748214e71cSJoe 
16758214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
16768214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj"));
16774a0cbf56SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->M, user->M));
16788214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
16794a0cbf56SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
16808214e71cSJoe 
16814a0cbf56SMatthew G. Knepley   PetscCall(VecISCopy(rhoRhsFull, user->isPot, SCATTER_FORWARD, rhoRhs));
16824a0cbf56SMatthew G. Knepley   //PetscCall(VecScale(rhoRhsFull, -1.0));
16838214e71cSJoe 
16844a0cbf56SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
16854a0cbf56SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhsFull, NULL, "-rho_full_view"));
16864a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
16874a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(user->dmPot, &rhoRhs));
16888214e71cSJoe   PetscCall(KSPDestroy(&ksp));
16898214e71cSJoe 
16904a0cbf56SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &phiFull));
16914a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
16924a0cbf56SMatthew G. Knepley   PetscCall(VecSet(phiFull, 0.0));
16934a0cbf56SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhsFull, phiFull));
16944a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhsFull));
16958214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
16968214e71cSJoe 
16974a0cbf56SMatthew G. Knepley   PetscCall(VecISCopy(phiFull, user->isPot, SCATTER_REVERSE, phi));
16984a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
16994a0cbf56SMatthew G. Knepley 
17008214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
17014a0cbf56SMatthew G. Knepley   PetscCall(DMGlobalToLocalBegin(dm, phiFull, INSERT_VALUES, locPhi));
17024a0cbf56SMatthew G. Knepley   PetscCall(DMGlobalToLocalEnd(dm, phiFull, INSERT_VALUES, locPhi));
17034a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &phiFull));
170484467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
17058214e71cSJoe 
17068214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
17078214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
17088214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
17098214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
17108214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
17114a0cbf56SMatthew G. Knepley 
17124a0cbf56SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
17138214e71cSJoe   PetscTabulation tab;
17148214e71cSJoe   PetscReal      *pcoord, *refcoord;
17154a0cbf56SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
17164a0cbf56SMatthew G. Knepley   PetscInt        maxNcp    = 0;
17174a0cbf56SMatthew G. Knepley 
17184a0cbf56SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
17194a0cbf56SMatthew G. Knepley     PetscInt Ncp;
17204a0cbf56SMatthew G. Knepley 
17214a0cbf56SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
17224a0cbf56SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
17234a0cbf56SMatthew G. Knepley   }
17244a0cbf56SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
17254a0cbf56SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
17264a0cbf56SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
17274a0cbf56SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
17284a0cbf56SMatthew G. Knepley     PetscScalar *clPhi = NULL;
17298214e71cSJoe     PetscInt    *points;
17308214e71cSJoe     PetscInt     Ncp;
17318214e71cSJoe 
17328214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
17338214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
17348214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1735f1e6e573SMatthew G. Knepley     {
1736f1e6e573SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1737f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1738f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1739f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1740f1e6e573SMatthew G. Knepley       }
1741f1e6e573SMatthew G. Knepley     }
17424a0cbf56SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
17438214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
17448214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
17458214e71cSJoe       const PetscInt p = points[cp];
17468214e71cSJoe 
17478214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1748f1e6e573SMatthew G. Knepley       PetscCall(PetscFEInterpolateAtPoints_Static(fe, tab, clPhi, chunkgeom, cp, &E[p * dim]));
1749f1e6e573SMatthew G. Knepley       PetscCall(PetscFEPushforward(fe, chunkgeom, 1, &E[p * dim]));
17504a0cbf56SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
17518214e71cSJoe     }
17528214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
175384467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
17548214e71cSJoe   }
17554a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
17564a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
17574a0cbf56SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
17588214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
17598214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
17608214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1761f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
176284467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
17638214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
17648214e71cSJoe }
17658214e71cSJoe 
17664a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles(SNES snes, DM sw)
17678214e71cSJoe {
17684a0cbf56SMatthew G. Knepley   AppCtx    *user;
17694a0cbf56SMatthew G. Knepley   Mat        M_p;
17704a0cbf56SMatthew G. Knepley   PetscReal *E;
17718214e71cSJoe   PetscInt   dim, Np;
17728214e71cSJoe 
17738214e71cSJoe   PetscFunctionBegin;
17748214e71cSJoe   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
17758214e71cSJoe   PetscValidHeaderSpecific(sw, DM_CLASSID, 2);
17768214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
17778214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
17784a0cbf56SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &user));
17798214e71cSJoe 
17804a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "moments"));
17814a0cbf56SMatthew G. Knepley   // TODO: Could share sort context with space cellDM
17824a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmMigrate(sw, PETSC_FALSE));
17834a0cbf56SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(sw, user->dmPot, &M_p));
17844a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
17854a0cbf56SMatthew G. Knepley 
17864a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
17874a0cbf56SMatthew G. Knepley   PetscCall(PetscArrayzero(E, Np * dim));
17884a0cbf56SMatthew G. Knepley   user->validE = PETSC_TRUE;
17894a0cbf56SMatthew G. Knepley 
17904a0cbf56SMatthew G. Knepley   switch (user->em) {
17918214e71cSJoe   case EM_COULOMB:
17928214e71cSJoe     PetscCall(ComputeFieldAtParticles_Coulomb(snes, sw, E));
17938214e71cSJoe     break;
17944a0cbf56SMatthew G. Knepley   case EM_PRIMAL:
17954a0cbf56SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Primal(snes, sw, M_p, E));
17964a0cbf56SMatthew G. Knepley     break;
17978214e71cSJoe   case EM_MIXED:
17984a0cbf56SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Mixed(snes, sw, M_p, E));
17998214e71cSJoe     break;
18008214e71cSJoe   case EM_NONE:
18018214e71cSJoe     break;
18028214e71cSJoe   default:
18034a0cbf56SMatthew G. Knepley     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No solver for electrostatic model %s", EMTypes[user->em]);
18048214e71cSJoe   }
18054a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
18064a0cbf56SMatthew G. Knepley   PetscCall(MatDestroy(&M_p));
18078214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18088214e71cSJoe }
18098214e71cSJoe 
18108214e71cSJoe static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec G, void *ctx)
18118214e71cSJoe {
18128214e71cSJoe   DM                 sw;
18138214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
18148214e71cSJoe   const PetscScalar *u;
18158214e71cSJoe   PetscScalar       *g;
18168214e71cSJoe   PetscReal         *E, m_p = 1., q_p = -1.;
18178214e71cSJoe   PetscInt           dim, d, Np, p;
1818b80bf5b1SJoe Pusztay 
1819b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
18208214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
18214a0cbf56SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
18224a0cbf56SMatthew G. Knepley 
18238214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
18248214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
18254a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
18268214e71cSJoe   PetscCall(VecGetArrayRead(U, &u));
18278214e71cSJoe   PetscCall(VecGetArray(G, &g));
18288214e71cSJoe   Np /= 2 * dim;
18298214e71cSJoe   for (p = 0; p < Np; ++p) {
18308214e71cSJoe     for (d = 0; d < dim; ++d) {
18318214e71cSJoe       g[(p * 2 + 0) * dim + d] = u[(p * 2 + 1) * dim + d];
18328214e71cSJoe       g[(p * 2 + 1) * dim + d] = q_p * E[p * dim + d] / m_p;
18338214e71cSJoe     }
18348214e71cSJoe   }
18358214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
18368214e71cSJoe   PetscCall(VecRestoreArrayRead(U, &u));
18378214e71cSJoe   PetscCall(VecRestoreArray(G, &g));
18388214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18398214e71cSJoe }
18408214e71cSJoe 
18418214e71cSJoe /* J_{ij} = dF_i/dx_j
18428214e71cSJoe    J_p = (  0   1)
18438214e71cSJoe          (-w^2  0)
18448214e71cSJoe    TODO Now there is another term with w^2 from the electric field. I think we will need to invert the operator.
18458214e71cSJoe         Perhaps we can approximate the Jacobian using only the cellwise P-P gradient from Coulomb
18468214e71cSJoe */
18478214e71cSJoe static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat P, void *ctx)
18488214e71cSJoe {
18498214e71cSJoe   DM               sw;
18508214e71cSJoe   const PetscReal *coords, *vel;
18518214e71cSJoe   PetscInt         dim, d, Np, p, rStart;
18528214e71cSJoe 
18538214e71cSJoe   PetscFunctionBeginUser;
18548214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
18558214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
18568214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
18578214e71cSJoe   PetscCall(MatGetOwnershipRange(J, &rStart, NULL));
1858045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1859045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
18608214e71cSJoe   Np /= 2 * dim;
18618214e71cSJoe   for (p = 0; p < Np; ++p) {
18628214e71cSJoe     const PetscReal x0      = coords[p * dim + 0];
18638214e71cSJoe     const PetscReal vy0     = vel[p * dim + 1];
18648214e71cSJoe     const PetscReal omega   = vy0 / x0;
18658214e71cSJoe     PetscScalar     vals[4] = {0., 1., -PetscSqr(omega), 0.};
18668214e71cSJoe 
18678214e71cSJoe     for (d = 0; d < dim; ++d) {
18688214e71cSJoe       const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart};
18698214e71cSJoe       PetscCall(MatSetValues(J, 2, rows, 2, rows, vals, INSERT_VALUES));
18708214e71cSJoe     }
18718214e71cSJoe   }
1872045208b8SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1873045208b8SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
18748214e71cSJoe   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
18758214e71cSJoe   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
18768214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18778214e71cSJoe }
18788214e71cSJoe 
18798214e71cSJoe static PetscErrorCode RHSFunctionX(TS ts, PetscReal t, Vec V, Vec Xres, void *ctx)
18808214e71cSJoe {
18818214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
18828214e71cSJoe   DM                 sw;
18838214e71cSJoe   const PetscScalar *v;
18848214e71cSJoe   PetscScalar       *xres;
18858214e71cSJoe   PetscInt           Np, p, d, dim;
18868214e71cSJoe 
18878214e71cSJoe   PetscFunctionBeginUser;
188884467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsXEvent, ts, 0, 0, 0));
18898214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
18908214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
18918214e71cSJoe   PetscCall(VecGetLocalSize(Xres, &Np));
18929566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(V, &v));
18938214e71cSJoe   PetscCall(VecGetArray(Xres, &xres));
1894b80bf5b1SJoe Pusztay   Np /= dim;
1895b80bf5b1SJoe Pusztay   for (p = 0; p < Np; ++p) {
1896045208b8SMatthew G. Knepley     for (d = 0; d < dim; ++d) xres[p * dim + d] = v[p * dim + d];
1897b80bf5b1SJoe Pusztay   }
18989566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(V, &v));
18998214e71cSJoe   PetscCall(VecRestoreArray(Xres, &xres));
190084467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsXEvent, ts, 0, 0, 0));
19013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1902b80bf5b1SJoe Pusztay }
1903b80bf5b1SJoe Pusztay 
19048214e71cSJoe static PetscErrorCode RHSFunctionV(TS ts, PetscReal t, Vec X, Vec Vres, void *ctx)
19058214e71cSJoe {
19068214e71cSJoe   DM                 sw;
19078214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
19088214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
19098214e71cSJoe   const PetscScalar *x;
19108214e71cSJoe   PetscScalar       *vres;
19114a0cbf56SMatthew G. Knepley   PetscReal         *E, m_p, q_p;
19128214e71cSJoe   PetscInt           Np, p, dim, d;
19138214e71cSJoe   Parameter         *param;
19148214e71cSJoe 
19158214e71cSJoe   PetscFunctionBeginUser;
191684467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsVEvent, ts, 0, 0, 0));
19178214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19184a0cbf56SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
19194a0cbf56SMatthew G. Knepley 
19208214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
19218214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
19228214e71cSJoe   PetscCall(PetscBagGetData(user->bag, (void **)&param));
19238214e71cSJoe   m_p = user->masses[0] * param->m0;
19248214e71cSJoe   q_p = user->charges[0] * param->q0;
19258214e71cSJoe   PetscCall(VecGetLocalSize(Vres, &Np));
19268214e71cSJoe   PetscCall(VecGetArrayRead(X, &x));
19278214e71cSJoe   PetscCall(VecGetArray(Vres, &vres));
19288214e71cSJoe   Np /= dim;
19298214e71cSJoe   for (p = 0; p < Np; ++p) {
1930045208b8SMatthew G. Knepley     for (d = 0; d < dim; ++d) vres[p * dim + d] = q_p * E[p * dim + d] / m_p;
19318214e71cSJoe   }
19328214e71cSJoe   PetscCall(VecRestoreArrayRead(X, &x));
19338214e71cSJoe   /*
1934d7c1f440SPierre Jolivet     Synchronized, ordered output for parallel/sequential test cases.
19358214e71cSJoe     In the 1D (on the 2D mesh) case, every y component should be zero.
19368214e71cSJoe   */
19378214e71cSJoe   if (user->checkVRes) {
19388214e71cSJoe     PetscBool pr = user->checkVRes > 1 ? PETSC_TRUE : PETSC_FALSE;
19398214e71cSJoe     PetscInt  step;
19408214e71cSJoe 
19418214e71cSJoe     PetscCall(TSGetStepNumber(ts, &step));
19428214e71cSJoe     if (pr) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step: %" PetscInt_FMT "\n", step));
19438214e71cSJoe     for (PetscInt p = 0; p < Np; ++p) {
19448214e71cSJoe       if (pr) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Residual: %.12g %.12g\n", (double)PetscRealPart(vres[p * dim + 0]), (double)PetscRealPart(vres[p * dim + 1])));
19458214e71cSJoe       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]));
19468214e71cSJoe     }
19478214e71cSJoe     if (pr) PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
19488214e71cSJoe   }
19498214e71cSJoe   PetscCall(VecRestoreArray(Vres, &vres));
19508214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
195184467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsVEvent, ts, 0, 0, 0));
19528214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
19538214e71cSJoe }
19548214e71cSJoe 
19558214e71cSJoe static PetscErrorCode CreateSolution(TS ts)
19568214e71cSJoe {
19578214e71cSJoe   DM       sw;
19588214e71cSJoe   Vec      u;
19598214e71cSJoe   PetscInt dim, Np;
19608214e71cSJoe 
19618214e71cSJoe   PetscFunctionBegin;
19628214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19638214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
19648214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
19658214e71cSJoe   PetscCall(VecCreate(PETSC_COMM_WORLD, &u));
19668214e71cSJoe   PetscCall(VecSetBlockSize(u, dim));
19678214e71cSJoe   PetscCall(VecSetSizes(u, 2 * Np * dim, PETSC_DECIDE));
19688214e71cSJoe   PetscCall(VecSetUp(u));
19698214e71cSJoe   PetscCall(TSSetSolution(ts, u));
19708214e71cSJoe   PetscCall(VecDestroy(&u));
19718214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
19728214e71cSJoe }
19738214e71cSJoe 
19748214e71cSJoe static PetscErrorCode SetProblem(TS ts)
19758214e71cSJoe {
19768214e71cSJoe   AppCtx *user;
19778214e71cSJoe   DM      sw;
19788214e71cSJoe 
19798214e71cSJoe   PetscFunctionBegin;
19808214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19818214e71cSJoe   PetscCall(DMGetApplicationContext(sw, (void **)&user));
19828214e71cSJoe   // Define unified system for (X, V)
19838214e71cSJoe   {
19848214e71cSJoe     Mat      J;
19858214e71cSJoe     PetscInt dim, Np;
19868214e71cSJoe 
19878214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
19888214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
19898214e71cSJoe     PetscCall(MatCreate(PETSC_COMM_WORLD, &J));
19908214e71cSJoe     PetscCall(MatSetSizes(J, 2 * Np * dim, 2 * Np * dim, PETSC_DECIDE, PETSC_DECIDE));
19918214e71cSJoe     PetscCall(MatSetBlockSize(J, 2 * dim));
19928214e71cSJoe     PetscCall(MatSetFromOptions(J));
19938214e71cSJoe     PetscCall(MatSetUp(J));
19948214e71cSJoe     PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, user));
19958214e71cSJoe     PetscCall(TSSetRHSJacobian(ts, J, J, RHSJacobian, user));
19968214e71cSJoe     PetscCall(MatDestroy(&J));
19978214e71cSJoe   }
19988214e71cSJoe   /* Define split system for X and V */
19998214e71cSJoe   {
20008214e71cSJoe     Vec             u;
20018214e71cSJoe     IS              isx, isv, istmp;
20028214e71cSJoe     const PetscInt *idx;
20038214e71cSJoe     PetscInt        dim, Np, rstart;
20048214e71cSJoe 
20058214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
20068214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
20078214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
20088214e71cSJoe     PetscCall(VecGetOwnershipRange(u, &rstart, NULL));
20098214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 0, 2, &istmp));
20108214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
20118214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isx));
20128214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
20138214e71cSJoe     PetscCall(ISDestroy(&istmp));
20148214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 1, 2, &istmp));
20158214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
20168214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isv));
20178214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
20188214e71cSJoe     PetscCall(ISDestroy(&istmp));
20198214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "position", isx));
20208214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "momentum", isv));
20218214e71cSJoe     PetscCall(ISDestroy(&isx));
20228214e71cSJoe     PetscCall(ISDestroy(&isv));
20238214e71cSJoe     PetscCall(TSRHSSplitSetRHSFunction(ts, "position", NULL, RHSFunctionX, user));
20248214e71cSJoe     PetscCall(TSRHSSplitSetRHSFunction(ts, "momentum", NULL, RHSFunctionV, user));
20258214e71cSJoe   }
20268214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
20278214e71cSJoe }
20288214e71cSJoe 
20298214e71cSJoe static PetscErrorCode DMSwarmTSRedistribute(TS ts)
20308214e71cSJoe {
20318214e71cSJoe   DM        sw;
20328214e71cSJoe   Vec       u;
20338214e71cSJoe   PetscReal t, maxt, dt;
20348214e71cSJoe   PetscInt  n, maxn;
20358214e71cSJoe 
20368214e71cSJoe   PetscFunctionBegin;
20378214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
20388214e71cSJoe   PetscCall(TSGetTime(ts, &t));
20398214e71cSJoe   PetscCall(TSGetMaxTime(ts, &maxt));
20408214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
20418214e71cSJoe   PetscCall(TSGetStepNumber(ts, &n));
20428214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
20438214e71cSJoe 
20448214e71cSJoe   PetscCall(TSReset(ts));
20458214e71cSJoe   PetscCall(TSSetDM(ts, sw));
20468214e71cSJoe   PetscCall(TSSetFromOptions(ts));
20478214e71cSJoe   PetscCall(TSSetTime(ts, t));
20488214e71cSJoe   PetscCall(TSSetMaxTime(ts, maxt));
20498214e71cSJoe   PetscCall(TSSetTimeStep(ts, dt));
20508214e71cSJoe   PetscCall(TSSetStepNumber(ts, n));
20518214e71cSJoe   PetscCall(TSSetMaxSteps(ts, maxn));
20528214e71cSJoe 
20538214e71cSJoe   PetscCall(CreateSolution(ts));
20548214e71cSJoe   PetscCall(SetProblem(ts));
20558214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
20568214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
20578214e71cSJoe }
20588214e71cSJoe 
20598214e71cSJoe PetscErrorCode line(PetscInt dim, PetscReal time, const PetscReal dummy[], PetscInt p, PetscScalar x[], void *ctx)
20608214e71cSJoe {
20618214e71cSJoe   DM        sw, cdm;
20628214e71cSJoe   PetscInt  Np;
20638214e71cSJoe   PetscReal low[2], high[2];
20648214e71cSJoe   AppCtx   *user = (AppCtx *)ctx;
20658214e71cSJoe 
20668214e71cSJoe   sw = user->swarm;
20678214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &cdm));
20688214e71cSJoe   // Get the bounding box so we can equally space the particles
20698214e71cSJoe   PetscCall(DMGetLocalBoundingBox(cdm, low, high));
20708214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
20718214e71cSJoe   // shift it by h/2 so nothing is initialized directly on a boundary
20728214e71cSJoe   x[0] = ((high[0] - low[0]) / Np) * (p + 0.5);
20738214e71cSJoe   x[1] = 0.;
20748214e71cSJoe   return PETSC_SUCCESS;
20758214e71cSJoe }
20768214e71cSJoe 
2077b80bf5b1SJoe Pusztay /*
20788214e71cSJoe   InitializeSolveAndSwarm - Set the solution values to the swarm coordinates and velocities, and also possibly set the initial values.
20798214e71cSJoe 
20808214e71cSJoe   Input Parameters:
20818214e71cSJoe + ts         - The TS
2082d7c1f440SPierre Jolivet - useInitial - Flag to also set the initial conditions to the current coordinates and velocities and setup the problem
20838214e71cSJoe 
20848214e71cSJoe   Output Parameters:
20858214e71cSJoe . u - The initialized solution vector
20868214e71cSJoe 
20878214e71cSJoe   Level: advanced
20888214e71cSJoe 
20898214e71cSJoe .seealso: InitializeSolve()
2090b80bf5b1SJoe Pusztay */
20918214e71cSJoe static PetscErrorCode InitializeSolveAndSwarm(TS ts, PetscBool useInitial)
2092d71ae5a4SJacob Faibussowitsch {
20938214e71cSJoe   DM       sw;
2094045208b8SMatthew G. Knepley   Vec      u, gc, gv;
20958214e71cSJoe   IS       isx, isv;
20968214e71cSJoe   PetscInt dim;
20978214e71cSJoe   AppCtx  *user;
2098b80bf5b1SJoe Pusztay 
2099b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
21008214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
21018214e71cSJoe   PetscCall(DMGetApplicationContext(sw, &user));
21028214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
21038214e71cSJoe   if (useInitial) {
21048214e71cSJoe     PetscReal v0[2] = {1., 0.};
21058214e71cSJoe     if (user->perturbed_weights) {
21068214e71cSJoe       PetscCall(InitializeParticles_PerturbedWeights(sw, user));
21078214e71cSJoe     } else {
21088214e71cSJoe       PetscCall(DMSwarmComputeLocalSizeFromOptions(sw));
21098214e71cSJoe       PetscCall(DMSwarmInitializeCoordinates(sw));
21108214e71cSJoe       PetscCall(DMSwarmInitializeVelocitiesFromOptions(sw, v0));
21118214e71cSJoe     }
21128214e71cSJoe     PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
21138214e71cSJoe     PetscCall(DMSwarmTSRedistribute(ts));
21148214e71cSJoe   }
2115045208b8SMatthew G. Knepley   PetscCall(DMSetUp(sw));
21168214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
21178214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
21188214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
21198214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
21208214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
21218214e71cSJoe   PetscCall(VecISCopy(u, isx, SCATTER_FORWARD, gc));
21228214e71cSJoe   PetscCall(VecISCopy(u, isv, SCATTER_FORWARD, gv));
21238214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
21248214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
21258214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
21268214e71cSJoe }
21278214e71cSJoe 
21288214e71cSJoe static PetscErrorCode InitializeSolve(TS ts, Vec u)
2129b80bf5b1SJoe Pusztay {
21308214e71cSJoe   PetscFunctionBegin;
21318214e71cSJoe   PetscCall(TSSetSolution(ts, u));
21328214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_TRUE));
21338214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
2134b80bf5b1SJoe Pusztay }
2135b80bf5b1SJoe Pusztay 
21368214e71cSJoe static PetscErrorCode MigrateParticles(TS ts)
21378214e71cSJoe {
21388214e71cSJoe   DM               sw, cdm;
21398214e71cSJoe   const PetscReal *L;
21409072cb8bSMatthew G. Knepley   AppCtx          *ctx;
21418214e71cSJoe 
21428214e71cSJoe   PetscFunctionBeginUser;
21438214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
21449072cb8bSMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &ctx));
21458214e71cSJoe   PetscCall(DMViewFromOptions(sw, NULL, "-migrate_view_pre"));
21468214e71cSJoe   {
21478214e71cSJoe     Vec        u, gc, gv, position, momentum;
21488214e71cSJoe     IS         isx, isv;
21498214e71cSJoe     PetscReal *pos, *mom;
21508214e71cSJoe 
21518214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
21528214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
21538214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
21548214e71cSJoe     PetscCall(VecGetSubVector(u, isx, &position));
21558214e71cSJoe     PetscCall(VecGetSubVector(u, isv, &momentum));
21568214e71cSJoe     PetscCall(VecGetArray(position, &pos));
21578214e71cSJoe     PetscCall(VecGetArray(momentum, &mom));
21588214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
21598214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
21608214e71cSJoe     PetscCall(VecISCopy(u, isx, SCATTER_REVERSE, gc));
21618214e71cSJoe     PetscCall(VecISCopy(u, isv, SCATTER_REVERSE, gv));
21628214e71cSJoe 
21638214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &cdm));
21648214e71cSJoe     PetscCall(DMGetPeriodicity(cdm, NULL, NULL, &L));
21658214e71cSJoe     if ((L[0] || L[1]) >= 0.) {
21668214e71cSJoe       PetscReal *x, *v, upper[3], lower[3];
21678214e71cSJoe       PetscInt   Np, dim;
21688214e71cSJoe 
21698214e71cSJoe       PetscCall(DMSwarmGetLocalSize(sw, &Np));
21708214e71cSJoe       PetscCall(DMGetDimension(cdm, &dim));
21718214e71cSJoe       PetscCall(DMGetBoundingBox(cdm, lower, upper));
21728214e71cSJoe       PetscCall(VecGetArray(gc, &x));
21738214e71cSJoe       PetscCall(VecGetArray(gv, &v));
21748214e71cSJoe       for (PetscInt p = 0; p < Np; ++p) {
21758214e71cSJoe         for (PetscInt d = 0; d < dim; ++d) {
21768214e71cSJoe           if (pos[p * dim + d] < lower[d]) {
21778214e71cSJoe             x[p * dim + d] = pos[p * dim + d] + (upper[d] - lower[d]);
21788214e71cSJoe           } else if (pos[p * dim + d] > upper[d]) {
21798214e71cSJoe             x[p * dim + d] = pos[p * dim + d] - (upper[d] - lower[d]);
21808214e71cSJoe           } else {
21818214e71cSJoe             x[p * dim + d] = pos[p * dim + d];
21828214e71cSJoe           }
21838214e71cSJoe           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]);
21848214e71cSJoe           v[p * dim + d] = mom[p * dim + d];
21858214e71cSJoe         }
21868214e71cSJoe       }
21878214e71cSJoe       PetscCall(VecRestoreArray(gc, &x));
21888214e71cSJoe       PetscCall(VecRestoreArray(gv, &v));
21898214e71cSJoe     }
21908214e71cSJoe     PetscCall(VecRestoreArray(position, &pos));
21918214e71cSJoe     PetscCall(VecRestoreArray(momentum, &mom));
21928214e71cSJoe     PetscCall(VecRestoreSubVector(u, isx, &position));
21938214e71cSJoe     PetscCall(VecRestoreSubVector(u, isv, &momentum));
21948214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
21958214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
21968214e71cSJoe   }
21978214e71cSJoe   PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
21989072cb8bSMatthew G. Knepley   PetscInt step;
21999072cb8bSMatthew G. Knepley 
22009072cb8bSMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &step));
2201045208b8SMatthew G. Knepley   if (!(step % ctx->remapFreq)) {
22029072cb8bSMatthew G. Knepley     // Monitor electric field before we destroy it
22039072cb8bSMatthew G. Knepley     PetscReal ptime;
22049072cb8bSMatthew G. Knepley     PetscInt  step;
22059072cb8bSMatthew G. Knepley 
22069072cb8bSMatthew G. Knepley     PetscCall(TSGetStepNumber(ts, &step));
22079072cb8bSMatthew G. Knepley     PetscCall(TSGetTime(ts, &ptime));
22089072cb8bSMatthew G. Knepley     if (ctx->efield_monitor) PetscCall(MonitorEField(ts, step, ptime, NULL, ctx));
22099072cb8bSMatthew G. Knepley     if (ctx->poisson_monitor) PetscCall(MonitorPoisson(ts, step, ptime, NULL, ctx));
22109072cb8bSMatthew G. Knepley     PetscCall(DMSwarmRemap(sw));
22119072cb8bSMatthew G. Knepley     ctx->validE = PETSC_FALSE;
22129072cb8bSMatthew G. Knepley   }
22139072cb8bSMatthew G. Knepley   // This MUST come last, since it recreates the subswarms and they must DMClone() the new swarm
22148214e71cSJoe   PetscCall(DMSwarmTSRedistribute(ts));
22158214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_FALSE));
22163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2217b80bf5b1SJoe Pusztay }
2218b80bf5b1SJoe Pusztay 
2219d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
2220d71ae5a4SJacob Faibussowitsch {
2221b80bf5b1SJoe Pusztay   DM        dm, sw;
22228214e71cSJoe   TS        ts;
22238214e71cSJoe   Vec       u;
22248214e71cSJoe   PetscReal dt;
22258214e71cSJoe   PetscInt  maxn;
2226b80bf5b1SJoe Pusztay   AppCtx    user;
2227b80bf5b1SJoe Pusztay 
22289566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
22298214e71cSJoe   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
22308214e71cSJoe   PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &user.bag));
22318214e71cSJoe   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
22328214e71cSJoe   PetscCall(CreatePoisson(dm, &user));
22338214e71cSJoe   PetscCall(CreateSwarm(dm, &user, &sw));
22348214e71cSJoe   PetscCall(SetupParameters(PETSC_COMM_WORLD, &user));
22358214e71cSJoe   PetscCall(InitializeConstants(sw, &user));
22368214e71cSJoe   PetscCall(DMSetApplicationContext(sw, &user));
2237b80bf5b1SJoe Pusztay 
22388214e71cSJoe   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
22398214e71cSJoe   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
22409566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts, sw));
22418214e71cSJoe   PetscCall(TSSetMaxTime(ts, 0.1));
22428214e71cSJoe   PetscCall(TSSetTimeStep(ts, 0.00001));
22438214e71cSJoe   PetscCall(TSSetMaxSteps(ts, 100));
22448214e71cSJoe   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
22458214e71cSJoe 
22468214e71cSJoe   if (user.efield_monitor) PetscCall(TSMonitorSet(ts, MonitorEField, &user, NULL));
2247f1e6e573SMatthew G. Knepley   if (user.moment_monitor) PetscCall(TSMonitorSet(ts, MonitorMoments, &user, NULL));
22488214e71cSJoe   if (user.initial_monitor) PetscCall(TSMonitorSet(ts, MonitorInitialConditions, &user, NULL));
22499072cb8bSMatthew G. Knepley   if (user.positions_monitor) PetscCall(TSMonitorSet(ts, MonitorPositions_2D, &user, NULL));
22508214e71cSJoe   if (user.poisson_monitor) PetscCall(TSMonitorSet(ts, MonitorPoisson, &user, NULL));
2251fd7102fcSMatthew G. Knepley   if (user.velocity_monitor >= 0) PetscCall(TSMonitorSet(ts, MonitorVelocity, &user, NULL));
22528214e71cSJoe 
22538214e71cSJoe   PetscCall(TSSetFromOptions(ts));
22548214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
22558214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
22568214e71cSJoe   user.steps    = maxn;
22578214e71cSJoe   user.stepSize = dt;
22588214e71cSJoe   PetscCall(SetupContext(dm, sw, &user));
22598214e71cSJoe   PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve));
22608214e71cSJoe   PetscCall(TSSetPostStep(ts, MigrateParticles));
22618214e71cSJoe   PetscCall(CreateSolution(ts));
22628214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
22638214e71cSJoe   PetscCall(TSComputeInitialCondition(ts, u));
22648214e71cSJoe   PetscCall(CheckNonNegativeWeights(sw, &user));
22658214e71cSJoe   PetscCall(TSSolve(ts, NULL));
22668214e71cSJoe 
22679566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&user.snes));
22684a0cbf56SMatthew G. Knepley   PetscCall(DMDestroy(&user.dmPot));
22694a0cbf56SMatthew G. Knepley   PetscCall(ISDestroy(&user.isPot));
2270f1e6e573SMatthew G. Knepley   PetscCall(MatDestroy(&user.M));
2271f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomDestroy(&user.fegeom));
22729566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
22739566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sw));
22749566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
22758214e71cSJoe   PetscCall(DestroyContext(&user));
22769566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
2277b122ec5aSJacob Faibussowitsch   return 0;
2278b80bf5b1SJoe Pusztay }
2279b80bf5b1SJoe Pusztay 
2280b80bf5b1SJoe Pusztay /*TEST
2281b80bf5b1SJoe Pusztay 
2282b80bf5b1SJoe Pusztay    build:
22838214e71cSJoe     requires: !complex double
22848214e71cSJoe 
22858214e71cSJoe   # This tests that we can put particles in a box and compute the Coulomb force
22868214e71cSJoe   # Recommend -draw_size 500,500
22878214e71cSJoe    testset:
22888214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2289045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 20 \
2290045208b8SMatthew G. Knepley              -dm_plex_box_lower 0 -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
22919072cb8bSMatthew G. Knepley            -vdm_plex_simplex 0 \
22928214e71cSJoe            -dm_swarm_coordinate_density constant -dm_swarm_num_particles 100 \
22938214e71cSJoe            -sigma 1.0e-8 -timeScale 2.0e-14 \
22948214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
22958214e71cSJoe            -output_step 50 -check_vel_res
22968214e71cSJoe      test:
22978214e71cSJoe        suffix: none_1d
22989072cb8bSMatthew G. Knepley        requires:
22998214e71cSJoe        args: -em_type none -error
23008214e71cSJoe      test:
23018214e71cSJoe        suffix: coulomb_1d
23028214e71cSJoe        args: -em_type coulomb
23038214e71cSJoe 
23048214e71cSJoe    # for viewers
23058214e71cSJoe    #-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
23068214e71cSJoe    testset:
23078214e71cSJoe      nsize: {{1 2}}
23088214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2309045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 36 \
2310045208b8SMatthew G. Knepley              -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
23118214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
23128214e71cSJoe              -vdm_plex_box_lower -3 -vdm_plex_box_upper 3 \
231384467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -twostream -charges -1.,1. -sigma 1.0e-8 \
23148214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
23158214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 2 \
23168214e71cSJoe              -ts_dt 0.01 -ts_max_time 5 -ts_max_steps 10 \
23178214e71cSJoe            -em_snes_atol 1.e-15 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
231884467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
23198214e71cSJoe      test:
23208214e71cSJoe        suffix: two_stream_c0
23218214e71cSJoe        args: -em_type primal -petscfe_default_quadrature_order 2 -petscspace_degree 2 -em_pc_type svd
23228214e71cSJoe      test:
23238214e71cSJoe        suffix: two_stream_rt
23248214e71cSJoe        requires: superlu_dist
23258214e71cSJoe        args: -em_type mixed \
23268214e71cSJoe                -potential_petscspace_degree 0 \
23278214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
23288214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
2329045208b8SMatthew G. Knepley                -field_petscspace_degree 1 -field_petscfe_default_quadrature_order 1 \
23308214e71cSJoe              -em_snes_error_if_not_converged \
23318214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
23328214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
23338214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
23348214e71cSJoe                -em_fieldsplit_field_pc_type lu \
23358214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
23368214e71cSJoe                -em_fieldsplit_potential_pc_type svd
23378214e71cSJoe 
233884467f86SMatthew G. Knepley    # For an eyeball check, we use
23399072cb8bSMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 10,1 -vdm_plex_box_faces 2000 -efield_monitor
23408214e71cSJoe    # For verification, we use
234184467f86SMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 100,1 -vdm_plex_box_faces 8000 -dm_swarm_num_particles 800000 -monitor_efield
23428214e71cSJoe    # -ts_monitor_sp_swarm_multi_species 0 -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500
23438214e71cSJoe    testset:
23448214e71cSJoe      nsize: {{1 2}}
23458214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2346045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 10 \
2347045208b8SMatthew G. Knepley              -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
23488214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
23498214e71cSJoe              -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \
2350f1e6e573SMatthew G. Knepley              -vpetscspace_degree 2 -vdm_plex_hash_location \
235184467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -charges -1.,1. \
23528214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
23538214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
23548214e71cSJoe              -ts_dt 0.03 -ts_max_time 500 -ts_max_steps 1 \
23558214e71cSJoe            -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
235684467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
23578214e71cSJoe 
23588214e71cSJoe      test:
23598214e71cSJoe        suffix: uniform_equilibrium_1d
23608214e71cSJoe        args: -cosine_coefficients 0.0,0.5 -em_type primal -petscspace_degree 1 -em_pc_type svd
23618214e71cSJoe      test:
236275155f48SMatthew G. Knepley        suffix: uniform_equilibrium_1d_real
2363045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
236475155f48SMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
236575155f48SMatthew G. Knepley              -cosine_coefficients 0.0 -em_type primal -petscspace_degree 1 -em_pc_type svd
236675155f48SMatthew G. Knepley      test:
23678214e71cSJoe        suffix: uniform_primal_1d
23688214e71cSJoe        args: -em_type primal -petscspace_degree 1 -em_pc_type svd
23698214e71cSJoe      test:
237075155f48SMatthew G. Knepley        suffix: uniform_primal_1d_real
2371045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
237275155f48SMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
237375155f48SMatthew G. Knepley              -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd
23749072cb8bSMatthew G. Knepley      # NOT WORKING -ftop_pc_type bjacobi -ftop_sub_pc_type lu -ftop_sub_pc_factor_shift_type nonzero
23759072cb8bSMatthew G. Knepley      test:
23769072cb8bSMatthew G. Knepley        suffix: uniform_primal_1d_real_pfak
23779072cb8bSMatthew G. Knepley        nsize: 1
2378045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
23799072cb8bSMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
23809072cb8bSMatthew 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 \
23819072cb8bSMatthew G. Knepley                -remap_dm_plex_box_lower 0.,-10. -remap_dm_plex_box_upper 12.5664,10. \
23829072cb8bSMatthew G. Knepley                -remap_petscspace_degree 2 -remap_dm_plex_hash_location \
2383045208b8SMatthew G. Knepley              -remap_freq 1 -dm_swarm_remap_type pfak \
23849072cb8bSMatthew G. Knepley                -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 \
23859072cb8bSMatthew G. Knepley                -ptof_pc_type lu \
23869072cb8bSMatthew G. Knepley              -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd -em_proj_pc_type lu
238775155f48SMatthew G. Knepley      test:
23888214e71cSJoe        requires: superlu_dist
23898214e71cSJoe        suffix: uniform_mixed_1d
23908214e71cSJoe        args: -em_type mixed \
23918214e71cSJoe                -potential_petscspace_degree 0 \
23928214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
23938214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
2394045208b8SMatthew G. Knepley                -field_petscspace_degree 1 \
23958214e71cSJoe              -em_snes_error_if_not_converged \
23968214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
23978214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
23988214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
23998214e71cSJoe                -em_fieldsplit_field_pc_type lu \
24008214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
24018214e71cSJoe                -em_fieldsplit_potential_pc_type svd
24028214e71cSJoe 
2403b80bf5b1SJoe Pusztay TEST*/
2404