xref: /petsc/src/ts/tutorials/hamiltonian/ex2.c (revision 4a0cbf56f3c1d47f3fb031bb76cf3f0006704aef)
18214e71cSJoe static char help[] = "Landau Damping/Two Stream instability test using Vlasov-Poisson equations\n";
2b80bf5b1SJoe Pusztay 
38214e71cSJoe /*
49072cb8bSMatthew G. Knepley   TODO:
59072cb8bSMatthew G. Knepley   - Cache mesh geometry
69072cb8bSMatthew G. Knepley   - Move electrostatic solver to MG+SVD
79072cb8bSMatthew G. Knepley 
88214e71cSJoe   To run the code with particles sinusoidally perturbed in x space use the test "pp_poisson_bsi_1d_4" or "pp_poisson_bsi_2d_4"
98214e71cSJoe   According to Lukas, good damping results come at ~16k particles per cell
108214e71cSJoe 
119072cb8bSMatthew G. Knepley   To visualize the maximum electric field use
128214e71cSJoe 
139072cb8bSMatthew G. Knepley     -efield_monitor
148214e71cSJoe 
159072cb8bSMatthew G. Knepley   To monitor velocity moments of the distribution use
16f1e6e573SMatthew G. Knepley 
179072cb8bSMatthew G. Knepley     -ptof_pc_type lu -moments_monitor
189072cb8bSMatthew G. Knepley 
199072cb8bSMatthew G. Knepley   To monitor the particle positions in phase space use
209072cb8bSMatthew G. Knepley 
219072cb8bSMatthew G. Knepley     -positions_monitor
229072cb8bSMatthew G. Knepley 
239072cb8bSMatthew G. Knepley   To monitor the charge density, E field, and potential use
249072cb8bSMatthew G. Knepley 
259072cb8bSMatthew G. Knepley     -poisson_monitor
269072cb8bSMatthew G. Knepley 
279072cb8bSMatthew G. Knepley   To monitor the remapping field use
289072cb8bSMatthew G. Knepley 
299072cb8bSMatthew G. Knepley     -remap_uf_view draw
30f1e6e573SMatthew G. Knepley 
318214e71cSJoe   To visualize the swarm distribution use
328214e71cSJoe 
338214e71cSJoe     -ts_monitor_hg_swarm
348214e71cSJoe 
358214e71cSJoe   To visualize the particles, we can use
368214e71cSJoe 
378214e71cSJoe     -ts_monitor_sp_swarm -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500
388214e71cSJoe 
3984467f86SMatthew G. Knepley For a Landau Damping verification run, we use
4084467f86SMatthew G. Knepley 
41045208b8SMatthew G. Knepley   # Physics
42045208b8SMatthew G. Knepley   -cosine_coefficients 0.01 -dm_swarm_num_species 1 -charges -1. -perturbed_weights -total_weight 1.
43045208b8SMatthew G. Knepley   # Spatial Mesh
44045208b8SMatthew G. Knepley   -dm_plex_dim 1 -dm_plex_box_faces 40 -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic  -dm_plex_hash_location
45045208b8SMatthew G. Knepley   # Velocity Mesh
46045208b8SMatthew G. Knepley   -vdm_plex_dim 1 -vdm_plex_box_faces 40 -vdm_plex_box_lower -6 -vdm_plex_box_upper 6 -vpetscspace_degree 2 -vdm_plex_hash_location
47045208b8SMatthew G. Knepley   # Remap Space
48045208b8SMatthew G. Knepley   -dm_swarm_remap_type pfak -remap_freq 100
49045208b8SMatthew G. Knepley   -remap_dm_plex_dim 2 -remap_dm_plex_simplex 0 -remap_dm_plex_box_faces 20,20 -remap_dm_plex_box_bd periodic,none -remap_dm_plex_box_lower 0.,-6.
50045208b8SMatthew G. Knepley     -remap_dm_plex_box_upper 12.5664,6. -remap_petscspace_degree 1 -remap_dm_plex_hash_location
51045208b8SMatthew G. Knepley   # Remap Solve
52045208b8SMatthew G. Knepley   -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 -ptof_pc_type lu
53045208b8SMatthew G. Knepley   # EM Solve
54045208b8SMatthew G. Knepley   -em_type primal -petscspace_degree 1 -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged -em_pc_type svd -em_proj_pc_type lu
55045208b8SMatthew G. Knepley   # Timestepping
56045208b8SMatthew G. Knepley   -ts_type basicsymplectic -ts_basicsymplectic_type 1 -ts_dt 0.03 -ts_max_steps 1500 -ts_max_time 100
57045208b8SMatthew G. Knepley   # Monitoring
58045208b8SMatthew G. Knepley   -output_step 1 -check_vel_res -efield_monitor -poisson_monitor -positions_monitor -dm_swarm_print_coords 0 -remap_uf_view draw
59045208b8SMatthew G. Knepley     -ftop_ksp_lsqr_monitor -ftop_ksp_converged_reason
6084467f86SMatthew G. Knepley 
618214e71cSJoe */
62b80bf5b1SJoe Pusztay #include <petscts.h>
638214e71cSJoe #include <petscdmplex.h>
648214e71cSJoe #include <petscdmswarm.h>
658214e71cSJoe #include <petscfe.h>
668214e71cSJoe #include <petscds.h>
678214e71cSJoe #include <petscbag.h>
688214e71cSJoe #include <petscdraw.h>
698214e71cSJoe #include <petsc/private/dmpleximpl.h>  /* For norm and dot */
708214e71cSJoe #include <petsc/private/petscfeimpl.h> /* For interpolation */
7184467f86SMatthew G. Knepley #include <petsc/private/dmswarmimpl.h> /* For swarm debugging */
728214e71cSJoe #include "petscdm.h"
738214e71cSJoe #include "petscdmlabel.h"
748214e71cSJoe 
758214e71cSJoe PETSC_EXTERN PetscErrorCode stream(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
768214e71cSJoe PETSC_EXTERN PetscErrorCode line(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
778214e71cSJoe 
788214e71cSJoe const char *EMTypes[] = {"primal", "mixed", "coulomb", "none", "EMType", "EM_", NULL};
798214e71cSJoe typedef enum {
808214e71cSJoe   EM_PRIMAL,
818214e71cSJoe   EM_MIXED,
828214e71cSJoe   EM_COULOMB,
838214e71cSJoe   EM_NONE
848214e71cSJoe } EMType;
858214e71cSJoe 
868214e71cSJoe typedef enum {
878214e71cSJoe   V0,
888214e71cSJoe   X0,
898214e71cSJoe   T0,
908214e71cSJoe   M0,
918214e71cSJoe   Q0,
928214e71cSJoe   PHI0,
938214e71cSJoe   POISSON,
948214e71cSJoe   VLASOV,
958214e71cSJoe   SIGMA,
968214e71cSJoe   NUM_CONSTANTS
978214e71cSJoe } ConstantType;
988214e71cSJoe typedef struct {
998214e71cSJoe   PetscScalar v0; /* Velocity scale, often the thermal velocity */
1008214e71cSJoe   PetscScalar t0; /* Time scale */
1018214e71cSJoe   PetscScalar x0; /* Space scale */
1028214e71cSJoe   PetscScalar m0; /* Mass scale */
1038214e71cSJoe   PetscScalar q0; /* Charge scale */
1048214e71cSJoe   PetscScalar kb;
1058214e71cSJoe   PetscScalar epsi0;
1068214e71cSJoe   PetscScalar phi0;          /* Potential scale */
1078214e71cSJoe   PetscScalar poissonNumber; /* Non-Dimensional Poisson Number */
1088214e71cSJoe   PetscScalar vlasovNumber;  /* Non-Dimensional Vlasov Number */
1098214e71cSJoe   PetscReal   sigma;         /* Nondimensional charge per length in x */
1108214e71cSJoe } Parameter;
111b80bf5b1SJoe Pusztay 
112b80bf5b1SJoe Pusztay typedef struct {
1139072cb8bSMatthew G. Knepley   PetscBag     bag;               // Problem parameters
1149072cb8bSMatthew G. Knepley   PetscBool    error;             // Flag for printing the error
1159072cb8bSMatthew G. Knepley   PetscInt     remapFreq;         // Number of timesteps between remapping
1169072cb8bSMatthew G. Knepley   PetscBool    efield_monitor;    // Flag to show electric field monitor
1179072cb8bSMatthew G. Knepley   PetscBool    moment_monitor;    // Flag to show distribution moment monitor
1189072cb8bSMatthew G. Knepley   PetscBool    positions_monitor; // Flag to show particle positins at each time step
1199072cb8bSMatthew G. Knepley   PetscBool    poisson_monitor;   // Flag to display charge, E field, and potential at each solve
1209072cb8bSMatthew G. Knepley   PetscBool    initial_monitor;   // Flag to monitor the initial conditions
1219072cb8bSMatthew G. Knepley   PetscBool    perturbed_weights; // Uniformly sample x,v space with gaussian weights
1229072cb8bSMatthew G. Knepley   PetscInt     ostep;             // Print the energy at each ostep time steps
1238214e71cSJoe   PetscInt     numParticles;
1248214e71cSJoe   PetscReal    timeScale;              /* Nondimensionalizing time scale */
1258214e71cSJoe   PetscReal    charges[2];             /* The charges of each species */
1268214e71cSJoe   PetscReal    masses[2];              /* The masses of each species */
1278214e71cSJoe   PetscReal    thermal_energy[2];      /* Thermal Energy (used to get other constants)*/
1288214e71cSJoe   PetscReal    cosine_coefficients[2]; /*(alpha, k)*/
1298214e71cSJoe   PetscReal    totalWeight;
1308214e71cSJoe   PetscReal    stepSize;
1318214e71cSJoe   PetscInt     steps;
1328214e71cSJoe   PetscReal    initVel;
133f1e6e573SMatthew G. Knepley   EMType       em;     // Type of electrostatic model
134f1e6e573SMatthew G. Knepley   SNES         snes;   // EM solver
135*4a0cbf56SMatthew G. Knepley   DM           dmPot;  // The DM for potential
136*4a0cbf56SMatthew G. Knepley   IS           isPot;  // The IS for potential, or NULL in primal
137*4a0cbf56SMatthew G. Knepley   Mat          M;      // The finite element mass matrix for potential
138f1e6e573SMatthew G. Knepley   PetscFEGeom *fegeom; // Geometric information for the DM cells
1398214e71cSJoe   PetscDraw    drawic_x;
1408214e71cSJoe   PetscDraw    drawic_v;
1418214e71cSJoe   PetscDraw    drawic_w;
1428214e71cSJoe   PetscDrawHG  drawhgic_x;
1438214e71cSJoe   PetscDrawHG  drawhgic_v;
1448214e71cSJoe   PetscDrawHG  drawhgic_w;
1459072cb8bSMatthew G. Knepley   PetscBool    validE;     // Flag to indicate E-field in swarm is valid
14675155f48SMatthew G. Knepley   PetscReal    drawlgEmin; // The minimum lg(E) to plot
14775155f48SMatthew G. Knepley   PetscDrawLG  drawlgE;    // Logarithm of maximum electric field
14875155f48SMatthew G. Knepley   PetscDrawSP  drawspE;    // Electric field at particle positions
14975155f48SMatthew G. Knepley   PetscDrawSP  drawspX;    // Particle positions
15075155f48SMatthew G. Knepley   PetscViewer  viewerRho;  // Charge density viewer
15175155f48SMatthew G. Knepley   PetscViewer  viewerPhi;  // Potential viewer
1528214e71cSJoe   DM           swarm;
1538214e71cSJoe   PetscRandom  random;
1548214e71cSJoe   PetscBool    twostream;
1558214e71cSJoe   PetscBool    checkweights;
1568214e71cSJoe   PetscInt     checkVRes; /* Flag to check/output velocity residuals for nightly tests */
15784467f86SMatthew G. Knepley 
15884467f86SMatthew G. Knepley   PetscLogEvent RhsXEvent, RhsVEvent, ESolveEvent, ETabEvent;
159b80bf5b1SJoe Pusztay } AppCtx;
160b80bf5b1SJoe Pusztay 
161d71ae5a4SJacob Faibussowitsch static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
162d71ae5a4SJacob Faibussowitsch {
163b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
1648214e71cSJoe   PetscInt d                      = 2;
1658214e71cSJoe   PetscInt maxSpecies             = 2;
1668214e71cSJoe   options->error                  = PETSC_FALSE;
1679072cb8bSMatthew G. Knepley   options->remapFreq              = 1;
1688214e71cSJoe   options->efield_monitor         = PETSC_FALSE;
169f1e6e573SMatthew G. Knepley   options->moment_monitor         = PETSC_FALSE;
1708214e71cSJoe   options->initial_monitor        = PETSC_FALSE;
1718214e71cSJoe   options->perturbed_weights      = PETSC_FALSE;
1728214e71cSJoe   options->poisson_monitor        = PETSC_FALSE;
1739072cb8bSMatthew G. Knepley   options->positions_monitor      = PETSC_FALSE;
1748214e71cSJoe   options->ostep                  = 100;
1758214e71cSJoe   options->timeScale              = 2.0e-14;
1768214e71cSJoe   options->charges[0]             = -1.0;
1778214e71cSJoe   options->charges[1]             = 1.0;
1788214e71cSJoe   options->masses[0]              = 1.0;
1798214e71cSJoe   options->masses[1]              = 1000.0;
1808214e71cSJoe   options->thermal_energy[0]      = 1.0;
1818214e71cSJoe   options->thermal_energy[1]      = 1.0;
1828214e71cSJoe   options->cosine_coefficients[0] = 0.01;
1838214e71cSJoe   options->cosine_coefficients[1] = 0.5;
1848214e71cSJoe   options->initVel                = 1;
1858214e71cSJoe   options->totalWeight            = 1.0;
1868214e71cSJoe   options->drawic_x               = NULL;
1878214e71cSJoe   options->drawic_v               = NULL;
1888214e71cSJoe   options->drawic_w               = NULL;
1898214e71cSJoe   options->drawhgic_x             = NULL;
1908214e71cSJoe   options->drawhgic_v             = NULL;
1918214e71cSJoe   options->drawhgic_w             = NULL;
19275155f48SMatthew G. Knepley   options->drawlgEmin             = -6;
19375155f48SMatthew G. Knepley   options->drawlgE                = NULL;
19475155f48SMatthew G. Knepley   options->drawspE                = NULL;
19575155f48SMatthew G. Knepley   options->drawspX                = NULL;
19675155f48SMatthew G. Knepley   options->viewerRho              = NULL;
19775155f48SMatthew G. Knepley   options->viewerPhi              = NULL;
1988214e71cSJoe   options->em                     = EM_COULOMB;
199*4a0cbf56SMatthew G. Knepley   options->snes                   = NULL;
200*4a0cbf56SMatthew G. Knepley   options->dmPot                  = NULL;
201*4a0cbf56SMatthew G. Knepley   options->isPot                  = NULL;
202*4a0cbf56SMatthew G. Knepley   options->M                      = NULL;
2038214e71cSJoe   options->numParticles           = 32768;
2048214e71cSJoe   options->twostream              = PETSC_FALSE;
2058214e71cSJoe   options->checkweights           = PETSC_FALSE;
2068214e71cSJoe   options->checkVRes              = 0;
207b80bf5b1SJoe Pusztay 
2088214e71cSJoe   PetscOptionsBegin(comm, "", "Landau Damping and Two Stream options", "DMSWARM");
2098214e71cSJoe   PetscCall(PetscOptionsBool("-error", "Flag to print the error", "ex2.c", options->error, &options->error, NULL));
2109072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsInt("-remap_freq", "Number", "ex2.c", options->remapFreq, &options->remapFreq, NULL));
2119072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-efield_monitor", "Flag to plot log(max E) over time", "ex2.c", options->efield_monitor, &options->efield_monitor, NULL));
2129072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsReal("-efield_min_monitor", "Minimum E field to plot", "ex2.c", options->drawlgEmin, &options->drawlgEmin, NULL));
2139072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-moments_monitor", "Flag to show moments table", "ex2.c", options->moment_monitor, &options->moment_monitor, NULL));
2149072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-ics_monitor", "Flag to show initial condition histograms", "ex2.c", options->initial_monitor, &options->initial_monitor, NULL));
2159072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-positions_monitor", "The flag to show particle positions", "ex2.c", options->positions_monitor, &options->positions_monitor, NULL));
2169072cb8bSMatthew G. Knepley   PetscCall(PetscOptionsBool("-poisson_monitor", "The flag to show charges, Efield and potential solve", "ex2.c", options->poisson_monitor, &options->poisson_monitor, NULL));
2178214e71cSJoe   PetscCall(PetscOptionsBool("-twostream", "Run two stream instability", "ex2.c", options->twostream, &options->twostream, NULL));
2188214e71cSJoe   PetscCall(PetscOptionsBool("-perturbed_weights", "Flag to run uniform sampling with perturbed weights", "ex2.c", options->perturbed_weights, &options->perturbed_weights, NULL));
2198214e71cSJoe   PetscCall(PetscOptionsBool("-check_weights", "Ensure all particle weights are positive", "ex2.c", options->checkweights, &options->checkweights, NULL));
2208214e71cSJoe   PetscCall(PetscOptionsInt("-check_vel_res", "Check particle velocity residuals for nightly tests", "ex2.c", options->checkVRes, &options->checkVRes, NULL));
2218214e71cSJoe   PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", "ex2.c", options->ostep, &options->ostep, NULL));
2228214e71cSJoe   PetscCall(PetscOptionsReal("-timeScale", "Nondimensionalizing time scale", "ex2.c", options->timeScale, &options->timeScale, NULL));
2238214e71cSJoe   PetscCall(PetscOptionsReal("-initial_velocity", "Initial velocity of perturbed particle", "ex2.c", options->initVel, &options->initVel, NULL));
2248214e71cSJoe   PetscCall(PetscOptionsReal("-total_weight", "Total weight of all particles", "ex2.c", options->totalWeight, &options->totalWeight, NULL));
2258214e71cSJoe   PetscCall(PetscOptionsRealArray("-cosine_coefficients", "Amplitude and frequency of cosine equation used in initialization", "ex2.c", options->cosine_coefficients, &d, NULL));
2268214e71cSJoe   PetscCall(PetscOptionsRealArray("-charges", "Species charges", "ex2.c", options->charges, &maxSpecies, NULL));
2278214e71cSJoe   PetscCall(PetscOptionsEnum("-em_type", "Type of electrostatic solver", "ex2.c", EMTypes, (PetscEnum)options->em, (PetscEnum *)&options->em, NULL));
228d0609cedSBarry Smith   PetscOptionsEnd();
22984467f86SMatthew G. Knepley 
23084467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsX", TS_CLASSID, &options->RhsXEvent));
23184467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsV", TS_CLASSID, &options->RhsVEvent));
23284467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ESolve", TS_CLASSID, &options->ESolveEvent));
23384467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ETab", TS_CLASSID, &options->ETabEvent));
2343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
235b80bf5b1SJoe Pusztay }
236b80bf5b1SJoe Pusztay 
2378214e71cSJoe static PetscErrorCode SetupContext(DM dm, DM sw, AppCtx *user)
2388214e71cSJoe {
2398214e71cSJoe   PetscFunctionBeginUser;
2408214e71cSJoe   if (user->efield_monitor) {
24175155f48SMatthew G. Knepley     PetscDraw     draw;
24275155f48SMatthew G. Knepley     PetscDrawAxis axis;
24375155f48SMatthew G. Knepley 
24475155f48SMatthew G. Knepley     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "Max Electric Field", 0, 300, 400, 300, &draw));
24575155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_Efield"));
24675155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
24775155f48SMatthew G. Knepley     PetscCall(PetscDrawLGCreate(draw, 1, &user->drawlgE));
24875155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
24975155f48SMatthew G. Knepley     PetscCall(PetscDrawLGGetAxis(user->drawlgE, &axis));
25075155f48SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Electron Electric Field", "time", "E_max"));
25175155f48SMatthew G. Knepley     PetscCall(PetscDrawLGSetLimits(user->drawlgE, 0., user->steps * user->stepSize, user->drawlgEmin, 0.));
2528214e71cSJoe   }
2538214e71cSJoe   if (user->initial_monitor) {
2548214e71cSJoe     PetscDrawAxis axis1, axis2, axis3;
2558214e71cSJoe     PetscReal     dmboxlower[2], dmboxupper[2];
2568214e71cSJoe     PetscInt      dim, cStart, cEnd;
2578214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
2588214e71cSJoe     PetscCall(DMGetBoundingBox(dm, dmboxlower, dmboxupper));
2598214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2608214e71cSJoe 
2618214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_x", 0, 300, 400, 300, &user->drawic_x));
26275155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(user->drawic_x, "ex9_ic_x"));
2638214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawic_x));
2646497c311SBarry Smith     PetscCall(PetscDrawHGCreate(user->drawic_x, (int)dim, &user->drawhgic_x));
2658214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_x, &axis1));
2666497c311SBarry Smith     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_x, (int)(cEnd - cStart)));
2678214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis1, "Initial X Distribution", "X", "counts"));
2688214e71cSJoe     PetscCall(PetscDrawAxisSetLimits(axis1, dmboxlower[0], dmboxupper[0], 0, 1500));
2698214e71cSJoe 
2708214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_v", 400, 300, 400, 300, &user->drawic_v));
27175155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(user->drawic_v, "ex9_ic_v"));
2728214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawic_v));
2736497c311SBarry Smith     PetscCall(PetscDrawHGCreate(user->drawic_v, (int)dim, &user->drawhgic_v));
2748214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_v, &axis2));
2758214e71cSJoe     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_v, 1000));
2768214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis2, "Initial V_x Distribution", "V", "counts"));
2778214e71cSJoe     PetscCall(PetscDrawAxisSetLimits(axis2, -1, 1, 0, 1500));
2788214e71cSJoe 
2798214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_w", 800, 300, 400, 300, &user->drawic_w));
28075155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(user->drawic_w, "ex9_ic_w"));
2818214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawic_w));
2826497c311SBarry Smith     PetscCall(PetscDrawHGCreate(user->drawic_w, (int)dim, &user->drawhgic_w));
2838214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_w, &axis3));
2848214e71cSJoe     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_w, 10));
2858214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis3, "Initial W Distribution", "weight", "counts"));
2868214e71cSJoe     PetscCall(PetscDrawAxisSetLimits(axis3, 0, 0.01, 0, 5000));
2878214e71cSJoe   }
2889072cb8bSMatthew G. Knepley   if (user->positions_monitor) {
28975155f48SMatthew G. Knepley     PetscDraw     draw;
2908214e71cSJoe     PetscDrawAxis axis;
2918214e71cSJoe 
29275155f48SMatthew G. Knepley     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "Particle Position", 0, 0, 400, 300, &draw));
29375155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_pos"));
29475155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
29575155f48SMatthew G. Knepley     PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspX));
29675155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
29775155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetDimension(user->drawspX, 1));
29875155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetAxis(user->drawspX, &axis));
2998214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "v"));
30075155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspX));
3018214e71cSJoe   }
3028214e71cSJoe   if (user->poisson_monitor) {
30375155f48SMatthew G. Knepley     Vec           rho, phi;
30475155f48SMatthew G. Knepley     PetscDraw     draw;
30575155f48SMatthew G. Knepley     PetscDrawAxis axis;
3068214e71cSJoe 
30775155f48SMatthew G. Knepley     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "Electric_Field", 0, 0, 400, 300, &draw));
30875155f48SMatthew G. Knepley     PetscCall(PetscDrawSetFromOptions(draw));
30975155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_E_spatial"));
31075155f48SMatthew G. Knepley     PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspE));
31175155f48SMatthew G. Knepley     PetscCall(PetscDrawDestroy(&draw));
31275155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetDimension(user->drawspE, 1));
31375155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetAxis(user->drawspE, &axis));
31475155f48SMatthew G. Knepley     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "E"));
31575155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspE));
3168214e71cSJoe 
31775155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, NULL, "Charge Density", 0, 0, 400, 300, &user->viewerRho));
31875155f48SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerRho, "rho_"));
31975155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerRho, 0, &draw));
32075155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_rho_spatial"));
32175155f48SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerRho));
322*4a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
32375155f48SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)rho, "charge_density"));
324*4a0cbf56SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
3258214e71cSJoe 
32675155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, NULL, "Potential", 400, 0, 400, 300, &user->viewerPhi));
32775155f48SMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerPhi, "phi_"));
32875155f48SMatthew G. Knepley     PetscCall(PetscViewerDrawGetDraw(user->viewerPhi, 0, &draw));
32975155f48SMatthew G. Knepley     PetscCall(PetscDrawSetSave(draw, "ex9_phi_spatial"));
33075155f48SMatthew G. Knepley     PetscCall(PetscViewerSetFromOptions(user->viewerPhi));
331*4a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
33275155f48SMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)phi, "potential"));
333*4a0cbf56SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
3348214e71cSJoe   }
3358214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3368214e71cSJoe }
3378214e71cSJoe 
3388214e71cSJoe static PetscErrorCode DestroyContext(AppCtx *user)
3398214e71cSJoe {
3408214e71cSJoe   PetscFunctionBeginUser;
3418214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_x));
3428214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawic_x));
3438214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_v));
3448214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawic_v));
3458214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_w));
3468214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawic_w));
3478214e71cSJoe 
34875155f48SMatthew G. Knepley   PetscCall(PetscDrawLGDestroy(&user->drawlgE));
34975155f48SMatthew G. Knepley   PetscCall(PetscDrawSPDestroy(&user->drawspE));
35075155f48SMatthew G. Knepley   PetscCall(PetscDrawSPDestroy(&user->drawspX));
35175155f48SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerRho));
35275155f48SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&user->viewerPhi));
3538214e71cSJoe 
3548214e71cSJoe   PetscCall(PetscBagDestroy(&user->bag));
3558214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3568214e71cSJoe }
3578214e71cSJoe 
3588214e71cSJoe static PetscErrorCode CheckNonNegativeWeights(DM sw, AppCtx *user)
3598214e71cSJoe {
3608214e71cSJoe   const PetscScalar *w;
3618214e71cSJoe   PetscInt           Np;
3628214e71cSJoe 
3638214e71cSJoe   PetscFunctionBeginUser;
3648214e71cSJoe   if (!user->checkweights) PetscFunctionReturn(PETSC_SUCCESS);
3658214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w));
3668214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
3678214e71cSJoe   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]);
3688214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w));
3698214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3708214e71cSJoe }
3718214e71cSJoe 
3729072cb8bSMatthew G. Knepley static PetscErrorCode computeVelocityFEMMoments(DM sw, PetscReal moments[], AppCtx *user)
3738214e71cSJoe {
3749072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
375f1e6e573SMatthew G. Knepley   DM            vdm;
376f1e6e573SMatthew G. Knepley   Vec           u[1];
377f1e6e573SMatthew G. Knepley   const char   *fields[1] = {"w_q"};
3788214e71cSJoe 
379f1e6e573SMatthew G. Knepley   PetscFunctionBegin;
3809072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "velocity"));
3819072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
3829072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
383f1e6e573SMatthew G. Knepley   PetscCall(DMGetGlobalVector(vdm, &u[0]));
384f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmProjectFields(sw, vdm, 1, fields, u, SCATTER_FORWARD));
385f1e6e573SMatthew G. Knepley   PetscCall(DMPlexComputeMoments(vdm, u[0], moments));
386f1e6e573SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(vdm, &u[0]));
3879072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
3888214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3898214e71cSJoe }
3908214e71cSJoe 
3918214e71cSJoe static PetscErrorCode MonitorEField(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
3928214e71cSJoe {
3938214e71cSJoe   AppCtx    *user = (AppCtx *)ctx;
394f1e6e573SMatthew G. Knepley   DM         sw;
395f1e6e573SMatthew G. Knepley   PetscReal *E, *x, *weight;
396f1e6e573SMatthew G. Knepley   PetscReal  Enorm = 0., lgEnorm, lgEmax, sum = 0., Emax = 0., chargesum = 0.;
397f1e6e573SMatthew G. Knepley   PetscReal  pmoments[4]; /* \int f, \int v f, \int v^2 f */
398f1e6e573SMatthew G. Knepley   PetscInt  *species, dim, Np;
3998214e71cSJoe 
4008214e71cSJoe   PetscFunctionBeginUser;
4019072cb8bSMatthew G. Knepley   if (step < 0 || !user->validE) PetscFunctionReturn(PETSC_SUCCESS);
4028214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
4038214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
4048214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
4058214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
4068214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
4078214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
4088214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
4098214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
4108214e71cSJoe 
411f1e6e573SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
412f1e6e573SMatthew G. Knepley     for (PetscInt d = 0; d < 1; ++d) {
413f1e6e573SMatthew G. Knepley       PetscReal temp = PetscAbsReal(E[p * dim + d]);
4148214e71cSJoe       if (temp > Emax) Emax = temp;
4158214e71cSJoe     }
4168214e71cSJoe     Enorm += PetscSqrtReal(E[p * dim] * E[p * dim]);
4178214e71cSJoe     sum += E[p * dim];
4188214e71cSJoe     chargesum += user->charges[0] * weight[p];
4198214e71cSJoe   }
4208214e71cSJoe   lgEnorm = Enorm != 0 ? PetscLog10Real(Enorm) : -16.;
42175155f48SMatthew G. Knepley   lgEmax  = Emax != 0 ? PetscLog10Real(Emax) : user->drawlgEmin;
4228214e71cSJoe 
4238214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
4248214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
4258214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
4268214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
42775155f48SMatthew G. Knepley   PetscCall(PetscDrawLGAddPoint(user->drawlgE, &t, &lgEmax));
42875155f48SMatthew G. Knepley   PetscCall(PetscDrawLGDraw(user->drawlgE));
42975155f48SMatthew G. Knepley   PetscDraw draw;
43075155f48SMatthew G. Knepley   PetscCall(PetscDrawLGGetDraw(user->drawlgE, &draw));
43175155f48SMatthew G. Knepley   PetscCall(PetscDrawSave(draw));
432f1e6e573SMatthew G. Knepley 
433f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
43475155f48SMatthew 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]));
43575155f48SMatthew G. Knepley   PetscCall(DMViewFromOptions(sw, NULL, "-sw_efield_view"));
436f1e6e573SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
437f1e6e573SMatthew G. Knepley }
438f1e6e573SMatthew G. Knepley 
439f1e6e573SMatthew G. Knepley static PetscErrorCode MonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
440f1e6e573SMatthew G. Knepley {
441f1e6e573SMatthew G. Knepley   AppCtx   *user = (AppCtx *)ctx;
442f1e6e573SMatthew G. Knepley   DM        sw;
443f1e6e573SMatthew G. Knepley   PetscReal pmoments[4], fmoments[4]; /* \int f, \int v f, \int v^2 f */
444f1e6e573SMatthew G. Knepley 
445f1e6e573SMatthew G. Knepley   PetscFunctionBeginUser;
446f1e6e573SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
447f1e6e573SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
448f1e6e573SMatthew G. Knepley 
449f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
450f1e6e573SMatthew G. Knepley   PetscCall(computeVelocityFEMMoments(sw, fmoments, user));
451f1e6e573SMatthew G. Knepley 
452f1e6e573SMatthew 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]));
4538214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
4548214e71cSJoe }
4558214e71cSJoe 
4568214e71cSJoe PetscErrorCode MonitorInitialConditions(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
4578214e71cSJoe {
4588214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
4598214e71cSJoe   DM                 dm, sw;
4608214e71cSJoe   const PetscScalar *u;
4618214e71cSJoe   PetscReal         *weight, *pos, *vel;
4628214e71cSJoe   PetscInt           dim, p, Np, cStart, cEnd;
4638214e71cSJoe 
4648214e71cSJoe   PetscFunctionBegin;
4658214e71cSJoe   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
4668214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
4678214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &dm));
4688214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
4698214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
4708214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
4718214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
4728214e71cSJoe 
4738214e71cSJoe   if (step == 0) {
4748214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_x));
4758214e71cSJoe     PetscCall(PetscDrawHGGetDraw(user->drawhgic_x, &user->drawic_x));
4768214e71cSJoe     PetscCall(PetscDrawClear(user->drawic_x));
4778214e71cSJoe     PetscCall(PetscDrawFlush(user->drawic_x));
4788214e71cSJoe 
4798214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_v));
4808214e71cSJoe     PetscCall(PetscDrawHGGetDraw(user->drawhgic_v, &user->drawic_v));
4818214e71cSJoe     PetscCall(PetscDrawClear(user->drawic_v));
4828214e71cSJoe     PetscCall(PetscDrawFlush(user->drawic_v));
4838214e71cSJoe 
4848214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_w));
4858214e71cSJoe     PetscCall(PetscDrawHGGetDraw(user->drawhgic_w, &user->drawic_w));
4868214e71cSJoe     PetscCall(PetscDrawClear(user->drawic_w));
4878214e71cSJoe     PetscCall(PetscDrawFlush(user->drawic_w));
4888214e71cSJoe 
4898214e71cSJoe     PetscCall(VecGetArrayRead(U, &u));
4908214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
4918214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
4928214e71cSJoe     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
4938214e71cSJoe 
4948214e71cSJoe     PetscCall(VecGetLocalSize(U, &Np));
4958214e71cSJoe     Np /= dim * 2;
4968214e71cSJoe     for (p = 0; p < Np; ++p) {
4978214e71cSJoe       PetscCall(PetscDrawHGAddValue(user->drawhgic_x, pos[p * dim]));
4988214e71cSJoe       PetscCall(PetscDrawHGAddValue(user->drawhgic_v, vel[p * dim]));
4998214e71cSJoe       PetscCall(PetscDrawHGAddValue(user->drawhgic_w, weight[p]));
5008214e71cSJoe     }
5018214e71cSJoe 
5028214e71cSJoe     PetscCall(VecRestoreArrayRead(U, &u));
5038214e71cSJoe     PetscCall(PetscDrawHGDraw(user->drawhgic_x));
5048214e71cSJoe     PetscCall(PetscDrawHGSave(user->drawhgic_x));
5058214e71cSJoe 
5068214e71cSJoe     PetscCall(PetscDrawHGDraw(user->drawhgic_v));
5078214e71cSJoe     PetscCall(PetscDrawHGSave(user->drawhgic_v));
5088214e71cSJoe 
5098214e71cSJoe     PetscCall(PetscDrawHGDraw(user->drawhgic_w));
5108214e71cSJoe     PetscCall(PetscDrawHGSave(user->drawhgic_w));
5118214e71cSJoe 
5128214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
5138214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
5148214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
5158214e71cSJoe   }
5168214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5178214e71cSJoe }
5188214e71cSJoe 
5198214e71cSJoe static PetscErrorCode MonitorPositions_2D(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
5208214e71cSJoe {
5218214e71cSJoe   AppCtx         *user = (AppCtx *)ctx;
5228214e71cSJoe   DM              dm, sw;
5238214e71cSJoe   PetscScalar    *x, *v, *weight;
5248214e71cSJoe   PetscReal       lower[3], upper[3], speed;
5258214e71cSJoe   const PetscInt *s;
5268214e71cSJoe   PetscInt        dim, cStart, cEnd, c;
5278214e71cSJoe 
5288214e71cSJoe   PetscFunctionBeginUser;
5298214e71cSJoe   if (step > 0 && step % user->ostep == 0) {
5308214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
5318214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
5328214e71cSJoe     PetscCall(DMGetDimension(dm, &dim));
5338214e71cSJoe     PetscCall(DMGetBoundingBox(dm, lower, upper));
5348214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
5358214e71cSJoe     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5368214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
5378214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
5388214e71cSJoe     PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&s));
5398214e71cSJoe     PetscCall(DMSwarmSortGetAccess(sw));
54075155f48SMatthew G. Knepley     PetscCall(PetscDrawSPReset(user->drawspX));
54175155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], lower[1], upper[1]));
54275155f48SMatthew G. Knepley     PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], -12, 12));
5438214e71cSJoe     for (c = 0; c < cEnd - cStart; ++c) {
5448214e71cSJoe       PetscInt *pidx, Npc, q;
5458214e71cSJoe       PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
5468214e71cSJoe       for (q = 0; q < Npc; ++q) {
5478214e71cSJoe         const PetscInt p = pidx[q];
5488214e71cSJoe         if (s[p] == 0) {
5499072cb8bSMatthew G. Knepley           speed = 0.;
5509072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) speed += PetscSqr(v[p * dim + d]);
5519072cb8bSMatthew G. Knepley           speed = PetscSqrtReal(speed);
552045208b8SMatthew G. Knepley           if (dim == 1) {
55375155f48SMatthew G. Knepley             PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &v[p * dim], &speed));
5548214e71cSJoe           } else {
55575155f48SMatthew G. Knepley             PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &x[p * dim + 1], &speed));
5568214e71cSJoe           }
5578214e71cSJoe         } else if (s[p] == 1) {
55875155f48SMatthew G. Knepley           PetscCall(PetscDrawSPAddPoint(user->drawspX, &x[p * dim], &v[p * dim]));
5598214e71cSJoe         }
5608214e71cSJoe       }
56184467f86SMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
5628214e71cSJoe     }
56375155f48SMatthew G. Knepley     PetscCall(PetscDrawSPDraw(user->drawspX, PETSC_TRUE));
56475155f48SMatthew G. Knepley     PetscDraw draw;
56575155f48SMatthew G. Knepley     PetscCall(PetscDrawSPGetDraw(user->drawspX, &draw));
56675155f48SMatthew G. Knepley     PetscCall(PetscDrawSave(draw));
5678214e71cSJoe     PetscCall(DMSwarmSortRestoreAccess(sw));
5688214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5698214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
5708214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
5718214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&s));
5728214e71cSJoe   }
5738214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5748214e71cSJoe }
5758214e71cSJoe 
5768214e71cSJoe static PetscErrorCode MonitorPoisson(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
5778214e71cSJoe {
5788214e71cSJoe   AppCtx *user = (AppCtx *)ctx;
5798214e71cSJoe   DM      dm, sw;
5808214e71cSJoe 
5818214e71cSJoe   PetscFunctionBeginUser;
5828214e71cSJoe   if (step > 0 && step % user->ostep == 0) {
5838214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
5848214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
5859072cb8bSMatthew G. Knepley 
5869072cb8bSMatthew G. Knepley     if (user->validE) {
5879072cb8bSMatthew G. Knepley       PetscScalar *x, *E, *weight;
5889072cb8bSMatthew G. Knepley       PetscReal    lower[3], upper[3], xval;
5899072cb8bSMatthew G. Knepley       PetscDraw    draw;
5909072cb8bSMatthew G. Knepley       PetscInt     dim, cStart, cEnd;
5919072cb8bSMatthew G. Knepley 
5928214e71cSJoe       PetscCall(DMGetDimension(dm, &dim));
5938214e71cSJoe       PetscCall(DMGetBoundingBox(dm, lower, upper));
5948214e71cSJoe       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
5958214e71cSJoe 
59675155f48SMatthew G. Knepley       PetscCall(PetscDrawSPReset(user->drawspE));
5978214e71cSJoe       PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5988214e71cSJoe       PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
5998214e71cSJoe       PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
6008214e71cSJoe 
6018214e71cSJoe       PetscCall(DMSwarmSortGetAccess(sw));
6029072cb8bSMatthew G. Knepley       for (PetscInt c = 0; c < cEnd - cStart; ++c) {
60375155f48SMatthew G. Knepley         PetscReal Eavg = 0.0;
6049072cb8bSMatthew G. Knepley         PetscInt *pidx, Npc;
6059072cb8bSMatthew G. Knepley 
6068214e71cSJoe         PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
6079072cb8bSMatthew G. Knepley         for (PetscInt q = 0; q < Npc; ++q) {
6088214e71cSJoe           const PetscInt p = pidx[q];
60975155f48SMatthew G. Knepley           Eavg += E[p * dim];
6108214e71cSJoe         }
61175155f48SMatthew G. Knepley         Eavg /= Npc;
6128214e71cSJoe         xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart));
61375155f48SMatthew G. Knepley         PetscCall(PetscDrawSPAddPoint(user->drawspE, &xval, &Eavg));
61484467f86SMatthew G. Knepley         PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
6158214e71cSJoe       }
61675155f48SMatthew G. Knepley       PetscCall(PetscDrawSPDraw(user->drawspE, PETSC_TRUE));
61775155f48SMatthew G. Knepley       PetscCall(PetscDrawSPGetDraw(user->drawspE, &draw));
61875155f48SMatthew G. Knepley       PetscCall(PetscDrawSave(draw));
6198214e71cSJoe       PetscCall(DMSwarmSortRestoreAccess(sw));
6208214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
6218214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
6228214e71cSJoe       PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
6239072cb8bSMatthew G. Knepley     }
62475155f48SMatthew G. Knepley 
62575155f48SMatthew G. Knepley     Vec rho, phi;
62675155f48SMatthew G. Knepley 
627*4a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
62875155f48SMatthew G. Knepley     PetscCall(VecView(rho, user->viewerRho));
629*4a0cbf56SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
63075155f48SMatthew G. Knepley 
631*4a0cbf56SMatthew G. Knepley     PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
63275155f48SMatthew G. Knepley     PetscCall(VecView(phi, user->viewerPhi));
633*4a0cbf56SMatthew G. Knepley     PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
6348214e71cSJoe   }
6358214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
6368214e71cSJoe }
6378214e71cSJoe 
6388214e71cSJoe static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx)
6398214e71cSJoe {
6408214e71cSJoe   PetscBag   bag;
6418214e71cSJoe   Parameter *p;
6428214e71cSJoe 
6438214e71cSJoe   PetscFunctionBeginUser;
6448214e71cSJoe   /* setup PETSc parameter bag */
6458214e71cSJoe   PetscCall(PetscBagGetData(ctx->bag, (void **)&p));
6468214e71cSJoe   PetscCall(PetscBagSetName(ctx->bag, "par", "Vlasov-Poisson Parameters"));
6478214e71cSJoe   bag = ctx->bag;
6488214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "v0", "Velocity scale, m/s"));
6498214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->t0, 1.0, "t0", "Time scale, s"));
6508214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->x0, 1.0, "x0", "Space scale, m"));
6518214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "phi0", "Potential scale, kg*m^2/A*s^3"));
6528214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->q0, 1.0, "q0", "Charge Scale, A*s"));
6538214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->m0, 1.0, "m0", "Mass Scale, kg"));
6548214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->epsi0, 1.0, "epsi0", "Permittivity of Free Space, kg"));
6558214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->kb, 1.0, "kb", "Boltzmann Constant, m^2 kg/s^2 K^1"));
6568214e71cSJoe 
6578214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->sigma, 1.0, "sigma", "Charge per unit area, C/m^3"));
6588214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->poissonNumber, 1.0, "poissonNumber", "Non-Dimensional Poisson Number"));
6598214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->vlasovNumber, 1.0, "vlasovNumber", "Non-Dimensional Vlasov Number"));
6608214e71cSJoe   PetscCall(PetscBagSetFromOptions(bag));
6618214e71cSJoe   {
6628214e71cSJoe     PetscViewer       viewer;
6638214e71cSJoe     PetscViewerFormat format;
6648214e71cSJoe     PetscBool         flg;
6658214e71cSJoe 
666648c30bcSBarry Smith     PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg));
6678214e71cSJoe     if (flg) {
6688214e71cSJoe       PetscCall(PetscViewerPushFormat(viewer, format));
6698214e71cSJoe       PetscCall(PetscBagView(bag, viewer));
6708214e71cSJoe       PetscCall(PetscViewerFlush(viewer));
6718214e71cSJoe       PetscCall(PetscViewerPopFormat(viewer));
6728214e71cSJoe       PetscCall(PetscViewerDestroy(&viewer));
6738214e71cSJoe     }
6748214e71cSJoe   }
6758214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
6768214e71cSJoe }
6778214e71cSJoe 
6788214e71cSJoe static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
679d71ae5a4SJacob Faibussowitsch {
680b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
6819566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
6829566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
6839566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*dm));
6849072cb8bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*dm, "space"));
6859566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
686f1e6e573SMatthew G. Knepley 
687f1e6e573SMatthew G. Knepley   // Cache the mesh geometry
688f1e6e573SMatthew G. Knepley   DMField         coordField;
689f1e6e573SMatthew G. Knepley   IS              cellIS;
690f1e6e573SMatthew G. Knepley   PetscQuadrature quad;
691f1e6e573SMatthew G. Knepley   PetscReal      *wt, *pt;
692f1e6e573SMatthew G. Knepley   PetscInt        cdim, cStart, cEnd;
693f1e6e573SMatthew G. Knepley 
694f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateField(*dm, &coordField));
695f1e6e573SMatthew G. Knepley   PetscCheck(coordField, comm, PETSC_ERR_USER, "DM must have a coordinate field");
696f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateDim(*dm, &cdim));
697f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd));
698f1e6e573SMatthew G. Knepley   PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cellIS));
699f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
700f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(1, &wt));
701f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(2, &pt));
702f1e6e573SMatthew G. Knepley   wt[0] = 1.;
703f1e6e573SMatthew G. Knepley   pt[0] = -1.;
704f1e6e573SMatthew G. Knepley   pt[1] = -1.;
705f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureSetData(quad, cdim, 1, 1, pt, wt));
706f1e6e573SMatthew G. Knepley   PetscCall(DMFieldCreateFEGeom(coordField, cellIS, quad, PETSC_FALSE, &user->fegeom));
707f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&quad));
708f1e6e573SMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
7093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
710b80bf5b1SJoe Pusztay }
711b80bf5b1SJoe Pusztay 
7128214e71cSJoe 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[])
7138214e71cSJoe {
7148214e71cSJoe   f0[0] = -constants[SIGMA];
7158214e71cSJoe }
7168214e71cSJoe 
717d71ae5a4SJacob 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[])
718d71ae5a4SJacob Faibussowitsch {
719b80bf5b1SJoe Pusztay   PetscInt d;
720ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) f1[d] = u_x[d];
721b80bf5b1SJoe Pusztay }
722b80bf5b1SJoe Pusztay 
7238214e71cSJoe 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[])
724d71ae5a4SJacob Faibussowitsch {
725b80bf5b1SJoe Pusztay   PetscInt d;
726ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) g3[d * dim + d] = 1.0;
727b80bf5b1SJoe Pusztay }
728b80bf5b1SJoe Pusztay 
7298214e71cSJoe static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
730d71ae5a4SJacob Faibussowitsch {
7318214e71cSJoe   *u = 0.0;
7328214e71cSJoe   return PETSC_SUCCESS;
733b80bf5b1SJoe Pusztay }
734b80bf5b1SJoe Pusztay 
735b80bf5b1SJoe Pusztay /*
7368214e71cSJoe    /  I   -grad\ / q \ = /0\
7378214e71cSJoe    \-div    0  / \phi/   \f/
738b80bf5b1SJoe Pusztay */
7398214e71cSJoe 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[])
740d71ae5a4SJacob Faibussowitsch {
7418214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[d] += u[uOff[0] + d];
7428214e71cSJoe }
7438214e71cSJoe 
7448214e71cSJoe 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[])
7458214e71cSJoe {
7468214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f1[d * dim + d] = u[uOff[1]];
7478214e71cSJoe }
7488214e71cSJoe 
7498214e71cSJoe 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[])
7508214e71cSJoe {
7518214e71cSJoe   f0[0] += constants[SIGMA];
7528214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[0] += u_x[uOff_x[0] + d * dim + d];
7538214e71cSJoe }
7548214e71cSJoe 
7558214e71cSJoe /* Boundary residual. Dirichlet boundary for u means u_bdy=p*n */
7568214e71cSJoe 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[])
7578214e71cSJoe {
7588214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g0[d * dim + d] = 1.0;
7598214e71cSJoe }
7608214e71cSJoe 
7618214e71cSJoe 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[])
7628214e71cSJoe {
7638214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g2[d * dim + d] = 1.0;
7648214e71cSJoe }
7658214e71cSJoe 
7668214e71cSJoe 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[])
7678214e71cSJoe {
7688214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g1[d * dim + d] = 1.0;
7698214e71cSJoe }
7708214e71cSJoe 
7718214e71cSJoe static PetscErrorCode CreateFEM(DM dm, AppCtx *user)
7728214e71cSJoe {
7738214e71cSJoe   PetscFE   fephi, feq;
7748214e71cSJoe   PetscDS   ds;
7758214e71cSJoe   PetscBool simplex;
7768214e71cSJoe   PetscInt  dim;
7778214e71cSJoe 
7788214e71cSJoe   PetscFunctionBeginUser;
7798214e71cSJoe   PetscCall(DMGetDimension(dm, &dim));
7808214e71cSJoe   PetscCall(DMPlexIsSimplex(dm, &simplex));
7818214e71cSJoe   if (user->em == EM_MIXED) {
7828214e71cSJoe     DMLabel        label;
7838214e71cSJoe     const PetscInt id = 1;
7848214e71cSJoe 
7858214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "field_", PETSC_DETERMINE, &feq));
7868214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)feq, "field"));
7878214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "potential_", PETSC_DETERMINE, &fephi));
7888214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
7898214e71cSJoe     PetscCall(PetscFECopyQuadrature(feq, fephi));
7908214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)feq));
7918214e71cSJoe     PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fephi));
7928214e71cSJoe     PetscCall(DMCreateDS(dm));
7938214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
7948214e71cSJoe     PetscCall(PetscFEDestroy(&feq));
7958214e71cSJoe 
7968214e71cSJoe     PetscCall(DMGetLabel(dm, "marker", &label));
7978214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
7988214e71cSJoe 
7998214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, f0_q, f1_q));
8008214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 1, f0_phi_backgroundCharge, NULL));
8018214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_qq, NULL, NULL, NULL));
8028214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_qphi, NULL));
8038214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_phiq, NULL, NULL));
8048214e71cSJoe 
8058214e71cSJoe     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void))zero, NULL, NULL, NULL));
8068214e71cSJoe 
807f1e6e573SMatthew G. Knepley   } else {
8088214e71cSJoe     MatNullSpace nullsp;
8098214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, PETSC_DETERMINE, &fephi));
8108214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
8118214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fephi));
8128214e71cSJoe     PetscCall(DMCreateDS(dm));
8138214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
8148214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, ion_f0, laplacian_f1));
8158214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, laplacian_g3));
8168214e71cSJoe     PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullsp));
8178214e71cSJoe     PetscCall(PetscObjectCompose((PetscObject)fephi, "nullspace", (PetscObject)nullsp));
8188214e71cSJoe     PetscCall(MatNullSpaceDestroy(&nullsp));
8198214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
8208214e71cSJoe   }
8218214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
8228214e71cSJoe }
8238214e71cSJoe 
8248214e71cSJoe static PetscErrorCode CreatePoisson(DM dm, AppCtx *user)
8258214e71cSJoe {
8268214e71cSJoe   SNES         snes;
8278214e71cSJoe   Mat          J;
8288214e71cSJoe   MatNullSpace nullSpace;
8298214e71cSJoe 
8308214e71cSJoe   PetscFunctionBeginUser;
8318214e71cSJoe   PetscCall(CreateFEM(dm, user));
8328214e71cSJoe   PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes));
8338214e71cSJoe   PetscCall(SNESSetOptionsPrefix(snes, "em_"));
8348214e71cSJoe   PetscCall(SNESSetDM(snes, dm));
8358214e71cSJoe   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, user));
8368214e71cSJoe   PetscCall(SNESSetFromOptions(snes));
8378214e71cSJoe 
8388214e71cSJoe   PetscCall(DMCreateMatrix(dm, &J));
8398214e71cSJoe   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullSpace));
8408214e71cSJoe   PetscCall(MatSetNullSpace(J, nullSpace));
8418214e71cSJoe   PetscCall(MatNullSpaceDestroy(&nullSpace));
8428214e71cSJoe   PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL));
8438214e71cSJoe   PetscCall(MatDestroy(&J));
844*4a0cbf56SMatthew G. Knepley   if (user->em == EM_MIXED) {
845*4a0cbf56SMatthew G. Knepley     const PetscInt potential = 1;
846*4a0cbf56SMatthew G. Knepley 
847*4a0cbf56SMatthew G. Knepley     PetscCall(DMCreateSubDM(dm, 1, &potential, &user->isPot, &user->dmPot));
848*4a0cbf56SMatthew G. Knepley   } else {
849*4a0cbf56SMatthew G. Knepley     user->dmPot = dm;
850*4a0cbf56SMatthew G. Knepley     PetscCall(PetscObjectReference((PetscObject)user->dmPot));
851*4a0cbf56SMatthew G. Knepley   }
852*4a0cbf56SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(user->dmPot, user->dmPot, &user->M));
853f1e6e573SMatthew G. Knepley   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
8548214e71cSJoe   user->snes = snes;
8558214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
8568214e71cSJoe }
8578214e71cSJoe 
8588214e71cSJoe PetscErrorCode PetscPDFPertubedConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
8598214e71cSJoe {
8608214e71cSJoe   p[0] = (1 + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
8618214e71cSJoe   p[1] = (1 + 0.01 * PetscCosReal(0.5 * x[1])) / (2 * PETSC_PI);
8628214e71cSJoe   return PETSC_SUCCESS;
8638214e71cSJoe }
8648214e71cSJoe PetscErrorCode PetscPDFPertubedConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
8658214e71cSJoe {
8668214e71cSJoe   p[0] = (1. + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
8678214e71cSJoe   return PETSC_SUCCESS;
8688214e71cSJoe }
8698214e71cSJoe 
8708214e71cSJoe PetscErrorCode PetscPDFCosine1D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
8718214e71cSJoe {
8728214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.0;
8738214e71cSJoe   const PetscReal k     = scale ? scale[1] : 1.;
8748214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * x[0]));
8758214e71cSJoe   return PETSC_SUCCESS;
8768214e71cSJoe }
8778214e71cSJoe 
8788214e71cSJoe PetscErrorCode PetscPDFCosine2D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
8798214e71cSJoe {
8808214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.;
8818214e71cSJoe   const PetscReal k     = scale ? scale[0] : 1.;
8828214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * (x[0] + x[1])));
8838214e71cSJoe   return PETSC_SUCCESS;
8848214e71cSJoe }
8858214e71cSJoe 
88684467f86SMatthew G. Knepley static PetscErrorCode CreateVelocityDM(DM sw, DM *vdm)
8878214e71cSJoe {
888f1e6e573SMatthew G. Knepley   PetscFE        fe;
889f1e6e573SMatthew G. Knepley   DMPolytopeType ct;
890f1e6e573SMatthew G. Knepley   PetscInt       dim, cStart;
891f1e6e573SMatthew G. Knepley   const char    *prefix = "v";
892f1e6e573SMatthew G. Knepley 
89384467f86SMatthew G. Knepley   PetscFunctionBegin;
89484467f86SMatthew G. Knepley   PetscCall(DMCreate(PETSC_COMM_SELF, vdm));
89584467f86SMatthew G. Knepley   PetscCall(DMSetType(*vdm, DMPLEX));
896f1e6e573SMatthew G. Knepley   PetscCall(DMPlexSetOptionsPrefix(*vdm, prefix));
89784467f86SMatthew G. Knepley   PetscCall(DMSetFromOptions(*vdm));
8989072cb8bSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*vdm, "velocity"));
89984467f86SMatthew G. Knepley   PetscCall(DMViewFromOptions(*vdm, NULL, "-dm_view"));
900f1e6e573SMatthew G. Knepley 
901f1e6e573SMatthew G. Knepley   PetscCall(DMGetDimension(*vdm, &dim));
902f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*vdm, 0, &cStart, NULL));
903f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetCellType(*vdm, cStart, &ct));
904f1e6e573SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe));
905f1e6e573SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "distribution"));
906f1e6e573SMatthew G. Knepley   PetscCall(DMSetField(*vdm, 0, NULL, (PetscObject)fe));
907f1e6e573SMatthew G. Knepley   PetscCall(DMCreateDS(*vdm));
908f1e6e573SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
90984467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
9108214e71cSJoe }
9118214e71cSJoe 
9129072cb8bSMatthew G. Knepley /*
9139072cb8bSMatthew G. Knepley   InitializeParticles_Centroid - Initialize a regular grid of particles.
9149072cb8bSMatthew G. Knepley 
9159072cb8bSMatthew G. Knepley   Input Parameters:
9169072cb8bSMatthew G. Knepley + sw      - The `DMSWARM`
9179072cb8bSMatthew G. Knepley - force1D - Treat the spatial domain as 1D
9189072cb8bSMatthew G. Knepley 
9199072cb8bSMatthew G. Knepley   Notes:
9209072cb8bSMatthew G. Knepley   This functions sets the species, cellid, spatial coordinate, and velocity fields for all particles.
9219072cb8bSMatthew G. Knepley 
9229072cb8bSMatthew G. Knepley   It places one particle in the centroid of each cell in the implicit tensor product of the spatial
9239072cb8bSMatthew G. Knepley   and velocity meshes.
9249072cb8bSMatthew G. Knepley */
925045208b8SMatthew G. Knepley static PetscErrorCode InitializeParticles_Centroid(DM sw)
9268214e71cSJoe {
92784467f86SMatthew G. Knepley   DM_Swarm     *swarm = (DM_Swarm *)sw->data;
9289072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
92984467f86SMatthew G. Knepley   DM            xdm, vdm;
93084467f86SMatthew G. Knepley   PetscReal     vmin[3], vmax[3];
93184467f86SMatthew G. Knepley   PetscReal    *x, *v;
93284467f86SMatthew G. Knepley   PetscInt     *species, *cellid;
93384467f86SMatthew G. Knepley   PetscInt      dim, xcStart, xcEnd, vcStart, vcEnd, Ns, Np, Npc, debug;
9348214e71cSJoe   PetscBool     flg;
93584467f86SMatthew G. Knepley   MPI_Comm      comm;
9369072cb8bSMatthew G. Knepley   const char   *cellidname;
9378214e71cSJoe 
9388214e71cSJoe   PetscFunctionBegin;
93984467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
94084467f86SMatthew G. Knepley 
94184467f86SMatthew G. Knepley   PetscOptionsBegin(comm, "", "DMSwarm Options", "DMSWARM");
9428214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
9438214e71cSJoe   PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg));
9448214e71cSJoe   if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns));
94584467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_coords", "Debug output level for particle coordinate computations", "InitializeParticles", 0, &swarm->printCoords, NULL, 0));
94684467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_weights", "Debug output level for particle weight computations", "InitializeWeights", 0, &swarm->printWeights, NULL, 0));
9478214e71cSJoe   PetscOptionsEnd();
94884467f86SMatthew G. Knepley   debug = swarm->printCoords;
9498214e71cSJoe 
9508214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
95184467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
95284467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
9538214e71cSJoe 
954045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
955045208b8SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
95684467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
9578214e71cSJoe 
95884467f86SMatthew G. Knepley   // One particle per centroid on the tensor product grid
95984467f86SMatthew G. Knepley   Npc = (vcEnd - vcStart) * Ns;
96084467f86SMatthew G. Knepley   Np  = (xcEnd - xcStart) * Npc;
9618214e71cSJoe   PetscCall(DMSwarmSetLocalSizes(sw, Np, 0));
96284467f86SMatthew G. Knepley   if (debug) {
96384467f86SMatthew G. Knepley     PetscInt gNp;
96484467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Np, &gNp, 1, MPIU_INT, MPIU_SUM, comm));
96584467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global Np = %" PetscInt_FMT "\n", gNp));
9668214e71cSJoe   }
9678214e71cSJoe 
96884467f86SMatthew G. Knepley   // Set species and cellid
9699072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetCellDMActive(sw, &celldm));
9709072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMGetCellID(celldm, &cellidname));
97184467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
9729072cb8bSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, cellidname, NULL, NULL, (void **)&cellid));
97384467f86SMatthew G. Knepley   for (PetscInt c = 0, p = 0; c < xcEnd - xcStart; ++c) {
97484467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
97584467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q, ++p) {
97684467f86SMatthew G. Knepley         species[p] = s;
97784467f86SMatthew G. Knepley         cellid[p]  = c;
97884467f86SMatthew G. Knepley       }
97984467f86SMatthew G. Knepley     }
98084467f86SMatthew G. Knepley   }
98184467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
9829072cb8bSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, cellidname, NULL, NULL, (void **)&cellid));
98384467f86SMatthew G. Knepley 
98484467f86SMatthew G. Knepley   // Set particle coordinates
9858214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
9868214e71cSJoe   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
9878214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
98884467f86SMatthew G. Knepley   PetscCall(DMGetBoundingBox(vdm, vmin, vmax));
98984467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(xdm));
99084467f86SMatthew G. Knepley   for (PetscInt c = 0; c < xcEnd - xcStart; ++c) {
99184467f86SMatthew G. Knepley     const PetscInt cell = c + xcStart;
9928214e71cSJoe     PetscInt      *pidx, Npc;
9938214e71cSJoe     PetscReal      centroid[3], volume;
9948214e71cSJoe 
9958214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
99684467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFVM(xdm, cell, &volume, centroid, NULL));
99784467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
99884467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q) {
99984467f86SMatthew G. Knepley         const PetscInt p = pidx[q * Ns + s];
10008214e71cSJoe 
100184467f86SMatthew G. Knepley         for (PetscInt d = 0; d < dim; ++d) {
10028214e71cSJoe           x[p * dim + d] = centroid[d];
100384467f86SMatthew G. Knepley           v[p * dim + d] = vmin[0] + (q + 0.5) * ((vmax[0] - vmin[0]) / (Npc / Ns));
10048214e71cSJoe         }
10059072cb8bSMatthew G. Knepley         if (debug > 1) {
10069072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "Particle %4" PetscInt_FMT " ", p));
10079072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  x: ("));
10089072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
10099072cb8bSMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
10109072cb8bSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", x[p * dim + d]));
10119072cb8bSMatthew G. Knepley           }
10129072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ") v:("));
10139072cb8bSMatthew G. Knepley           for (PetscInt d = 0; d < dim; ++d) {
10149072cb8bSMatthew G. Knepley             if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
10159072cb8bSMatthew G. Knepley             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", v[p * dim + d]));
10169072cb8bSMatthew G. Knepley           }
10179072cb8bSMatthew G. Knepley           PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
10189072cb8bSMatthew G. Knepley         }
10198214e71cSJoe       }
10208214e71cSJoe     }
102184467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
10228214e71cSJoe   }
10238214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
10248214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
10258214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
102684467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
102784467f86SMatthew G. Knepley }
102884467f86SMatthew G. Knepley 
102984467f86SMatthew G. Knepley /*
103084467f86SMatthew G. Knepley   InitializeWeights - Compute weight for each local particle
103184467f86SMatthew G. Knepley 
103284467f86SMatthew G. Knepley   Input Parameters:
103384467f86SMatthew G. Knepley + sw          - The `DMSwarm`
103484467f86SMatthew G. Knepley . totalWeight - The sum of all particle weights
103584467f86SMatthew G. Knepley . func        - The PDF for the particle spatial distribution
103684467f86SMatthew G. Knepley - param       - The PDF parameters
103784467f86SMatthew G. Knepley 
103884467f86SMatthew G. Knepley   Notes:
103984467f86SMatthew G. Knepley   The PDF for velocity is assumed to be a Gaussian
104084467f86SMatthew G. Knepley 
104184467f86SMatthew G. Knepley   The particle weights are returned in the `w_q` field of `sw`.
104284467f86SMatthew G. Knepley */
1043045208b8SMatthew G. Knepley static PetscErrorCode InitializeWeights(DM sw, PetscReal totalWeight, PetscProbFunc func, const PetscReal param[])
104484467f86SMatthew G. Knepley {
104584467f86SMatthew G. Knepley   DM               xdm, vdm;
1046045208b8SMatthew G. Knepley   DMSwarmCellDM    celldm;
104784467f86SMatthew G. Knepley   PetscScalar     *weight;
104884467f86SMatthew G. Knepley   PetscQuadrature  xquad;
104984467f86SMatthew G. Knepley   const PetscReal *xq, *xwq;
105084467f86SMatthew G. Knepley   const PetscInt   order = 5;
1051045208b8SMatthew G. Knepley   PetscReal        xi0[3];
105284467f86SMatthew G. Knepley   PetscReal        xwtot = 0., pwtot = 0.;
105384467f86SMatthew G. Knepley   PetscInt         xNq;
105484467f86SMatthew G. Knepley   PetscInt         dim, Ns, xcStart, xcEnd, vcStart, vcEnd, debug = ((DM_Swarm *)sw->data)->printWeights;
105584467f86SMatthew G. Knepley   MPI_Comm         comm;
105684467f86SMatthew G. Knepley   PetscMPIInt      rank;
105784467f86SMatthew G. Knepley 
105884467f86SMatthew G. Knepley   PetscFunctionBegin;
105984467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
106084467f86SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
106184467f86SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
106284467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
106384467f86SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
106484467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
1065045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm));
1066045208b8SMatthew G. Knepley   PetscCall(DMSwarmCellDMGetDM(celldm, &vdm));
106784467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
106884467f86SMatthew G. Knepley 
106984467f86SMatthew G. Knepley   // Setup Quadrature for spatial and velocity weight calculations
1070045208b8SMatthew G. Knepley   PetscCall(PetscDTGaussTensorQuadrature(dim, 1, order, -1.0, 1.0, &xquad));
107184467f86SMatthew G. Knepley   PetscCall(PetscQuadratureGetData(xquad, NULL, NULL, &xNq, &xq, &xwq));
107284467f86SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) xi0[d] = -1.0;
107384467f86SMatthew G. Knepley 
107484467f86SMatthew G. Knepley   // Integrate the density function to get the weights of particles in each cell
107584467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(vdm));
107684467f86SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
107784467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
107884467f86SMatthew G. Knepley   for (PetscInt c = xcStart; c < xcEnd; ++c) {
107984467f86SMatthew G. Knepley     PetscReal          xv0[3], xJ[9], xinvJ[9], xdetJ, xqr[3], xden, xw = 0.;
108084467f86SMatthew G. Knepley     PetscInt          *pidx, Npc;
108184467f86SMatthew G. Knepley     PetscInt           xNc;
108284467f86SMatthew G. Knepley     const PetscScalar *xarray;
108384467f86SMatthew G. Knepley     PetscScalar       *xcoords = NULL;
108484467f86SMatthew G. Knepley     PetscBool          xisDG;
108584467f86SMatthew G. Knepley 
108684467f86SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
108784467f86SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
108884467f86SMatthew 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);
108984467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFEM(xdm, c, NULL, xv0, xJ, xinvJ, &xdetJ));
109084467f86SMatthew G. Knepley     for (PetscInt q = 0; q < xNq; ++q) {
109184467f86SMatthew G. Knepley       // Transform quadrature points from ref space to real space
1092045208b8SMatthew G. Knepley       CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xq[q * dim], xqr);
109384467f86SMatthew G. Knepley       // Get probability density at quad point
109484467f86SMatthew G. Knepley       //   No need to scale xqr since PDF will be periodic
109584467f86SMatthew G. Knepley       PetscCall((*func)(xqr, param, &xden));
109684467f86SMatthew G. Knepley       xw += xden * (xwq[q] * xdetJ);
109784467f86SMatthew G. Knepley     }
109884467f86SMatthew G. Knepley     xwtot += xw;
109984467f86SMatthew G. Knepley     if (debug) {
110084467f86SMatthew G. Knepley       IS              globalOrdering;
110184467f86SMatthew G. Knepley       const PetscInt *ordering;
110284467f86SMatthew G. Knepley 
110384467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellNumbering(xdm, &globalOrdering));
110484467f86SMatthew G. Knepley       PetscCall(ISGetIndices(globalOrdering, &ordering));
110575155f48SMatthew 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));
110684467f86SMatthew G. Knepley       PetscCall(ISRestoreIndices(globalOrdering, &ordering));
110784467f86SMatthew G. Knepley     }
110884467f86SMatthew G. Knepley     // Set weights to be Gaussian in velocity cells
110984467f86SMatthew G. Knepley     for (PetscInt vc = vcStart; vc < vcEnd; ++vc) {
111084467f86SMatthew G. Knepley       const PetscInt     p  = pidx[vc * Ns + 0];
111184467f86SMatthew G. Knepley       PetscReal          vw = 0.;
111284467f86SMatthew G. Knepley       PetscInt           vNc;
111384467f86SMatthew G. Knepley       const PetscScalar *varray;
111484467f86SMatthew G. Knepley       PetscScalar       *vcoords = NULL;
111584467f86SMatthew G. Knepley       PetscBool          visDG;
111684467f86SMatthew G. Knepley 
111784467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
111884467f86SMatthew G. Knepley       // TODO: Fix 2 stream Ask Joe
111984467f86SMatthew G. Knepley       //   Two stream function from 1/2pi v^2 e^(-v^2/2)
112084467f86SMatthew 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.)));
112184467f86SMatthew G. Knepley       vw = 0.5 * (PetscErfReal(vcoords[1] / PetscSqrtReal(2.)) - PetscErfReal(vcoords[0] / PetscSqrtReal(2.)));
112284467f86SMatthew G. Knepley 
112384467f86SMatthew G. Knepley       weight[p] = totalWeight * vw * xw;
112484467f86SMatthew G. Knepley       pwtot += weight[p];
11259072cb8bSMatthew 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);
112684467f86SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
112784467f86SMatthew G. Knepley       if (debug > 1) PetscCall(PetscPrintf(comm, "particle %" PetscInt_FMT ": %g, vw: %g xw: %g\n", p, weight[p], vw, xw));
112884467f86SMatthew G. Knepley     }
112984467f86SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
113084467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
113184467f86SMatthew G. Knepley   }
113284467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
113384467f86SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
113484467f86SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&xquad));
113584467f86SMatthew G. Knepley 
113684467f86SMatthew G. Knepley   if (debug) {
113784467f86SMatthew G. Knepley     PetscReal wtot[2] = {pwtot, xwtot}, gwtot[2];
113884467f86SMatthew G. Knepley 
113984467f86SMatthew G. Knepley     PetscCall(PetscSynchronizedFlush(comm, NULL));
114084467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(wtot, gwtot, 2, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
114184467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "particle weight sum = %1.10f cell weight sum = %1.10f\n", (double)gwtot[0], (double)gwtot[1]));
114284467f86SMatthew G. Knepley   }
114384467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
114484467f86SMatthew G. Knepley }
114584467f86SMatthew G. Knepley 
114684467f86SMatthew G. Knepley static PetscErrorCode InitializeParticles_PerturbedWeights(DM sw, AppCtx *user)
114784467f86SMatthew G. Knepley {
114884467f86SMatthew G. Knepley   PetscReal scale[2] = {user->cosine_coefficients[0], user->cosine_coefficients[1]};
114975155f48SMatthew G. Knepley   PetscInt  dim;
115084467f86SMatthew G. Knepley 
115184467f86SMatthew G. Knepley   PetscFunctionBegin;
115275155f48SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
1153045208b8SMatthew G. Knepley   PetscCall(InitializeParticles_Centroid(sw));
1154045208b8SMatthew G. Knepley   PetscCall(InitializeWeights(sw, user->totalWeight, dim == 1 ? PetscPDFCosine1D : PetscPDFCosine2D, scale));
11558214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
11568214e71cSJoe }
11578214e71cSJoe 
11588214e71cSJoe static PetscErrorCode InitializeConstants(DM sw, AppCtx *user)
11598214e71cSJoe {
11608214e71cSJoe   DM         dm;
11618214e71cSJoe   PetscInt  *species;
11628214e71cSJoe   PetscReal *weight, totalCharge = 0., totalWeight = 0., gmin[3], gmax[3], global_charge, global_weight;
11638214e71cSJoe   PetscInt   Np, dim;
11648214e71cSJoe 
11658214e71cSJoe   PetscFunctionBegin;
11668214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &dm));
11678214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
11688214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
11698214e71cSJoe   PetscCall(DMGetBoundingBox(dm, gmin, gmax));
11708214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
11718214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
11728214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
11738214e71cSJoe     totalWeight += weight[p];
11748214e71cSJoe     totalCharge += user->charges[species[p]] * weight[p];
11758214e71cSJoe   }
11768214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
11778214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
11788214e71cSJoe   {
11798214e71cSJoe     Parameter *param;
11808214e71cSJoe     PetscReal  Area;
11818214e71cSJoe 
11828214e71cSJoe     PetscCall(PetscBagGetData(user->bag, (void **)&param));
11838214e71cSJoe     switch (dim) {
11848214e71cSJoe     case 1:
11858214e71cSJoe       Area = (gmax[0] - gmin[0]);
11868214e71cSJoe       break;
11878214e71cSJoe     case 2:
11888214e71cSJoe       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]);
11898214e71cSJoe       break;
11908214e71cSJoe     case 3:
11918214e71cSJoe       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]) * (gmax[2] - gmin[2]);
11928214e71cSJoe       break;
11938214e71cSJoe     default:
11948214e71cSJoe       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", dim);
11958214e71cSJoe     }
1196462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalWeight, &global_weight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
1197462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalCharge, &global_charge, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
11988214e71cSJoe     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));
11998214e71cSJoe     param->sigma = PetscAbsReal(global_charge / (Area));
12008214e71cSJoe 
12018214e71cSJoe     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "sigma: %g\n", (double)param->sigma));
12028214e71cSJoe     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,
12038214e71cSJoe                           (double)param->vlasovNumber));
12048214e71cSJoe   }
12058214e71cSJoe   /* Setup Constants */
12068214e71cSJoe   {
12078214e71cSJoe     PetscDS    ds;
12088214e71cSJoe     Parameter *param;
12098214e71cSJoe     PetscCall(PetscBagGetData(user->bag, (void **)&param));
12108214e71cSJoe     PetscScalar constants[NUM_CONSTANTS];
12118214e71cSJoe     constants[SIGMA]   = param->sigma;
12128214e71cSJoe     constants[V0]      = param->v0;
12138214e71cSJoe     constants[T0]      = param->t0;
12148214e71cSJoe     constants[X0]      = param->x0;
12158214e71cSJoe     constants[M0]      = param->m0;
12168214e71cSJoe     constants[Q0]      = param->q0;
12178214e71cSJoe     constants[PHI0]    = param->phi0;
12188214e71cSJoe     constants[POISSON] = param->poissonNumber;
12198214e71cSJoe     constants[VLASOV]  = param->vlasovNumber;
12208214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
12218214e71cSJoe     PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants));
12228214e71cSJoe   }
12238214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
12248214e71cSJoe }
12258214e71cSJoe 
12268214e71cSJoe static PetscErrorCode CreateSwarm(DM dm, AppCtx *user, DM *sw)
12278214e71cSJoe {
12289072cb8bSMatthew G. Knepley   DMSwarmCellDM celldm;
12299072cb8bSMatthew G. Knepley   DM            vdm;
12308214e71cSJoe   PetscReal     v0[2] = {1., 0.};
12318214e71cSJoe   PetscInt      dim;
1232b80bf5b1SJoe Pusztay 
1233b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
12349566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
12359566063dSJacob Faibussowitsch   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw));
12369566063dSJacob Faibussowitsch   PetscCall(DMSetType(*sw, DMSWARM));
12379566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*sw, dim));
12389566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC));
1239045208b8SMatthew G. Knepley   PetscCall(DMSetApplicationContext(*sw, user));
12409072cb8bSMatthew G. Knepley 
12419566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR));
12428214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL));
12438214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "species", 1, PETSC_INT));
12448214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "E_field", dim, PETSC_REAL));
12459072cb8bSMatthew G. Knepley 
12469072cb8bSMatthew G. Knepley   const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"};
12479072cb8bSMatthew G. Knepley 
12489072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(dm, 2, fieldnames, 1, fieldnames, &celldm));
12499072cb8bSMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
12509072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
12519072cb8bSMatthew G. Knepley 
12529072cb8bSMatthew G. Knepley   const char *vfieldnames[1] = {"w_q"};
12539072cb8bSMatthew G. Knepley 
12549072cb8bSMatthew G. Knepley   PetscCall(CreateVelocityDM(*sw, &vdm));
12559072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(vdm, 1, vfieldnames, 1, &fieldnames[1], &celldm));
12569072cb8bSMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
12579072cb8bSMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
12589072cb8bSMatthew G. Knepley   PetscCall(DMDestroy(&vdm));
12599072cb8bSMatthew G. Knepley 
1260*4a0cbf56SMatthew G. Knepley   DM mdm;
1261*4a0cbf56SMatthew G. Knepley 
1262*4a0cbf56SMatthew G. Knepley   PetscCall(DMClone(dm, &mdm));
1263*4a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)mdm, "moments"));
1264*4a0cbf56SMatthew G. Knepley   PetscCall(DMCopyDisc(dm, mdm));
1265*4a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmCellDMCreate(mdm, 1, vfieldnames, 1, fieldnames, &celldm));
1266*4a0cbf56SMatthew G. Knepley   PetscCall(DMDestroy(&mdm));
1267*4a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmAddCellDM(*sw, celldm));
1268*4a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmCellDMDestroy(&celldm));
1269*4a0cbf56SMatthew G. Knepley 
12709566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*sw));
1271045208b8SMatthew G. Knepley   PetscCall(DMSetUp(*sw));
1272045208b8SMatthew G. Knepley 
12739072cb8bSMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(*sw, "space"));
12748214e71cSJoe   user->swarm = *sw;
1275045208b8SMatthew G. Knepley   // TODO: This is redundant init since it is done in InitializeSolveAndSwarm, however DMSetUp() requires the local size be set
12768214e71cSJoe   if (user->perturbed_weights) {
12778214e71cSJoe     PetscCall(InitializeParticles_PerturbedWeights(*sw, user));
1278b80bf5b1SJoe Pusztay   } else {
12798214e71cSJoe     PetscCall(DMSwarmComputeLocalSizeFromOptions(*sw));
12808214e71cSJoe     PetscCall(DMSwarmInitializeCoordinates(*sw));
12818214e71cSJoe     PetscCall(DMSwarmInitializeVelocitiesFromOptions(*sw, v0));
1282b80bf5b1SJoe Pusztay   }
12839566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles"));
12849566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view"));
12853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1286b80bf5b1SJoe Pusztay }
1287b80bf5b1SJoe Pusztay 
12888214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Coulomb(SNES snes, DM sw, PetscReal E[])
1289d71ae5a4SJacob Faibussowitsch {
12908214e71cSJoe   AppCtx     *user;
12918214e71cSJoe   PetscReal  *coords;
12928214e71cSJoe   PetscInt   *species, dim, Np, Ns;
12938214e71cSJoe   PetscMPIInt size;
12948214e71cSJoe 
12958214e71cSJoe   PetscFunctionBegin;
12968214e71cSJoe   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)snes), &size));
12978214e71cSJoe   PetscCheck(size == 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Coulomb code only works in serial");
12988214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
12998214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
13008214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
13018214e71cSJoe   PetscCall(DMGetApplicationContext(sw, (void *)&user));
13028214e71cSJoe 
13038214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
13048214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
13058214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
13068214e71cSJoe     PetscReal *pcoord = &coords[p * dim];
13078214e71cSJoe     PetscReal  pE[3]  = {0., 0., 0.};
13088214e71cSJoe 
13098214e71cSJoe     /* Calculate field at particle p due to particle q */
13108214e71cSJoe     for (PetscInt q = 0; q < Np; ++q) {
13118214e71cSJoe       PetscReal *qcoord = &coords[q * dim];
13128214e71cSJoe       PetscReal  rpq[3], r, r3, q_q;
13138214e71cSJoe 
13148214e71cSJoe       if (p == q) continue;
13158214e71cSJoe       q_q = user->charges[species[q]] * 1.;
13168214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) rpq[d] = pcoord[d] - qcoord[d];
13178214e71cSJoe       r = DMPlex_NormD_Internal(dim, rpq);
13188214e71cSJoe       if (r < PETSC_SQRT_MACHINE_EPSILON) continue;
13198214e71cSJoe       r3 = PetscPowRealInt(r, 3);
13208214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pE[d] += q_q * rpq[d] / r3;
13218214e71cSJoe     }
13228214e71cSJoe     for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = pE[d];
13238214e71cSJoe   }
13248214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
13258214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
13268214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
13278214e71cSJoe }
13288214e71cSJoe 
1329*4a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Primal(SNES snes, DM sw, Mat M_p, PetscReal E[])
13308214e71cSJoe {
1331b80bf5b1SJoe Pusztay   DM         dm;
13328214e71cSJoe   AppCtx    *user;
13338214e71cSJoe   PetscDS    ds;
13348214e71cSJoe   PetscFE    fe;
1335*4a0cbf56SMatthew G. Knepley   KSP        ksp;
133675155f48SMatthew G. Knepley   Vec        rhoRhs;      // Weak charge density, \int phi_i rho
133775155f48SMatthew G. Knepley   Vec        rho;         // Charge density, M^{-1} rhoRhs
133875155f48SMatthew G. Knepley   Vec        phi, locPhi; // Potential
133975155f48SMatthew G. Knepley   Vec        f;           // Particle weights
13408214e71cSJoe   PetscReal *coords;
13418214e71cSJoe   PetscInt   dim, cStart, cEnd, Np;
13428214e71cSJoe 
13438214e71cSJoe   PetscFunctionBegin;
134484467f86SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, (void *)&user));
134584467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
13468214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
13478214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
13488214e71cSJoe 
13498214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
135075155f48SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhs));
135175155f48SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
1352*4a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
13538214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
13548214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
135575155f48SMatthew G. Knepley 
13568214e71cSJoe   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
1357f1e6e573SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->M, NULL, "-m_view"));
13588214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
135975155f48SMatthew G. Knepley 
136075155f48SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
13618214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
13628214e71cSJoe 
13638214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
13648214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj_"));
1365f1e6e573SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->M, user->M));
13668214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
136775155f48SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
13688214e71cSJoe 
136975155f48SMatthew G. Knepley   PetscCall(VecScale(rhoRhs, -1.0));
13708214e71cSJoe 
137175155f48SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
1372*4a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
13738214e71cSJoe   PetscCall(KSPDestroy(&ksp));
13748214e71cSJoe 
1375*4a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
13768214e71cSJoe   PetscCall(VecSet(phi, 0.0));
137775155f48SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhs, phi));
137875155f48SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhs));
13798214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
13808214e71cSJoe 
13818214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
13828214e71cSJoe   PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi));
13838214e71cSJoe   PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi));
1384*4a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
138584467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
13868214e71cSJoe 
13878214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
13888214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
13898214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
13908214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
13918214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
13928214e71cSJoe 
139384467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
13948214e71cSJoe   PetscTabulation tab;
13958214e71cSJoe   PetscReal      *pcoord, *refcoord;
1396045208b8SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
1397045208b8SMatthew G. Knepley   PetscInt        maxNcp    = 0;
1398045208b8SMatthew G. Knepley 
1399045208b8SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1400045208b8SMatthew G. Knepley     PetscInt Ncp;
1401045208b8SMatthew G. Knepley 
1402045208b8SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
1403045208b8SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
1404045208b8SMatthew G. Knepley   }
1405045208b8SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1406045208b8SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1407045208b8SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
1408045208b8SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1409045208b8SMatthew G. Knepley     PetscScalar *clPhi = NULL;
14108214e71cSJoe     PetscInt    *points;
14118214e71cSJoe     PetscInt     Ncp;
14128214e71cSJoe 
14138214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
14148214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
14158214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1416f1e6e573SMatthew G. Knepley     {
1417f1e6e573SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1418f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1419f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1420f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1421f1e6e573SMatthew G. Knepley       }
1422f1e6e573SMatthew G. Knepley     }
1423045208b8SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
14248214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
14258214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
14268214e71cSJoe       const PetscReal *basisDer = tab->T[1];
14278214e71cSJoe       const PetscInt   p        = points[cp];
14288214e71cSJoe 
14298214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1430f1e6e573SMatthew G. Knepley       PetscCall(PetscFEFreeInterpolateGradient_Static(fe, basisDer, clPhi, dim, chunkgeom->invJ, NULL, cp, &E[p * dim]));
1431045208b8SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
14328214e71cSJoe     }
14338214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
143484467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
14358214e71cSJoe   }
1436045208b8SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1437045208b8SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1438045208b8SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
14398214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
14408214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
14418214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1442f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
144384467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
14448214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
14458214e71cSJoe }
14468214e71cSJoe 
1447*4a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Mixed(SNES snes, DM sw, Mat M_p, PetscReal E[])
14488214e71cSJoe {
1449*4a0cbf56SMatthew G. Knepley   DM         dm;
14508214e71cSJoe   AppCtx    *user;
14518214e71cSJoe   PetscDS    ds;
14528214e71cSJoe   PetscFE    fe;
1453*4a0cbf56SMatthew G. Knepley   KSP        ksp;
1454*4a0cbf56SMatthew G. Knepley   Vec        rhoRhs, rhoRhsFull;   // Weak charge density, \int phi_i rho, and embedding in mixed problem
1455*4a0cbf56SMatthew G. Knepley   Vec        rho;                  // Charge density, M^{-1} rhoRhs
1456*4a0cbf56SMatthew G. Knepley   Vec        phi, locPhi, phiFull; // Potential and embedding in mixed problem
1457*4a0cbf56SMatthew G. Knepley   Vec        f;                    // Particle weights
145875155f48SMatthew G. Knepley   PetscReal *coords;
1459*4a0cbf56SMatthew G. Knepley   PetscInt   dim, cStart, cEnd, Np;
14608214e71cSJoe 
14618214e71cSJoe   PetscFunctionBegin;
146284467f86SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &user));
146384467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
14648214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
14658214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
14668214e71cSJoe 
14678214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
1468*4a0cbf56SMatthew G. Knepley   PetscCall(DMGetGlobalVector(user->dmPot, &rhoRhs));
1469*4a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density"));
1470*4a0cbf56SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &rhoRhsFull));
1471*4a0cbf56SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)rhoRhsFull, "Weak charge density"));
1472*4a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho));
14738214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
14748214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
1475*4a0cbf56SMatthew G. Knepley 
1476*4a0cbf56SMatthew G. Knepley   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
1477*4a0cbf56SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->M, NULL, "-m_view"));
14788214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
1479*4a0cbf56SMatthew G. Knepley 
1480*4a0cbf56SMatthew G. Knepley   PetscCall(MatMultTranspose(M_p, f, rhoRhs));
14818214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
14828214e71cSJoe 
14838214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
14848214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj"));
1485*4a0cbf56SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->M, user->M));
14868214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
1487*4a0cbf56SMatthew G. Knepley   PetscCall(KSPSolve(ksp, rhoRhs, rho));
14888214e71cSJoe 
1489*4a0cbf56SMatthew G. Knepley   PetscCall(VecISCopy(rhoRhsFull, user->isPot, SCATTER_FORWARD, rhoRhs));
1490*4a0cbf56SMatthew G. Knepley   //PetscCall(VecScale(rhoRhsFull, -1.0));
14918214e71cSJoe 
1492*4a0cbf56SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view"));
1493*4a0cbf56SMatthew G. Knepley   PetscCall(VecViewFromOptions(rhoRhsFull, NULL, "-rho_full_view"));
1494*4a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho));
1495*4a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(user->dmPot, &rhoRhs));
14968214e71cSJoe   PetscCall(KSPDestroy(&ksp));
14978214e71cSJoe 
1498*4a0cbf56SMatthew G. Knepley   PetscCall(DMGetGlobalVector(dm, &phiFull));
1499*4a0cbf56SMatthew G. Knepley   PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi));
1500*4a0cbf56SMatthew G. Knepley   PetscCall(VecSet(phiFull, 0.0));
1501*4a0cbf56SMatthew G. Knepley   PetscCall(SNESSolve(snes, rhoRhsFull, phiFull));
1502*4a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &rhoRhsFull));
15038214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
15048214e71cSJoe 
1505*4a0cbf56SMatthew G. Knepley   PetscCall(VecISCopy(phiFull, user->isPot, SCATTER_REVERSE, phi));
1506*4a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi));
1507*4a0cbf56SMatthew G. Knepley 
15088214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
1509*4a0cbf56SMatthew G. Knepley   PetscCall(DMGlobalToLocalBegin(dm, phiFull, INSERT_VALUES, locPhi));
1510*4a0cbf56SMatthew G. Knepley   PetscCall(DMGlobalToLocalEnd(dm, phiFull, INSERT_VALUES, locPhi));
1511*4a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(dm, &phiFull));
151284467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
15138214e71cSJoe 
15148214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
15158214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
15168214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
15178214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
15188214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1519*4a0cbf56SMatthew G. Knepley 
1520*4a0cbf56SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
15218214e71cSJoe   PetscTabulation tab;
15228214e71cSJoe   PetscReal      *pcoord, *refcoord;
1523*4a0cbf56SMatthew G. Knepley   PetscFEGeom    *chunkgeom = NULL;
1524*4a0cbf56SMatthew G. Knepley   PetscInt        maxNcp    = 0;
1525*4a0cbf56SMatthew G. Knepley 
1526*4a0cbf56SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1527*4a0cbf56SMatthew G. Knepley     PetscInt Ncp;
1528*4a0cbf56SMatthew G. Knepley 
1529*4a0cbf56SMatthew G. Knepley     PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp));
1530*4a0cbf56SMatthew G. Knepley     maxNcp = PetscMax(maxNcp, Ncp);
1531*4a0cbf56SMatthew G. Knepley   }
1532*4a0cbf56SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1533*4a0cbf56SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1534*4a0cbf56SMatthew G. Knepley   PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab));
1535*4a0cbf56SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
1536*4a0cbf56SMatthew G. Knepley     PetscScalar *clPhi = NULL;
15378214e71cSJoe     PetscInt    *points;
15388214e71cSJoe     PetscInt     Ncp;
15398214e71cSJoe 
15408214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
15418214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
15428214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1543f1e6e573SMatthew G. Knepley     {
1544f1e6e573SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1545f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1546f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1547f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1548f1e6e573SMatthew G. Knepley       }
1549f1e6e573SMatthew G. Knepley     }
1550*4a0cbf56SMatthew G. Knepley     PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab));
15518214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
15528214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
15538214e71cSJoe       const PetscInt p = points[cp];
15548214e71cSJoe 
15558214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1556f1e6e573SMatthew G. Knepley       PetscCall(PetscFEInterpolateAtPoints_Static(fe, tab, clPhi, chunkgeom, cp, &E[p * dim]));
1557f1e6e573SMatthew G. Knepley       PetscCall(PetscFEPushforward(fe, chunkgeom, 1, &E[p * dim]));
1558*4a0cbf56SMatthew G. Knepley       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0;
15598214e71cSJoe     }
15608214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
156184467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
15628214e71cSJoe   }
1563*4a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord));
1564*4a0cbf56SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord));
1565*4a0cbf56SMatthew G. Knepley   PetscCall(PetscTabulationDestroy(&tab));
15668214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
15678214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
15688214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1569f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
157084467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
15718214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
15728214e71cSJoe }
15738214e71cSJoe 
1574*4a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles(SNES snes, DM sw)
15758214e71cSJoe {
1576*4a0cbf56SMatthew G. Knepley   AppCtx    *user;
1577*4a0cbf56SMatthew G. Knepley   Mat        M_p;
1578*4a0cbf56SMatthew G. Knepley   PetscReal *E;
15798214e71cSJoe   PetscInt   dim, Np;
15808214e71cSJoe 
15818214e71cSJoe   PetscFunctionBegin;
15828214e71cSJoe   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
15838214e71cSJoe   PetscValidHeaderSpecific(sw, DM_CLASSID, 2);
15848214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
15858214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
1586*4a0cbf56SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &user));
15878214e71cSJoe 
1588*4a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "moments"));
1589*4a0cbf56SMatthew G. Knepley   // TODO: Could share sort context with space cellDM
1590*4a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmMigrate(sw, PETSC_FALSE));
1591*4a0cbf56SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(sw, user->dmPot, &M_p));
1592*4a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmSetCellDMActive(sw, "space"));
1593*4a0cbf56SMatthew G. Knepley 
1594*4a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
1595*4a0cbf56SMatthew G. Knepley   PetscCall(PetscArrayzero(E, Np * dim));
1596*4a0cbf56SMatthew G. Knepley   user->validE = PETSC_TRUE;
1597*4a0cbf56SMatthew G. Knepley 
1598*4a0cbf56SMatthew G. Knepley   switch (user->em) {
15998214e71cSJoe   case EM_COULOMB:
16008214e71cSJoe     PetscCall(ComputeFieldAtParticles_Coulomb(snes, sw, E));
16018214e71cSJoe     break;
1602*4a0cbf56SMatthew G. Knepley   case EM_PRIMAL:
1603*4a0cbf56SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Primal(snes, sw, M_p, E));
1604*4a0cbf56SMatthew G. Knepley     break;
16058214e71cSJoe   case EM_MIXED:
1606*4a0cbf56SMatthew G. Knepley     PetscCall(ComputeFieldAtParticles_Mixed(snes, sw, M_p, E));
16078214e71cSJoe     break;
16088214e71cSJoe   case EM_NONE:
16098214e71cSJoe     break;
16108214e71cSJoe   default:
1611*4a0cbf56SMatthew G. Knepley     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No solver for electrostatic model %s", EMTypes[user->em]);
16128214e71cSJoe   }
1613*4a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
1614*4a0cbf56SMatthew G. Knepley   PetscCall(MatDestroy(&M_p));
16158214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16168214e71cSJoe }
16178214e71cSJoe 
16188214e71cSJoe static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec G, void *ctx)
16198214e71cSJoe {
16208214e71cSJoe   DM                 sw;
16218214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
16228214e71cSJoe   const PetscScalar *u;
16238214e71cSJoe   PetscScalar       *g;
16248214e71cSJoe   PetscReal         *E, m_p = 1., q_p = -1.;
16258214e71cSJoe   PetscInt           dim, d, Np, p;
1626b80bf5b1SJoe Pusztay 
1627b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
16288214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
1629*4a0cbf56SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
1630*4a0cbf56SMatthew G. Knepley 
16318214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16328214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
1633*4a0cbf56SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
16348214e71cSJoe   PetscCall(VecGetArrayRead(U, &u));
16358214e71cSJoe   PetscCall(VecGetArray(G, &g));
16368214e71cSJoe   Np /= 2 * dim;
16378214e71cSJoe   for (p = 0; p < Np; ++p) {
16388214e71cSJoe     for (d = 0; d < dim; ++d) {
16398214e71cSJoe       g[(p * 2 + 0) * dim + d] = u[(p * 2 + 1) * dim + d];
16408214e71cSJoe       g[(p * 2 + 1) * dim + d] = q_p * E[p * dim + d] / m_p;
16418214e71cSJoe     }
16428214e71cSJoe   }
16438214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
16448214e71cSJoe   PetscCall(VecRestoreArrayRead(U, &u));
16458214e71cSJoe   PetscCall(VecRestoreArray(G, &g));
16468214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16478214e71cSJoe }
16488214e71cSJoe 
16498214e71cSJoe /* J_{ij} = dF_i/dx_j
16508214e71cSJoe    J_p = (  0   1)
16518214e71cSJoe          (-w^2  0)
16528214e71cSJoe    TODO Now there is another term with w^2 from the electric field. I think we will need to invert the operator.
16538214e71cSJoe         Perhaps we can approximate the Jacobian using only the cellwise P-P gradient from Coulomb
16548214e71cSJoe */
16558214e71cSJoe static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat P, void *ctx)
16568214e71cSJoe {
16578214e71cSJoe   DM               sw;
16588214e71cSJoe   const PetscReal *coords, *vel;
16598214e71cSJoe   PetscInt         dim, d, Np, p, rStart;
16608214e71cSJoe 
16618214e71cSJoe   PetscFunctionBeginUser;
16628214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
16638214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16648214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
16658214e71cSJoe   PetscCall(MatGetOwnershipRange(J, &rStart, NULL));
1666045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1667045208b8SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
16688214e71cSJoe   Np /= 2 * dim;
16698214e71cSJoe   for (p = 0; p < Np; ++p) {
16708214e71cSJoe     const PetscReal x0      = coords[p * dim + 0];
16718214e71cSJoe     const PetscReal vy0     = vel[p * dim + 1];
16728214e71cSJoe     const PetscReal omega   = vy0 / x0;
16738214e71cSJoe     PetscScalar     vals[4] = {0., 1., -PetscSqr(omega), 0.};
16748214e71cSJoe 
16758214e71cSJoe     for (d = 0; d < dim; ++d) {
16768214e71cSJoe       const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart};
16778214e71cSJoe       PetscCall(MatSetValues(J, 2, rows, 2, rows, vals, INSERT_VALUES));
16788214e71cSJoe     }
16798214e71cSJoe   }
1680045208b8SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1681045208b8SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
16828214e71cSJoe   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
16838214e71cSJoe   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
16848214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16858214e71cSJoe }
16868214e71cSJoe 
16878214e71cSJoe static PetscErrorCode RHSFunctionX(TS ts, PetscReal t, Vec V, Vec Xres, void *ctx)
16888214e71cSJoe {
16898214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
16908214e71cSJoe   DM                 sw;
16918214e71cSJoe   const PetscScalar *v;
16928214e71cSJoe   PetscScalar       *xres;
16938214e71cSJoe   PetscInt           Np, p, d, dim;
16948214e71cSJoe 
16958214e71cSJoe   PetscFunctionBeginUser;
169684467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsXEvent, ts, 0, 0, 0));
16978214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
16988214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16998214e71cSJoe   PetscCall(VecGetLocalSize(Xres, &Np));
17009566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(V, &v));
17018214e71cSJoe   PetscCall(VecGetArray(Xres, &xres));
1702b80bf5b1SJoe Pusztay   Np /= dim;
1703b80bf5b1SJoe Pusztay   for (p = 0; p < Np; ++p) {
1704045208b8SMatthew G. Knepley     for (d = 0; d < dim; ++d) xres[p * dim + d] = v[p * dim + d];
1705b80bf5b1SJoe Pusztay   }
17069566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(V, &v));
17078214e71cSJoe   PetscCall(VecRestoreArray(Xres, &xres));
170884467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsXEvent, ts, 0, 0, 0));
17093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1710b80bf5b1SJoe Pusztay }
1711b80bf5b1SJoe Pusztay 
17128214e71cSJoe static PetscErrorCode RHSFunctionV(TS ts, PetscReal t, Vec X, Vec Vres, void *ctx)
17138214e71cSJoe {
17148214e71cSJoe   DM                 sw;
17158214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
17168214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
17178214e71cSJoe   const PetscScalar *x;
17188214e71cSJoe   PetscScalar       *vres;
1719*4a0cbf56SMatthew G. Knepley   PetscReal         *E, m_p, q_p;
17208214e71cSJoe   PetscInt           Np, p, dim, d;
17218214e71cSJoe   Parameter         *param;
17228214e71cSJoe 
17238214e71cSJoe   PetscFunctionBeginUser;
172484467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsVEvent, ts, 0, 0, 0));
17258214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
1726*4a0cbf56SMatthew G. Knepley   PetscCall(ComputeFieldAtParticles(snes, sw));
1727*4a0cbf56SMatthew G. Knepley 
17288214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
17298214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
17308214e71cSJoe   PetscCall(PetscBagGetData(user->bag, (void **)&param));
17318214e71cSJoe   m_p = user->masses[0] * param->m0;
17328214e71cSJoe   q_p = user->charges[0] * param->q0;
17338214e71cSJoe   PetscCall(VecGetLocalSize(Vres, &Np));
17348214e71cSJoe   PetscCall(VecGetArrayRead(X, &x));
17358214e71cSJoe   PetscCall(VecGetArray(Vres, &vres));
17368214e71cSJoe   Np /= dim;
17378214e71cSJoe   for (p = 0; p < Np; ++p) {
1738045208b8SMatthew G. Knepley     for (d = 0; d < dim; ++d) vres[p * dim + d] = q_p * E[p * dim + d] / m_p;
17398214e71cSJoe   }
17408214e71cSJoe   PetscCall(VecRestoreArrayRead(X, &x));
17418214e71cSJoe   /*
1742d7c1f440SPierre Jolivet     Synchronized, ordered output for parallel/sequential test cases.
17438214e71cSJoe     In the 1D (on the 2D mesh) case, every y component should be zero.
17448214e71cSJoe   */
17458214e71cSJoe   if (user->checkVRes) {
17468214e71cSJoe     PetscBool pr = user->checkVRes > 1 ? PETSC_TRUE : PETSC_FALSE;
17478214e71cSJoe     PetscInt  step;
17488214e71cSJoe 
17498214e71cSJoe     PetscCall(TSGetStepNumber(ts, &step));
17508214e71cSJoe     if (pr) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step: %" PetscInt_FMT "\n", step));
17518214e71cSJoe     for (PetscInt p = 0; p < Np; ++p) {
17528214e71cSJoe       if (pr) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Residual: %.12g %.12g\n", (double)PetscRealPart(vres[p * dim + 0]), (double)PetscRealPart(vres[p * dim + 1])));
17538214e71cSJoe       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]));
17548214e71cSJoe     }
17558214e71cSJoe     if (pr) PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
17568214e71cSJoe   }
17578214e71cSJoe   PetscCall(VecRestoreArray(Vres, &vres));
17588214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
175984467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsVEvent, ts, 0, 0, 0));
17608214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
17618214e71cSJoe }
17628214e71cSJoe 
17638214e71cSJoe static PetscErrorCode CreateSolution(TS ts)
17648214e71cSJoe {
17658214e71cSJoe   DM       sw;
17668214e71cSJoe   Vec      u;
17678214e71cSJoe   PetscInt dim, Np;
17688214e71cSJoe 
17698214e71cSJoe   PetscFunctionBegin;
17708214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
17718214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
17728214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
17738214e71cSJoe   PetscCall(VecCreate(PETSC_COMM_WORLD, &u));
17748214e71cSJoe   PetscCall(VecSetBlockSize(u, dim));
17758214e71cSJoe   PetscCall(VecSetSizes(u, 2 * Np * dim, PETSC_DECIDE));
17768214e71cSJoe   PetscCall(VecSetUp(u));
17778214e71cSJoe   PetscCall(TSSetSolution(ts, u));
17788214e71cSJoe   PetscCall(VecDestroy(&u));
17798214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
17808214e71cSJoe }
17818214e71cSJoe 
17828214e71cSJoe static PetscErrorCode SetProblem(TS ts)
17838214e71cSJoe {
17848214e71cSJoe   AppCtx *user;
17858214e71cSJoe   DM      sw;
17868214e71cSJoe 
17878214e71cSJoe   PetscFunctionBegin;
17888214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
17898214e71cSJoe   PetscCall(DMGetApplicationContext(sw, (void **)&user));
17908214e71cSJoe   // Define unified system for (X, V)
17918214e71cSJoe   {
17928214e71cSJoe     Mat      J;
17938214e71cSJoe     PetscInt dim, Np;
17948214e71cSJoe 
17958214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
17968214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
17978214e71cSJoe     PetscCall(MatCreate(PETSC_COMM_WORLD, &J));
17988214e71cSJoe     PetscCall(MatSetSizes(J, 2 * Np * dim, 2 * Np * dim, PETSC_DECIDE, PETSC_DECIDE));
17998214e71cSJoe     PetscCall(MatSetBlockSize(J, 2 * dim));
18008214e71cSJoe     PetscCall(MatSetFromOptions(J));
18018214e71cSJoe     PetscCall(MatSetUp(J));
18028214e71cSJoe     PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, user));
18038214e71cSJoe     PetscCall(TSSetRHSJacobian(ts, J, J, RHSJacobian, user));
18048214e71cSJoe     PetscCall(MatDestroy(&J));
18058214e71cSJoe   }
18068214e71cSJoe   /* Define split system for X and V */
18078214e71cSJoe   {
18088214e71cSJoe     Vec             u;
18098214e71cSJoe     IS              isx, isv, istmp;
18108214e71cSJoe     const PetscInt *idx;
18118214e71cSJoe     PetscInt        dim, Np, rstart;
18128214e71cSJoe 
18138214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
18148214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
18158214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
18168214e71cSJoe     PetscCall(VecGetOwnershipRange(u, &rstart, NULL));
18178214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 0, 2, &istmp));
18188214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
18198214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isx));
18208214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
18218214e71cSJoe     PetscCall(ISDestroy(&istmp));
18228214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 1, 2, &istmp));
18238214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
18248214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isv));
18258214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
18268214e71cSJoe     PetscCall(ISDestroy(&istmp));
18278214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "position", isx));
18288214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "momentum", isv));
18298214e71cSJoe     PetscCall(ISDestroy(&isx));
18308214e71cSJoe     PetscCall(ISDestroy(&isv));
18318214e71cSJoe     PetscCall(TSRHSSplitSetRHSFunction(ts, "position", NULL, RHSFunctionX, user));
18328214e71cSJoe     PetscCall(TSRHSSplitSetRHSFunction(ts, "momentum", NULL, RHSFunctionV, user));
18338214e71cSJoe   }
18348214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18358214e71cSJoe }
18368214e71cSJoe 
18378214e71cSJoe static PetscErrorCode DMSwarmTSRedistribute(TS ts)
18388214e71cSJoe {
18398214e71cSJoe   DM        sw;
18408214e71cSJoe   Vec       u;
18418214e71cSJoe   PetscReal t, maxt, dt;
18428214e71cSJoe   PetscInt  n, maxn;
18438214e71cSJoe 
18448214e71cSJoe   PetscFunctionBegin;
18458214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
18468214e71cSJoe   PetscCall(TSGetTime(ts, &t));
18478214e71cSJoe   PetscCall(TSGetMaxTime(ts, &maxt));
18488214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
18498214e71cSJoe   PetscCall(TSGetStepNumber(ts, &n));
18508214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
18518214e71cSJoe 
18528214e71cSJoe   PetscCall(TSReset(ts));
18538214e71cSJoe   PetscCall(TSSetDM(ts, sw));
18548214e71cSJoe   PetscCall(TSSetFromOptions(ts));
18558214e71cSJoe   PetscCall(TSSetTime(ts, t));
18568214e71cSJoe   PetscCall(TSSetMaxTime(ts, maxt));
18578214e71cSJoe   PetscCall(TSSetTimeStep(ts, dt));
18588214e71cSJoe   PetscCall(TSSetStepNumber(ts, n));
18598214e71cSJoe   PetscCall(TSSetMaxSteps(ts, maxn));
18608214e71cSJoe 
18618214e71cSJoe   PetscCall(CreateSolution(ts));
18628214e71cSJoe   PetscCall(SetProblem(ts));
18638214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
18648214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18658214e71cSJoe }
18668214e71cSJoe 
18678214e71cSJoe PetscErrorCode line(PetscInt dim, PetscReal time, const PetscReal dummy[], PetscInt p, PetscScalar x[], void *ctx)
18688214e71cSJoe {
18698214e71cSJoe   DM        sw, cdm;
18708214e71cSJoe   PetscInt  Np;
18718214e71cSJoe   PetscReal low[2], high[2];
18728214e71cSJoe   AppCtx   *user = (AppCtx *)ctx;
18738214e71cSJoe 
18748214e71cSJoe   sw = user->swarm;
18758214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &cdm));
18768214e71cSJoe   // Get the bounding box so we can equally space the particles
18778214e71cSJoe   PetscCall(DMGetLocalBoundingBox(cdm, low, high));
18788214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
18798214e71cSJoe   // shift it by h/2 so nothing is initialized directly on a boundary
18808214e71cSJoe   x[0] = ((high[0] - low[0]) / Np) * (p + 0.5);
18818214e71cSJoe   x[1] = 0.;
18828214e71cSJoe   return PETSC_SUCCESS;
18838214e71cSJoe }
18848214e71cSJoe 
1885b80bf5b1SJoe Pusztay /*
18868214e71cSJoe   InitializeSolveAndSwarm - Set the solution values to the swarm coordinates and velocities, and also possibly set the initial values.
18878214e71cSJoe 
18888214e71cSJoe   Input Parameters:
18898214e71cSJoe + ts         - The TS
1890d7c1f440SPierre Jolivet - useInitial - Flag to also set the initial conditions to the current coordinates and velocities and setup the problem
18918214e71cSJoe 
18928214e71cSJoe   Output Parameters:
18938214e71cSJoe . u - The initialized solution vector
18948214e71cSJoe 
18958214e71cSJoe   Level: advanced
18968214e71cSJoe 
18978214e71cSJoe .seealso: InitializeSolve()
1898b80bf5b1SJoe Pusztay */
18998214e71cSJoe static PetscErrorCode InitializeSolveAndSwarm(TS ts, PetscBool useInitial)
1900d71ae5a4SJacob Faibussowitsch {
19018214e71cSJoe   DM       sw;
1902045208b8SMatthew G. Knepley   Vec      u, gc, gv;
19038214e71cSJoe   IS       isx, isv;
19048214e71cSJoe   PetscInt dim;
19058214e71cSJoe   AppCtx  *user;
1906b80bf5b1SJoe Pusztay 
1907b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
19088214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19098214e71cSJoe   PetscCall(DMGetApplicationContext(sw, &user));
19108214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
19118214e71cSJoe   if (useInitial) {
19128214e71cSJoe     PetscReal v0[2] = {1., 0.};
19138214e71cSJoe     if (user->perturbed_weights) {
19148214e71cSJoe       PetscCall(InitializeParticles_PerturbedWeights(sw, user));
19158214e71cSJoe     } else {
19168214e71cSJoe       PetscCall(DMSwarmComputeLocalSizeFromOptions(sw));
19178214e71cSJoe       PetscCall(DMSwarmInitializeCoordinates(sw));
19188214e71cSJoe       PetscCall(DMSwarmInitializeVelocitiesFromOptions(sw, v0));
19198214e71cSJoe     }
19208214e71cSJoe     PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
19218214e71cSJoe     PetscCall(DMSwarmTSRedistribute(ts));
19228214e71cSJoe   }
1923045208b8SMatthew G. Knepley   PetscCall(DMSetUp(sw));
19248214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
19258214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
19268214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
19278214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19288214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
19298214e71cSJoe   PetscCall(VecISCopy(u, isx, SCATTER_FORWARD, gc));
19308214e71cSJoe   PetscCall(VecISCopy(u, isv, SCATTER_FORWARD, gv));
19318214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19328214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
19338214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
19348214e71cSJoe }
19358214e71cSJoe 
19368214e71cSJoe static PetscErrorCode InitializeSolve(TS ts, Vec u)
1937b80bf5b1SJoe Pusztay {
19388214e71cSJoe   PetscFunctionBegin;
19398214e71cSJoe   PetscCall(TSSetSolution(ts, u));
19408214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_TRUE));
19418214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
1942b80bf5b1SJoe Pusztay }
1943b80bf5b1SJoe Pusztay 
19448214e71cSJoe static PetscErrorCode MigrateParticles(TS ts)
19458214e71cSJoe {
19468214e71cSJoe   DM               sw, cdm;
19478214e71cSJoe   const PetscReal *L;
19489072cb8bSMatthew G. Knepley   AppCtx          *ctx;
19498214e71cSJoe 
19508214e71cSJoe   PetscFunctionBeginUser;
19518214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19529072cb8bSMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &ctx));
19538214e71cSJoe   PetscCall(DMViewFromOptions(sw, NULL, "-migrate_view_pre"));
19548214e71cSJoe   {
19558214e71cSJoe     Vec        u, gc, gv, position, momentum;
19568214e71cSJoe     IS         isx, isv;
19578214e71cSJoe     PetscReal *pos, *mom;
19588214e71cSJoe 
19598214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
19608214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
19618214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
19628214e71cSJoe     PetscCall(VecGetSubVector(u, isx, &position));
19638214e71cSJoe     PetscCall(VecGetSubVector(u, isv, &momentum));
19648214e71cSJoe     PetscCall(VecGetArray(position, &pos));
19658214e71cSJoe     PetscCall(VecGetArray(momentum, &mom));
19668214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19678214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
19688214e71cSJoe     PetscCall(VecISCopy(u, isx, SCATTER_REVERSE, gc));
19698214e71cSJoe     PetscCall(VecISCopy(u, isv, SCATTER_REVERSE, gv));
19708214e71cSJoe 
19718214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &cdm));
19728214e71cSJoe     PetscCall(DMGetPeriodicity(cdm, NULL, NULL, &L));
19738214e71cSJoe     if ((L[0] || L[1]) >= 0.) {
19748214e71cSJoe       PetscReal *x, *v, upper[3], lower[3];
19758214e71cSJoe       PetscInt   Np, dim;
19768214e71cSJoe 
19778214e71cSJoe       PetscCall(DMSwarmGetLocalSize(sw, &Np));
19788214e71cSJoe       PetscCall(DMGetDimension(cdm, &dim));
19798214e71cSJoe       PetscCall(DMGetBoundingBox(cdm, lower, upper));
19808214e71cSJoe       PetscCall(VecGetArray(gc, &x));
19818214e71cSJoe       PetscCall(VecGetArray(gv, &v));
19828214e71cSJoe       for (PetscInt p = 0; p < Np; ++p) {
19838214e71cSJoe         for (PetscInt d = 0; d < dim; ++d) {
19848214e71cSJoe           if (pos[p * dim + d] < lower[d]) {
19858214e71cSJoe             x[p * dim + d] = pos[p * dim + d] + (upper[d] - lower[d]);
19868214e71cSJoe           } else if (pos[p * dim + d] > upper[d]) {
19878214e71cSJoe             x[p * dim + d] = pos[p * dim + d] - (upper[d] - lower[d]);
19888214e71cSJoe           } else {
19898214e71cSJoe             x[p * dim + d] = pos[p * dim + d];
19908214e71cSJoe           }
19918214e71cSJoe           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]);
19928214e71cSJoe           v[p * dim + d] = mom[p * dim + d];
19938214e71cSJoe         }
19948214e71cSJoe       }
19958214e71cSJoe       PetscCall(VecRestoreArray(gc, &x));
19968214e71cSJoe       PetscCall(VecRestoreArray(gv, &v));
19978214e71cSJoe     }
19988214e71cSJoe     PetscCall(VecRestoreArray(position, &pos));
19998214e71cSJoe     PetscCall(VecRestoreArray(momentum, &mom));
20008214e71cSJoe     PetscCall(VecRestoreSubVector(u, isx, &position));
20018214e71cSJoe     PetscCall(VecRestoreSubVector(u, isv, &momentum));
20028214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
20038214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
20048214e71cSJoe   }
20058214e71cSJoe   PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
20069072cb8bSMatthew G. Knepley   PetscInt step;
20079072cb8bSMatthew G. Knepley 
20089072cb8bSMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &step));
2009045208b8SMatthew G. Knepley   if (!(step % ctx->remapFreq)) {
20109072cb8bSMatthew G. Knepley     // Monitor electric field before we destroy it
20119072cb8bSMatthew G. Knepley     PetscReal ptime;
20129072cb8bSMatthew G. Knepley     PetscInt  step;
20139072cb8bSMatthew G. Knepley 
20149072cb8bSMatthew G. Knepley     PetscCall(TSGetStepNumber(ts, &step));
20159072cb8bSMatthew G. Knepley     PetscCall(TSGetTime(ts, &ptime));
20169072cb8bSMatthew G. Knepley     if (ctx->efield_monitor) PetscCall(MonitorEField(ts, step, ptime, NULL, ctx));
20179072cb8bSMatthew G. Knepley     if (ctx->poisson_monitor) PetscCall(MonitorPoisson(ts, step, ptime, NULL, ctx));
20189072cb8bSMatthew G. Knepley     PetscCall(DMSwarmRemap(sw));
20199072cb8bSMatthew G. Knepley     ctx->validE = PETSC_FALSE;
20209072cb8bSMatthew G. Knepley   }
20219072cb8bSMatthew G. Knepley   // This MUST come last, since it recreates the subswarms and they must DMClone() the new swarm
20228214e71cSJoe   PetscCall(DMSwarmTSRedistribute(ts));
20238214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_FALSE));
20243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2025b80bf5b1SJoe Pusztay }
2026b80bf5b1SJoe Pusztay 
2027d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
2028d71ae5a4SJacob Faibussowitsch {
2029b80bf5b1SJoe Pusztay   DM        dm, sw;
20308214e71cSJoe   TS        ts;
20318214e71cSJoe   Vec       u;
20328214e71cSJoe   PetscReal dt;
20338214e71cSJoe   PetscInt  maxn;
2034b80bf5b1SJoe Pusztay   AppCtx    user;
2035b80bf5b1SJoe Pusztay 
20369566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
20378214e71cSJoe   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
20388214e71cSJoe   PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &user.bag));
20398214e71cSJoe   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
20408214e71cSJoe   PetscCall(CreatePoisson(dm, &user));
20418214e71cSJoe   PetscCall(CreateSwarm(dm, &user, &sw));
20428214e71cSJoe   PetscCall(SetupParameters(PETSC_COMM_WORLD, &user));
20438214e71cSJoe   PetscCall(InitializeConstants(sw, &user));
20448214e71cSJoe   PetscCall(DMSetApplicationContext(sw, &user));
2045b80bf5b1SJoe Pusztay 
20468214e71cSJoe   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
20478214e71cSJoe   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
20489566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts, sw));
20498214e71cSJoe   PetscCall(TSSetMaxTime(ts, 0.1));
20508214e71cSJoe   PetscCall(TSSetTimeStep(ts, 0.00001));
20518214e71cSJoe   PetscCall(TSSetMaxSteps(ts, 100));
20528214e71cSJoe   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
20538214e71cSJoe 
20548214e71cSJoe   if (user.efield_monitor) PetscCall(TSMonitorSet(ts, MonitorEField, &user, NULL));
2055f1e6e573SMatthew G. Knepley   if (user.moment_monitor) PetscCall(TSMonitorSet(ts, MonitorMoments, &user, NULL));
20568214e71cSJoe   if (user.initial_monitor) PetscCall(TSMonitorSet(ts, MonitorInitialConditions, &user, NULL));
20579072cb8bSMatthew G. Knepley   if (user.positions_monitor) PetscCall(TSMonitorSet(ts, MonitorPositions_2D, &user, NULL));
20588214e71cSJoe   if (user.poisson_monitor) PetscCall(TSMonitorSet(ts, MonitorPoisson, &user, NULL));
20598214e71cSJoe 
20608214e71cSJoe   PetscCall(TSSetFromOptions(ts));
20618214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
20628214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
20638214e71cSJoe   user.steps    = maxn;
20648214e71cSJoe   user.stepSize = dt;
20658214e71cSJoe   PetscCall(SetupContext(dm, sw, &user));
20668214e71cSJoe   PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve));
20678214e71cSJoe   PetscCall(TSSetPostStep(ts, MigrateParticles));
20688214e71cSJoe   PetscCall(CreateSolution(ts));
20698214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
20708214e71cSJoe   PetscCall(TSComputeInitialCondition(ts, u));
20718214e71cSJoe   PetscCall(CheckNonNegativeWeights(sw, &user));
20728214e71cSJoe   PetscCall(TSSolve(ts, NULL));
20738214e71cSJoe 
20749566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&user.snes));
2075*4a0cbf56SMatthew G. Knepley   PetscCall(DMDestroy(&user.dmPot));
2076*4a0cbf56SMatthew G. Knepley   PetscCall(ISDestroy(&user.isPot));
2077f1e6e573SMatthew G. Knepley   PetscCall(MatDestroy(&user.M));
2078f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomDestroy(&user.fegeom));
20799566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
20809566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sw));
20819566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
20828214e71cSJoe   PetscCall(DestroyContext(&user));
20839566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
2084b122ec5aSJacob Faibussowitsch   return 0;
2085b80bf5b1SJoe Pusztay }
2086b80bf5b1SJoe Pusztay 
2087b80bf5b1SJoe Pusztay /*TEST
2088b80bf5b1SJoe Pusztay 
2089b80bf5b1SJoe Pusztay    build:
20908214e71cSJoe     requires: !complex double
20918214e71cSJoe 
20928214e71cSJoe   # This tests that we can put particles in a box and compute the Coulomb force
20938214e71cSJoe   # Recommend -draw_size 500,500
20948214e71cSJoe    testset:
20958214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2096045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 20 \
2097045208b8SMatthew G. Knepley              -dm_plex_box_lower 0 -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
20989072cb8bSMatthew G. Knepley            -vdm_plex_simplex 0 \
20998214e71cSJoe            -dm_swarm_coordinate_density constant -dm_swarm_num_particles 100 \
21008214e71cSJoe            -sigma 1.0e-8 -timeScale 2.0e-14 \
21018214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
21028214e71cSJoe            -output_step 50 -check_vel_res
21038214e71cSJoe      test:
21048214e71cSJoe        suffix: none_1d
21059072cb8bSMatthew G. Knepley        requires:
21068214e71cSJoe        args: -em_type none -error
21078214e71cSJoe      test:
21088214e71cSJoe        suffix: coulomb_1d
21098214e71cSJoe        args: -em_type coulomb
21108214e71cSJoe 
21118214e71cSJoe    # for viewers
21128214e71cSJoe    #-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
21138214e71cSJoe    testset:
21148214e71cSJoe      nsize: {{1 2}}
21158214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2116045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 36 \
2117045208b8SMatthew G. Knepley              -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
21188214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
21198214e71cSJoe              -vdm_plex_box_lower -3 -vdm_plex_box_upper 3 \
212084467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -twostream -charges -1.,1. -sigma 1.0e-8 \
21218214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
21228214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 2 \
21238214e71cSJoe              -ts_dt 0.01 -ts_max_time 5 -ts_max_steps 10 \
21248214e71cSJoe            -em_snes_atol 1.e-15 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
212584467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
21268214e71cSJoe      test:
21278214e71cSJoe        suffix: two_stream_c0
21288214e71cSJoe        args: -em_type primal -petscfe_default_quadrature_order 2 -petscspace_degree 2 -em_pc_type svd
21298214e71cSJoe      test:
21308214e71cSJoe        suffix: two_stream_rt
21318214e71cSJoe        requires: superlu_dist
21328214e71cSJoe        args: -em_type mixed \
21338214e71cSJoe                -potential_petscspace_degree 0 \
21348214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
21358214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
2136045208b8SMatthew G. Knepley                -field_petscspace_degree 1 -field_petscfe_default_quadrature_order 1 \
21378214e71cSJoe              -em_snes_error_if_not_converged \
21388214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
21398214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
21408214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
21418214e71cSJoe                -em_fieldsplit_field_pc_type lu \
21428214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
21438214e71cSJoe                -em_fieldsplit_potential_pc_type svd
21448214e71cSJoe 
214584467f86SMatthew G. Knepley    # For an eyeball check, we use
21469072cb8bSMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 10,1 -vdm_plex_box_faces 2000 -efield_monitor
21478214e71cSJoe    # For verification, we use
214884467f86SMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 100,1 -vdm_plex_box_faces 8000 -dm_swarm_num_particles 800000 -monitor_efield
21498214e71cSJoe    # -ts_monitor_sp_swarm_multi_species 0 -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500
21508214e71cSJoe    testset:
21518214e71cSJoe      nsize: {{1 2}}
21528214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
2153045208b8SMatthew G. Knepley      args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 10 \
2154045208b8SMatthew G. Knepley              -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
21558214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
21568214e71cSJoe              -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \
2157f1e6e573SMatthew G. Knepley              -vpetscspace_degree 2 -vdm_plex_hash_location \
215884467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -charges -1.,1. \
21598214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
21608214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
21618214e71cSJoe              -ts_dt 0.03 -ts_max_time 500 -ts_max_steps 1 \
21628214e71cSJoe            -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
216384467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
21648214e71cSJoe 
21658214e71cSJoe      test:
21668214e71cSJoe        suffix: uniform_equilibrium_1d
21678214e71cSJoe        args: -cosine_coefficients 0.0,0.5 -em_type primal -petscspace_degree 1 -em_pc_type svd
21688214e71cSJoe      test:
216975155f48SMatthew G. Knepley        suffix: uniform_equilibrium_1d_real
2170045208b8SMatthew 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.0 -em_type primal -petscspace_degree 1 -em_pc_type svd
217375155f48SMatthew G. Knepley      test:
21748214e71cSJoe        suffix: uniform_primal_1d
21758214e71cSJoe        args: -em_type primal -petscspace_degree 1 -em_pc_type svd
21768214e71cSJoe      test:
217775155f48SMatthew G. Knepley        suffix: uniform_primal_1d_real
2178045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
217975155f48SMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
218075155f48SMatthew G. Knepley              -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd
21819072cb8bSMatthew G. Knepley      # NOT WORKING -ftop_pc_type bjacobi -ftop_sub_pc_type lu -ftop_sub_pc_factor_shift_type nonzero
21829072cb8bSMatthew G. Knepley      test:
21839072cb8bSMatthew G. Knepley        suffix: uniform_primal_1d_real_pfak
21849072cb8bSMatthew G. Knepley        nsize: 1
2185045208b8SMatthew G. Knepley        args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \
21869072cb8bSMatthew G. Knepley                -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \
21879072cb8bSMatthew 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 \
21889072cb8bSMatthew G. Knepley                -remap_dm_plex_box_lower 0.,-10. -remap_dm_plex_box_upper 12.5664,10. \
21899072cb8bSMatthew G. Knepley                -remap_petscspace_degree 2 -remap_dm_plex_hash_location \
2190045208b8SMatthew G. Knepley              -remap_freq 1 -dm_swarm_remap_type pfak \
21919072cb8bSMatthew G. Knepley                -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 \
21929072cb8bSMatthew G. Knepley                -ptof_pc_type lu \
21939072cb8bSMatthew G. Knepley              -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd -em_proj_pc_type lu
219475155f48SMatthew G. Knepley      test:
21958214e71cSJoe        requires: superlu_dist
21968214e71cSJoe        suffix: uniform_mixed_1d
21978214e71cSJoe        args: -em_type mixed \
21988214e71cSJoe                -potential_petscspace_degree 0 \
21998214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
22008214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
2201045208b8SMatthew G. Knepley                -field_petscspace_degree 1 \
22028214e71cSJoe              -em_snes_error_if_not_converged \
22038214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
22048214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
22058214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
22068214e71cSJoe                -em_fieldsplit_field_pc_type lu \
22078214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
22088214e71cSJoe                -em_fieldsplit_potential_pc_type svd
22098214e71cSJoe 
2210b80bf5b1SJoe Pusztay TEST*/
2211