xref: /petsc/src/ts/tutorials/hamiltonian/ex2.c (revision 045208b8c415bb6757b08f194d55e168bad3d369)
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 
41*045208b8SMatthew G. Knepley   # Physics
42*045208b8SMatthew G. Knepley   -cosine_coefficients 0.01 -dm_swarm_num_species 1 -charges -1. -perturbed_weights -total_weight 1.
43*045208b8SMatthew G. Knepley   # Spatial Mesh
44*045208b8SMatthew 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
45*045208b8SMatthew G. Knepley   # Velocity Mesh
46*045208b8SMatthew 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
47*045208b8SMatthew G. Knepley   # Remap Space
48*045208b8SMatthew G. Knepley   -dm_swarm_remap_type pfak -remap_freq 100
49*045208b8SMatthew 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.
50*045208b8SMatthew G. Knepley     -remap_dm_plex_box_upper 12.5664,6. -remap_petscspace_degree 1 -remap_dm_plex_hash_location
51*045208b8SMatthew G. Knepley   # Remap Solve
52*045208b8SMatthew G. Knepley   -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 -ptof_pc_type lu
53*045208b8SMatthew G. Knepley   # EM Solve
54*045208b8SMatthew 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
55*045208b8SMatthew G. Knepley   # Timestepping
56*045208b8SMatthew G. Knepley   -ts_type basicsymplectic -ts_basicsymplectic_type 1 -ts_dt 0.03 -ts_max_steps 1500 -ts_max_time 100
57*045208b8SMatthew G. Knepley   # Monitoring
58*045208b8SMatthew G. Knepley   -output_step 1 -check_vel_res -efield_monitor -poisson_monitor -positions_monitor -dm_swarm_print_coords 0 -remap_uf_view draw
59*045208b8SMatthew G. Knepley     -ftop_ksp_lsqr_monitor -ftop_ksp_converged_reason
6084467f86SMatthew G. Knepley 
618214e71cSJoe */
62b80bf5b1SJoe Pusztay #include <petscts.h>
638214e71cSJoe #include <petscdmplex.h>
648214e71cSJoe #include <petscdmswarm.h>
658214e71cSJoe #include <petscfe.h>
668214e71cSJoe #include <petscds.h>
678214e71cSJoe #include <petscbag.h>
688214e71cSJoe #include <petscdraw.h>
698214e71cSJoe #include <petsc/private/dmpleximpl.h>  /* For norm and dot */
708214e71cSJoe #include <petsc/private/petscfeimpl.h> /* For interpolation */
7184467f86SMatthew G. Knepley #include <petsc/private/dmswarmimpl.h> /* For swarm debugging */
728214e71cSJoe #include "petscdm.h"
738214e71cSJoe #include "petscdmlabel.h"
748214e71cSJoe 
758214e71cSJoe PETSC_EXTERN PetscErrorCode stream(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
768214e71cSJoe PETSC_EXTERN PetscErrorCode line(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
778214e71cSJoe 
788214e71cSJoe const char *EMTypes[] = {"primal", "mixed", "coulomb", "none", "EMType", "EM_", NULL};
798214e71cSJoe typedef enum {
808214e71cSJoe   EM_PRIMAL,
818214e71cSJoe   EM_MIXED,
828214e71cSJoe   EM_COULOMB,
838214e71cSJoe   EM_NONE
848214e71cSJoe } EMType;
858214e71cSJoe 
868214e71cSJoe typedef enum {
878214e71cSJoe   V0,
888214e71cSJoe   X0,
898214e71cSJoe   T0,
908214e71cSJoe   M0,
918214e71cSJoe   Q0,
928214e71cSJoe   PHI0,
938214e71cSJoe   POISSON,
948214e71cSJoe   VLASOV,
958214e71cSJoe   SIGMA,
968214e71cSJoe   NUM_CONSTANTS
978214e71cSJoe } ConstantType;
988214e71cSJoe typedef struct {
998214e71cSJoe   PetscScalar v0; /* Velocity scale, often the thermal velocity */
1008214e71cSJoe   PetscScalar t0; /* Time scale */
1018214e71cSJoe   PetscScalar x0; /* Space scale */
1028214e71cSJoe   PetscScalar m0; /* Mass scale */
1038214e71cSJoe   PetscScalar q0; /* Charge scale */
1048214e71cSJoe   PetscScalar kb;
1058214e71cSJoe   PetscScalar epsi0;
1068214e71cSJoe   PetscScalar phi0;          /* Potential scale */
1078214e71cSJoe   PetscScalar poissonNumber; /* Non-Dimensional Poisson Number */
1088214e71cSJoe   PetscScalar vlasovNumber;  /* Non-Dimensional Vlasov Number */
1098214e71cSJoe   PetscReal   sigma;         /* Nondimensional charge per length in x */
1108214e71cSJoe } Parameter;
111b80bf5b1SJoe Pusztay 
112b80bf5b1SJoe Pusztay typedef struct {
1139072cb8bSMatthew G. Knepley   PetscBag     bag;               // Problem parameters
1149072cb8bSMatthew G. Knepley   PetscBool    error;             // Flag for printing the error
1159072cb8bSMatthew G. Knepley   PetscInt     remapFreq;         // Number of timesteps between remapping
1169072cb8bSMatthew G. Knepley   PetscBool    efield_monitor;    // Flag to show electric field monitor
1179072cb8bSMatthew G. Knepley   PetscBool    moment_monitor;    // Flag to show distribution moment monitor
1189072cb8bSMatthew G. Knepley   PetscBool    positions_monitor; // Flag to show particle positins at each time step
1199072cb8bSMatthew G. Knepley   PetscBool    poisson_monitor;   // Flag to display charge, E field, and potential at each solve
1209072cb8bSMatthew G. Knepley   PetscBool    initial_monitor;   // Flag to monitor the initial conditions
1219072cb8bSMatthew G. Knepley   PetscBool    perturbed_weights; // Uniformly sample x,v space with gaussian weights
1229072cb8bSMatthew G. Knepley   PetscInt     ostep;             // Print the energy at each ostep time steps
1238214e71cSJoe   PetscInt     numParticles;
1248214e71cSJoe   PetscReal    timeScale;              /* Nondimensionalizing time scale */
1258214e71cSJoe   PetscReal    charges[2];             /* The charges of each species */
1268214e71cSJoe   PetscReal    masses[2];              /* The masses of each species */
1278214e71cSJoe   PetscReal    thermal_energy[2];      /* Thermal Energy (used to get other constants)*/
1288214e71cSJoe   PetscReal    cosine_coefficients[2]; /*(alpha, k)*/
1298214e71cSJoe   PetscReal    totalWeight;
1308214e71cSJoe   PetscReal    stepSize;
1318214e71cSJoe   PetscInt     steps;
1328214e71cSJoe   PetscReal    initVel;
133f1e6e573SMatthew G. Knepley   EMType       em;     // Type of electrostatic model
134f1e6e573SMatthew G. Knepley   SNES         snes;   // EM solver
135f1e6e573SMatthew G. Knepley   Mat          M;      // The finite element mass matrix
136f1e6e573SMatthew G. Knepley   PetscFEGeom *fegeom; // Geometric information for the DM cells
1378214e71cSJoe   PetscDraw    drawic_x;
1388214e71cSJoe   PetscDraw    drawic_v;
1398214e71cSJoe   PetscDraw    drawic_w;
1408214e71cSJoe   PetscDrawHG  drawhgic_x;
1418214e71cSJoe   PetscDrawHG  drawhgic_v;
1428214e71cSJoe   PetscDrawHG  drawhgic_w;
1439072cb8bSMatthew G. Knepley   PetscBool    validE;     // Flag to indicate E-field in swarm is valid
14475155f48SMatthew G. Knepley   PetscReal    drawlgEmin; // The minimum lg(E) to plot
14575155f48SMatthew G. Knepley   PetscDrawLG  drawlgE;    // Logarithm of maximum electric field
14675155f48SMatthew G. Knepley   PetscDrawSP  drawspE;    // Electric field at particle positions
14775155f48SMatthew G. Knepley   PetscDrawSP  drawspX;    // Particle positions
14875155f48SMatthew G. Knepley   PetscViewer  viewerRho;  // Charge density viewer
14975155f48SMatthew G. Knepley   PetscViewer  viewerPhi;  // Potential viewer
1508214e71cSJoe   DM           swarm;
1518214e71cSJoe   PetscRandom  random;
1528214e71cSJoe   PetscBool    twostream;
1538214e71cSJoe   PetscBool    checkweights;
1548214e71cSJoe   PetscInt     checkVRes; /* Flag to check/output velocity residuals for nightly tests */
15584467f86SMatthew G. Knepley 
15684467f86SMatthew G. Knepley   PetscLogEvent RhsXEvent, RhsVEvent, ESolveEvent, ETabEvent;
157b80bf5b1SJoe Pusztay } AppCtx;
158b80bf5b1SJoe Pusztay 
159d71ae5a4SJacob Faibussowitsch static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
160d71ae5a4SJacob Faibussowitsch {
161b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
1628214e71cSJoe   PetscInt d                      = 2;
1638214e71cSJoe   PetscInt maxSpecies             = 2;
1648214e71cSJoe   options->error                  = PETSC_FALSE;
1659072cb8bSMatthew G. Knepley   options->remapFreq              = 1;
1668214e71cSJoe   options->efield_monitor         = PETSC_FALSE;
167f1e6e573SMatthew G. Knepley   options->moment_monitor         = PETSC_FALSE;
1688214e71cSJoe   options->initial_monitor        = PETSC_FALSE;
1698214e71cSJoe   options->perturbed_weights      = PETSC_FALSE;
1708214e71cSJoe   options->poisson_monitor        = PETSC_FALSE;
1719072cb8bSMatthew G. Knepley   options->positions_monitor      = PETSC_FALSE;
1728214e71cSJoe   options->ostep                  = 100;
1738214e71cSJoe   options->timeScale              = 2.0e-14;
1748214e71cSJoe   options->charges[0]             = -1.0;
1758214e71cSJoe   options->charges[1]             = 1.0;
1768214e71cSJoe   options->masses[0]              = 1.0;
1778214e71cSJoe   options->masses[1]              = 1000.0;
1788214e71cSJoe   options->thermal_energy[0]      = 1.0;
1798214e71cSJoe   options->thermal_energy[1]      = 1.0;
1808214e71cSJoe   options->cosine_coefficients[0] = 0.01;
1818214e71cSJoe   options->cosine_coefficients[1] = 0.5;
1828214e71cSJoe   options->initVel                = 1;
1838214e71cSJoe   options->totalWeight            = 1.0;
1848214e71cSJoe   options->drawic_x               = NULL;
1858214e71cSJoe   options->drawic_v               = NULL;
1868214e71cSJoe   options->drawic_w               = NULL;
1878214e71cSJoe   options->drawhgic_x             = NULL;
1888214e71cSJoe   options->drawhgic_v             = NULL;
1898214e71cSJoe   options->drawhgic_w             = NULL;
19075155f48SMatthew G. Knepley   options->drawlgEmin             = -6;
19175155f48SMatthew G. Knepley   options->drawlgE                = NULL;
19275155f48SMatthew G. Knepley   options->drawspE                = NULL;
19375155f48SMatthew G. Knepley   options->drawspX                = NULL;
19475155f48SMatthew G. Knepley   options->viewerRho              = NULL;
19575155f48SMatthew G. Knepley   options->viewerPhi              = NULL;
1968214e71cSJoe   options->em                     = EM_COULOMB;
1978214e71cSJoe   options->numParticles           = 32768;
1988214e71cSJoe   options->twostream              = PETSC_FALSE;
1998214e71cSJoe   options->checkweights           = PETSC_FALSE;
2008214e71cSJoe   options->checkVRes              = 0;
201b80bf5b1SJoe Pusztay 
2028214e71cSJoe   PetscOptionsBegin(comm, "", "Landau Damping and Two Stream options", "DMSWARM");
2038214e71cSJoe   PetscCall(PetscOptionsBool("-error", "Flag to print the error", "ex2.c", options->error, &options->error, NULL));
2049072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsInt("-remap_freq", "Number", "ex2.c", options->remapFreq, &options->remapFreq, NULL));
2059072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-efield_monitor", "Flag to plot log(max E) over time", "ex2.c", options->efield_monitor, &options->efield_monitor, NULL));
2069072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsReal("-efield_min_monitor", "Minimum E field to plot", "ex2.c", options->drawlgEmin, &options->drawlgEmin, NULL));
2079072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-moments_monitor", "Flag to show moments table", "ex2.c", options->moment_monitor, &options->moment_monitor, NULL));
2089072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-ics_monitor", "Flag to show initial condition histograms", "ex2.c", options->initial_monitor, &options->initial_monitor, NULL));
2099072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-positions_monitor", "The flag to show particle positions", "ex2.c", options->positions_monitor, &options->positions_monitor, NULL));
2109072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-poisson_monitor", "The flag to show charges, Efield and potential solve", "ex2.c", options->poisson_monitor, &options->poisson_monitor, NULL));
2118214e71cSJoe   PetscCall(PetscOptionsBool("-twostream", "Run two stream instability", "ex2.c", options->twostream, &options->twostream, NULL));
2128214e71cSJoe   PetscCall(PetscOptionsBool("-perturbed_weights", "Flag to run uniform sampling with perturbed weights", "ex2.c", options->perturbed_weights, &options->perturbed_weights, NULL));
2138214e71cSJoe   PetscCall(PetscOptionsBool("-check_weights", "Ensure all particle weights are positive", "ex2.c", options->checkweights, &options->checkweights, NULL));
2148214e71cSJoe   PetscCall(PetscOptionsInt("-check_vel_res", "Check particle velocity residuals for nightly tests", "ex2.c", options->checkVRes, &options->checkVRes, NULL));
2158214e71cSJoe   PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", "ex2.c", options->ostep, &options->ostep, NULL));
2168214e71cSJoe   PetscCall(PetscOptionsReal("-timeScale", "Nondimensionalizing time scale", "ex2.c", options->timeScale, &options->timeScale, NULL));
2178214e71cSJoe   PetscCall(PetscOptionsReal("-initial_velocity", "Initial velocity of perturbed particle", "ex2.c", options->initVel, &options->initVel, NULL));
2188214e71cSJoe   PetscCall(PetscOptionsReal("-total_weight", "Total weight of all particles", "ex2.c", options->totalWeight, &options->totalWeight, NULL));
2198214e71cSJoe   PetscCall(PetscOptionsRealArray("-cosine_coefficients", "Amplitude and frequency of cosine equation used in initialization", "ex2.c", options->cosine_coefficients, &d, NULL));
2208214e71cSJoe   PetscCall(PetscOptionsRealArray("-charges", "Species charges", "ex2.c", options->charges, &maxSpecies, NULL));
2218214e71cSJoe   PetscCall(PetscOptionsEnum("-em_type", "Type of electrostatic solver", "ex2.c", EMTypes, (PetscEnum)options->em, (PetscEnum *)&options->em, NULL));
222d0609cedSBarry Smith   PetscOptionsEnd();
22384467f86SMatthew G. Knepley 
22484467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsX", TS_CLASSID, &options->RhsXEvent));
22584467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsV", TS_CLASSID, &options->RhsVEvent));
22684467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ESolve", TS_CLASSID, &options->ESolveEvent));
22784467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ETab", TS_CLASSID, &options->ETabEvent));
2283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
229b80bf5b1SJoe Pusztay }
230b80bf5b1SJoe Pusztay 
2318214e71cSJoe static PetscErrorCode SetupContext(DM dm, DM sw, AppCtx *user)
2328214e71cSJoe {
2338214e71cSJoe   PetscFunctionBeginUser;
2348214e71cSJoe   if (user->efield_monitor) {
23575155f48SMatthew G. Knepley     PetscDraw     draw;
23675155f48SMatthew G. Knepley     PetscDrawAxis axis;
23775155f48SMatthew G. Knepley 
23875155f48SMatthew G. Knepley     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "Max Electric Field", 0, 300, 400, 300, &draw));
23975155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_Efield"));
24075155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
24175155f48SMatthew G. Knepley     PetscCall(PetscDrawLGCreate(draw, 1, &user->drawlgE));
24275155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
24375155f48SMatthew G. Knepley     PetscCall(PetscDrawLGGetAxis(user->drawlgE, &axis));
24475155f48SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Electron Electric Field", "time", "E_max"));
24575155f48SMatthew G. Knepley     PetscCall(PetscDrawLGSetLimits(user->drawlgE, 0., user->steps * user->stepSize, user->drawlgEmin, 0.));
2468214e71cSJoe   }
2478214e71cSJoe   if (user->initial_monitor) {
2488214e71cSJoe     PetscDrawAxis axis1, axis2, axis3;
2498214e71cSJoe     PetscReal     dmboxlower[2], dmboxupper[2];
2508214e71cSJoe     PetscInt      dim, cStart, cEnd;
2518214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
2528214e71cSJoe     PetscCall(DMGetBoundingBox(dm, dmboxlower, dmboxupper));
2538214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2548214e71cSJoe 
2558214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_x", 0, 300, 400, 300, &user->drawic_x));
25675155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(user->drawic_x, "ex9_ic_x"));
2578214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawic_x));
2586497c311SBarry Smith     PetscCall(PetscDrawHGCreate(user->drawic_x, (int)dim, &user->drawhgic_x));
2598214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_x, &axis1));
2606497c311SBarry Smith     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_x, (int)(cEnd - cStart)));
2618214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis1, "Initial X Distribution", "X", "counts"));
2628214e71cSJoe     PetscCall(PetscDrawAxisSetLimits(axis1, dmboxlower[0], dmboxupper[0], 0, 1500));
2638214e71cSJoe 
2648214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_v", 400, 300, 400, 300, &user->drawic_v));
26575155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(user->drawic_v, "ex9_ic_v"));
2668214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawic_v));
2676497c311SBarry Smith     PetscCall(PetscDrawHGCreate(user->drawic_v, (int)dim, &user->drawhgic_v));
2688214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_v, &axis2));
2698214e71cSJoe     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_v, 1000));
2708214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis2, "Initial V_x Distribution", "V", "counts"));
2718214e71cSJoe     PetscCall(PetscDrawAxisSetLimits(axis2, -1, 1, 0, 1500));
2728214e71cSJoe 
2738214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_w", 800, 300, 400, 300, &user->drawic_w));
27475155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(user->drawic_w, "ex9_ic_w"));
2758214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawic_w));
2766497c311SBarry Smith     PetscCall(PetscDrawHGCreate(user->drawic_w, (int)dim, &user->drawhgic_w));
2778214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_w, &axis3));
2788214e71cSJoe     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_w, 10));
2798214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis3, "Initial W Distribution", "weight", "counts"));
2808214e71cSJoe     PetscCall(PetscDrawAxisSetLimits(axis3, 0, 0.01, 0, 5000));
2818214e71cSJoe   }
2829072cb8bSMatthew G. Knepley   if (user->positions_monitor) {
28375155f48SMatthew G. Knepley     PetscDraw     draw;
2848214e71cSJoe     PetscDrawAxis axis;
2858214e71cSJoe 
28675155f48SMatthew G. Knepley     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "Particle Position", 0, 0, 400, 300, &draw));
28775155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_pos"));
28875155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
28975155f48SMatthew G. Knepley     PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspX));
29075155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
29175155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetDimension(user->drawspX, 1));
29275155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetAxis(user->drawspX, &axis));
2938214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "v"));
29475155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspX));
2958214e71cSJoe   }
2968214e71cSJoe   if (user->poisson_monitor) {
29775155f48SMatthew G. Knepley     Vec           rho, phi;
29875155f48SMatthew G. Knepley     PetscDraw     draw;
29975155f48SMatthew G. Knepley     PetscDrawAxis axis;
3008214e71cSJoe 
30175155f48SMatthew G. Knepley     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "Electric_Field", 0, 0, 400, 300, &draw));
30275155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
30375155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_E_spatial"));
30475155f48SMatthew G. Knepley     PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspE));
30575155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
30675155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetDimension(user->drawspE, 1));
30775155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetAxis(user->drawspE, &axis));
30875155f48SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "E"));
30975155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspE));
3108214e71cSJoe 
31175155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, NULL, "Charge Density", 0, 0, 400, 300, &user->viewerRho));
31275155f48SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerRho, "rho_"));
31375155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerRho, 0, &draw));
31475155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_spatial"));
31575155f48SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerRho));
31675155f48SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(dm, "rho", &rho));
31775155f48SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rho, "charge_density"));
31875155f48SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(dm, "rho", &rho));
3198214e71cSJoe 
32075155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, NULL, "Potential", 400, 0, 400, 300, &user->viewerPhi));
32175155f48SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerPhi, "phi_"));
32275155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerPhi, 0, &draw));
32375155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_phi_spatial"));
32475155f48SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerPhi));
32575155f48SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(dm, "phi", &phi));
32675155f48SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)phi, "potential"));
32775155f48SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(dm, "phi", &phi));
3288214e71cSJoe   }
3298214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3308214e71cSJoe }
3318214e71cSJoe 
3328214e71cSJoe static PetscErrorCode DestroyContext(AppCtx *user)
3338214e71cSJoe {
3348214e71cSJoe   PetscFunctionBeginUser;
3358214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_x));
3368214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawic_x));
3378214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_v));
3388214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawic_v));
3398214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_w));
3408214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawic_w));
3418214e71cSJoe 
34275155f48SMatthew G. Knepley   PetscCall(PetscDrawLGDestroy(&user->drawlgE));
34375155f48SMatthew G. Knepley   PetscCall(PetscDrawSPDestroy(&user->drawspE));
34475155f48SMatthew G. Knepley   PetscCall(PetscDrawSPDestroy(&user->drawspX));
34575155f48SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerRho));
34675155f48SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerPhi));
3478214e71cSJoe 
3488214e71cSJoe   PetscCall(PetscBagDestroy(&user->bag));
3498214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3508214e71cSJoe }
3518214e71cSJoe 
3528214e71cSJoe static PetscErrorCode CheckNonNegativeWeights(DM sw, AppCtx *user)
3538214e71cSJoe {
3548214e71cSJoe   const PetscScalar *w;
3558214e71cSJoe   PetscInt           Np;
3568214e71cSJoe 
3578214e71cSJoe   PetscFunctionBeginUser;
3588214e71cSJoe   if (!user->checkweights) PetscFunctionReturn(PETSC_SUCCESS);
3598214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w));
3608214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
3618214e71cSJoe   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]);
3628214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w));
3638214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3648214e71cSJoe }
3658214e71cSJoe 
3669072cb8bSMatthew G. Knepley static PetscErrorCode computeVelocityFEMMoments(DM sw, PetscReal moments[], AppCtx *user)
3678214e71cSJoe {
3689072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
369f1e6e573SMatthew G. Knepley   DM            vdm;
370f1e6e573SMatthew G. Knepley   Vec           u[1];
371f1e6e573SMatthew G. Knepley   const char   *fields[1] = {"w_q"};
3728214e71cSJoe 
373f1e6e573SMatthew G. Knepley   PetscFunctionBegin;
3749072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "velocity"));
3759072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
3769072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
377f1e6e573SMatthew G. Knepley   PetscCall(DMGetGlobalVector(vdm, &u[0]));
378f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmProjectFields(sw, vdm, 1, fields, u, SCATTER_FORWARD));
379f1e6e573SMatthew G. Knepley   PetscCall(DMPlexComputeMoments(vdm, u[0], moments));
380f1e6e573SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(vdm, &u[0]));
3819072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
3828214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3838214e71cSJoe }
3848214e71cSJoe 
3858214e71cSJoe static PetscErrorCode MonitorEField(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
3868214e71cSJoe {
3878214e71cSJoe   AppCtx    *user = (AppCtx *)ctx;
388f1e6e573SMatthew G. Knepley   DM         sw;
389f1e6e573SMatthew G. Knepley   PetscReal *E, *x, *weight;
390f1e6e573SMatthew G. Knepley   PetscReal  Enorm = 0., lgEnorm, lgEmax, sum = 0., Emax = 0., chargesum = 0.;
391f1e6e573SMatthew G. Knepley   PetscReal  pmoments[4]; /* \int f, \int v f, \int v^2 f */
392f1e6e573SMatthew G. Knepley   PetscInt  *species, dim, Np;
3938214e71cSJoe 
3948214e71cSJoe   PetscFunctionBeginUser;
3959072cb8bSMatthew G. Knepley   if (step < 0 || !user->validE) PetscFunctionReturn(PETSC_SUCCESS);
3968214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
3978214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
3988214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
3998214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
4008214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
4018214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
4028214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
4038214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
4048214e71cSJoe 
405f1e6e573SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
406f1e6e573SMatthew G. Knepley     for (PetscInt d = 0; d < 1; ++d) {
407f1e6e573SMatthew G. Knepley       PetscReal temp = PetscAbsReal(E[p * dim + d]);
4088214e71cSJoe       if (temp > Emax) Emax = temp;
4098214e71cSJoe     }
4108214e71cSJoe     Enorm += PetscSqrtReal(E[p * dim] * E[p * dim]);
4118214e71cSJoe     sum += E[p * dim];
4128214e71cSJoe     chargesum += user->charges[0] * weight[p];
4138214e71cSJoe   }
4148214e71cSJoe   lgEnorm = Enorm != 0 ? PetscLog10Real(Enorm) : -16.;
41575155f48SMatthew G. Knepley   lgEmax  = Emax != 0 ? PetscLog10Real(Emax) : user->drawlgEmin;
4168214e71cSJoe 
4178214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
4188214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
4198214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
4208214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
42175155f48SMatthew G. Knepley   PetscCall(PetscDrawLGAddPoint(user->drawlgE, &t, &lgEmax));
42275155f48SMatthew G. Knepley   PetscCall(PetscDrawLGDraw(user->drawlgE));
42375155f48SMatthew G. Knepley   PetscDraw draw;
42475155f48SMatthew G. Knepley   PetscCall(PetscDrawLGGetDraw(user->drawlgE, &draw));
42575155f48SMatthew G. Knepley   PetscCall(PetscDrawSave(draw));
426f1e6e573SMatthew G. Knepley 
427f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
42875155f48SMatthew G. Knepley   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%f\t%+e\t%e\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n", (double)t, (double)sum, (double)Enorm, (double)lgEnorm, (double)Emax, (double)lgEmax, (double)chargesum, (double)pmoments[0], (double)pmoments[1], (double)pmoments[1 + dim]));
42975155f48SMatthew G. Knepley   PetscCall(DMViewFromOptions(sw, NULL, "-sw_efield_view"));
430f1e6e573SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
431f1e6e573SMatthew G. Knepley }
432f1e6e573SMatthew G. Knepley 
433f1e6e573SMatthew G. Knepley static PetscErrorCode MonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
434f1e6e573SMatthew G. Knepley {
435f1e6e573SMatthew G. Knepley   AppCtx   *user = (AppCtx *)ctx;
436f1e6e573SMatthew G. Knepley   DM        sw;
437f1e6e573SMatthew G. Knepley   PetscReal pmoments[4], fmoments[4]; /* \int f, \int v f, \int v^2 f */
438f1e6e573SMatthew G. Knepley 
439f1e6e573SMatthew G. Knepley   PetscFunctionBeginUser;
440f1e6e573SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
441f1e6e573SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
442f1e6e573SMatthew G. Knepley 
443f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
444f1e6e573SMatthew G. Knepley   PetscCall(computeVelocityFEMMoments(sw, fmoments, user));
445f1e6e573SMatthew G. Knepley 
446f1e6e573SMatthew 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]));
4478214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
4488214e71cSJoe }
4498214e71cSJoe 
4508214e71cSJoe PetscErrorCode MonitorInitialConditions(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
4518214e71cSJoe {
4528214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
4538214e71cSJoe   DM                 dm, sw;
4548214e71cSJoe   const PetscScalar *u;
4558214e71cSJoe   PetscReal         *weight, *pos, *vel;
4568214e71cSJoe   PetscInt           dim, p, Np, cStart, cEnd;
4578214e71cSJoe 
4588214e71cSJoe   PetscFunctionBegin;
4598214e71cSJoe   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
4608214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
4618214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &dm));
4628214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
4638214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
4648214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
4658214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
4668214e71cSJoe 
4678214e71cSJoe   if (step == 0) {
4688214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_x));
4698214e71cSJoe     PetscCall(PetscDrawHGGetDraw(user->drawhgic_x, &user->drawic_x));
4708214e71cSJoe     PetscCall(PetscDrawClear(user->drawic_x));
4718214e71cSJoe     PetscCall(PetscDrawFlush(user->drawic_x));
4728214e71cSJoe 
4738214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_v));
4748214e71cSJoe     PetscCall(PetscDrawHGGetDraw(user->drawhgic_v, &user->drawic_v));
4758214e71cSJoe     PetscCall(PetscDrawClear(user->drawic_v));
4768214e71cSJoe     PetscCall(PetscDrawFlush(user->drawic_v));
4778214e71cSJoe 
4788214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_w));
4798214e71cSJoe     PetscCall(PetscDrawHGGetDraw(user->drawhgic_w, &user->drawic_w));
4808214e71cSJoe     PetscCall(PetscDrawClear(user->drawic_w));
4818214e71cSJoe     PetscCall(PetscDrawFlush(user->drawic_w));
4828214e71cSJoe 
4838214e71cSJoe     PetscCall(VecGetArrayRead(U, &u));
4848214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
4858214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
4868214e71cSJoe     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
4878214e71cSJoe 
4888214e71cSJoe     PetscCall(VecGetLocalSize(U, &Np));
4898214e71cSJoe     Np /= dim * 2;
4908214e71cSJoe     for (p = 0; p < Np; ++p) {
4918214e71cSJoe       PetscCall(PetscDrawHGAddValue(user->drawhgic_x, pos[p * dim]));
4928214e71cSJoe       PetscCall(PetscDrawHGAddValue(user->drawhgic_v, vel[p * dim]));
4938214e71cSJoe       PetscCall(PetscDrawHGAddValue(user->drawhgic_w, weight[p]));
4948214e71cSJoe     }
4958214e71cSJoe 
4968214e71cSJoe     PetscCall(VecRestoreArrayRead(U, &u));
4978214e71cSJoe     PetscCall(PetscDrawHGDraw(user->drawhgic_x));
4988214e71cSJoe     PetscCall(PetscDrawHGSave(user->drawhgic_x));
4998214e71cSJoe 
5008214e71cSJoe     PetscCall(PetscDrawHGDraw(user->drawhgic_v));
5018214e71cSJoe     PetscCall(PetscDrawHGSave(user->drawhgic_v));
5028214e71cSJoe 
5038214e71cSJoe     PetscCall(PetscDrawHGDraw(user->drawhgic_w));
5048214e71cSJoe     PetscCall(PetscDrawHGSave(user->drawhgic_w));
5058214e71cSJoe 
5068214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
5078214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
5088214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
5098214e71cSJoe   }
5108214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5118214e71cSJoe }
5128214e71cSJoe 
5138214e71cSJoe static PetscErrorCode MonitorPositions_2D(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
5148214e71cSJoe {
5158214e71cSJoe   AppCtx         *user = (AppCtx *)ctx;
5168214e71cSJoe   DM              dm, sw;
5178214e71cSJoe   PetscScalar    *x, *v, *weight;
5188214e71cSJoe   PetscReal       lower[3], upper[3], speed;
5198214e71cSJoe   const PetscInt *s;
5208214e71cSJoe   PetscInt        dim, cStart, cEnd, c;
5218214e71cSJoe 
5228214e71cSJoe   PetscFunctionBeginUser;
5238214e71cSJoe   if (step > 0 && step % user->ostep == 0) {
5248214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
5258214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
5268214e71cSJoe     PetscCall(DMGetDimension(dm, &dim));
5278214e71cSJoe     PetscCall(DMGetBoundingBox(dm, lower, upper));
5288214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
5298214e71cSJoe     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5308214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
5318214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
5328214e71cSJoe     PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&s));
5338214e71cSJoe     PetscCall(DMSwarmSortGetAccess(sw));
53475155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspX));
53575155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], lower[1], upper[1]));
53675155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], -12, 12));
5378214e71cSJoe     for (c = 0; c < cEnd - cStart; ++c) {
5388214e71cSJoe       PetscInt *pidx, Npc, q;
5398214e71cSJoe       PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
5408214e71cSJoe       for (q = 0; q < Npc; ++q) {
5418214e71cSJoe         const PetscInt p = pidx[q];
5428214e71cSJoe         if (s[p] == 0) {
5439072cb8bSMatthew G. Knepley           speed = 0.;
5449072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) speed += PetscSqr(v[p * dim + d]);
5459072cb8bSMatthew G. Knepley           speed = PetscSqrtReal(speed);
546*045208b8SMatthew G. Knepley           if (dim == 1) {
54775155f48SMatthew G. Knepley             PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &v[p * dim], &speed));
5488214e71cSJoe           } else {
54975155f48SMatthew G. Knepley             PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &x[p * dim + 1], &speed));
5508214e71cSJoe           }
5518214e71cSJoe         } else if (s[p] == 1) {
55275155f48SMatthew G. Knepley           PetscCall(PetscDrawSPAddPoint(user->drawspX, &x[p * dim], &v[p * dim]));
5538214e71cSJoe         }
5548214e71cSJoe       }
55584467f86SMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
5568214e71cSJoe     }
55775155f48SMatthew G. Knepley     PetscCall(PetscDrawSPDraw(user->drawspX, PETSC_TRUE));
55875155f48SMatthew G. Knepley     PetscDraw draw;
55975155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetDraw(user->drawspX, &draw));
56075155f48SMatthew G. Knepley     PetscCall(PetscDrawSave(draw));
5618214e71cSJoe     PetscCall(DMSwarmSortRestoreAccess(sw));
5628214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5638214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
5648214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
5658214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&s));
5668214e71cSJoe   }
5678214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5688214e71cSJoe }
5698214e71cSJoe 
5708214e71cSJoe static PetscErrorCode MonitorPoisson(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
5718214e71cSJoe {
5728214e71cSJoe   AppCtx *user = (AppCtx *)ctx;
5738214e71cSJoe   DM      dm, sw;
5748214e71cSJoe 
5758214e71cSJoe   PetscFunctionBeginUser;
5768214e71cSJoe   if (step > 0 && step % user->ostep == 0) {
5778214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
5788214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
5799072cb8bSMatthew G. Knepley 
5809072cb8bSMatthew G. Knepley     if (user->validE) {
5819072cb8bSMatthew G. Knepley       PetscScalar *x, *E, *weight;
5829072cb8bSMatthew G. Knepley       PetscReal    lower[3], upper[3], xval;
5839072cb8bSMatthew G. Knepley       PetscDraw    draw;
5849072cb8bSMatthew G. Knepley       PetscInt     dim, cStart, cEnd;
5859072cb8bSMatthew G. Knepley 
5868214e71cSJoe       PetscCall(DMGetDimension(dm, &dim));
5878214e71cSJoe       PetscCall(DMGetBoundingBox(dm, lower, upper));
5888214e71cSJoe       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
5898214e71cSJoe 
59075155f48SMatthew G. Knepley       PetscCall(PetscDrawSPReset(user->drawspE));
5918214e71cSJoe       PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5928214e71cSJoe       PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
5938214e71cSJoe       PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
5948214e71cSJoe 
5958214e71cSJoe       PetscCall(DMSwarmSortGetAccess(sw));
5969072cb8bSMatthew G. Knepley       for (PetscInt c = 0; c < cEnd - cStart; ++c) {
59775155f48SMatthew G. Knepley         PetscReal Eavg = 0.0;
5989072cb8bSMatthew G. Knepley         PetscInt *pidx, Npc;
5999072cb8bSMatthew G. Knepley 
6008214e71cSJoe         PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
6019072cb8bSMatthew G. Knepley         for (PetscInt q = 0; q < Npc; ++q) {
6028214e71cSJoe           const PetscInt p = pidx[q];
60375155f48SMatthew G. Knepley           Eavg += E[p * dim];
6048214e71cSJoe         }
60575155f48SMatthew G. Knepley         Eavg /= Npc;
6068214e71cSJoe         xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart));
60775155f48SMatthew G. Knepley         PetscCall(PetscDrawSPAddPoint(user->drawspE, &xval, &Eavg));
60884467f86SMatthew G. Knepley         PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
6098214e71cSJoe       }
61075155f48SMatthew G. Knepley       PetscCall(PetscDrawSPDraw(user->drawspE, PETSC_TRUE));
61175155f48SMatthew G. Knepley       PetscCall(PetscDrawSPGetDraw(user->drawspE, &draw));
61275155f48SMatthew G. Knepley       PetscCall(PetscDrawSave(draw));
6138214e71cSJoe       PetscCall(DMSwarmSortRestoreAccess(sw));
6148214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
6158214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
6168214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
6179072cb8bSMatthew G. Knepley     }
61875155f48SMatthew G. Knepley 
61975155f48SMatthew G. Knepley     Vec rho, phi;
62075155f48SMatthew G. Knepley 
62175155f48SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(dm, "rho", &rho));
62275155f48SMatthew G. Knepley     PetscCall(VecView(rho, user->viewerRho));
62375155f48SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(dm, "rho", &rho));
62475155f48SMatthew G. Knepley 
62575155f48SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(dm, "phi", &phi));
62675155f48SMatthew G. Knepley     PetscCall(VecView(phi, user->viewerPhi));
62775155f48SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(dm, "phi", &phi));
6288214e71cSJoe   }
6298214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
6308214e71cSJoe }
6318214e71cSJoe 
6328214e71cSJoe static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx)
6338214e71cSJoe {
6348214e71cSJoe   PetscBag   bag;
6358214e71cSJoe   Parameter *p;
6368214e71cSJoe 
6378214e71cSJoe   PetscFunctionBeginUser;
6388214e71cSJoe   /* setup PETSc parameter bag */
6398214e71cSJoe   PetscCall(PetscBagGetData(ctx->bag, (void **)&p));
6408214e71cSJoe   PetscCall(PetscBagSetName(ctx->bag, "par", "Vlasov-Poisson Parameters"));
6418214e71cSJoe   bag = ctx->bag;
6428214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "v0", "Velocity scale, m/s"));
6438214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->t0, 1.0, "t0", "Time scale, s"));
6448214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->x0, 1.0, "x0", "Space scale, m"));
6458214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "phi0", "Potential scale, kg*m^2/A*s^3"));
6468214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->q0, 1.0, "q0", "Charge Scale, A*s"));
6478214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->m0, 1.0, "m0", "Mass Scale, kg"));
6488214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->epsi0, 1.0, "epsi0", "Permittivity of Free Space, kg"));
6498214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->kb, 1.0, "kb", "Boltzmann Constant, m^2 kg/s^2 K^1"));
6508214e71cSJoe 
6518214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->sigma, 1.0, "sigma", "Charge per unit area, C/m^3"));
6528214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->poissonNumber, 1.0, "poissonNumber", "Non-Dimensional Poisson Number"));
6538214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->vlasovNumber, 1.0, "vlasovNumber", "Non-Dimensional Vlasov Number"));
6548214e71cSJoe   PetscCall(PetscBagSetFromOptions(bag));
6558214e71cSJoe   {
6568214e71cSJoe     PetscViewer       viewer;
6578214e71cSJoe     PetscViewerFormat format;
6588214e71cSJoe     PetscBool         flg;
6598214e71cSJoe 
660648c30bcSBarry Smith     PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg));
6618214e71cSJoe     if (flg) {
6628214e71cSJoe       PetscCall(PetscViewerPushFormat(viewer, format));
6638214e71cSJoe       PetscCall(PetscBagView(bag, viewer));
6648214e71cSJoe       PetscCall(PetscViewerFlush(viewer));
6658214e71cSJoe       PetscCall(PetscViewerPopFormat(viewer));
6668214e71cSJoe       PetscCall(PetscViewerDestroy(&viewer));
6678214e71cSJoe     }
6688214e71cSJoe   }
6698214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
6708214e71cSJoe }
6718214e71cSJoe 
6728214e71cSJoe static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
673d71ae5a4SJacob Faibussowitsch {
674b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
6759566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
6769566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
6779566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*dm));
6789072cb8bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*dm, "space"));
6799566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
680f1e6e573SMatthew G. Knepley 
681f1e6e573SMatthew G. Knepley   // Cache the mesh geometry
682f1e6e573SMatthew G. Knepley   DMField         coordField;
683f1e6e573SMatthew G. Knepley   IS              cellIS;
684f1e6e573SMatthew G. Knepley   PetscQuadrature quad;
685f1e6e573SMatthew G. Knepley   PetscReal      *wt, *pt;
686f1e6e573SMatthew G. Knepley   PetscInt        cdim, cStart, cEnd;
687f1e6e573SMatthew G. Knepley 
688f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateField(*dm, &coordField));
689f1e6e573SMatthew G. Knepley   PetscCheck(coordField, comm, PETSC_ERR_USER, "DM must have a coordinate field");
690f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateDim(*dm, &cdim));
691f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd));
692f1e6e573SMatthew G. Knepley   PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cellIS));
693f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
694f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(1, &wt));
695f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(2, &pt));
696f1e6e573SMatthew G. Knepley   wt[0] = 1.;
697f1e6e573SMatthew G. Knepley   pt[0] = -1.;
698f1e6e573SMatthew G. Knepley   pt[1] = -1.;
699f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureSetData(quad, cdim, 1, 1, pt, wt));
700f1e6e573SMatthew G. Knepley   PetscCall(DMFieldCreateFEGeom(coordField, cellIS, quad, PETSC_FALSE, &user->fegeom));
701f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&quad));
702f1e6e573SMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
7033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
704b80bf5b1SJoe Pusztay }
705b80bf5b1SJoe Pusztay 
7068214e71cSJoe 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[])
7078214e71cSJoe {
7088214e71cSJoe   f0[0] = -constants[SIGMA];
7098214e71cSJoe }
7108214e71cSJoe 
711d71ae5a4SJacob 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[])
712d71ae5a4SJacob Faibussowitsch {
713b80bf5b1SJoe Pusztay   PetscInt d;
714ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) f1[d] = u_x[d];
715b80bf5b1SJoe Pusztay }
716b80bf5b1SJoe Pusztay 
7178214e71cSJoe 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[])
718d71ae5a4SJacob Faibussowitsch {
719b80bf5b1SJoe Pusztay   PetscInt d;
720ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) g3[d * dim + d] = 1.0;
721b80bf5b1SJoe Pusztay }
722b80bf5b1SJoe Pusztay 
7238214e71cSJoe static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
724d71ae5a4SJacob Faibussowitsch {
7258214e71cSJoe   *u = 0.0;
7268214e71cSJoe   return PETSC_SUCCESS;
727b80bf5b1SJoe Pusztay }
728b80bf5b1SJoe Pusztay 
729b80bf5b1SJoe Pusztay /*
7308214e71cSJoe    /  I   -grad\ / q \ = /0\
7318214e71cSJoe    \-div    0  / \phi/   \f/
732b80bf5b1SJoe Pusztay */
7338214e71cSJoe 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[])
734d71ae5a4SJacob Faibussowitsch {
7358214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[d] += u[uOff[0] + d];
7368214e71cSJoe }
7378214e71cSJoe 
7388214e71cSJoe 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[])
7398214e71cSJoe {
7408214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f1[d * dim + d] = u[uOff[1]];
7418214e71cSJoe }
7428214e71cSJoe 
7438214e71cSJoe 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[])
7448214e71cSJoe {
7458214e71cSJoe   f0[0] += constants[SIGMA];
7468214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[0] += u_x[uOff_x[0] + d * dim + d];
7478214e71cSJoe }
7488214e71cSJoe 
7498214e71cSJoe /* Boundary residual. Dirichlet boundary for u means u_bdy=p*n */
7508214e71cSJoe 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[])
7518214e71cSJoe {
7528214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g0[d * dim + d] = 1.0;
7538214e71cSJoe }
7548214e71cSJoe 
7558214e71cSJoe 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[])
7568214e71cSJoe {
7578214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g2[d * dim + d] = 1.0;
7588214e71cSJoe }
7598214e71cSJoe 
7608214e71cSJoe 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[])
7618214e71cSJoe {
7628214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g1[d * dim + d] = 1.0;
7638214e71cSJoe }
7648214e71cSJoe 
7658214e71cSJoe static PetscErrorCode CreateFEM(DM dm, AppCtx *user)
7668214e71cSJoe {
7678214e71cSJoe   PetscFE   fephi, feq;
7688214e71cSJoe   PetscDS   ds;
7698214e71cSJoe   PetscBool simplex;
7708214e71cSJoe   PetscInt  dim;
7718214e71cSJoe 
7728214e71cSJoe   PetscFunctionBeginUser;
7738214e71cSJoe   PetscCall(DMGetDimension(dm, &dim));
7748214e71cSJoe   PetscCall(DMPlexIsSimplex(dm, &simplex));
7758214e71cSJoe   if (user->em == EM_MIXED) {
7768214e71cSJoe     DMLabel        label;
7778214e71cSJoe     const PetscInt id = 1;
7788214e71cSJoe 
7798214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "field_", PETSC_DETERMINE, &feq));
7808214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)feq, "field"));
7818214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "potential_", PETSC_DETERMINE, &fephi));
7828214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
7838214e71cSJoe     PetscCall(PetscFECopyQuadrature(feq, fephi));
7848214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)feq));
7858214e71cSJoe     PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fephi));
7868214e71cSJoe     PetscCall(DMCreateDS(dm));
7878214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
7888214e71cSJoe     PetscCall(PetscFEDestroy(&feq));
7898214e71cSJoe 
7908214e71cSJoe     PetscCall(DMGetLabel(dm, "marker", &label));
7918214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
7928214e71cSJoe 
7938214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, f0_q, f1_q));
7948214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 1, f0_phi_backgroundCharge, NULL));
7958214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_qq, NULL, NULL, NULL));
7968214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_qphi, NULL));
7978214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_phiq, NULL, NULL));
7988214e71cSJoe 
7998214e71cSJoe     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void))zero, NULL, NULL, NULL));
8008214e71cSJoe 
801f1e6e573SMatthew G. Knepley   } else {
8028214e71cSJoe     MatNullSpace nullsp;
8038214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, PETSC_DETERMINE, &fephi));
8048214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
8058214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fephi));
8068214e71cSJoe     PetscCall(DMCreateDS(dm));
8078214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
8088214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, ion_f0, laplacian_f1));
8098214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, laplacian_g3));
8108214e71cSJoe     PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullsp));
8118214e71cSJoe     PetscCall(PetscObjectCompose((PetscObject)fephi, "nullspace", (PetscObject)nullsp));
8128214e71cSJoe     PetscCall(MatNullSpaceDestroy(&nullsp));
8138214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
8148214e71cSJoe   }
8158214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
8168214e71cSJoe }
8178214e71cSJoe 
8188214e71cSJoe static PetscErrorCode CreatePoisson(DM dm, AppCtx *user)
8198214e71cSJoe {
8208214e71cSJoe   SNES         snes;
8218214e71cSJoe   Mat          J;
8228214e71cSJoe   MatNullSpace nullSpace;
8238214e71cSJoe 
8248214e71cSJoe   PetscFunctionBeginUser;
8258214e71cSJoe   PetscCall(CreateFEM(dm, user));
8268214e71cSJoe   PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes));
8278214e71cSJoe   PetscCall(SNESSetOptionsPrefix(snes, "em_"));
8288214e71cSJoe   PetscCall(SNESSetDM(snes, dm));
8298214e71cSJoe   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, user));
8308214e71cSJoe   PetscCall(SNESSetFromOptions(snes));
8318214e71cSJoe 
8328214e71cSJoe   PetscCall(DMCreateMatrix(dm, &J));
8338214e71cSJoe   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullSpace));
8348214e71cSJoe   PetscCall(MatSetNullSpace(J, nullSpace));
8358214e71cSJoe   PetscCall(MatNullSpaceDestroy(&nullSpace));
8368214e71cSJoe   PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL));
8378214e71cSJoe   PetscCall(MatDestroy(&J));
838f1e6e573SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(dm, dm, &user->M));
839f1e6e573SMatthew G. Knepley   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
8408214e71cSJoe   user->snes = snes;
8418214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
8428214e71cSJoe }
8438214e71cSJoe 
8448214e71cSJoe PetscErrorCode PetscPDFPertubedConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
8458214e71cSJoe {
8468214e71cSJoe   p[0] = (1 + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
8478214e71cSJoe   p[1] = (1 + 0.01 * PetscCosReal(0.5 * x[1])) / (2 * PETSC_PI);
8488214e71cSJoe   return PETSC_SUCCESS;
8498214e71cSJoe }
8508214e71cSJoe PetscErrorCode PetscPDFPertubedConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
8518214e71cSJoe {
8528214e71cSJoe   p[0] = (1. + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
8538214e71cSJoe   return PETSC_SUCCESS;
8548214e71cSJoe }
8558214e71cSJoe 
8568214e71cSJoe PetscErrorCode PetscPDFCosine1D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
8578214e71cSJoe {
8588214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.0;
8598214e71cSJoe   const PetscReal k     = scale ? scale[1] : 1.;
8608214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * x[0]));
8618214e71cSJoe   return PETSC_SUCCESS;
8628214e71cSJoe }
8638214e71cSJoe 
8648214e71cSJoe PetscErrorCode PetscPDFCosine2D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
8658214e71cSJoe {
8668214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.;
8678214e71cSJoe   const PetscReal k     = scale ? scale[0] : 1.;
8688214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * (x[0] + x[1])));
8698214e71cSJoe   return PETSC_SUCCESS;
8708214e71cSJoe }
8718214e71cSJoe 
87284467f86SMatthew G. Knepley static PetscErrorCode CreateVelocityDM(DM sw, DM *vdm)
8738214e71cSJoe {
874f1e6e573SMatthew G. Knepley   PetscFE        fe;
875f1e6e573SMatthew G. Knepley   DMPolytopeType ct;
876f1e6e573SMatthew G. Knepley   PetscInt       dim, cStart;
877f1e6e573SMatthew G. Knepley   const char    *prefix = "v";
878f1e6e573SMatthew G. Knepley 
87984467f86SMatthew G. Knepley   PetscFunctionBegin;
88084467f86SMatthew G. Knepley   PetscCall(DMCreate(PETSC_COMM_SELF, vdm));
88184467f86SMatthew G. Knepley   PetscCall(DMSetType(*vdm, DMPLEX));
882f1e6e573SMatthew G. Knepley   PetscCall(DMPlexSetOptionsPrefix(*vdm, prefix));
88384467f86SMatthew G. Knepley   PetscCall(DMSetFromOptions(*vdm));
8849072cb8bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*vdm, "velocity"));
88584467f86SMatthew G. Knepley   PetscCall(DMViewFromOptions(*vdm, NULL, "-dm_view"));
886f1e6e573SMatthew G. Knepley 
887f1e6e573SMatthew G. Knepley   PetscCall(DMGetDimension(*vdm, &dim));
888f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*vdm, 0, &cStart, NULL));
889f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetCellType(*vdm, cStart, &ct));
890f1e6e573SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe));
891f1e6e573SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "distribution"));
892f1e6e573SMatthew G. Knepley   PetscCall(DMSetField(*vdm, 0, NULL, (PetscObject)fe));
893f1e6e573SMatthew G. Knepley   PetscCall(DMCreateDS(*vdm));
894f1e6e573SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
89584467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
8968214e71cSJoe }
8978214e71cSJoe 
8989072cb8bSMatthew G. Knepley /*
8999072cb8bSMatthew G. Knepley   InitializeParticles_Centroid - Initialize a regular grid of particles.
9009072cb8bSMatthew G. Knepley 
9019072cb8bSMatthew G. Knepley   Input Parameters:
9029072cb8bSMatthew G. Knepley + sw      - The `DMSWARM`
9039072cb8bSMatthew G. Knepley - force1D - Treat the spatial domain as 1D
9049072cb8bSMatthew G. Knepley 
9059072cb8bSMatthew G. Knepley   Notes:
9069072cb8bSMatthew G. Knepley   This functions sets the species, cellid, spatial coordinate, and velocity fields for all particles.
9079072cb8bSMatthew G. Knepley 
9089072cb8bSMatthew G. Knepley   It places one particle in the centroid of each cell in the implicit tensor product of the spatial
9099072cb8bSMatthew G. Knepley   and velocity meshes.
9109072cb8bSMatthew G. Knepley */
911*045208b8SMatthew G. Knepley static PetscErrorCode InitializeParticles_Centroid(DM sw)
9128214e71cSJoe {
91384467f86SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
9149072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
91584467f86SMatthew G. Knepley   DM            xdm, vdm;
91684467f86SMatthew G. Knepley   PetscReal     vmin[3], vmax[3];
91784467f86SMatthew G. Knepley   PetscReal    *x, *v;
91884467f86SMatthew G. Knepley   PetscInt     *species, *cellid;
91984467f86SMatthew G. Knepley   PetscInt      dim, xcStart, xcEnd, vcStart, vcEnd, Ns, Np, Npc, debug;
9208214e71cSJoe   PetscBool     flg;
92184467f86SMatthew G. Knepley   MPI_Comm      comm;
9229072cb8bSMatthew G. Knepley   const char   *cellidname;
9238214e71cSJoe 
9248214e71cSJoe   PetscFunctionBegin;
92584467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
92684467f86SMatthew G. Knepley 
92784467f86SMatthew G. Knepley   PetscOptionsBegin(comm, "", "DMSwarm Options", "DMSWARM");
9288214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
9298214e71cSJoe   PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg));
9308214e71cSJoe   if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns));
93184467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_coords", "Debug output level for particle coordinate computations", "InitializeParticles", 0, &swarm->printCoords, NULL, 0));
93284467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_weights", "Debug output level for particle weight computations", "InitializeWeights", 0, &swarm->printWeights, NULL, 0));
9338214e71cSJoe   PetscOptionsEnd();
93484467f86SMatthew G. Knepley   debug = swarm->printCoords;
9358214e71cSJoe 
9368214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
93784467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
93884467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
9398214e71cSJoe 
940*045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
941*045208b8SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
94284467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
9438214e71cSJoe 
94484467f86SMatthew G. Knepley   // One particle per centroid on the tensor product grid
94584467f86SMatthew G. Knepley   Npc = (vcEnd - vcStart) * Ns;
94684467f86SMatthew G. Knepley   Np  = (xcEnd - xcStart) * Npc;
9478214e71cSJoe   PetscCall(DMSwarmSetLocalSizes(sw, Np, 0));
94884467f86SMatthew G. Knepley   if (debug) {
94984467f86SMatthew G. Knepley     PetscInt gNp;
95084467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Np, &gNp, 1, MPIU_INT, MPIU_SUM, comm));
95184467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global Np = %" PetscInt_FMT "\n", gNp));
9528214e71cSJoe   }
9538214e71cSJoe 
95484467f86SMatthew G. Knepley   // Set species and cellid
9559072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
9569072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCellID(celldm, &cellidname));
95784467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
9589072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, cellidname, NULL, NULL, (void **)&cellid));
95984467f86SMatthew G. Knepley   for (PetscInt c = 0, p = 0; c < xcEnd - xcStart; ++c) {
96084467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
96184467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q, ++p) {
96284467f86SMatthew G. Knepley         species[p] = s;
96384467f86SMatthew G. Knepley         cellid[p]  = c;
96484467f86SMatthew G. Knepley       }
96584467f86SMatthew G. Knepley     }
96684467f86SMatthew G. Knepley   }
96784467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
9689072cb8bSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, cellidname, NULL, NULL, (void **)&cellid));
96984467f86SMatthew G. Knepley 
97084467f86SMatthew G. Knepley   // Set particle coordinates
9718214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
9728214e71cSJoe   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
9738214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
97484467f86SMatthew G. Knepley   PetscCall(DMGetBoundingBox(vdm, vmin, vmax));
97584467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(xdm));
97684467f86SMatthew G. Knepley   for (PetscInt c = 0; c < xcEnd - xcStart; ++c) {
97784467f86SMatthew G. Knepley     const PetscInt cell = c + xcStart;
9788214e71cSJoe     PetscInt      *pidx, Npc;
9798214e71cSJoe     PetscReal      centroid[3], volume;
9808214e71cSJoe 
9818214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
98284467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFVM(xdm, cell, &volume, centroid, NULL));
98384467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
98484467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q) {
98584467f86SMatthew G. Knepley         const PetscInt p = pidx[q * Ns + s];
9868214e71cSJoe 
98784467f86SMatthew G. Knepley         for (PetscInt d = 0; d < dim; ++d) {
9888214e71cSJoe           x[p * dim + d] = centroid[d];
98984467f86SMatthew G. Knepley           v[p * dim + d] = vmin[0] + (q + 0.5) * ((vmax[0] - vmin[0]) / (Npc / Ns));
9908214e71cSJoe         }
9919072cb8bSMatthew G. Knepley         if (debug > 1) {
9929072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "Particle %4" PetscInt_FMT " ", p));
9939072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  x: ("));
9949072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
9959072cb8bSMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
9969072cb8bSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", x[p * dim + d]));
9979072cb8bSMatthew G. Knepley           }
9989072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ") v:("));
9999072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
10009072cb8bSMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
10019072cb8bSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", v[p * dim + d]));
10029072cb8bSMatthew G. Knepley           }
10039072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
10049072cb8bSMatthew G. Knepley         }
10058214e71cSJoe       }
10068214e71cSJoe     }
100784467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
10088214e71cSJoe   }
10098214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
10108214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
10118214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
101284467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
101384467f86SMatthew G. Knepley }
101484467f86SMatthew G. Knepley 
101584467f86SMatthew G. Knepley /*
101684467f86SMatthew G. Knepley   InitializeWeights - Compute weight for each local particle
101784467f86SMatthew G. Knepley 
101884467f86SMatthew G. Knepley   Input Parameters:
101984467f86SMatthew G. Knepley + sw          - The `DMSwarm`
102084467f86SMatthew G. Knepley . totalWeight - The sum of all particle weights
102184467f86SMatthew G. Knepley . func        - The PDF for the particle spatial distribution
102284467f86SMatthew G. Knepley - param       - The PDF parameters
102384467f86SMatthew G. Knepley 
102484467f86SMatthew G. Knepley   Notes:
102584467f86SMatthew G. Knepley   The PDF for velocity is assumed to be a Gaussian
102684467f86SMatthew G. Knepley 
102784467f86SMatthew G. Knepley   The particle weights are returned in the `w_q` field of `sw`.
102884467f86SMatthew G. Knepley */
1029*045208b8SMatthew G. Knepley static PetscErrorCode InitializeWeights(DM sw, PetscReal totalWeight, PetscProbFunc func, const PetscReal param[])
103084467f86SMatthew G. Knepley {
103184467f86SMatthew G. Knepley   DM               xdm, vdm;
1032*045208b8SMatthew G. Knepley   DMSwarmCellDM    celldm;
103384467f86SMatthew G. Knepley   PetscScalar     *weight;
103484467f86SMatthew G. Knepley   PetscQuadrature  xquad;
103584467f86SMatthew G. Knepley   const PetscReal *xq, *xwq;
103684467f86SMatthew G. Knepley   const PetscInt   order = 5;
1037*045208b8SMatthew G. Knepley   PetscReal        xi0[3];
103884467f86SMatthew G. Knepley   PetscReal        xwtot = 0., pwtot = 0.;
103984467f86SMatthew G. Knepley   PetscInt         xNq;
104084467f86SMatthew G. Knepley   PetscInt         dim, Ns, xcStart, xcEnd, vcStart, vcEnd, debug = ((DM_Swarm *)sw->data)->printWeights;
104184467f86SMatthew G. Knepley   MPI_Comm         comm;
104284467f86SMatthew G. Knepley   PetscMPIInt      rank;
104384467f86SMatthew G. Knepley 
104484467f86SMatthew G. Knepley   PetscFunctionBegin;
104584467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
104684467f86SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
104784467f86SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
104884467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
104984467f86SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
105084467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
1051*045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
1052*045208b8SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
105384467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
105484467f86SMatthew G. Knepley 
105584467f86SMatthew G. Knepley   // Setup Quadrature for spatial and velocity weight calculations
1056*045208b8SMatthew G. Knepley   PetscCall(PetscDTGaussTensorQuadrature(dim, 1, order, -1.0, 1.0, &xquad));
105784467f86SMatthew G. Knepley   PetscCall(PetscQuadratureGetData(xquad, NULL, NULL, &xNq, &xq, &xwq));
105884467f86SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) xi0[d] = -1.0;
105984467f86SMatthew G. Knepley 
106084467f86SMatthew G. Knepley   // Integrate the density function to get the weights of particles in each cell
106184467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(vdm));
106284467f86SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
106384467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
106484467f86SMatthew G. Knepley   for (PetscInt c = xcStart; c < xcEnd; ++c) {
106584467f86SMatthew G. Knepley     PetscReal          xv0[3], xJ[9], xinvJ[9], xdetJ, xqr[3], xden, xw = 0.;
106684467f86SMatthew G. Knepley     PetscInt          *pidx, Npc;
106784467f86SMatthew G. Knepley     PetscInt           xNc;
106884467f86SMatthew G. Knepley     const PetscScalar *xarray;
106984467f86SMatthew G. Knepley     PetscScalar       *xcoords = NULL;
107084467f86SMatthew G. Knepley     PetscBool          xisDG;
107184467f86SMatthew G. Knepley 
107284467f86SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
107384467f86SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
107484467f86SMatthew 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);
107584467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFEM(xdm, c, NULL, xv0, xJ, xinvJ, &xdetJ));
107684467f86SMatthew G. Knepley     for (PetscInt q = 0; q < xNq; ++q) {
107784467f86SMatthew G. Knepley       // Transform quadrature points from ref space to real space
1078*045208b8SMatthew G. Knepley       CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xq[q * dim], xqr);
107984467f86SMatthew G. Knepley       // Get probability density at quad point
108084467f86SMatthew G. Knepley       //   No need to scale xqr since PDF will be periodic
108184467f86SMatthew G. Knepley       PetscCall((*func)(xqr, param, &xden));
108284467f86SMatthew G. Knepley       xw += xden * (xwq[q] * xdetJ);
108384467f86SMatthew G. Knepley     }
108484467f86SMatthew G. Knepley     xwtot += xw;
108584467f86SMatthew G. Knepley     if (debug) {
108684467f86SMatthew G. Knepley       IS              globalOrdering;
108784467f86SMatthew G. Knepley       const PetscInt *ordering;
108884467f86SMatthew G. Knepley 
108984467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellNumbering(xdm, &globalOrdering));
109084467f86SMatthew G. Knepley       PetscCall(ISGetIndices(globalOrdering, &ordering));
109175155f48SMatthew 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));
109284467f86SMatthew G. Knepley       PetscCall(ISRestoreIndices(globalOrdering, &ordering));
109384467f86SMatthew G. Knepley     }
109484467f86SMatthew G. Knepley     // Set weights to be Gaussian in velocity cells
109584467f86SMatthew G. Knepley     for (PetscInt vc = vcStart; vc < vcEnd; ++vc) {
109684467f86SMatthew G. Knepley       const PetscInt     p  = pidx[vc * Ns + 0];
109784467f86SMatthew G. Knepley       PetscReal          vw = 0.;
109884467f86SMatthew G. Knepley       PetscInt           vNc;
109984467f86SMatthew G. Knepley       const PetscScalar *varray;
110084467f86SMatthew G. Knepley       PetscScalar       *vcoords = NULL;
110184467f86SMatthew G. Knepley       PetscBool          visDG;
110284467f86SMatthew G. Knepley 
110384467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
110484467f86SMatthew G. Knepley       // TODO: Fix 2 stream Ask Joe
110584467f86SMatthew G. Knepley       //   Two stream function from 1/2pi v^2 e^(-v^2/2)
110684467f86SMatthew 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.)));
110784467f86SMatthew G. Knepley       vw = 0.5 * (PetscErfReal(vcoords[1] / PetscSqrtReal(2.)) - PetscErfReal(vcoords[0] / PetscSqrtReal(2.)));
110884467f86SMatthew G. Knepley 
110984467f86SMatthew G. Knepley       weight[p] = totalWeight * vw * xw;
111084467f86SMatthew G. Knepley       pwtot += weight[p];
11119072cb8bSMatthew G. Knepley       PetscCheck(weight[p] <= 10., PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Particle %" PetscInt_FMT " weight exceeeded 1: %g, %g, %g", p, xw, vw, totalWeight);
111284467f86SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
111384467f86SMatthew G. Knepley       if (debug > 1) PetscCall(PetscPrintf(comm, "particle %" PetscInt_FMT ": %g, vw: %g xw: %g\n", p, weight[p], vw, xw));
111484467f86SMatthew G. Knepley     }
111584467f86SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
111684467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
111784467f86SMatthew G. Knepley   }
111884467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
111984467f86SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
112084467f86SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&xquad));
112184467f86SMatthew G. Knepley 
112284467f86SMatthew G. Knepley   if (debug) {
112384467f86SMatthew G. Knepley     PetscReal wtot[2] = {pwtot, xwtot}, gwtot[2];
112484467f86SMatthew G. Knepley 
112584467f86SMatthew G. Knepley     PetscCall(PetscSynchronizedFlush(comm, NULL));
112684467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(wtot, gwtot, 2, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
112784467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "particle weight sum = %1.10f cell weight sum = %1.10f\n", (double)gwtot[0], (double)gwtot[1]));
112884467f86SMatthew G. Knepley   }
112984467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
113084467f86SMatthew G. Knepley }
113184467f86SMatthew G. Knepley 
113284467f86SMatthew G. Knepley static PetscErrorCode InitializeParticles_PerturbedWeights(DM sw, AppCtx *user)
113384467f86SMatthew G. Knepley {
113484467f86SMatthew G. Knepley   PetscReal scale[2] = {user->cosine_coefficients[0], user->cosine_coefficients[1]};
113575155f48SMatthew G. Knepley   PetscInt  dim;
113684467f86SMatthew G. Knepley 
113784467f86SMatthew G. Knepley   PetscFunctionBegin;
113875155f48SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1139*045208b8SMatthew G. Knepley   PetscCall(InitializeParticles_Centroid(sw));
1140*045208b8SMatthew G. Knepley   PetscCall(InitializeWeights(sw, user->totalWeight, dim == 1 ? PetscPDFCosine1D : PetscPDFCosine2D, scale));
11418214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
11428214e71cSJoe }
11438214e71cSJoe 
11448214e71cSJoe static PetscErrorCode InitializeConstants(DM sw, AppCtx *user)
11458214e71cSJoe {
11468214e71cSJoe   DM         dm;
11478214e71cSJoe   PetscInt  *species;
11488214e71cSJoe   PetscReal *weight, totalCharge = 0., totalWeight = 0., gmin[3], gmax[3], global_charge, global_weight;
11498214e71cSJoe   PetscInt   Np, dim;
11508214e71cSJoe 
11518214e71cSJoe   PetscFunctionBegin;
11528214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &dm));
11538214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
11548214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
11558214e71cSJoe   PetscCall(DMGetBoundingBox(dm, gmin, gmax));
11568214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
11578214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
11588214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
11598214e71cSJoe     totalWeight += weight[p];
11608214e71cSJoe     totalCharge += user->charges[species[p]] * weight[p];
11618214e71cSJoe   }
11628214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
11638214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
11648214e71cSJoe   {
11658214e71cSJoe     Parameter *param;
11668214e71cSJoe     PetscReal  Area;
11678214e71cSJoe 
11688214e71cSJoe     PetscCall(PetscBagGetData(user->bag, (void **)&param));
11698214e71cSJoe     switch (dim) {
11708214e71cSJoe     case 1:
11718214e71cSJoe       Area = (gmax[0] - gmin[0]);
11728214e71cSJoe       break;
11738214e71cSJoe     case 2:
11748214e71cSJoe       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]);
11758214e71cSJoe       break;
11768214e71cSJoe     case 3:
11778214e71cSJoe       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]) * (gmax[2] - gmin[2]);
11788214e71cSJoe       break;
11798214e71cSJoe     default:
11808214e71cSJoe       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", dim);
11818214e71cSJoe     }
1182462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalWeight, &global_weight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
1183462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalCharge, &global_charge, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
11848214e71cSJoe     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));
11858214e71cSJoe     param->sigma = PetscAbsReal(global_charge / (Area));
11868214e71cSJoe 
11878214e71cSJoe     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "sigma: %g\n", (double)param->sigma));
11888214e71cSJoe     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,
11898214e71cSJoe                           (double)param->vlasovNumber));
11908214e71cSJoe   }
11918214e71cSJoe   /* Setup Constants */
11928214e71cSJoe   {
11938214e71cSJoe     PetscDS    ds;
11948214e71cSJoe     Parameter *param;
11958214e71cSJoe     PetscCall(PetscBagGetData(user->bag, (void **)&param));
11968214e71cSJoe     PetscScalar constants[NUM_CONSTANTS];
11978214e71cSJoe     constants[SIGMA]   = param->sigma;
11988214e71cSJoe     constants[V0]      = param->v0;
11998214e71cSJoe     constants[T0]      = param->t0;
12008214e71cSJoe     constants[X0]      = param->x0;
12018214e71cSJoe     constants[M0]      = param->m0;
12028214e71cSJoe     constants[Q0]      = param->q0;
12038214e71cSJoe     constants[PHI0]    = param->phi0;
12048214e71cSJoe     constants[POISSON] = param->poissonNumber;
12058214e71cSJoe     constants[VLASOV]  = param->vlasovNumber;
12068214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
12078214e71cSJoe     PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants));
12088214e71cSJoe   }
12098214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
12108214e71cSJoe }
12118214e71cSJoe 
12128214e71cSJoe static PetscErrorCode CreateSwarm(DM dm, AppCtx *user, DM *sw)
12138214e71cSJoe {
12149072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
12159072cb8bSMatthew G. Knepley   DM            vdm;
12168214e71cSJoe   PetscReal     v0[2] = {1., 0.};
12178214e71cSJoe   PetscInt      dim;
1218b80bf5b1SJoe Pusztay 
1219b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
12209566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
12219566063dSJacob Faibussowitsch   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw));
12229566063dSJacob Faibussowitsch   PetscCall(DMSetType(*sw, DMSWARM));
12239566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*sw, dim));
12249566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC));
1225*045208b8SMatthew G. Knepley   PetscCall(DMSetApplicationContext(*sw, user));
12269072cb8bSMatthew G. Knepley 
12279566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR));
12288214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL));
12298214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "species", 1, PETSC_INT));
12308214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "E_field", dim, PETSC_REAL));
12319072cb8bSMatthew G. Knepley 
12329072cb8bSMatthew G. Knepley   const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"};
12339072cb8bSMatthew G. Knepley 
12349072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(dm, 2, fieldnames, 1, fieldnames, &celldm));
12359072cb8bSMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
12369072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
12379072cb8bSMatthew G. Knepley 
12389072cb8bSMatthew G. Knepley   const char *vfieldnames[1] = {"w_q"};
12399072cb8bSMatthew G. Knepley 
12409072cb8bSMatthew G. Knepley   PetscCall(CreateVelocityDM(*sw, &vdm));
12419072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(vdm, 1, vfieldnames, 1, &fieldnames[1], &celldm));
12429072cb8bSMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
12439072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
12449072cb8bSMatthew G. Knepley   PetscCall(DMDestroy(&vdm));
12459072cb8bSMatthew G. Knepley 
12469566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*sw));
1247*045208b8SMatthew G. Knepley   PetscCall(DMSetUp(*sw));
1248*045208b8SMatthew G. Knepley 
12499072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(*sw, "space"));
12508214e71cSJoe   user->swarm = *sw;
1251*045208b8SMatthew G. Knepley   // TODO: This is redundant init since it is done in InitializeSolveAndSwarm, however DMSetUp() requires the local size be set
12528214e71cSJoe   if (user->perturbed_weights) {
12538214e71cSJoe     PetscCall(InitializeParticles_PerturbedWeights(*sw, user));
1254b80bf5b1SJoe Pusztay   } else {
12558214e71cSJoe     PetscCall(DMSwarmComputeLocalSizeFromOptions(*sw));
12568214e71cSJoe     PetscCall(DMSwarmInitializeCoordinates(*sw));
12578214e71cSJoe     PetscCall(DMSwarmInitializeVelocitiesFromOptions(*sw, v0));
1258b80bf5b1SJoe Pusztay   }
12599566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles"));
12609566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view"));
12613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1262b80bf5b1SJoe Pusztay }
1263b80bf5b1SJoe Pusztay 
12648214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Coulomb(SNES snes, DM sw, PetscReal E[])
1265d71ae5a4SJacob Faibussowitsch {
12668214e71cSJoe   AppCtx     *user;
12678214e71cSJoe   PetscReal  *coords;
12688214e71cSJoe   PetscInt   *species, dim, Np, Ns;
12698214e71cSJoe   PetscMPIInt size;
12708214e71cSJoe 
12718214e71cSJoe   PetscFunctionBegin;
12728214e71cSJoe   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)snes), &size));
12738214e71cSJoe   PetscCheck(size == 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Coulomb code only works in serial");
12748214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
12758214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
12768214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
12778214e71cSJoe   PetscCall(DMGetApplicationContext(sw, (void *)&user));
12788214e71cSJoe 
12798214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
12808214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
12818214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
12828214e71cSJoe     PetscReal *pcoord = &coords[p * dim];
12838214e71cSJoe     PetscReal  pE[3]  = {0., 0., 0.};
12848214e71cSJoe 
12858214e71cSJoe     /* Calculate field at particle p due to particle q */
12868214e71cSJoe     for (PetscInt q = 0; q < Np; ++q) {
12878214e71cSJoe       PetscReal *qcoord = &coords[q * dim];
12888214e71cSJoe       PetscReal  rpq[3], r, r3, q_q;
12898214e71cSJoe 
12908214e71cSJoe       if (p == q) continue;
12918214e71cSJoe       q_q = user->charges[species[q]] * 1.;
12928214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) rpq[d] = pcoord[d] - qcoord[d];
12938214e71cSJoe       r = DMPlex_NormD_Internal(dim, rpq);
12948214e71cSJoe       if (r < PETSC_SQRT_MACHINE_EPSILON) continue;
12958214e71cSJoe       r3 = PetscPowRealInt(r, 3);
12968214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pE[d] += q_q * rpq[d] / r3;
12978214e71cSJoe     }
12988214e71cSJoe     for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = pE[d];
12998214e71cSJoe   }
13008214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
13018214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
13028214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
13038214e71cSJoe }
13048214e71cSJoe 
13058214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Primal(SNES snes, DM sw, PetscReal E[])
13068214e71cSJoe {
1307b80bf5b1SJoe Pusztay   DM         dm;
13088214e71cSJoe   AppCtx    *user;
13098214e71cSJoe   PetscDS    ds;
13108214e71cSJoe   PetscFE    fe;
1311f1e6e573SMatthew G. Knepley   Mat        M_p;
131275155f48SMatthew G. Knepley   Vec        rhoRhs;      // Weak charge density, \int phi_i rho
131375155f48SMatthew G. Knepley   Vec        rho;         // Charge density, M^{-1} rhoRhs
131475155f48SMatthew G. Knepley   Vec        phi, locPhi; // Potential
131575155f48SMatthew G. Knepley   Vec        f;           // Particle weights
13168214e71cSJoe   PetscReal *coords;
13178214e71cSJoe   PetscInt   dim, cStart, cEnd, Np;
13188214e71cSJoe 
13198214e71cSJoe   PetscFunctionBegin;
132084467f86SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, (void *)&user));
132184467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
13228214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
13238214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
13248214e71cSJoe 
13258214e71cSJoe   KSP          ksp;
132684467f86SMatthew G. Knepley   const char **oldFields;
132784467f86SMatthew G. Knepley   PetscInt     Nf;
132884467f86SMatthew G. Knepley   const char **tmp;
13298214e71cSJoe 
13308214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
133184467f86SMatthew G. Knepley   PetscCall(DMSwarmVectorGetField(sw, &Nf, &tmp));
133284467f86SMatthew G. Knepley   PetscCall(PetscMalloc1(Nf, &oldFields));
133384467f86SMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscStrallocpy(tmp[f], (char **)&oldFields[f]));
1334f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmVectorDefineField(sw, "w_q"));
13358214e71cSJoe   PetscCall(DMCreateMassMatrix(sw, dm, &M_p));
1336f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmVectorDefineFields(sw, Nf, oldFields));
133784467f86SMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscFree(oldFields[f]));
133884467f86SMatthew G. Knepley   PetscCall(PetscFree(oldFields));
13398214e71cSJoe 
134075155f48SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhs));
134175155f48SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
134275155f48SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(dm, "rho", &rho));
13438214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
13448214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
134575155f48SMatthew G. Knepley 
13468214e71cSJoe   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
1347f1e6e573SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->M, NULL, "-m_view"));
13488214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
134975155f48SMatthew G. Knepley 
135075155f48SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
13518214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
13528214e71cSJoe 
13538214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
13548214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj_"));
1355f1e6e573SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->M, user->M));
13568214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
135775155f48SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
13588214e71cSJoe 
135975155f48SMatthew G. Knepley   PetscCall(VecScale(rhoRhs, -1.0));
13608214e71cSJoe 
136175155f48SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
136275155f48SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(dm, "rho", &rho));
13638214e71cSJoe   PetscCall(KSPDestroy(&ksp));
13648214e71cSJoe   PetscCall(MatDestroy(&M_p));
13658214e71cSJoe 
136675155f48SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(dm, "phi", &phi));
13678214e71cSJoe   PetscCall(VecSet(phi, 0.0));
136875155f48SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhs, phi));
136975155f48SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhs));
13708214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
13718214e71cSJoe 
13728214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
13738214e71cSJoe   PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi));
13748214e71cSJoe   PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi));
137575155f48SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(dm, "phi", &phi));
137684467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
13778214e71cSJoe 
13788214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
13798214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
13808214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
13818214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
13828214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
13838214e71cSJoe 
138484467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
13858214e71cSJoe   PetscTabulation tab;
13868214e71cSJoe   PetscReal      *pcoord, *refcoord;
1387*045208b8SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
1388*045208b8SMatthew G. Knepley   PetscInt        maxNcp    = 0;
1389*045208b8SMatthew G. Knepley 
1390*045208b8SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1391*045208b8SMatthew G. Knepley     PetscInt Ncp;
1392*045208b8SMatthew G. Knepley 
1393*045208b8SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
1394*045208b8SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
1395*045208b8SMatthew G. Knepley   }
1396*045208b8SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1397*045208b8SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1398*045208b8SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
1399*045208b8SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1400*045208b8SMatthew G. Knepley     PetscScalar *clPhi = NULL;
14018214e71cSJoe     PetscInt    *points;
14028214e71cSJoe     PetscInt     Ncp;
14038214e71cSJoe 
14048214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
14058214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
14068214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1407f1e6e573SMatthew G. Knepley     {
1408f1e6e573SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1409f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1410f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1411f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1412f1e6e573SMatthew G. Knepley       }
1413f1e6e573SMatthew G. Knepley     }
1414*045208b8SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
14158214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
14168214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
14178214e71cSJoe       const PetscReal *basisDer = tab->T[1];
14188214e71cSJoe       const PetscInt   p        = points[cp];
14198214e71cSJoe 
14208214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1421f1e6e573SMatthew G. Knepley       PetscCall(PetscFEFreeInterpolateGradient_Static(fe, basisDer, clPhi, dim, chunkgeom->invJ, NULL, cp, &E[p * dim]));
1422*045208b8SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
14238214e71cSJoe     }
14248214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
142584467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
14268214e71cSJoe   }
1427*045208b8SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1428*045208b8SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1429*045208b8SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
14308214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
14318214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
14328214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1433f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
143484467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
14358214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
14368214e71cSJoe }
14378214e71cSJoe 
14388214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Mixed(SNES snes, DM sw, PetscReal E[])
14398214e71cSJoe {
14408214e71cSJoe   AppCtx         *user;
14418214e71cSJoe   DM              dm, potential_dm;
14428214e71cSJoe   KSP             ksp;
14438214e71cSJoe   IS              potential_IS;
14448214e71cSJoe   PetscDS         ds;
14458214e71cSJoe   PetscFE         fe;
14468214e71cSJoe   Mat             M_p, M;
14478214e71cSJoe   Vec             phi, locPhi, rho, f, temp_rho, rho0;
14488214e71cSJoe   PetscQuadrature q;
144975155f48SMatthew G. Knepley   PetscReal      *coords;
145084467f86SMatthew G. Knepley   PetscInt        dim, cStart, cEnd, Np, pot_field = 1;
145184467f86SMatthew G. Knepley   const char    **oldFields;
145284467f86SMatthew G. Knepley   PetscInt        Nf;
145384467f86SMatthew G. Knepley   const char    **tmp;
14548214e71cSJoe 
14558214e71cSJoe   PetscFunctionBegin;
145684467f86SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &user));
145784467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
14588214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
14598214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
14608214e71cSJoe 
14618214e71cSJoe   /* Create the charges rho */
14628214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
14638214e71cSJoe   PetscCall(DMGetGlobalVector(dm, &rho));
14648214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)rho, "rho"));
14658214e71cSJoe 
146684467f86SMatthew G. Knepley   PetscCall(DMCreateSubDM(dm, 1, &pot_field, &potential_IS, &potential_dm));
14678214e71cSJoe 
146884467f86SMatthew G. Knepley   PetscCall(DMSwarmVectorGetField(sw, &Nf, &tmp));
146984467f86SMatthew G. Knepley   PetscCall(PetscMalloc1(Nf, &oldFields));
147084467f86SMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscStrallocpy(tmp[f], (char **)&oldFields[f]));
1471f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmVectorDefineField(sw, "w_q"));
14728214e71cSJoe   PetscCall(DMCreateMassMatrix(sw, potential_dm, &M_p));
1473f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmVectorDefineFields(sw, Nf, oldFields));
147484467f86SMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscFree(oldFields[f]));
147584467f86SMatthew G. Knepley   PetscCall(PetscFree(oldFields));
14768214e71cSJoe 
14778214e71cSJoe   PetscCall(DMCreateMassMatrix(potential_dm, potential_dm, &M));
14788214e71cSJoe   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
14798214e71cSJoe   PetscCall(MatViewFromOptions(M, NULL, "-m_view"));
14808214e71cSJoe   PetscCall(DMGetGlobalVector(potential_dm, &temp_rho));
14818214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)temp_rho, "Mf"));
14828214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
14838214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
14848214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
14858214e71cSJoe   PetscCall(MatMultTranspose(M_p, f, temp_rho));
14868214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
14878214e71cSJoe   PetscCall(DMGetGlobalVector(potential_dm, &rho0));
14888214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)rho0, "Charge density (rho0) from Mixed Compute"));
14898214e71cSJoe 
14908214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
14918214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj"));
14928214e71cSJoe   PetscCall(KSPSetOperators(ksp, M, M));
14938214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
14948214e71cSJoe   PetscCall(KSPSolve(ksp, temp_rho, rho0));
14958214e71cSJoe   PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view"));
14968214e71cSJoe 
14978214e71cSJoe   PetscCall(VecISCopy(rho, potential_IS, SCATTER_FORWARD, temp_rho));
14988214e71cSJoe   PetscCall(VecScale(rho, 0.25));
14998214e71cSJoe   PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view"));
15008214e71cSJoe   PetscCall(VecViewFromOptions(temp_rho, NULL, "-temprho_view"));
15018214e71cSJoe   PetscCall(VecViewFromOptions(rho, NULL, "-rho_view"));
15028214e71cSJoe   PetscCall(DMRestoreGlobalVector(potential_dm, &temp_rho));
15038214e71cSJoe   PetscCall(DMRestoreGlobalVector(potential_dm, &rho0));
15048214e71cSJoe 
15058214e71cSJoe   PetscCall(MatDestroy(&M_p));
15068214e71cSJoe   PetscCall(MatDestroy(&M));
15078214e71cSJoe   PetscCall(KSPDestroy(&ksp));
15088214e71cSJoe   PetscCall(DMDestroy(&potential_dm));
15098214e71cSJoe   PetscCall(ISDestroy(&potential_IS));
15108214e71cSJoe 
15118214e71cSJoe   PetscCall(DMGetGlobalVector(dm, &phi));
15128214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)phi, "potential"));
15138214e71cSJoe   PetscCall(VecSet(phi, 0.0));
15148214e71cSJoe   PetscCall(SNESSolve(snes, rho, phi));
15158214e71cSJoe   PetscCall(DMRestoreGlobalVector(dm, &rho));
15168214e71cSJoe 
15178214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
15188214e71cSJoe 
15198214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
15208214e71cSJoe   PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi));
15218214e71cSJoe   PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi));
15228214e71cSJoe   PetscCall(DMRestoreGlobalVector(dm, &phi));
152384467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
15248214e71cSJoe 
152584467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
15268214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
15278214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
15288214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
15298214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
15308214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
15318214e71cSJoe   PetscCall(PetscFEGetQuadrature(fe, &q));
1532f1e6e573SMatthew G. Knepley   PetscFEGeom *chunkgeom = NULL;
15338214e71cSJoe   for (PetscInt c = cStart; c < cEnd; ++c) {
15348214e71cSJoe     PetscTabulation tab;
15358214e71cSJoe     PetscScalar    *clPhi = NULL;
15368214e71cSJoe     PetscReal      *pcoord, *refcoord;
15378214e71cSJoe     PetscInt       *points;
15388214e71cSJoe     PetscInt        Ncp;
15398214e71cSJoe 
15408214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
15418214e71cSJoe     PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord));
15428214e71cSJoe     PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord));
15438214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
15448214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1545f1e6e573SMatthew G. Knepley     {
1546f1e6e573SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1547f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1548f1e6e573SMatthew G. Knepley         // Apply the inverse affine transformation for each point
1549f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1550f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1551f1e6e573SMatthew G. Knepley       }
1552f1e6e573SMatthew G. Knepley     }
15538214e71cSJoe     PetscCall(PetscFECreateTabulation(fe, 1, Ncp, refcoord, 1, &tab));
15548214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
15558214e71cSJoe 
15568214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
15578214e71cSJoe       const PetscInt p = points[cp];
15588214e71cSJoe 
15598214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1560f1e6e573SMatthew G. Knepley       PetscCall(PetscFEInterpolateAtPoints_Static(fe, tab, clPhi, chunkgeom, cp, &E[p * dim]));
1561f1e6e573SMatthew G. Knepley       PetscCall(PetscFEPushforward(fe, chunkgeom, 1, &E[p * dim]));
1562*045208b8SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -2.0;
15638214e71cSJoe     }
15648214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
1565f1e6e573SMatthew G. Knepley     PetscCall(PetscTabulationDestroy(&tab));
15668214e71cSJoe     PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord));
15678214e71cSJoe     PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord));
156884467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
15698214e71cSJoe   }
15708214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
15718214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
15728214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1573f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
157484467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
15758214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
15768214e71cSJoe }
15778214e71cSJoe 
15788214e71cSJoe static PetscErrorCode ComputeFieldAtParticles(SNES snes, DM sw, PetscReal E[])
15798214e71cSJoe {
15808214e71cSJoe   AppCtx  *ctx;
15818214e71cSJoe   PetscInt dim, Np;
15828214e71cSJoe 
15838214e71cSJoe   PetscFunctionBegin;
15848214e71cSJoe   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
15858214e71cSJoe   PetscValidHeaderSpecific(sw, DM_CLASSID, 2);
15868214e71cSJoe   PetscAssertPointer(E, 3);
15878214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
15888214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
15898214e71cSJoe   PetscCall(DMGetApplicationContext(sw, &ctx));
15908214e71cSJoe   PetscCall(PetscArrayzero(E, Np * dim));
15919072cb8bSMatthew G. Knepley   ctx->validE = PETSC_TRUE;
15928214e71cSJoe 
15938214e71cSJoe   switch (ctx->em) {
15948214e71cSJoe   case EM_PRIMAL:
15958214e71cSJoe     PetscCall(ComputeFieldAtParticles_Primal(snes, sw, E));
15968214e71cSJoe     break;
15978214e71cSJoe   case EM_COULOMB:
15988214e71cSJoe     PetscCall(ComputeFieldAtParticles_Coulomb(snes, sw, E));
15998214e71cSJoe     break;
16008214e71cSJoe   case EM_MIXED:
16018214e71cSJoe     PetscCall(ComputeFieldAtParticles_Mixed(snes, sw, E));
16028214e71cSJoe     break;
16038214e71cSJoe   case EM_NONE:
16048214e71cSJoe     break;
16058214e71cSJoe   default:
16068214e71cSJoe     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No solver for electrostatic model %s", EMTypes[ctx->em]);
16078214e71cSJoe   }
16088214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16098214e71cSJoe }
16108214e71cSJoe 
16118214e71cSJoe static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec G, void *ctx)
16128214e71cSJoe {
16138214e71cSJoe   DM                 sw;
16148214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
16158214e71cSJoe   const PetscScalar *u;
16168214e71cSJoe   PetscScalar       *g;
16178214e71cSJoe   PetscReal         *E, m_p = 1., q_p = -1.;
16188214e71cSJoe   PetscInt           dim, d, Np, p;
1619b80bf5b1SJoe Pusztay 
1620b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
16218214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
16228214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16238214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
16248214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
16258214e71cSJoe   PetscCall(VecGetArrayRead(U, &u));
16268214e71cSJoe   PetscCall(VecGetArray(G, &g));
16278214e71cSJoe 
16288214e71cSJoe   PetscCall(ComputeFieldAtParticles(snes, sw, E));
16298214e71cSJoe 
16308214e71cSJoe   Np /= 2 * dim;
16318214e71cSJoe   for (p = 0; p < Np; ++p) {
16328214e71cSJoe     for (d = 0; d < dim; ++d) {
16338214e71cSJoe       g[(p * 2 + 0) * dim + d] = u[(p * 2 + 1) * dim + d];
16348214e71cSJoe       g[(p * 2 + 1) * dim + d] = q_p * E[p * dim + d] / m_p;
16358214e71cSJoe     }
16368214e71cSJoe   }
16378214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
16388214e71cSJoe   PetscCall(VecRestoreArrayRead(U, &u));
16398214e71cSJoe   PetscCall(VecRestoreArray(G, &g));
16408214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16418214e71cSJoe }
16428214e71cSJoe 
16438214e71cSJoe /* J_{ij} = dF_i/dx_j
16448214e71cSJoe    J_p = (  0   1)
16458214e71cSJoe          (-w^2  0)
16468214e71cSJoe    TODO Now there is another term with w^2 from the electric field. I think we will need to invert the operator.
16478214e71cSJoe         Perhaps we can approximate the Jacobian using only the cellwise P-P gradient from Coulomb
16488214e71cSJoe */
16498214e71cSJoe static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat P, void *ctx)
16508214e71cSJoe {
16518214e71cSJoe   DM               sw;
16528214e71cSJoe   const PetscReal *coords, *vel;
16538214e71cSJoe   PetscInt         dim, d, Np, p, rStart;
16548214e71cSJoe 
16558214e71cSJoe   PetscFunctionBeginUser;
16568214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
16578214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16588214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
16598214e71cSJoe   PetscCall(MatGetOwnershipRange(J, &rStart, NULL));
1660*045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1661*045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
16628214e71cSJoe   Np /= 2 * dim;
16638214e71cSJoe   for (p = 0; p < Np; ++p) {
16648214e71cSJoe     const PetscReal x0      = coords[p * dim + 0];
16658214e71cSJoe     const PetscReal vy0     = vel[p * dim + 1];
16668214e71cSJoe     const PetscReal omega   = vy0 / x0;
16678214e71cSJoe     PetscScalar     vals[4] = {0., 1., -PetscSqr(omega), 0.};
16688214e71cSJoe 
16698214e71cSJoe     for (d = 0; d < dim; ++d) {
16708214e71cSJoe       const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart};
16718214e71cSJoe       PetscCall(MatSetValues(J, 2, rows, 2, rows, vals, INSERT_VALUES));
16728214e71cSJoe     }
16738214e71cSJoe   }
1674*045208b8SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1675*045208b8SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
16768214e71cSJoe   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
16778214e71cSJoe   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
16788214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16798214e71cSJoe }
16808214e71cSJoe 
16818214e71cSJoe static PetscErrorCode RHSFunctionX(TS ts, PetscReal t, Vec V, Vec Xres, void *ctx)
16828214e71cSJoe {
16838214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
16848214e71cSJoe   DM                 sw;
16858214e71cSJoe   const PetscScalar *v;
16868214e71cSJoe   PetscScalar       *xres;
16878214e71cSJoe   PetscInt           Np, p, d, dim;
16888214e71cSJoe 
16898214e71cSJoe   PetscFunctionBeginUser;
169084467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsXEvent, ts, 0, 0, 0));
16918214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
16928214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16938214e71cSJoe   PetscCall(VecGetLocalSize(Xres, &Np));
16949566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(V, &v));
16958214e71cSJoe   PetscCall(VecGetArray(Xres, &xres));
1696b80bf5b1SJoe Pusztay   Np /= dim;
1697b80bf5b1SJoe Pusztay   for (p = 0; p < Np; ++p) {
1698*045208b8SMatthew G. Knepley     for (d = 0; d < dim; ++d) xres[p * dim + d] = v[p * dim + d];
1699b80bf5b1SJoe Pusztay   }
17009566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(V, &v));
17018214e71cSJoe   PetscCall(VecRestoreArray(Xres, &xres));
170284467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsXEvent, ts, 0, 0, 0));
17033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1704b80bf5b1SJoe Pusztay }
1705b80bf5b1SJoe Pusztay 
17068214e71cSJoe static PetscErrorCode RHSFunctionV(TS ts, PetscReal t, Vec X, Vec Vres, void *ctx)
17078214e71cSJoe {
17088214e71cSJoe   DM                 sw;
17098214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
17108214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
17118214e71cSJoe   const PetscScalar *x;
17128214e71cSJoe   PetscReal         *E, m_p, q_p;
17138214e71cSJoe   PetscScalar       *vres;
17148214e71cSJoe   PetscInt           Np, p, dim, d;
17158214e71cSJoe   Parameter         *param;
17168214e71cSJoe 
17178214e71cSJoe   PetscFunctionBeginUser;
171884467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsVEvent, ts, 0, 0, 0));
17198214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
17208214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
17218214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
17228214e71cSJoe   PetscCall(PetscBagGetData(user->bag, (void **)&param));
17238214e71cSJoe   m_p = user->masses[0] * param->m0;
17248214e71cSJoe   q_p = user->charges[0] * param->q0;
17258214e71cSJoe   PetscCall(VecGetLocalSize(Vres, &Np));
17268214e71cSJoe   PetscCall(VecGetArrayRead(X, &x));
17278214e71cSJoe   PetscCall(VecGetArray(Vres, &vres));
17288214e71cSJoe   PetscCall(ComputeFieldAtParticles(snes, sw, E));
17298214e71cSJoe 
17308214e71cSJoe   Np /= dim;
17318214e71cSJoe   for (p = 0; p < Np; ++p) {
1732*045208b8SMatthew G. Knepley     for (d = 0; d < dim; ++d) vres[p * dim + d] = q_p * E[p * dim + d] / m_p;
17338214e71cSJoe   }
17348214e71cSJoe   PetscCall(VecRestoreArrayRead(X, &x));
17358214e71cSJoe   /*
1736d7c1f440SPierre Jolivet     Synchronized, ordered output for parallel/sequential test cases.
17378214e71cSJoe     In the 1D (on the 2D mesh) case, every y component should be zero.
17388214e71cSJoe   */
17398214e71cSJoe   if (user->checkVRes) {
17408214e71cSJoe     PetscBool pr = user->checkVRes > 1 ? PETSC_TRUE : PETSC_FALSE;
17418214e71cSJoe     PetscInt  step;
17428214e71cSJoe 
17438214e71cSJoe     PetscCall(TSGetStepNumber(ts, &step));
17448214e71cSJoe     if (pr) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step: %" PetscInt_FMT "\n", step));
17458214e71cSJoe     for (PetscInt p = 0; p < Np; ++p) {
17468214e71cSJoe       if (pr) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Residual: %.12g %.12g\n", (double)PetscRealPart(vres[p * dim + 0]), (double)PetscRealPart(vres[p * dim + 1])));
17478214e71cSJoe       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]));
17488214e71cSJoe     }
17498214e71cSJoe     if (pr) PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
17508214e71cSJoe   }
17518214e71cSJoe   PetscCall(VecRestoreArray(Vres, &vres));
17528214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
175384467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsVEvent, ts, 0, 0, 0));
17548214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
17558214e71cSJoe }
17568214e71cSJoe 
17578214e71cSJoe static PetscErrorCode CreateSolution(TS ts)
17588214e71cSJoe {
17598214e71cSJoe   DM       sw;
17608214e71cSJoe   Vec      u;
17618214e71cSJoe   PetscInt dim, Np;
17628214e71cSJoe 
17638214e71cSJoe   PetscFunctionBegin;
17648214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
17658214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
17668214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
17678214e71cSJoe   PetscCall(VecCreate(PETSC_COMM_WORLD, &u));
17688214e71cSJoe   PetscCall(VecSetBlockSize(u, dim));
17698214e71cSJoe   PetscCall(VecSetSizes(u, 2 * Np * dim, PETSC_DECIDE));
17708214e71cSJoe   PetscCall(VecSetUp(u));
17718214e71cSJoe   PetscCall(TSSetSolution(ts, u));
17728214e71cSJoe   PetscCall(VecDestroy(&u));
17738214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
17748214e71cSJoe }
17758214e71cSJoe 
17768214e71cSJoe static PetscErrorCode SetProblem(TS ts)
17778214e71cSJoe {
17788214e71cSJoe   AppCtx *user;
17798214e71cSJoe   DM      sw;
17808214e71cSJoe 
17818214e71cSJoe   PetscFunctionBegin;
17828214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
17838214e71cSJoe   PetscCall(DMGetApplicationContext(sw, (void **)&user));
17848214e71cSJoe   // Define unified system for (X, V)
17858214e71cSJoe   {
17868214e71cSJoe     Mat      J;
17878214e71cSJoe     PetscInt dim, Np;
17888214e71cSJoe 
17898214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
17908214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
17918214e71cSJoe     PetscCall(MatCreate(PETSC_COMM_WORLD, &J));
17928214e71cSJoe     PetscCall(MatSetSizes(J, 2 * Np * dim, 2 * Np * dim, PETSC_DECIDE, PETSC_DECIDE));
17938214e71cSJoe     PetscCall(MatSetBlockSize(J, 2 * dim));
17948214e71cSJoe     PetscCall(MatSetFromOptions(J));
17958214e71cSJoe     PetscCall(MatSetUp(J));
17968214e71cSJoe     PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, user));
17978214e71cSJoe     PetscCall(TSSetRHSJacobian(ts, J, J, RHSJacobian, user));
17988214e71cSJoe     PetscCall(MatDestroy(&J));
17998214e71cSJoe   }
18008214e71cSJoe   /* Define split system for X and V */
18018214e71cSJoe   {
18028214e71cSJoe     Vec             u;
18038214e71cSJoe     IS              isx, isv, istmp;
18048214e71cSJoe     const PetscInt *idx;
18058214e71cSJoe     PetscInt        dim, Np, rstart;
18068214e71cSJoe 
18078214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
18088214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
18098214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
18108214e71cSJoe     PetscCall(VecGetOwnershipRange(u, &rstart, NULL));
18118214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 0, 2, &istmp));
18128214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
18138214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isx));
18148214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
18158214e71cSJoe     PetscCall(ISDestroy(&istmp));
18168214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 1, 2, &istmp));
18178214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
18188214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isv));
18198214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
18208214e71cSJoe     PetscCall(ISDestroy(&istmp));
18218214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "position", isx));
18228214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "momentum", isv));
18238214e71cSJoe     PetscCall(ISDestroy(&isx));
18248214e71cSJoe     PetscCall(ISDestroy(&isv));
18258214e71cSJoe     PetscCall(TSRHSSplitSetRHSFunction(ts, "position", NULL, RHSFunctionX, user));
18268214e71cSJoe     PetscCall(TSRHSSplitSetRHSFunction(ts, "momentum", NULL, RHSFunctionV, user));
18278214e71cSJoe   }
18288214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18298214e71cSJoe }
18308214e71cSJoe 
18318214e71cSJoe static PetscErrorCode DMSwarmTSRedistribute(TS ts)
18328214e71cSJoe {
18338214e71cSJoe   DM        sw;
18348214e71cSJoe   Vec       u;
18358214e71cSJoe   PetscReal t, maxt, dt;
18368214e71cSJoe   PetscInt  n, maxn;
18378214e71cSJoe 
18388214e71cSJoe   PetscFunctionBegin;
18398214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
18408214e71cSJoe   PetscCall(TSGetTime(ts, &t));
18418214e71cSJoe   PetscCall(TSGetMaxTime(ts, &maxt));
18428214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
18438214e71cSJoe   PetscCall(TSGetStepNumber(ts, &n));
18448214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
18458214e71cSJoe 
18468214e71cSJoe   PetscCall(TSReset(ts));
18478214e71cSJoe   PetscCall(TSSetDM(ts, sw));
18488214e71cSJoe   PetscCall(TSSetFromOptions(ts));
18498214e71cSJoe   PetscCall(TSSetTime(ts, t));
18508214e71cSJoe   PetscCall(TSSetMaxTime(ts, maxt));
18518214e71cSJoe   PetscCall(TSSetTimeStep(ts, dt));
18528214e71cSJoe   PetscCall(TSSetStepNumber(ts, n));
18538214e71cSJoe   PetscCall(TSSetMaxSteps(ts, maxn));
18548214e71cSJoe 
18558214e71cSJoe   PetscCall(CreateSolution(ts));
18568214e71cSJoe   PetscCall(SetProblem(ts));
18578214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
18588214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18598214e71cSJoe }
18608214e71cSJoe 
18618214e71cSJoe PetscErrorCode line(PetscInt dim, PetscReal time, const PetscReal dummy[], PetscInt p, PetscScalar x[], void *ctx)
18628214e71cSJoe {
18638214e71cSJoe   DM        sw, cdm;
18648214e71cSJoe   PetscInt  Np;
18658214e71cSJoe   PetscReal low[2], high[2];
18668214e71cSJoe   AppCtx   *user = (AppCtx *)ctx;
18678214e71cSJoe 
18688214e71cSJoe   sw = user->swarm;
18698214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &cdm));
18708214e71cSJoe   // Get the bounding box so we can equally space the particles
18718214e71cSJoe   PetscCall(DMGetLocalBoundingBox(cdm, low, high));
18728214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
18738214e71cSJoe   // shift it by h/2 so nothing is initialized directly on a boundary
18748214e71cSJoe   x[0] = ((high[0] - low[0]) / Np) * (p + 0.5);
18758214e71cSJoe   x[1] = 0.;
18768214e71cSJoe   return PETSC_SUCCESS;
18778214e71cSJoe }
18788214e71cSJoe 
1879b80bf5b1SJoe Pusztay /*
18808214e71cSJoe   InitializeSolveAndSwarm - Set the solution values to the swarm coordinates and velocities, and also possibly set the initial values.
18818214e71cSJoe 
18828214e71cSJoe   Input Parameters:
18838214e71cSJoe + ts         - The TS
1884d7c1f440SPierre Jolivet - useInitial - Flag to also set the initial conditions to the current coordinates and velocities and setup the problem
18858214e71cSJoe 
18868214e71cSJoe   Output Parameters:
18878214e71cSJoe . u - The initialized solution vector
18888214e71cSJoe 
18898214e71cSJoe   Level: advanced
18908214e71cSJoe 
18918214e71cSJoe .seealso: InitializeSolve()
1892b80bf5b1SJoe Pusztay */
18938214e71cSJoe static PetscErrorCode InitializeSolveAndSwarm(TS ts, PetscBool useInitial)
1894d71ae5a4SJacob Faibussowitsch {
18958214e71cSJoe   DM       sw;
1896*045208b8SMatthew G. Knepley   Vec      u, gc, gv;
18978214e71cSJoe   IS       isx, isv;
18988214e71cSJoe   PetscInt dim;
18998214e71cSJoe   AppCtx  *user;
1900b80bf5b1SJoe Pusztay 
1901b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
19028214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19038214e71cSJoe   PetscCall(DMGetApplicationContext(sw, &user));
19048214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
19058214e71cSJoe   if (useInitial) {
19068214e71cSJoe     PetscReal v0[2] = {1., 0.};
19078214e71cSJoe     if (user->perturbed_weights) {
19088214e71cSJoe       PetscCall(InitializeParticles_PerturbedWeights(sw, user));
19098214e71cSJoe     } else {
19108214e71cSJoe       PetscCall(DMSwarmComputeLocalSizeFromOptions(sw));
19118214e71cSJoe       PetscCall(DMSwarmInitializeCoordinates(sw));
19128214e71cSJoe       PetscCall(DMSwarmInitializeVelocitiesFromOptions(sw, v0));
19138214e71cSJoe     }
19148214e71cSJoe     PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
19158214e71cSJoe     PetscCall(DMSwarmTSRedistribute(ts));
19168214e71cSJoe   }
1917*045208b8SMatthew G. Knepley   PetscCall(DMSetUp(sw));
19188214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
19198214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
19208214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
19218214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19228214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
19238214e71cSJoe   PetscCall(VecISCopy(u, isx, SCATTER_FORWARD, gc));
19248214e71cSJoe   PetscCall(VecISCopy(u, isv, SCATTER_FORWARD, gv));
19258214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19268214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
19278214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
19288214e71cSJoe }
19298214e71cSJoe 
19308214e71cSJoe static PetscErrorCode InitializeSolve(TS ts, Vec u)
1931b80bf5b1SJoe Pusztay {
19328214e71cSJoe   PetscFunctionBegin;
19338214e71cSJoe   PetscCall(TSSetSolution(ts, u));
19348214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_TRUE));
19358214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
1936b80bf5b1SJoe Pusztay }
1937b80bf5b1SJoe Pusztay 
19388214e71cSJoe static PetscErrorCode MigrateParticles(TS ts)
19398214e71cSJoe {
19408214e71cSJoe   DM               sw, cdm;
19418214e71cSJoe   const PetscReal *L;
19429072cb8bSMatthew G. Knepley   AppCtx          *ctx;
19438214e71cSJoe 
19448214e71cSJoe   PetscFunctionBeginUser;
19458214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19469072cb8bSMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &ctx));
19478214e71cSJoe   PetscCall(DMViewFromOptions(sw, NULL, "-migrate_view_pre"));
19488214e71cSJoe   {
19498214e71cSJoe     Vec        u, gc, gv, position, momentum;
19508214e71cSJoe     IS         isx, isv;
19518214e71cSJoe     PetscReal *pos, *mom;
19528214e71cSJoe 
19538214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
19548214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
19558214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
19568214e71cSJoe     PetscCall(VecGetSubVector(u, isx, &position));
19578214e71cSJoe     PetscCall(VecGetSubVector(u, isv, &momentum));
19588214e71cSJoe     PetscCall(VecGetArray(position, &pos));
19598214e71cSJoe     PetscCall(VecGetArray(momentum, &mom));
19608214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19618214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
19628214e71cSJoe     PetscCall(VecISCopy(u, isx, SCATTER_REVERSE, gc));
19638214e71cSJoe     PetscCall(VecISCopy(u, isv, SCATTER_REVERSE, gv));
19648214e71cSJoe 
19658214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &cdm));
19668214e71cSJoe     PetscCall(DMGetPeriodicity(cdm, NULL, NULL, &L));
19678214e71cSJoe     if ((L[0] || L[1]) >= 0.) {
19688214e71cSJoe       PetscReal *x, *v, upper[3], lower[3];
19698214e71cSJoe       PetscInt   Np, dim;
19708214e71cSJoe 
19718214e71cSJoe       PetscCall(DMSwarmGetLocalSize(sw, &Np));
19728214e71cSJoe       PetscCall(DMGetDimension(cdm, &dim));
19738214e71cSJoe       PetscCall(DMGetBoundingBox(cdm, lower, upper));
19748214e71cSJoe       PetscCall(VecGetArray(gc, &x));
19758214e71cSJoe       PetscCall(VecGetArray(gv, &v));
19768214e71cSJoe       for (PetscInt p = 0; p < Np; ++p) {
19778214e71cSJoe         for (PetscInt d = 0; d < dim; ++d) {
19788214e71cSJoe           if (pos[p * dim + d] < lower[d]) {
19798214e71cSJoe             x[p * dim + d] = pos[p * dim + d] + (upper[d] - lower[d]);
19808214e71cSJoe           } else if (pos[p * dim + d] > upper[d]) {
19818214e71cSJoe             x[p * dim + d] = pos[p * dim + d] - (upper[d] - lower[d]);
19828214e71cSJoe           } else {
19838214e71cSJoe             x[p * dim + d] = pos[p * dim + d];
19848214e71cSJoe           }
19858214e71cSJoe           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]);
19868214e71cSJoe           v[p * dim + d] = mom[p * dim + d];
19878214e71cSJoe         }
19888214e71cSJoe       }
19898214e71cSJoe       PetscCall(VecRestoreArray(gc, &x));
19908214e71cSJoe       PetscCall(VecRestoreArray(gv, &v));
19918214e71cSJoe     }
19928214e71cSJoe     PetscCall(VecRestoreArray(position, &pos));
19938214e71cSJoe     PetscCall(VecRestoreArray(momentum, &mom));
19948214e71cSJoe     PetscCall(VecRestoreSubVector(u, isx, &position));
19958214e71cSJoe     PetscCall(VecRestoreSubVector(u, isv, &momentum));
19968214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
19978214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19988214e71cSJoe   }
19998214e71cSJoe   PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
20009072cb8bSMatthew G. Knepley   PetscInt step;
20019072cb8bSMatthew G. Knepley 
20029072cb8bSMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &step));
2003*045208b8SMatthew G. Knepley   if (!(step % ctx->remapFreq)) {
20049072cb8bSMatthew G. Knepley     // Monitor electric field before we destroy it
20059072cb8bSMatthew G. Knepley     PetscReal ptime;
20069072cb8bSMatthew G. Knepley     PetscInt  step;
20079072cb8bSMatthew G. Knepley 
20089072cb8bSMatthew G. Knepley     PetscCall(TSGetStepNumber(ts, &step));
20099072cb8bSMatthew G. Knepley     PetscCall(TSGetTime(ts, &ptime));
20109072cb8bSMatthew G. Knepley     if (ctx->efield_monitor) PetscCall(MonitorEField(ts, step, ptime, NULL, ctx));
20119072cb8bSMatthew G. Knepley     if (ctx->poisson_monitor) PetscCall(MonitorPoisson(ts, step, ptime, NULL, ctx));
20129072cb8bSMatthew G. Knepley     PetscCall(DMSwarmRemap(sw));
20139072cb8bSMatthew G. Knepley     ctx->validE = PETSC_FALSE;
20149072cb8bSMatthew G. Knepley   }
20159072cb8bSMatthew G. Knepley   // This MUST come last, since it recreates the subswarms and they must DMClone() the new swarm
20168214e71cSJoe   PetscCall(DMSwarmTSRedistribute(ts));
20178214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_FALSE));
20183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2019b80bf5b1SJoe Pusztay }
2020b80bf5b1SJoe Pusztay 
2021d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
2022d71ae5a4SJacob Faibussowitsch {
2023b80bf5b1SJoe Pusztay   DM        dm, sw;
20248214e71cSJoe   TS        ts;
20258214e71cSJoe   Vec       u;
20268214e71cSJoe   PetscReal dt;
20278214e71cSJoe   PetscInt  maxn;
2028b80bf5b1SJoe Pusztay   AppCtx    user;
2029b80bf5b1SJoe Pusztay 
20309566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
20318214e71cSJoe   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
20328214e71cSJoe   PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &user.bag));
20338214e71cSJoe   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
20348214e71cSJoe   PetscCall(CreatePoisson(dm, &user));
20358214e71cSJoe   PetscCall(CreateSwarm(dm, &user, &sw));
20368214e71cSJoe   PetscCall(SetupParameters(PETSC_COMM_WORLD, &user));
20378214e71cSJoe   PetscCall(InitializeConstants(sw, &user));
20388214e71cSJoe   PetscCall(DMSetApplicationContext(sw, &user));
2039b80bf5b1SJoe Pusztay 
20408214e71cSJoe   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
20418214e71cSJoe   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
20429566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts, sw));
20438214e71cSJoe   PetscCall(TSSetMaxTime(ts, 0.1));
20448214e71cSJoe   PetscCall(TSSetTimeStep(ts, 0.00001));
20458214e71cSJoe   PetscCall(TSSetMaxSteps(ts, 100));
20468214e71cSJoe   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
20478214e71cSJoe 
20488214e71cSJoe   if (user.efield_monitor) PetscCall(TSMonitorSet(ts, MonitorEField, &user, NULL));
2049f1e6e573SMatthew G. Knepley   if (user.moment_monitor) PetscCall(TSMonitorSet(ts, MonitorMoments, &user, NULL));
20508214e71cSJoe   if (user.initial_monitor) PetscCall(TSMonitorSet(ts, MonitorInitialConditions, &user, NULL));
20519072cb8bSMatthew G. Knepley   if (user.positions_monitor) PetscCall(TSMonitorSet(ts, MonitorPositions_2D, &user, NULL));
20528214e71cSJoe   if (user.poisson_monitor) PetscCall(TSMonitorSet(ts, MonitorPoisson, &user, NULL));
20538214e71cSJoe 
20548214e71cSJoe   PetscCall(TSSetFromOptions(ts));
20558214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
20568214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
20578214e71cSJoe   user.steps    = maxn;
20588214e71cSJoe   user.stepSize = dt;
20598214e71cSJoe   PetscCall(SetupContext(dm, sw, &user));
20608214e71cSJoe   PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve));
20618214e71cSJoe   PetscCall(TSSetPostStep(ts, MigrateParticles));
20628214e71cSJoe   PetscCall(CreateSolution(ts));
20638214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
20648214e71cSJoe   PetscCall(TSComputeInitialCondition(ts, u));
20658214e71cSJoe   PetscCall(CheckNonNegativeWeights(sw, &user));
20668214e71cSJoe   PetscCall(TSSolve(ts, NULL));
20678214e71cSJoe 
20689566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&user.snes));
2069f1e6e573SMatthew G. Knepley   PetscCall(MatDestroy(&user.M));
2070f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomDestroy(&user.fegeom));
20719566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
20729566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sw));
20739566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
20748214e71cSJoe   PetscCall(DestroyContext(&user));
20759566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
2076b122ec5aSJacob Faibussowitsch   return 0;
2077b80bf5b1SJoe Pusztay }
2078b80bf5b1SJoe Pusztay 
2079b80bf5b1SJoe Pusztay /*TEST
2080b80bf5b1SJoe Pusztay 
2081b80bf5b1SJoe Pusztay    build:
20828214e71cSJoe     requires: !complex double
20838214e71cSJoe 
20848214e71cSJoe   # This tests that we can put particles in a box and compute the Coulomb force
20858214e71cSJoe   # Recommend -draw_size 500,500
20868214e71cSJoe    testset:
20878214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2088*045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 20 \
2089*045208b8SMatthew G. Knepley              -dm_plex_box_lower 0 -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
20909072cb8bSMatthew G. Knepley            -vdm_plex_simplex 0 \
20918214e71cSJoe            -dm_swarm_coordinate_density constant -dm_swarm_num_particles 100 \
20928214e71cSJoe            -sigma 1.0e-8 -timeScale 2.0e-14 \
20938214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
20948214e71cSJoe            -output_step 50 -check_vel_res
20958214e71cSJoe      test:
20968214e71cSJoe        suffix: none_1d
20979072cb8bSMatthew G. Knepley        requires:
20988214e71cSJoe        args: -em_type none -error
20998214e71cSJoe      test:
21008214e71cSJoe        suffix: coulomb_1d
21018214e71cSJoe        args: -em_type coulomb
21028214e71cSJoe 
21038214e71cSJoe    # for viewers
21048214e71cSJoe    #-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
21058214e71cSJoe    testset:
21068214e71cSJoe      nsize: {{1 2}}
21078214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2108*045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 36 \
2109*045208b8SMatthew G. Knepley              -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
21108214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
21118214e71cSJoe              -vdm_plex_box_lower -3 -vdm_plex_box_upper 3 \
211284467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -twostream -charges -1.,1. -sigma 1.0e-8 \
21138214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
21148214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 2 \
21158214e71cSJoe              -ts_dt 0.01 -ts_max_time 5 -ts_max_steps 10 \
21168214e71cSJoe            -em_snes_atol 1.e-15 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
211784467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
21188214e71cSJoe      test:
21198214e71cSJoe        suffix: two_stream_c0
21208214e71cSJoe        args: -em_type primal -petscfe_default_quadrature_order 2 -petscspace_degree 2 -em_pc_type svd
21218214e71cSJoe      test:
21228214e71cSJoe        suffix: two_stream_rt
21238214e71cSJoe        requires: superlu_dist
21248214e71cSJoe        args: -em_type mixed \
21258214e71cSJoe                -potential_petscspace_degree 0 \
21268214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
21278214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
2128*045208b8SMatthew G. Knepley                -field_petscspace_degree 1 -field_petscfe_default_quadrature_order 1 \
21298214e71cSJoe              -em_snes_error_if_not_converged \
21308214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
21318214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
21328214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
21338214e71cSJoe                -em_fieldsplit_field_pc_type lu \
21348214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
21358214e71cSJoe                -em_fieldsplit_potential_pc_type svd
21368214e71cSJoe 
213784467f86SMatthew G. Knepley    # For an eyeball check, we use
21389072cb8bSMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 10,1 -vdm_plex_box_faces 2000 -efield_monitor
21398214e71cSJoe    # For verification, we use
214084467f86SMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 100,1 -vdm_plex_box_faces 8000 -dm_swarm_num_particles 800000 -monitor_efield
21418214e71cSJoe    # -ts_monitor_sp_swarm_multi_species 0 -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500
21428214e71cSJoe    testset:
21438214e71cSJoe      nsize: {{1 2}}
21448214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2145*045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 10 \
2146*045208b8SMatthew G. Knepley              -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
21478214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
21488214e71cSJoe              -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \
2149f1e6e573SMatthew G. Knepley              -vpetscspace_degree 2 -vdm_plex_hash_location \
215084467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -charges -1.,1. \
21518214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
21528214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
21538214e71cSJoe              -ts_dt 0.03 -ts_max_time 500 -ts_max_steps 1 \
21548214e71cSJoe            -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
215584467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
21568214e71cSJoe 
21578214e71cSJoe      test:
21588214e71cSJoe        suffix: uniform_equilibrium_1d
21598214e71cSJoe        args: -cosine_coefficients 0.0,0.5 -em_type primal -petscspace_degree 1 -em_pc_type svd
21608214e71cSJoe      test:
216175155f48SMatthew G. Knepley        suffix: uniform_equilibrium_1d_real
2162*045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
216375155f48SMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
216475155f48SMatthew G. Knepley              -cosine_coefficients 0.0 -em_type primal -petscspace_degree 1 -em_pc_type svd
216575155f48SMatthew G. Knepley      test:
21668214e71cSJoe        suffix: uniform_primal_1d
21678214e71cSJoe        args: -em_type primal -petscspace_degree 1 -em_pc_type svd
21688214e71cSJoe      test:
216975155f48SMatthew G. Knepley        suffix: uniform_primal_1d_real
2170*045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
217175155f48SMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
217275155f48SMatthew G. Knepley              -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd
21739072cb8bSMatthew G. Knepley      # NOT WORKING -ftop_pc_type bjacobi -ftop_sub_pc_type lu -ftop_sub_pc_factor_shift_type nonzero
21749072cb8bSMatthew G. Knepley      test:
21759072cb8bSMatthew G. Knepley        suffix: uniform_primal_1d_real_pfak
21769072cb8bSMatthew G. Knepley        nsize: 1
2177*045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
21789072cb8bSMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
21799072cb8bSMatthew 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 \
21809072cb8bSMatthew G. Knepley                -remap_dm_plex_box_lower 0.,-10. -remap_dm_plex_box_upper 12.5664,10. \
21819072cb8bSMatthew G. Knepley                -remap_petscspace_degree 2 -remap_dm_plex_hash_location \
2182*045208b8SMatthew G. Knepley              -remap_freq 1 -dm_swarm_remap_type pfak \
21839072cb8bSMatthew G. Knepley                -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 \
21849072cb8bSMatthew G. Knepley                -ptof_pc_type lu \
21859072cb8bSMatthew G. Knepley              -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd -em_proj_pc_type lu
218675155f48SMatthew G. Knepley      test:
21878214e71cSJoe        requires: superlu_dist
21888214e71cSJoe        suffix: uniform_mixed_1d
21898214e71cSJoe        args: -em_type mixed \
21908214e71cSJoe                -potential_petscspace_degree 0 \
21918214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
21928214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
2193*045208b8SMatthew G. Knepley                -field_petscspace_degree 1 \
21948214e71cSJoe              -em_snes_error_if_not_converged \
21958214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
21968214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
21978214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
21988214e71cSJoe                -em_fieldsplit_field_pc_type lu \
21998214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
22008214e71cSJoe                -em_fieldsplit_potential_pc_type svd
22018214e71cSJoe 
2202b80bf5b1SJoe Pusztay TEST*/
2203