xref: /petsc/src/ts/tutorials/hamiltonian/ex2.c (revision f1e6e573d790696a6038ba5e06f1a0b2f249dda2)
18214e71cSJoe static char help[] = "Landau Damping/Two Stream instability test using Vlasov-Poisson equations\n";
2b80bf5b1SJoe Pusztay 
38214e71cSJoe /*
48214e71cSJoe   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"
58214e71cSJoe   According to Lukas, good damping results come at ~16k particles per cell
68214e71cSJoe 
78214e71cSJoe   To visualize the efield use
88214e71cSJoe 
98214e71cSJoe     -monitor_efield
108214e71cSJoe 
11*f1e6e573SMatthew G. Knepley   To monitor moments of the distribution use
12*f1e6e573SMatthew G. Knepley 
13*f1e6e573SMatthew G. Knepley     -ptof_pc_type lu -monitor_moments
14*f1e6e573SMatthew G. Knepley 
158214e71cSJoe   To visualize the swarm distribution use
168214e71cSJoe 
178214e71cSJoe     -ts_monitor_hg_swarm
188214e71cSJoe 
198214e71cSJoe   To visualize the particles, we can use
208214e71cSJoe 
218214e71cSJoe     -ts_monitor_sp_swarm -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500
228214e71cSJoe 
2384467f86SMatthew G. Knepley For a Landau Damping verification run, we use
2484467f86SMatthew G. Knepley 
2584467f86SMatthew G. Knepley     -dm_plex_dim 2 -fake_1D -dm_plex_simplex 0 -dm_plex_box_faces 10,1 \
2684467f86SMatthew G. Knepley       -dm_plex_box_lower 0.,-0.5 -dm_plex_box_upper 12.5664,0.5 -dm_plex_box_bd periodic,none \
2784467f86SMatthew G. Knepley     -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 2000 -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \
2884467f86SMatthew G. Knepley     -dm_swarm_num_species 1 -charges -1.,1. \
2984467f86SMatthew G. Knepley     -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
3084467f86SMatthew G. Knepley     -ts_type basicsymplectic -ts_basicsymplectic_type 1 -ts_dt 0.03 -ts_max_time 500 -ts_max_steps 500 \
3184467f86SMatthew 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 \
3284467f86SMatthew G. Knepley     -output_step 100 -check_vel_res -monitor_efield -ts_monitor -log_view
3384467f86SMatthew G. Knepley 
348214e71cSJoe */
35b80bf5b1SJoe Pusztay #include <petscts.h>
368214e71cSJoe #include <petscdmplex.h>
378214e71cSJoe #include <petscdmswarm.h>
388214e71cSJoe #include <petscfe.h>
398214e71cSJoe #include <petscds.h>
408214e71cSJoe #include <petscbag.h>
418214e71cSJoe #include <petscdraw.h>
428214e71cSJoe #include <petsc/private/dmpleximpl.h>  /* For norm and dot */
438214e71cSJoe #include <petsc/private/petscfeimpl.h> /* For interpolation */
4484467f86SMatthew G. Knepley #include <petsc/private/dmswarmimpl.h> /* For swarm debugging */
458214e71cSJoe #include "petscdm.h"
468214e71cSJoe #include "petscdmlabel.h"
478214e71cSJoe 
488214e71cSJoe PETSC_EXTERN PetscErrorCode stream(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
498214e71cSJoe PETSC_EXTERN PetscErrorCode line(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
508214e71cSJoe 
518214e71cSJoe const char *EMTypes[] = {"primal", "mixed", "coulomb", "none", "EMType", "EM_", NULL};
528214e71cSJoe typedef enum {
538214e71cSJoe   EM_PRIMAL,
548214e71cSJoe   EM_MIXED,
558214e71cSJoe   EM_COULOMB,
568214e71cSJoe   EM_NONE
578214e71cSJoe } EMType;
588214e71cSJoe 
598214e71cSJoe typedef enum {
608214e71cSJoe   V0,
618214e71cSJoe   X0,
628214e71cSJoe   T0,
638214e71cSJoe   M0,
648214e71cSJoe   Q0,
658214e71cSJoe   PHI0,
668214e71cSJoe   POISSON,
678214e71cSJoe   VLASOV,
688214e71cSJoe   SIGMA,
698214e71cSJoe   NUM_CONSTANTS
708214e71cSJoe } ConstantType;
718214e71cSJoe typedef struct {
728214e71cSJoe   PetscScalar v0; /* Velocity scale, often the thermal velocity */
738214e71cSJoe   PetscScalar t0; /* Time scale */
748214e71cSJoe   PetscScalar x0; /* Space scale */
758214e71cSJoe   PetscScalar m0; /* Mass scale */
768214e71cSJoe   PetscScalar q0; /* Charge scale */
778214e71cSJoe   PetscScalar kb;
788214e71cSJoe   PetscScalar epsi0;
798214e71cSJoe   PetscScalar phi0;          /* Potential scale */
808214e71cSJoe   PetscScalar poissonNumber; /* Non-Dimensional Poisson Number */
818214e71cSJoe   PetscScalar vlasovNumber;  /* Non-Dimensional Vlasov Number */
828214e71cSJoe   PetscReal   sigma;         /* Nondimensional charge per length in x */
838214e71cSJoe } Parameter;
84b80bf5b1SJoe Pusztay 
85b80bf5b1SJoe Pusztay typedef struct {
868214e71cSJoe   PetscBag     bag;            /* Problem parameters */
878214e71cSJoe   PetscBool    error;          /* Flag for printing the error */
888214e71cSJoe   PetscBool    efield_monitor; /* Flag to show electric field monitor */
89*f1e6e573SMatthew G. Knepley   PetscBool    moment_monitor; /* Flag to show distribution moment monitor */
908214e71cSJoe   PetscBool    initial_monitor;
918214e71cSJoe   PetscBool    fake_1D;           /* Run simulation in 2D but zeroing second dimension */
928214e71cSJoe   PetscBool    perturbed_weights; /* Uniformly sample x,v space with gaussian weights */
938214e71cSJoe   PetscBool    poisson_monitor;
948214e71cSJoe   PetscInt     ostep; /* print the energy at each ostep time steps */
958214e71cSJoe   PetscInt     numParticles;
968214e71cSJoe   PetscReal    timeScale;              /* Nondimensionalizing time scale */
978214e71cSJoe   PetscReal    charges[2];             /* The charges of each species */
988214e71cSJoe   PetscReal    masses[2];              /* The masses of each species */
998214e71cSJoe   PetscReal    thermal_energy[2];      /* Thermal Energy (used to get other constants)*/
1008214e71cSJoe   PetscReal    cosine_coefficients[2]; /*(alpha, k)*/
1018214e71cSJoe   PetscReal    totalWeight;
1028214e71cSJoe   PetscReal    stepSize;
1038214e71cSJoe   PetscInt     steps;
1048214e71cSJoe   PetscReal    initVel;
105*f1e6e573SMatthew G. Knepley   EMType       em;     // Type of electrostatic model
106*f1e6e573SMatthew G. Knepley   SNES         snes;   // EM solver
107*f1e6e573SMatthew G. Knepley   Mat          M;      // The finite element mass matrix
108*f1e6e573SMatthew G. Knepley   PetscFEGeom *fegeom; // Geometric information for the DM cells
1098214e71cSJoe   PetscDraw    drawef;
1108214e71cSJoe   PetscDrawLG  drawlg_ef;
1118214e71cSJoe   PetscDraw    drawic_x;
1128214e71cSJoe   PetscDraw    drawic_v;
1138214e71cSJoe   PetscDraw    drawic_w;
1148214e71cSJoe   PetscDrawHG  drawhgic_x;
1158214e71cSJoe   PetscDrawHG  drawhgic_v;
1168214e71cSJoe   PetscDrawHG  drawhgic_w;
1178214e71cSJoe   PetscDraw    EDraw;
1188214e71cSJoe   PetscDraw    RhoDraw;
1198214e71cSJoe   PetscDraw    PotDraw;
1208214e71cSJoe   PetscDrawSP  EDrawSP;
1218214e71cSJoe   PetscDrawSP  RhoDrawSP;
1228214e71cSJoe   PetscDrawSP  PotDrawSP;
1238214e71cSJoe   PetscBool    monitor_positions; /* Flag to show particle positins at each time step */
1248214e71cSJoe   PetscDraw    positionDraw;
1258214e71cSJoe   PetscDrawSP  positionDrawSP;
1268214e71cSJoe   DM           swarm;
1278214e71cSJoe   PetscRandom  random;
1288214e71cSJoe   PetscBool    twostream;
1298214e71cSJoe   PetscBool    checkweights;
1308214e71cSJoe   PetscInt     checkVRes; /* Flag to check/output velocity residuals for nightly tests */
13184467f86SMatthew G. Knepley 
13284467f86SMatthew G. Knepley   PetscLogEvent RhsXEvent, RhsVEvent, ESolveEvent, ETabEvent;
133b80bf5b1SJoe Pusztay } AppCtx;
134b80bf5b1SJoe Pusztay 
135d71ae5a4SJacob Faibussowitsch static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
136d71ae5a4SJacob Faibussowitsch {
137b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
1388214e71cSJoe   PetscInt d                      = 2;
1398214e71cSJoe   PetscInt maxSpecies             = 2;
1408214e71cSJoe   options->error                  = PETSC_FALSE;
1418214e71cSJoe   options->efield_monitor         = PETSC_FALSE;
142*f1e6e573SMatthew G. Knepley   options->moment_monitor         = PETSC_FALSE;
1438214e71cSJoe   options->initial_monitor        = PETSC_FALSE;
1448214e71cSJoe   options->fake_1D                = PETSC_FALSE;
1458214e71cSJoe   options->perturbed_weights      = PETSC_FALSE;
1468214e71cSJoe   options->poisson_monitor        = PETSC_FALSE;
1478214e71cSJoe   options->ostep                  = 100;
1488214e71cSJoe   options->timeScale              = 2.0e-14;
1498214e71cSJoe   options->charges[0]             = -1.0;
1508214e71cSJoe   options->charges[1]             = 1.0;
1518214e71cSJoe   options->masses[0]              = 1.0;
1528214e71cSJoe   options->masses[1]              = 1000.0;
1538214e71cSJoe   options->thermal_energy[0]      = 1.0;
1548214e71cSJoe   options->thermal_energy[1]      = 1.0;
1558214e71cSJoe   options->cosine_coefficients[0] = 0.01;
1568214e71cSJoe   options->cosine_coefficients[1] = 0.5;
1578214e71cSJoe   options->initVel                = 1;
1588214e71cSJoe   options->totalWeight            = 1.0;
1598214e71cSJoe   options->drawef                 = NULL;
1608214e71cSJoe   options->drawlg_ef              = NULL;
1618214e71cSJoe   options->drawic_x               = NULL;
1628214e71cSJoe   options->drawic_v               = NULL;
1638214e71cSJoe   options->drawic_w               = NULL;
1648214e71cSJoe   options->drawhgic_x             = NULL;
1658214e71cSJoe   options->drawhgic_v             = NULL;
1668214e71cSJoe   options->drawhgic_w             = NULL;
1678214e71cSJoe   options->EDraw                  = NULL;
1688214e71cSJoe   options->RhoDraw                = NULL;
1698214e71cSJoe   options->PotDraw                = NULL;
1708214e71cSJoe   options->EDrawSP                = NULL;
1718214e71cSJoe   options->RhoDrawSP              = NULL;
1728214e71cSJoe   options->PotDrawSP              = NULL;
1738214e71cSJoe   options->em                     = EM_COULOMB;
1748214e71cSJoe   options->numParticles           = 32768;
1758214e71cSJoe   options->monitor_positions      = PETSC_FALSE;
1768214e71cSJoe   options->positionDraw           = NULL;
1778214e71cSJoe   options->positionDrawSP         = NULL;
1788214e71cSJoe   options->twostream              = PETSC_FALSE;
1798214e71cSJoe   options->checkweights           = PETSC_FALSE;
1808214e71cSJoe   options->checkVRes              = 0;
181b80bf5b1SJoe Pusztay 
1828214e71cSJoe   PetscOptionsBegin(comm, "", "Landau Damping and Two Stream options", "DMSWARM");
1838214e71cSJoe   PetscCall(PetscOptionsBool("-error", "Flag to print the error", "ex2.c", options->error, &options->error, NULL));
1848214e71cSJoe   PetscCall(PetscOptionsBool("-monitor_efield", "Flag to show efield plot", "ex2.c", options->efield_monitor, &options->efield_monitor, NULL));
185*f1e6e573SMatthew G. Knepley   PetscCall(PetscOptionsBool("-monitor_moments", "Flag to show moments table", "ex2.c", options->moment_monitor, &options->moment_monitor, NULL));
1868214e71cSJoe   PetscCall(PetscOptionsBool("-monitor_ics", "Flag to show initial condition histograms", "ex2.c", options->initial_monitor, &options->initial_monitor, NULL));
1878214e71cSJoe   PetscCall(PetscOptionsBool("-monitor_positions", "The flag to show particle positions", "ex2.c", options->monitor_positions, &options->monitor_positions, NULL));
1888214e71cSJoe   PetscCall(PetscOptionsBool("-monitor_poisson", "The flag to show charges, Efield and potential solve", "ex2.c", options->poisson_monitor, &options->poisson_monitor, NULL));
1898214e71cSJoe   PetscCall(PetscOptionsBool("-fake_1D", "Flag to run a 1D simulation (but really in 2D)", "ex2.c", options->fake_1D, &options->fake_1D, NULL));
1908214e71cSJoe   PetscCall(PetscOptionsBool("-twostream", "Run two stream instability", "ex2.c", options->twostream, &options->twostream, NULL));
1918214e71cSJoe   PetscCall(PetscOptionsBool("-perturbed_weights", "Flag to run uniform sampling with perturbed weights", "ex2.c", options->perturbed_weights, &options->perturbed_weights, NULL));
1928214e71cSJoe   PetscCall(PetscOptionsBool("-check_weights", "Ensure all particle weights are positive", "ex2.c", options->checkweights, &options->checkweights, NULL));
1938214e71cSJoe   PetscCall(PetscOptionsInt("-check_vel_res", "Check particle velocity residuals for nightly tests", "ex2.c", options->checkVRes, &options->checkVRes, NULL));
1948214e71cSJoe   PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", "ex2.c", options->ostep, &options->ostep, NULL));
1958214e71cSJoe   PetscCall(PetscOptionsReal("-timeScale", "Nondimensionalizing time scale", "ex2.c", options->timeScale, &options->timeScale, NULL));
1968214e71cSJoe   PetscCall(PetscOptionsReal("-initial_velocity", "Initial velocity of perturbed particle", "ex2.c", options->initVel, &options->initVel, NULL));
1978214e71cSJoe   PetscCall(PetscOptionsReal("-total_weight", "Total weight of all particles", "ex2.c", options->totalWeight, &options->totalWeight, NULL));
1988214e71cSJoe   PetscCall(PetscOptionsRealArray("-cosine_coefficients", "Amplitude and frequency of cosine equation used in initialization", "ex2.c", options->cosine_coefficients, &d, NULL));
1998214e71cSJoe   PetscCall(PetscOptionsRealArray("-charges", "Species charges", "ex2.c", options->charges, &maxSpecies, NULL));
2008214e71cSJoe   PetscCall(PetscOptionsEnum("-em_type", "Type of electrostatic solver", "ex2.c", EMTypes, (PetscEnum)options->em, (PetscEnum *)&options->em, NULL));
201d0609cedSBarry Smith   PetscOptionsEnd();
20284467f86SMatthew G. Knepley 
20384467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsX", TS_CLASSID, &options->RhsXEvent));
20484467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("RhsV", TS_CLASSID, &options->RhsVEvent));
20584467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ESolve", TS_CLASSID, &options->ESolveEvent));
20684467f86SMatthew G. Knepley   PetscCall(PetscLogEventRegister("ETab", TS_CLASSID, &options->ETabEvent));
2073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
208b80bf5b1SJoe Pusztay }
209b80bf5b1SJoe Pusztay 
2108214e71cSJoe static PetscErrorCode SetupContext(DM dm, DM sw, AppCtx *user)
2118214e71cSJoe {
2128214e71cSJoe   PetscFunctionBeginUser;
2138214e71cSJoe   if (user->efield_monitor) {
2148214e71cSJoe     PetscDrawAxis axis_ef;
2158214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_efield", 0, 300, 400, 300, &user->drawef));
2168214e71cSJoe     PetscCall(PetscDrawSetSave(user->drawef, "ex9_Efield.png"));
2178214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawef));
2188214e71cSJoe     PetscCall(PetscDrawLGCreate(user->drawef, 1, &user->drawlg_ef));
2198214e71cSJoe     PetscCall(PetscDrawLGGetAxis(user->drawlg_ef, &axis_ef));
2208214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis_ef, "Electron Electric Field", "time", "E_max"));
2218214e71cSJoe     PetscCall(PetscDrawLGSetLimits(user->drawlg_ef, 0., user->steps * user->stepSize, -10., 0.));
2228214e71cSJoe     PetscCall(PetscDrawAxisSetLimits(axis_ef, 0., user->steps * user->stepSize, -10., 0.));
2238214e71cSJoe   }
2248214e71cSJoe   if (user->initial_monitor) {
2258214e71cSJoe     PetscDrawAxis axis1, axis2, axis3;
2268214e71cSJoe     PetscReal     dmboxlower[2], dmboxupper[2];
2278214e71cSJoe     PetscInt      dim, cStart, cEnd;
2288214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
2298214e71cSJoe     PetscCall(DMGetBoundingBox(dm, dmboxlower, dmboxupper));
2308214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2318214e71cSJoe 
2328214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_x", 0, 300, 400, 300, &user->drawic_x));
2338214e71cSJoe     PetscCall(PetscDrawSetSave(user->drawic_x, "ex9_ic_x.png"));
2348214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawic_x));
2356497c311SBarry Smith     PetscCall(PetscDrawHGCreate(user->drawic_x, (int)dim, &user->drawhgic_x));
2368214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_x, &axis1));
2376497c311SBarry Smith     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_x, (int)(cEnd - cStart)));
2388214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis1, "Initial X Distribution", "X", "counts"));
2398214e71cSJoe     PetscCall(PetscDrawAxisSetLimits(axis1, dmboxlower[0], dmboxupper[0], 0, 1500));
2408214e71cSJoe 
2418214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_v", 400, 300, 400, 300, &user->drawic_v));
2428214e71cSJoe     PetscCall(PetscDrawSetSave(user->drawic_v, "ex9_ic_v.png"));
2438214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawic_v));
2446497c311SBarry Smith     PetscCall(PetscDrawHGCreate(user->drawic_v, (int)dim, &user->drawhgic_v));
2458214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_v, &axis2));
2468214e71cSJoe     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_v, 1000));
2478214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis2, "Initial V_x Distribution", "V", "counts"));
2488214e71cSJoe     PetscCall(PetscDrawAxisSetLimits(axis2, -1, 1, 0, 1500));
2498214e71cSJoe 
2508214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_w", 800, 300, 400, 300, &user->drawic_w));
2518214e71cSJoe     PetscCall(PetscDrawSetSave(user->drawic_w, "ex9_ic_w.png"));
2528214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->drawic_w));
2536497c311SBarry Smith     PetscCall(PetscDrawHGCreate(user->drawic_w, (int)dim, &user->drawhgic_w));
2548214e71cSJoe     PetscCall(PetscDrawHGGetAxis(user->drawhgic_w, &axis3));
2558214e71cSJoe     PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_w, 10));
2568214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis3, "Initial W Distribution", "weight", "counts"));
2578214e71cSJoe     PetscCall(PetscDrawAxisSetLimits(axis3, 0, 0.01, 0, 5000));
2588214e71cSJoe   }
2598214e71cSJoe   if (user->monitor_positions) {
2608214e71cSJoe     PetscDrawAxis axis;
2618214e71cSJoe 
2628214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "position_monitor_species1", 0, 0, 400, 300, &user->positionDraw));
2638214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->positionDraw));
2648214e71cSJoe     PetscCall(PetscDrawSPCreate(user->positionDraw, 10, &user->positionDrawSP));
2658214e71cSJoe     PetscCall(PetscDrawSPSetDimension(user->positionDrawSP, 1));
2668214e71cSJoe     PetscCall(PetscDrawSPGetAxis(user->positionDrawSP, &axis));
2678214e71cSJoe     PetscCall(PetscDrawSPReset(user->positionDrawSP));
2688214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "v"));
2698214e71cSJoe     PetscCall(PetscDrawSetSave(user->positionDraw, "ex9_pos.png"));
2708214e71cSJoe   }
2718214e71cSJoe   if (user->poisson_monitor) {
2728214e71cSJoe     PetscDrawAxis axis_E, axis_Rho, axis_Pot;
2738214e71cSJoe 
274*f1e6e573SMatthew G. Knepley     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "Poisson_monitor", 0, 0, 400, 300, &user->EDraw));
2758214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->EDraw));
2768214e71cSJoe     PetscCall(PetscDrawSPCreate(user->EDraw, 10, &user->EDrawSP));
2778214e71cSJoe     PetscCall(PetscDrawSPSetDimension(user->EDrawSP, 1));
2788214e71cSJoe     PetscCall(PetscDrawSPGetAxis(user->EDrawSP, &axis_E));
2798214e71cSJoe     PetscCall(PetscDrawSPReset(user->EDrawSP));
2808214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis_E, "Particles", "x", "E"));
2818214e71cSJoe     PetscCall(PetscDrawSetSave(user->EDraw, "ex9_E_spatial.png"));
2828214e71cSJoe 
2838214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "rho_monitor", 0, 0, 400, 300, &user->RhoDraw));
2848214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->RhoDraw));
2858214e71cSJoe     PetscCall(PetscDrawSPCreate(user->RhoDraw, 10, &user->RhoDrawSP));
2868214e71cSJoe     PetscCall(PetscDrawSPSetDimension(user->RhoDrawSP, 1));
2878214e71cSJoe     PetscCall(PetscDrawSPGetAxis(user->RhoDrawSP, &axis_Rho));
2888214e71cSJoe     PetscCall(PetscDrawSPReset(user->RhoDrawSP));
2898214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis_Rho, "Particles", "x", "rho"));
2908214e71cSJoe     PetscCall(PetscDrawSetSave(user->RhoDraw, "ex9_rho_spatial.png"));
2918214e71cSJoe 
2928214e71cSJoe     PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "potential_monitor", 0, 0, 400, 300, &user->PotDraw));
2938214e71cSJoe     PetscCall(PetscDrawSetFromOptions(user->PotDraw));
2948214e71cSJoe     PetscCall(PetscDrawSPCreate(user->PotDraw, 10, &user->PotDrawSP));
2958214e71cSJoe     PetscCall(PetscDrawSPSetDimension(user->PotDrawSP, 1));
2968214e71cSJoe     PetscCall(PetscDrawSPGetAxis(user->PotDrawSP, &axis_Pot));
2978214e71cSJoe     PetscCall(PetscDrawSPReset(user->PotDrawSP));
2988214e71cSJoe     PetscCall(PetscDrawAxisSetLabels(axis_Pot, "Particles", "x", "potential"));
2998214e71cSJoe     PetscCall(PetscDrawSetSave(user->PotDraw, "ex9_phi_spatial.png"));
3008214e71cSJoe   }
3018214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3028214e71cSJoe }
3038214e71cSJoe 
3048214e71cSJoe static PetscErrorCode DestroyContext(AppCtx *user)
3058214e71cSJoe {
3068214e71cSJoe   PetscFunctionBeginUser;
3078214e71cSJoe   PetscCall(PetscDrawLGDestroy(&user->drawlg_ef));
3088214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawef));
3098214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_x));
3108214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawic_x));
3118214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_v));
3128214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawic_v));
3138214e71cSJoe   PetscCall(PetscDrawHGDestroy(&user->drawhgic_w));
3148214e71cSJoe   PetscCall(PetscDrawDestroy(&user->drawic_w));
3158214e71cSJoe   PetscCall(PetscDrawSPDestroy(&user->positionDrawSP));
3168214e71cSJoe   PetscCall(PetscDrawDestroy(&user->positionDraw));
3178214e71cSJoe 
3188214e71cSJoe   PetscCall(PetscDrawSPDestroy(&user->EDrawSP));
3198214e71cSJoe   PetscCall(PetscDrawDestroy(&user->EDraw));
3208214e71cSJoe   PetscCall(PetscDrawSPDestroy(&user->RhoDrawSP));
3218214e71cSJoe   PetscCall(PetscDrawDestroy(&user->RhoDraw));
3228214e71cSJoe   PetscCall(PetscDrawSPDestroy(&user->PotDrawSP));
3238214e71cSJoe   PetscCall(PetscDrawDestroy(&user->PotDraw));
3248214e71cSJoe 
3258214e71cSJoe   PetscCall(PetscBagDestroy(&user->bag));
3268214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3278214e71cSJoe }
3288214e71cSJoe 
3298214e71cSJoe static PetscErrorCode CheckNonNegativeWeights(DM sw, AppCtx *user)
3308214e71cSJoe {
3318214e71cSJoe   const PetscScalar *w;
3328214e71cSJoe   PetscInt           Np;
3338214e71cSJoe 
3348214e71cSJoe   PetscFunctionBeginUser;
3358214e71cSJoe   if (!user->checkweights) PetscFunctionReturn(PETSC_SUCCESS);
3368214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w));
3378214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
3388214e71cSJoe   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]);
3398214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w));
3408214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3418214e71cSJoe }
3428214e71cSJoe 
343*f1e6e573SMatthew G. Knepley static PetscErrorCode computeVelocityFEMMoments(DM sw, PetscReal moments[3], AppCtx *user)
3448214e71cSJoe {
345*f1e6e573SMatthew G. Knepley   DM          vdm;
346*f1e6e573SMatthew G. Knepley   Vec         u[1];
347*f1e6e573SMatthew G. Knepley   const char *fields[1] = {"w_q"};
3488214e71cSJoe 
349*f1e6e573SMatthew G. Knepley   PetscFunctionBegin;
350*f1e6e573SMatthew G. Knepley   PetscCall(PetscObjectQuery((PetscObject)sw, "__vdm__", (PetscObject *)&vdm));
351*f1e6e573SMatthew G. Knepley   PetscCall(DMGetGlobalVector(vdm, &u[0]));
352*f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmPushCellDM(sw, vdm, 1, fields, "velocity"));
353*f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmProjectFields(sw, vdm, 1, fields, u, SCATTER_FORWARD));
354*f1e6e573SMatthew G. Knepley   PetscCall(DMPlexComputeMoments(vdm, u[0], moments));
355*f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmPopCellDM(sw));
356*f1e6e573SMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(vdm, &u[0]));
3578214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
3588214e71cSJoe }
3598214e71cSJoe 
3608214e71cSJoe static PetscErrorCode MonitorEField(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
3618214e71cSJoe {
3628214e71cSJoe   AppCtx    *user = (AppCtx *)ctx;
363*f1e6e573SMatthew G. Knepley   DM         sw;
364*f1e6e573SMatthew G. Knepley   PetscReal *E, *x, *weight;
365*f1e6e573SMatthew G. Knepley   PetscReal  Enorm = 0., lgEnorm, lgEmax, sum = 0., Emax = 0., chargesum = 0.;
366*f1e6e573SMatthew G. Knepley   PetscReal  pmoments[4]; /* \int f, \int v f, \int v^2 f */
367*f1e6e573SMatthew G. Knepley   PetscInt  *species, dim, Np;
3688214e71cSJoe 
3698214e71cSJoe   PetscFunctionBeginUser;
3708214e71cSJoe   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
3718214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
3728214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
3738214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
3748214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
3758214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
3768214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
3778214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
3788214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
3798214e71cSJoe 
380*f1e6e573SMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
381*f1e6e573SMatthew G. Knepley     for (PetscInt d = 0; d < 1; ++d) {
382*f1e6e573SMatthew G. Knepley       PetscReal temp = PetscAbsReal(E[p * dim + d]);
3838214e71cSJoe       if (temp > Emax) Emax = temp;
3848214e71cSJoe     }
3858214e71cSJoe     Enorm += PetscSqrtReal(E[p * dim] * E[p * dim]);
3868214e71cSJoe     sum += E[p * dim];
3878214e71cSJoe     chargesum += user->charges[0] * weight[p];
3888214e71cSJoe   }
3898214e71cSJoe   lgEnorm = Enorm != 0 ? PetscLog10Real(Enorm) : -16.;
3908214e71cSJoe   lgEmax  = Emax != 0 ? PetscLog10Real(Emax) : -16.;
3918214e71cSJoe 
3928214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
3938214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
3948214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
3958214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
3968214e71cSJoe   PetscCall(PetscDrawLGAddPoint(user->drawlg_ef, &t, &lgEmax));
3978214e71cSJoe   PetscCall(PetscDrawLGDraw(user->drawlg_ef));
3988214e71cSJoe   PetscCall(PetscDrawSave(user->drawef));
399*f1e6e573SMatthew G. Knepley 
400*f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
401*f1e6e573SMatthew 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[3]));
402*f1e6e573SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
403*f1e6e573SMatthew G. Knepley }
404*f1e6e573SMatthew G. Knepley 
405*f1e6e573SMatthew G. Knepley static PetscErrorCode MonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
406*f1e6e573SMatthew G. Knepley {
407*f1e6e573SMatthew G. Knepley   AppCtx   *user = (AppCtx *)ctx;
408*f1e6e573SMatthew G. Knepley   DM        sw;
409*f1e6e573SMatthew G. Knepley   PetscReal pmoments[4], fmoments[4]; /* \int f, \int v f, \int v^2 f */
410*f1e6e573SMatthew G. Knepley 
411*f1e6e573SMatthew G. Knepley   PetscFunctionBeginUser;
412*f1e6e573SMatthew G. Knepley   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS);
413*f1e6e573SMatthew G. Knepley   PetscCall(TSGetDM(ts, &sw));
414*f1e6e573SMatthew G. Knepley 
415*f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments));
416*f1e6e573SMatthew G. Knepley   PetscCall(computeVelocityFEMMoments(sw, fmoments, user));
417*f1e6e573SMatthew G. Knepley 
418*f1e6e573SMatthew 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]));
4198214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
4208214e71cSJoe }
4218214e71cSJoe 
4228214e71cSJoe PetscErrorCode MonitorInitialConditions(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
4238214e71cSJoe {
4248214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
4258214e71cSJoe   DM                 dm, sw;
4268214e71cSJoe   const PetscScalar *u;
4278214e71cSJoe   PetscReal         *weight, *pos, *vel;
4288214e71cSJoe   PetscInt           dim, p, Np, cStart, cEnd;
4298214e71cSJoe 
4308214e71cSJoe   PetscFunctionBegin;
4318214e71cSJoe   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
4328214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
4338214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &dm));
4348214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
4358214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
4368214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
4378214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
4388214e71cSJoe 
4398214e71cSJoe   if (step == 0) {
4408214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_x));
4418214e71cSJoe     PetscCall(PetscDrawHGGetDraw(user->drawhgic_x, &user->drawic_x));
4428214e71cSJoe     PetscCall(PetscDrawClear(user->drawic_x));
4438214e71cSJoe     PetscCall(PetscDrawFlush(user->drawic_x));
4448214e71cSJoe 
4458214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_v));
4468214e71cSJoe     PetscCall(PetscDrawHGGetDraw(user->drawhgic_v, &user->drawic_v));
4478214e71cSJoe     PetscCall(PetscDrawClear(user->drawic_v));
4488214e71cSJoe     PetscCall(PetscDrawFlush(user->drawic_v));
4498214e71cSJoe 
4508214e71cSJoe     PetscCall(PetscDrawHGReset(user->drawhgic_w));
4518214e71cSJoe     PetscCall(PetscDrawHGGetDraw(user->drawhgic_w, &user->drawic_w));
4528214e71cSJoe     PetscCall(PetscDrawClear(user->drawic_w));
4538214e71cSJoe     PetscCall(PetscDrawFlush(user->drawic_w));
4548214e71cSJoe 
4558214e71cSJoe     PetscCall(VecGetArrayRead(U, &u));
4568214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel));
4578214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
4588214e71cSJoe     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
4598214e71cSJoe 
4608214e71cSJoe     PetscCall(VecGetLocalSize(U, &Np));
4618214e71cSJoe     Np /= dim * 2;
4628214e71cSJoe     for (p = 0; p < Np; ++p) {
4638214e71cSJoe       PetscCall(PetscDrawHGAddValue(user->drawhgic_x, pos[p * dim]));
4648214e71cSJoe       PetscCall(PetscDrawHGAddValue(user->drawhgic_v, vel[p * dim]));
4658214e71cSJoe       PetscCall(PetscDrawHGAddValue(user->drawhgic_w, weight[p]));
4668214e71cSJoe     }
4678214e71cSJoe 
4688214e71cSJoe     PetscCall(VecRestoreArrayRead(U, &u));
4698214e71cSJoe     PetscCall(PetscDrawHGDraw(user->drawhgic_x));
4708214e71cSJoe     PetscCall(PetscDrawHGSave(user->drawhgic_x));
4718214e71cSJoe 
4728214e71cSJoe     PetscCall(PetscDrawHGDraw(user->drawhgic_v));
4738214e71cSJoe     PetscCall(PetscDrawHGSave(user->drawhgic_v));
4748214e71cSJoe 
4758214e71cSJoe     PetscCall(PetscDrawHGDraw(user->drawhgic_w));
4768214e71cSJoe     PetscCall(PetscDrawHGSave(user->drawhgic_w));
4778214e71cSJoe 
4788214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos));
4798214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel));
4808214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
4818214e71cSJoe   }
4828214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
4838214e71cSJoe }
4848214e71cSJoe 
4858214e71cSJoe static PetscErrorCode MonitorPositions_2D(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
4868214e71cSJoe {
4878214e71cSJoe   AppCtx         *user = (AppCtx *)ctx;
4888214e71cSJoe   DM              dm, sw;
4898214e71cSJoe   PetscScalar    *x, *v, *weight;
4908214e71cSJoe   PetscReal       lower[3], upper[3], speed;
4918214e71cSJoe   const PetscInt *s;
4928214e71cSJoe   PetscInt        dim, cStart, cEnd, c;
4938214e71cSJoe 
4948214e71cSJoe   PetscFunctionBeginUser;
4958214e71cSJoe   if (step > 0 && step % user->ostep == 0) {
4968214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
4978214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
4988214e71cSJoe     PetscCall(DMGetDimension(dm, &dim));
4998214e71cSJoe     PetscCall(DMGetBoundingBox(dm, lower, upper));
5008214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
5018214e71cSJoe     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5028214e71cSJoe     PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
5038214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
5048214e71cSJoe     PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&s));
5058214e71cSJoe     PetscCall(DMSwarmSortGetAccess(sw));
5068214e71cSJoe     PetscCall(PetscDrawSPReset(user->positionDrawSP));
5078214e71cSJoe     PetscCall(PetscDrawSPSetLimits(user->positionDrawSP, lower[0], upper[0], lower[1], upper[1]));
5088214e71cSJoe     PetscCall(PetscDrawSPSetLimits(user->positionDrawSP, lower[0], upper[0], -12, 12));
5098214e71cSJoe     for (c = 0; c < cEnd - cStart; ++c) {
5108214e71cSJoe       PetscInt *pidx, Npc, q;
5118214e71cSJoe       PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
5128214e71cSJoe       for (q = 0; q < Npc; ++q) {
5138214e71cSJoe         const PetscInt p = pidx[q];
5148214e71cSJoe         if (s[p] == 0) {
5158214e71cSJoe           speed = PetscSqrtReal(PetscSqr(v[p * dim]) + PetscSqr(v[p * dim + 1]));
5168214e71cSJoe           if (dim == 1 || user->fake_1D) {
5178214e71cSJoe             PetscCall(PetscDrawSPAddPointColorized(user->positionDrawSP, &x[p * dim], &v[p * dim], &speed));
5188214e71cSJoe           } else {
5198214e71cSJoe             PetscCall(PetscDrawSPAddPointColorized(user->positionDrawSP, &x[p * dim], &x[p * dim + 1], &speed));
5208214e71cSJoe           }
5218214e71cSJoe         } else if (s[p] == 1) {
5228214e71cSJoe           PetscCall(PetscDrawSPAddPoint(user->positionDrawSP, &x[p * dim], &v[p * dim]));
5238214e71cSJoe         }
5248214e71cSJoe       }
52584467f86SMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
5268214e71cSJoe     }
5278214e71cSJoe     PetscCall(PetscDrawSPDraw(user->positionDrawSP, PETSC_TRUE));
5288214e71cSJoe     PetscCall(PetscDrawSave(user->positionDraw));
5298214e71cSJoe     PetscCall(DMSwarmSortRestoreAccess(sw));
5308214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5318214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
5328214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
5338214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&s));
5348214e71cSJoe   }
5358214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5368214e71cSJoe }
5378214e71cSJoe 
5388214e71cSJoe static PetscErrorCode MonitorPoisson(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx)
5398214e71cSJoe {
5408214e71cSJoe   AppCtx      *user = (AppCtx *)ctx;
5418214e71cSJoe   DM           dm, sw;
5428214e71cSJoe   PetscScalar *x, *E, *weight, *pot, *charges;
5438214e71cSJoe   PetscReal    lower[3], upper[3], xval;
5448214e71cSJoe   PetscInt     dim, cStart, cEnd, c;
5458214e71cSJoe 
5468214e71cSJoe   PetscFunctionBeginUser;
5478214e71cSJoe   if (step > 0 && step % user->ostep == 0) {
5488214e71cSJoe     PetscCall(TSGetDM(ts, &sw));
5498214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &dm));
5508214e71cSJoe     PetscCall(DMGetDimension(dm, &dim));
5518214e71cSJoe     PetscCall(DMGetBoundingBox(dm, lower, upper));
5528214e71cSJoe     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
5538214e71cSJoe 
5548214e71cSJoe     PetscCall(PetscDrawSPReset(user->RhoDrawSP));
5558214e71cSJoe     PetscCall(PetscDrawSPReset(user->EDrawSP));
5568214e71cSJoe     PetscCall(PetscDrawSPReset(user->PotDrawSP));
5578214e71cSJoe     PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5588214e71cSJoe     PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
5598214e71cSJoe     PetscCall(DMSwarmGetField(sw, "potential", NULL, NULL, (void **)&pot));
5608214e71cSJoe     PetscCall(DMSwarmGetField(sw, "charges", NULL, NULL, (void **)&charges));
5618214e71cSJoe     PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
5628214e71cSJoe 
5638214e71cSJoe     PetscCall(DMSwarmSortGetAccess(sw));
5648214e71cSJoe     for (c = 0; c < cEnd - cStart; ++c) {
5658214e71cSJoe       PetscReal Esum = 0.0;
5668214e71cSJoe       PetscInt *pidx, Npc, q;
5678214e71cSJoe       PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
5688214e71cSJoe       for (q = 0; q < Npc; ++q) {
5698214e71cSJoe         const PetscInt p = pidx[q];
5708214e71cSJoe         Esum += E[p * dim];
5718214e71cSJoe       }
5728214e71cSJoe       xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart));
5738214e71cSJoe       PetscCall(PetscDrawSPAddPoint(user->EDrawSP, &xval, &Esum));
57484467f86SMatthew G. Knepley       PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
5758214e71cSJoe     }
5768214e71cSJoe     for (c = 0; c < (cEnd - cStart); ++c) {
5778214e71cSJoe       xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart));
5788214e71cSJoe       PetscCall(PetscDrawSPAddPoint(user->RhoDrawSP, &xval, &charges[c]));
5798214e71cSJoe       PetscCall(PetscDrawSPAddPoint(user->PotDrawSP, &xval, &pot[c]));
5808214e71cSJoe     }
5818214e71cSJoe     PetscCall(PetscDrawSPDraw(user->RhoDrawSP, PETSC_TRUE));
5828214e71cSJoe     PetscCall(PetscDrawSave(user->RhoDraw));
5838214e71cSJoe     PetscCall(PetscDrawSPDraw(user->EDrawSP, PETSC_TRUE));
5848214e71cSJoe     PetscCall(PetscDrawSave(user->EDraw));
5858214e71cSJoe     PetscCall(PetscDrawSPDraw(user->PotDrawSP, PETSC_TRUE));
5868214e71cSJoe     PetscCall(PetscDrawSave(user->PotDraw));
5878214e71cSJoe     PetscCall(DMSwarmSortRestoreAccess(sw));
5888214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
5898214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "potential", NULL, NULL, (void **)&pot));
5908214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "charges", NULL, NULL, (void **)&charges));
5918214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
5928214e71cSJoe     PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
5938214e71cSJoe   }
5948214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
5958214e71cSJoe }
5968214e71cSJoe 
5978214e71cSJoe static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx)
5988214e71cSJoe {
5998214e71cSJoe   PetscBag   bag;
6008214e71cSJoe   Parameter *p;
6018214e71cSJoe 
6028214e71cSJoe   PetscFunctionBeginUser;
6038214e71cSJoe   /* setup PETSc parameter bag */
6048214e71cSJoe   PetscCall(PetscBagGetData(ctx->bag, (void **)&p));
6058214e71cSJoe   PetscCall(PetscBagSetName(ctx->bag, "par", "Vlasov-Poisson Parameters"));
6068214e71cSJoe   bag = ctx->bag;
6078214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "v0", "Velocity scale, m/s"));
6088214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->t0, 1.0, "t0", "Time scale, s"));
6098214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->x0, 1.0, "x0", "Space scale, m"));
6108214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "phi0", "Potential scale, kg*m^2/A*s^3"));
6118214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->q0, 1.0, "q0", "Charge Scale, A*s"));
6128214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->m0, 1.0, "m0", "Mass Scale, kg"));
6138214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->epsi0, 1.0, "epsi0", "Permittivity of Free Space, kg"));
6148214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->kb, 1.0, "kb", "Boltzmann Constant, m^2 kg/s^2 K^1"));
6158214e71cSJoe 
6168214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->sigma, 1.0, "sigma", "Charge per unit area, C/m^3"));
6178214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->poissonNumber, 1.0, "poissonNumber", "Non-Dimensional Poisson Number"));
6188214e71cSJoe   PetscCall(PetscBagRegisterScalar(bag, &p->vlasovNumber, 1.0, "vlasovNumber", "Non-Dimensional Vlasov Number"));
6198214e71cSJoe   PetscCall(PetscBagSetFromOptions(bag));
6208214e71cSJoe   {
6218214e71cSJoe     PetscViewer       viewer;
6228214e71cSJoe     PetscViewerFormat format;
6238214e71cSJoe     PetscBool         flg;
6248214e71cSJoe 
625648c30bcSBarry Smith     PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg));
6268214e71cSJoe     if (flg) {
6278214e71cSJoe       PetscCall(PetscViewerPushFormat(viewer, format));
6288214e71cSJoe       PetscCall(PetscBagView(bag, viewer));
6298214e71cSJoe       PetscCall(PetscViewerFlush(viewer));
6308214e71cSJoe       PetscCall(PetscViewerPopFormat(viewer));
6318214e71cSJoe       PetscCall(PetscViewerDestroy(&viewer));
6328214e71cSJoe     }
6338214e71cSJoe   }
6348214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
6358214e71cSJoe }
6368214e71cSJoe 
6378214e71cSJoe static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
638d71ae5a4SJacob Faibussowitsch {
639b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
6409566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
6419566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
6429566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*dm));
6439566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
644*f1e6e573SMatthew G. Knepley 
645*f1e6e573SMatthew G. Knepley   // Cache the mesh geometry
646*f1e6e573SMatthew G. Knepley   DMField         coordField;
647*f1e6e573SMatthew G. Knepley   IS              cellIS;
648*f1e6e573SMatthew G. Knepley   PetscQuadrature quad;
649*f1e6e573SMatthew G. Knepley   PetscReal      *wt, *pt;
650*f1e6e573SMatthew G. Knepley   PetscInt        cdim, cStart, cEnd;
651*f1e6e573SMatthew G. Knepley 
652*f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateField(*dm, &coordField));
653*f1e6e573SMatthew G. Knepley   PetscCheck(coordField, comm, PETSC_ERR_USER, "DM must have a coordinate field");
654*f1e6e573SMatthew G. Knepley   PetscCall(DMGetCoordinateDim(*dm, &cdim));
655*f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd));
656*f1e6e573SMatthew G. Knepley   PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cellIS));
657*f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad));
658*f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(1, &wt));
659*f1e6e573SMatthew G. Knepley   PetscCall(PetscMalloc1(2, &pt));
660*f1e6e573SMatthew G. Knepley   wt[0] = 1.;
661*f1e6e573SMatthew G. Knepley   pt[0] = -1.;
662*f1e6e573SMatthew G. Knepley   pt[1] = -1.;
663*f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureSetData(quad, cdim, 1, 1, pt, wt));
664*f1e6e573SMatthew G. Knepley   PetscCall(DMFieldCreateFEGeom(coordField, cellIS, quad, PETSC_FALSE, &user->fegeom));
665*f1e6e573SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&quad));
666*f1e6e573SMatthew G. Knepley   PetscCall(ISDestroy(&cellIS));
6673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
668b80bf5b1SJoe Pusztay }
669b80bf5b1SJoe Pusztay 
6708214e71cSJoe 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[])
6718214e71cSJoe {
6728214e71cSJoe   f0[0] = -constants[SIGMA];
6738214e71cSJoe }
6748214e71cSJoe 
675d71ae5a4SJacob 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[])
676d71ae5a4SJacob Faibussowitsch {
677b80bf5b1SJoe Pusztay   PetscInt d;
678ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) f1[d] = u_x[d];
679b80bf5b1SJoe Pusztay }
680b80bf5b1SJoe Pusztay 
6818214e71cSJoe 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[])
682d71ae5a4SJacob Faibussowitsch {
683b80bf5b1SJoe Pusztay   PetscInt d;
684ad540459SPierre Jolivet   for (d = 0; d < dim; ++d) g3[d * dim + d] = 1.0;
685b80bf5b1SJoe Pusztay }
686b80bf5b1SJoe Pusztay 
6878214e71cSJoe static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
688d71ae5a4SJacob Faibussowitsch {
6898214e71cSJoe   *u = 0.0;
6908214e71cSJoe   return PETSC_SUCCESS;
691b80bf5b1SJoe Pusztay }
692b80bf5b1SJoe Pusztay 
693b80bf5b1SJoe Pusztay /*
6948214e71cSJoe    /  I   -grad\ / q \ = /0\
6958214e71cSJoe    \-div    0  / \phi/   \f/
696b80bf5b1SJoe Pusztay */
6978214e71cSJoe 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[])
698d71ae5a4SJacob Faibussowitsch {
6998214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[d] += u[uOff[0] + d];
7008214e71cSJoe }
7018214e71cSJoe 
7028214e71cSJoe 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[])
7038214e71cSJoe {
7048214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f1[d * dim + d] = u[uOff[1]];
7058214e71cSJoe }
7068214e71cSJoe 
7078214e71cSJoe 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[])
7088214e71cSJoe {
7098214e71cSJoe   f0[0] += constants[SIGMA];
7108214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) f0[0] += u_x[uOff_x[0] + d * dim + d];
7118214e71cSJoe }
7128214e71cSJoe 
7138214e71cSJoe /* Boundary residual. Dirichlet boundary for u means u_bdy=p*n */
7148214e71cSJoe 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[])
7158214e71cSJoe {
7168214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g0[d * dim + d] = 1.0;
7178214e71cSJoe }
7188214e71cSJoe 
7198214e71cSJoe 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[])
7208214e71cSJoe {
7218214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g2[d * dim + d] = 1.0;
7228214e71cSJoe }
7238214e71cSJoe 
7248214e71cSJoe 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[])
7258214e71cSJoe {
7268214e71cSJoe   for (PetscInt d = 0; d < dim; ++d) g1[d * dim + d] = 1.0;
7278214e71cSJoe }
7288214e71cSJoe 
7298214e71cSJoe static PetscErrorCode CreateFEM(DM dm, AppCtx *user)
7308214e71cSJoe {
7318214e71cSJoe   PetscFE   fephi, feq;
7328214e71cSJoe   PetscDS   ds;
7338214e71cSJoe   PetscBool simplex;
7348214e71cSJoe   PetscInt  dim;
7358214e71cSJoe 
7368214e71cSJoe   PetscFunctionBeginUser;
7378214e71cSJoe   PetscCall(DMGetDimension(dm, &dim));
7388214e71cSJoe   PetscCall(DMPlexIsSimplex(dm, &simplex));
7398214e71cSJoe   if (user->em == EM_MIXED) {
7408214e71cSJoe     DMLabel        label;
7418214e71cSJoe     const PetscInt id = 1;
7428214e71cSJoe 
7438214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "field_", PETSC_DETERMINE, &feq));
7448214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)feq, "field"));
7458214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "potential_", PETSC_DETERMINE, &fephi));
7468214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
7478214e71cSJoe     PetscCall(PetscFECopyQuadrature(feq, fephi));
7488214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)feq));
7498214e71cSJoe     PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fephi));
7508214e71cSJoe     PetscCall(DMCreateDS(dm));
7518214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
7528214e71cSJoe     PetscCall(PetscFEDestroy(&feq));
7538214e71cSJoe 
7548214e71cSJoe     PetscCall(DMGetLabel(dm, "marker", &label));
7558214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
7568214e71cSJoe 
7578214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, f0_q, f1_q));
7588214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 1, f0_phi_backgroundCharge, NULL));
7598214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_qq, NULL, NULL, NULL));
7608214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_qphi, NULL));
7618214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_phiq, NULL, NULL));
7628214e71cSJoe 
7638214e71cSJoe     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void))zero, NULL, NULL, NULL));
7648214e71cSJoe 
765*f1e6e573SMatthew G. Knepley   } else {
7668214e71cSJoe     MatNullSpace nullsp;
7678214e71cSJoe     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, PETSC_DETERMINE, &fephi));
7688214e71cSJoe     PetscCall(PetscObjectSetName((PetscObject)fephi, "potential"));
7698214e71cSJoe     PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fephi));
7708214e71cSJoe     PetscCall(DMCreateDS(dm));
7718214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
7728214e71cSJoe     PetscCall(PetscDSSetResidual(ds, 0, ion_f0, laplacian_f1));
7738214e71cSJoe     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, laplacian_g3));
7748214e71cSJoe     PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullsp));
7758214e71cSJoe     PetscCall(PetscObjectCompose((PetscObject)fephi, "nullspace", (PetscObject)nullsp));
7768214e71cSJoe     PetscCall(MatNullSpaceDestroy(&nullsp));
7778214e71cSJoe     PetscCall(PetscFEDestroy(&fephi));
7788214e71cSJoe   }
7798214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
7808214e71cSJoe }
7818214e71cSJoe 
7828214e71cSJoe static PetscErrorCode CreatePoisson(DM dm, AppCtx *user)
7838214e71cSJoe {
7848214e71cSJoe   SNES         snes;
7858214e71cSJoe   Mat          J;
7868214e71cSJoe   MatNullSpace nullSpace;
7878214e71cSJoe 
7888214e71cSJoe   PetscFunctionBeginUser;
7898214e71cSJoe   PetscCall(CreateFEM(dm, user));
7908214e71cSJoe   PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes));
7918214e71cSJoe   PetscCall(SNESSetOptionsPrefix(snes, "em_"));
7928214e71cSJoe   PetscCall(SNESSetDM(snes, dm));
7938214e71cSJoe   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, user));
7948214e71cSJoe   PetscCall(SNESSetFromOptions(snes));
7958214e71cSJoe 
7968214e71cSJoe   PetscCall(DMCreateMatrix(dm, &J));
7978214e71cSJoe   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullSpace));
7988214e71cSJoe   PetscCall(MatSetNullSpace(J, nullSpace));
7998214e71cSJoe   PetscCall(MatNullSpaceDestroy(&nullSpace));
8008214e71cSJoe   PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL));
8018214e71cSJoe   PetscCall(MatDestroy(&J));
802*f1e6e573SMatthew G. Knepley   PetscCall(DMCreateMassMatrix(dm, dm, &user->M));
803*f1e6e573SMatthew G. Knepley   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
8048214e71cSJoe   user->snes = snes;
8058214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
8068214e71cSJoe }
8078214e71cSJoe 
8088214e71cSJoe PetscErrorCode PetscPDFPertubedConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
8098214e71cSJoe {
8108214e71cSJoe   p[0] = (1 + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
8118214e71cSJoe   p[1] = (1 + 0.01 * PetscCosReal(0.5 * x[1])) / (2 * PETSC_PI);
8128214e71cSJoe   return PETSC_SUCCESS;
8138214e71cSJoe }
8148214e71cSJoe PetscErrorCode PetscPDFPertubedConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[])
8158214e71cSJoe {
8168214e71cSJoe   p[0] = (1. + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI);
8178214e71cSJoe   return PETSC_SUCCESS;
8188214e71cSJoe }
8198214e71cSJoe 
8208214e71cSJoe PetscErrorCode PetscPDFCosine1D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
8218214e71cSJoe {
8228214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.0;
8238214e71cSJoe   const PetscReal k     = scale ? scale[1] : 1.;
8248214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * x[0]));
8258214e71cSJoe   return PETSC_SUCCESS;
8268214e71cSJoe }
8278214e71cSJoe 
8288214e71cSJoe PetscErrorCode PetscPDFCosine2D(const PetscReal x[], const PetscReal scale[], PetscReal p[])
8298214e71cSJoe {
8308214e71cSJoe   const PetscReal alpha = scale ? scale[0] : 0.;
8318214e71cSJoe   const PetscReal k     = scale ? scale[0] : 1.;
8328214e71cSJoe   p[0]                  = (1 + alpha * PetscCosReal(k * (x[0] + x[1])));
8338214e71cSJoe   return PETSC_SUCCESS;
8348214e71cSJoe }
8358214e71cSJoe 
83684467f86SMatthew G. Knepley static PetscErrorCode CreateVelocityDM(DM sw, DM *vdm)
8378214e71cSJoe {
838*f1e6e573SMatthew G. Knepley   PetscFE        fe;
839*f1e6e573SMatthew G. Knepley   DMPolytopeType ct;
840*f1e6e573SMatthew G. Knepley   PetscInt       dim, cStart;
841*f1e6e573SMatthew G. Knepley   const char    *prefix = "v";
842*f1e6e573SMatthew G. Knepley 
84384467f86SMatthew G. Knepley   PetscFunctionBegin;
84484467f86SMatthew G. Knepley   PetscCall(DMCreate(PETSC_COMM_SELF, vdm));
84584467f86SMatthew G. Knepley   PetscCall(DMSetType(*vdm, DMPLEX));
846*f1e6e573SMatthew G. Knepley   PetscCall(DMPlexSetOptionsPrefix(*vdm, prefix));
84784467f86SMatthew G. Knepley   PetscCall(DMSetFromOptions(*vdm));
84884467f86SMatthew G. Knepley   PetscCall(DMViewFromOptions(*vdm, NULL, "-dm_view"));
849*f1e6e573SMatthew G. Knepley 
850*f1e6e573SMatthew G. Knepley   PetscCall(DMGetDimension(*vdm, &dim));
851*f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(*vdm, 0, &cStart, NULL));
852*f1e6e573SMatthew G. Knepley   PetscCall(DMPlexGetCellType(*vdm, cStart, &ct));
853*f1e6e573SMatthew G. Knepley   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe));
854*f1e6e573SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fe, "distribution"));
855*f1e6e573SMatthew G. Knepley   PetscCall(DMSetField(*vdm, 0, NULL, (PetscObject)fe));
856*f1e6e573SMatthew G. Knepley   PetscCall(DMCreateDS(*vdm));
857*f1e6e573SMatthew G. Knepley   PetscCall(PetscFEDestroy(&fe));
85884467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
8598214e71cSJoe }
8608214e71cSJoe 
86184467f86SMatthew G. Knepley static PetscErrorCode InitializeParticles_Centroid(DM sw, PetscBool force1D)
8628214e71cSJoe {
86384467f86SMatthew G. Knepley   DM_Swarm  *swarm = (DM_Swarm *)sw->data;
86484467f86SMatthew G. Knepley   DM         xdm, vdm;
86584467f86SMatthew G. Knepley   PetscReal  vmin[3], vmax[3];
86684467f86SMatthew G. Knepley   PetscReal *x, *v;
86784467f86SMatthew G. Knepley   PetscInt  *species, *cellid;
86884467f86SMatthew G. Knepley   PetscInt   dim, xcStart, xcEnd, vcStart, vcEnd, Ns, Np, Npc, debug;
8698214e71cSJoe   PetscBool  flg;
87084467f86SMatthew G. Knepley   MPI_Comm   comm;
8718214e71cSJoe 
8728214e71cSJoe   PetscFunctionBegin;
87384467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
87484467f86SMatthew G. Knepley 
87584467f86SMatthew G. Knepley   PetscOptionsBegin(comm, "", "DMSwarm Options", "DMSWARM");
8768214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
8778214e71cSJoe   PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg));
8788214e71cSJoe   if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns));
87984467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_coords", "Debug output level for particle coordinate computations", "InitializeParticles", 0, &swarm->printCoords, NULL, 0));
88084467f86SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_weights", "Debug output level for particle weight computations", "InitializeWeights", 0, &swarm->printWeights, NULL, 0));
8818214e71cSJoe   PetscOptionsEnd();
88284467f86SMatthew G. Knepley   debug = swarm->printCoords;
8838214e71cSJoe 
8848214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
88584467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
88684467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
8878214e71cSJoe 
88884467f86SMatthew G. Knepley   PetscCall(PetscObjectQuery((PetscObject)sw, "__vdm__", (PetscObject *)&vdm));
88984467f86SMatthew G. Knepley   if (!vdm) {
89084467f86SMatthew G. Knepley     PetscCall(CreateVelocityDM(sw, &vdm));
89184467f86SMatthew G. Knepley     PetscCall(PetscObjectCompose((PetscObject)sw, "__vdm__", (PetscObject)vdm));
89284467f86SMatthew G. Knepley     PetscCall(DMDestroy(&vdm));
89384467f86SMatthew G. Knepley     PetscCall(PetscObjectQuery((PetscObject)sw, "__vdm__", (PetscObject *)&vdm));
89484467f86SMatthew G. Knepley   }
89584467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
8968214e71cSJoe 
89784467f86SMatthew G. Knepley   // One particle per centroid on the tensor product grid
89884467f86SMatthew G. Knepley   Npc = (vcEnd - vcStart) * Ns;
89984467f86SMatthew G. Knepley   Np  = (xcEnd - xcStart) * Npc;
9008214e71cSJoe   PetscCall(DMSwarmSetLocalSizes(sw, Np, 0));
90184467f86SMatthew G. Knepley   if (debug) {
90284467f86SMatthew G. Knepley     PetscInt gNp;
90384467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(&Np, &gNp, 1, MPIU_INT, MPIU_SUM, comm));
90484467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "Global Np = %" PetscInt_FMT "\n", gNp));
9058214e71cSJoe   }
9068214e71cSJoe 
90784467f86SMatthew G. Knepley   // Set species and cellid
90884467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
90984467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_cellid, NULL, NULL, (void **)&cellid));
91084467f86SMatthew G. Knepley   for (PetscInt c = 0, p = 0; c < xcEnd - xcStart; ++c) {
91184467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
91284467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q, ++p) {
91384467f86SMatthew G. Knepley         species[p] = s;
91484467f86SMatthew G. Knepley         cellid[p]  = c;
91584467f86SMatthew G. Knepley       }
91684467f86SMatthew G. Knepley     }
91784467f86SMatthew G. Knepley   }
91884467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
91984467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_cellid, NULL, NULL, (void **)&cellid));
92084467f86SMatthew G. Knepley 
92184467f86SMatthew G. Knepley   // Set particle coordinates
9228214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
9238214e71cSJoe   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
9248214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
92584467f86SMatthew G. Knepley   PetscCall(DMGetBoundingBox(vdm, vmin, vmax));
92684467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(xdm));
92784467f86SMatthew G. Knepley   for (PetscInt c = 0; c < xcEnd - xcStart; ++c) {
92884467f86SMatthew G. Knepley     const PetscInt cell = c + xcStart;
9298214e71cSJoe     PetscInt      *pidx, Npc;
9308214e71cSJoe     PetscReal      centroid[3], volume;
9318214e71cSJoe 
9328214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
93384467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFVM(xdm, cell, &volume, centroid, NULL));
93484467f86SMatthew G. Knepley     for (PetscInt s = 0; s < Ns; ++s) {
93584467f86SMatthew G. Knepley       for (PetscInt q = 0; q < Npc / Ns; ++q) {
93684467f86SMatthew G. Knepley         const PetscInt p = pidx[q * Ns + s];
9378214e71cSJoe 
93884467f86SMatthew G. Knepley         for (PetscInt d = 0; d < dim; ++d) {
9398214e71cSJoe           x[p * dim + d] = centroid[d];
94084467f86SMatthew G. Knepley           v[p * dim + d] = vmin[0] + (q + 0.5) * ((vmax[0] - vmin[0]) / (Npc / Ns));
94184467f86SMatthew G. Knepley           if (force1D && d > 0) v[p * dim + d] = 0.;
9428214e71cSJoe         }
9438214e71cSJoe       }
9448214e71cSJoe     }
94584467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
9468214e71cSJoe   }
9478214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
9488214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x));
9498214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
95084467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
95184467f86SMatthew G. Knepley }
95284467f86SMatthew G. Knepley 
95384467f86SMatthew G. Knepley /*
95484467f86SMatthew G. Knepley   InitializeWeights - Compute weight for each local particle
95584467f86SMatthew G. Knepley 
95684467f86SMatthew G. Knepley   Input Parameters:
95784467f86SMatthew G. Knepley + sw          - The `DMSwarm`
95884467f86SMatthew G. Knepley . totalWeight - The sum of all particle weights
95984467f86SMatthew G. Knepley . force1D     - Flag to treat the problem as 1D
96084467f86SMatthew G. Knepley . func        - The PDF for the particle spatial distribution
96184467f86SMatthew G. Knepley - param       - The PDF parameters
96284467f86SMatthew G. Knepley 
96384467f86SMatthew G. Knepley   Notes:
96484467f86SMatthew G. Knepley   The PDF for velocity is assumed to be a Gaussian
96584467f86SMatthew G. Knepley 
96684467f86SMatthew G. Knepley   The particle weights are returned in the `w_q` field of `sw`.
96784467f86SMatthew G. Knepley */
96884467f86SMatthew G. Knepley static PetscErrorCode InitializeWeights(DM sw, PetscReal totalWeight, PetscBool force1D, PetscProbFunc func, const PetscReal param[])
96984467f86SMatthew G. Knepley {
97084467f86SMatthew G. Knepley   DM               xdm, vdm;
97184467f86SMatthew G. Knepley   PetscScalar     *weight;
97284467f86SMatthew G. Knepley   PetscQuadrature  xquad;
97384467f86SMatthew G. Knepley   const PetscReal *xq, *xwq;
97484467f86SMatthew G. Knepley   const PetscInt   order = 5;
97584467f86SMatthew G. Knepley   PetscReal       *xqd   = NULL, xi0[3];
97684467f86SMatthew G. Knepley   PetscReal        xwtot = 0., pwtot = 0.;
97784467f86SMatthew G. Knepley   PetscInt         xNq;
97884467f86SMatthew G. Knepley   PetscInt         dim, Ns, xcStart, xcEnd, vcStart, vcEnd, debug = ((DM_Swarm *)sw->data)->printWeights;
97984467f86SMatthew G. Knepley   MPI_Comm         comm;
98084467f86SMatthew G. Knepley   PetscMPIInt      rank;
98184467f86SMatthew G. Knepley 
98284467f86SMatthew G. Knepley   PetscFunctionBegin;
98384467f86SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)sw, &comm));
98484467f86SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
98584467f86SMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
98684467f86SMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &xdm));
98784467f86SMatthew G. Knepley   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
98884467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd));
98984467f86SMatthew G. Knepley   PetscCall(PetscObjectQuery((PetscObject)sw, "__vdm__", (PetscObject *)&vdm));
99084467f86SMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd));
99184467f86SMatthew G. Knepley 
99284467f86SMatthew G. Knepley   // Setup Quadrature for spatial and velocity weight calculations
99384467f86SMatthew G. Knepley   if (force1D) PetscCall(PetscDTGaussTensorQuadrature(1, 1, order, -1.0, 1.0, &xquad));
99484467f86SMatthew G. Knepley   else PetscCall(PetscDTGaussTensorQuadrature(dim, 1, order, -1.0, 1.0, &xquad));
99584467f86SMatthew G. Knepley   PetscCall(PetscQuadratureGetData(xquad, NULL, NULL, &xNq, &xq, &xwq));
99684467f86SMatthew G. Knepley   if (force1D) {
99784467f86SMatthew G. Knepley     PetscCall(PetscCalloc1(xNq * dim, &xqd));
99884467f86SMatthew G. Knepley     for (PetscInt q = 0; q < xNq; ++q) xqd[q * dim] = xq[q];
99984467f86SMatthew G. Knepley   }
100084467f86SMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) xi0[d] = -1.0;
100184467f86SMatthew G. Knepley 
100284467f86SMatthew G. Knepley   // Integrate the density function to get the weights of particles in each cell
100384467f86SMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(vdm));
100484467f86SMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
100584467f86SMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
100684467f86SMatthew G. Knepley   for (PetscInt c = xcStart; c < xcEnd; ++c) {
100784467f86SMatthew G. Knepley     PetscReal          xv0[3], xJ[9], xinvJ[9], xdetJ, xqr[3], xden, xw = 0.;
100884467f86SMatthew G. Knepley     PetscInt          *pidx, Npc;
100984467f86SMatthew G. Knepley     PetscInt           xNc;
101084467f86SMatthew G. Knepley     const PetscScalar *xarray;
101184467f86SMatthew G. Knepley     PetscScalar       *xcoords = NULL;
101284467f86SMatthew G. Knepley     PetscBool          xisDG;
101384467f86SMatthew G. Knepley 
101484467f86SMatthew G. Knepley     PetscCall(DMPlexGetCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
101584467f86SMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx));
101684467f86SMatthew 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);
101784467f86SMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFEM(xdm, c, NULL, xv0, xJ, xinvJ, &xdetJ));
101884467f86SMatthew G. Knepley     for (PetscInt q = 0; q < xNq; ++q) {
101984467f86SMatthew G. Knepley       // Transform quadrature points from ref space to real space
102084467f86SMatthew G. Knepley       if (force1D) CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xqd[q * dim], xqr);
102184467f86SMatthew G. Knepley       else CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xq[q * dim], xqr);
102284467f86SMatthew G. Knepley       // Get probability density at quad point
102384467f86SMatthew G. Knepley       //   No need to scale xqr since PDF will be periodic
102484467f86SMatthew G. Knepley       PetscCall((*func)(xqr, param, &xden));
102584467f86SMatthew G. Knepley       if (force1D) xdetJ = xJ[0]; // Only want x contribution
102684467f86SMatthew G. Knepley       xw += xden * (xwq[q] * xdetJ);
102784467f86SMatthew G. Knepley     }
102884467f86SMatthew G. Knepley     xwtot += xw;
102984467f86SMatthew G. Knepley     if (debug) {
103084467f86SMatthew G. Knepley       IS              globalOrdering;
103184467f86SMatthew G. Knepley       const PetscInt *ordering;
103284467f86SMatthew G. Knepley 
103384467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellNumbering(xdm, &globalOrdering));
103484467f86SMatthew G. Knepley       PetscCall(ISGetIndices(globalOrdering, &ordering));
103584467f86SMatthew 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[2]), (double)xw));
103684467f86SMatthew G. Knepley       PetscCall(ISRestoreIndices(globalOrdering, &ordering));
103784467f86SMatthew G. Knepley     }
103884467f86SMatthew G. Knepley     // Set weights to be Gaussian in velocity cells
103984467f86SMatthew G. Knepley     for (PetscInt vc = vcStart; vc < vcEnd; ++vc) {
104084467f86SMatthew G. Knepley       const PetscInt     p  = pidx[vc * Ns + 0];
104184467f86SMatthew G. Knepley       PetscReal          vw = 0.;
104284467f86SMatthew G. Knepley       PetscInt           vNc;
104384467f86SMatthew G. Knepley       const PetscScalar *varray;
104484467f86SMatthew G. Knepley       PetscScalar       *vcoords = NULL;
104584467f86SMatthew G. Knepley       PetscBool          visDG;
104684467f86SMatthew G. Knepley 
104784467f86SMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
104884467f86SMatthew G. Knepley       // TODO: Fix 2 stream Ask Joe
104984467f86SMatthew G. Knepley       //   Two stream function from 1/2pi v^2 e^(-v^2/2)
105084467f86SMatthew 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.)));
105184467f86SMatthew G. Knepley       vw = 0.5 * (PetscErfReal(vcoords[1] / PetscSqrtReal(2.)) - PetscErfReal(vcoords[0] / PetscSqrtReal(2.)));
105284467f86SMatthew G. Knepley 
105384467f86SMatthew G. Knepley       weight[p] = totalWeight * vw * xw;
105484467f86SMatthew G. Knepley       pwtot += weight[p];
105584467f86SMatthew G. Knepley       PetscCheck(weight[p] <= 1., PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Particle %" PetscInt_FMT " weight exceeeded 1: %g, %g, %g", p, xw, vw, totalWeight);
105684467f86SMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords));
105784467f86SMatthew G. Knepley       if (debug > 1) PetscCall(PetscPrintf(comm, "particle %" PetscInt_FMT ": %g, vw: %g xw: %g\n", p, weight[p], vw, xw));
105884467f86SMatthew G. Knepley     }
105984467f86SMatthew G. Knepley     PetscCall(DMPlexRestoreCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords));
106084467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx));
106184467f86SMatthew G. Knepley   }
106284467f86SMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
106384467f86SMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
106484467f86SMatthew G. Knepley   PetscCall(PetscQuadratureDestroy(&xquad));
106584467f86SMatthew G. Knepley   if (force1D) PetscCall(PetscFree(xqd));
106684467f86SMatthew G. Knepley 
106784467f86SMatthew G. Knepley   if (debug) {
106884467f86SMatthew G. Knepley     PetscReal wtot[2] = {pwtot, xwtot}, gwtot[2];
106984467f86SMatthew G. Knepley 
107084467f86SMatthew G. Knepley     PetscCall(PetscSynchronizedFlush(comm, NULL));
107184467f86SMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(wtot, gwtot, 2, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
107284467f86SMatthew G. Knepley     PetscCall(PetscPrintf(comm, "particle weight sum = %1.10f cell weight sum = %1.10f\n", (double)gwtot[0], (double)gwtot[1]));
107384467f86SMatthew G. Knepley   }
107484467f86SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
107584467f86SMatthew G. Knepley }
107684467f86SMatthew G. Knepley 
107784467f86SMatthew G. Knepley static PetscErrorCode InitializeParticles_PerturbedWeights(DM sw, AppCtx *user)
107884467f86SMatthew G. Knepley {
107984467f86SMatthew G. Knepley   PetscReal scale[2] = {user->cosine_coefficients[0], user->cosine_coefficients[1]};
108084467f86SMatthew G. Knepley 
108184467f86SMatthew G. Knepley   PetscFunctionBegin;
108284467f86SMatthew G. Knepley   PetscCall(InitializeParticles_Centroid(sw, user->fake_1D));
108384467f86SMatthew G. Knepley   PetscCall(InitializeWeights(sw, user->totalWeight, user->fake_1D, user->fake_1D ? PetscPDFCosine1D : PetscPDFCosine2D, scale));
10848214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
10858214e71cSJoe }
10868214e71cSJoe 
10878214e71cSJoe static PetscErrorCode InitializeConstants(DM sw, AppCtx *user)
10888214e71cSJoe {
10898214e71cSJoe   DM         dm;
10908214e71cSJoe   PetscInt  *species;
10918214e71cSJoe   PetscReal *weight, totalCharge = 0., totalWeight = 0., gmin[3], gmax[3], global_charge, global_weight;
10928214e71cSJoe   PetscInt   Np, dim;
10938214e71cSJoe 
10948214e71cSJoe   PetscFunctionBegin;
10958214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &dm));
10968214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
10978214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
10988214e71cSJoe   PetscCall(DMGetBoundingBox(dm, gmin, gmax));
10998214e71cSJoe   PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight));
11008214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
11018214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
11028214e71cSJoe     totalWeight += weight[p];
11038214e71cSJoe     totalCharge += user->charges[species[p]] * weight[p];
11048214e71cSJoe   }
11058214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight));
11068214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
11078214e71cSJoe   {
11088214e71cSJoe     Parameter *param;
11098214e71cSJoe     PetscReal  Area;
11108214e71cSJoe 
11118214e71cSJoe     PetscCall(PetscBagGetData(user->bag, (void **)&param));
11128214e71cSJoe     switch (dim) {
11138214e71cSJoe     case 1:
11148214e71cSJoe       Area = (gmax[0] - gmin[0]);
11158214e71cSJoe       break;
11168214e71cSJoe     case 2:
11178214e71cSJoe       if (user->fake_1D) {
11188214e71cSJoe         Area = (gmax[0] - gmin[0]);
11198214e71cSJoe       } else {
11208214e71cSJoe         Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]);
11218214e71cSJoe       }
11228214e71cSJoe       break;
11238214e71cSJoe     case 3:
11248214e71cSJoe       Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]) * (gmax[2] - gmin[2]);
11258214e71cSJoe       break;
11268214e71cSJoe     default:
11278214e71cSJoe       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", dim);
11288214e71cSJoe     }
1129462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalWeight, &global_weight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
1130462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&totalCharge, &global_charge, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
11318214e71cSJoe     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));
11328214e71cSJoe     param->sigma = PetscAbsReal(global_charge / (Area));
11338214e71cSJoe 
11348214e71cSJoe     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "sigma: %g\n", (double)param->sigma));
11358214e71cSJoe     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,
11368214e71cSJoe                           (double)param->vlasovNumber));
11378214e71cSJoe   }
11388214e71cSJoe   /* Setup Constants */
11398214e71cSJoe   {
11408214e71cSJoe     PetscDS    ds;
11418214e71cSJoe     Parameter *param;
11428214e71cSJoe     PetscCall(PetscBagGetData(user->bag, (void **)&param));
11438214e71cSJoe     PetscScalar constants[NUM_CONSTANTS];
11448214e71cSJoe     constants[SIGMA]   = param->sigma;
11458214e71cSJoe     constants[V0]      = param->v0;
11468214e71cSJoe     constants[T0]      = param->t0;
11478214e71cSJoe     constants[X0]      = param->x0;
11488214e71cSJoe     constants[M0]      = param->m0;
11498214e71cSJoe     constants[Q0]      = param->q0;
11508214e71cSJoe     constants[PHI0]    = param->phi0;
11518214e71cSJoe     constants[POISSON] = param->poissonNumber;
11528214e71cSJoe     constants[VLASOV]  = param->vlasovNumber;
11538214e71cSJoe     PetscCall(DMGetDS(dm, &ds));
11548214e71cSJoe     PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants));
11558214e71cSJoe   }
11568214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
11578214e71cSJoe }
11588214e71cSJoe 
11598214e71cSJoe static PetscErrorCode InitializeVelocities_Fake1D(DM sw, AppCtx *user)
11608214e71cSJoe {
11618214e71cSJoe   DM         dm;
11628214e71cSJoe   PetscReal *v;
11638214e71cSJoe   PetscInt  *species, cStart, cEnd;
11648214e71cSJoe   PetscInt   dim, Np;
11658214e71cSJoe 
11668214e71cSJoe   PetscFunctionBegin;
11678214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
11688214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
11698214e71cSJoe   PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v));
11708214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
11718214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &dm));
11728214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
11738214e71cSJoe   PetscRandom rnd;
11748214e71cSJoe   PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)sw), &rnd));
11758214e71cSJoe   PetscCall(PetscRandomSetInterval(rnd, 0, 1.));
11768214e71cSJoe   PetscCall(PetscRandomSetFromOptions(rnd));
11778214e71cSJoe 
11788214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
11798214e71cSJoe     PetscReal a[3] = {0., 0., 0.}, vel[3] = {0., 0., 0.};
11808214e71cSJoe 
11818214e71cSJoe     PetscCall(PetscRandomGetValueReal(rnd, &a[0]));
11828214e71cSJoe     if (user->perturbed_weights) {
11838214e71cSJoe       PetscCall(PetscPDFSampleConstant1D(a, NULL, vel));
11848214e71cSJoe     } else {
11858214e71cSJoe       PetscCall(PetscPDFSampleGaussian1D(a, NULL, vel));
11868214e71cSJoe     }
11878214e71cSJoe     v[p * dim] = vel[0];
11888214e71cSJoe   }
11898214e71cSJoe   PetscCall(PetscRandomDestroy(&rnd));
11908214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v));
11918214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
11928214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
11938214e71cSJoe }
11948214e71cSJoe 
11958214e71cSJoe static PetscErrorCode CreateSwarm(DM dm, AppCtx *user, DM *sw)
11968214e71cSJoe {
11978214e71cSJoe   PetscReal v0[2] = {1., 0.};
11988214e71cSJoe   PetscInt  dim;
1199b80bf5b1SJoe Pusztay 
1200b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
12019566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
12029566063dSJacob Faibussowitsch   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw));
12039566063dSJacob Faibussowitsch   PetscCall(DMSetType(*sw, DMSWARM));
12049566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*sw, dim));
12059566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC));
12069566063dSJacob Faibussowitsch   PetscCall(DMSwarmSetCellDM(*sw, dm));
12079566063dSJacob Faibussowitsch   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR));
12088214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL));
12098214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "species", 1, PETSC_INT));
12108214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "initCoordinates", dim, PETSC_REAL));
12118214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "initVelocity", dim, PETSC_REAL));
12128214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "E_field", dim, PETSC_REAL));
12138214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "potential", dim, PETSC_REAL));
12148214e71cSJoe   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "charges", dim, PETSC_REAL));
12159566063dSJacob Faibussowitsch   PetscCall(DMSwarmFinalizeFieldRegister(*sw));
12168214e71cSJoe   PetscCall(DMSetApplicationContext(*sw, user));
12179566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*sw));
12188214e71cSJoe   user->swarm = *sw;
12198214e71cSJoe   if (user->perturbed_weights) {
12208214e71cSJoe     PetscCall(InitializeParticles_PerturbedWeights(*sw, user));
1221b80bf5b1SJoe Pusztay   } else {
12228214e71cSJoe     PetscCall(DMSwarmComputeLocalSizeFromOptions(*sw));
12238214e71cSJoe     PetscCall(DMSwarmInitializeCoordinates(*sw));
12248214e71cSJoe     if (user->fake_1D) {
12258214e71cSJoe       PetscCall(InitializeVelocities_Fake1D(*sw, user));
12269371c9d4SSatish Balay     } else {
12278214e71cSJoe       PetscCall(DMSwarmInitializeVelocitiesFromOptions(*sw, v0));
1228b80bf5b1SJoe Pusztay     }
1229b80bf5b1SJoe Pusztay   }
12309566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles"));
12319566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view"));
12328214e71cSJoe   {
12338214e71cSJoe     Vec gc, gc0, gv, gv0;
12348214e71cSJoe 
12358214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, DMSwarmPICField_coor, &gc));
12368214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, "initCoordinates", &gc0));
12378214e71cSJoe     PetscCall(VecCopy(gc, gc0));
12388214e71cSJoe     PetscCall(VecViewFromOptions(gc, NULL, "-ic_x_view"));
12398214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, DMSwarmPICField_coor, &gc));
12408214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, "initCoordinates", &gc0));
12418214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, "velocity", &gv));
12428214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, "initVelocity", &gv0));
12438214e71cSJoe     PetscCall(VecCopy(gv, gv0));
12448214e71cSJoe     PetscCall(VecViewFromOptions(gv, NULL, "-ic_v_view"));
12458214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, "velocity", &gv));
12468214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, "initVelocity", &gv0));
12478214e71cSJoe   }
124884467f86SMatthew G. Knepley   {
124984467f86SMatthew G. Knepley     const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"};
125084467f86SMatthew G. Knepley 
1251*f1e6e573SMatthew G. Knepley     PetscCall(DMSwarmVectorDefineFields(*sw, 2, fieldnames));
125284467f86SMatthew G. Knepley   }
12533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1254b80bf5b1SJoe Pusztay }
1255b80bf5b1SJoe Pusztay 
12568214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Coulomb(SNES snes, DM sw, PetscReal E[])
1257d71ae5a4SJacob Faibussowitsch {
12588214e71cSJoe   AppCtx     *user;
12598214e71cSJoe   PetscReal  *coords;
12608214e71cSJoe   PetscInt   *species, dim, Np, Ns;
12618214e71cSJoe   PetscMPIInt size;
12628214e71cSJoe 
12638214e71cSJoe   PetscFunctionBegin;
12648214e71cSJoe   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)snes), &size));
12658214e71cSJoe   PetscCheck(size == 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Coulomb code only works in serial");
12668214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
12678214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
12688214e71cSJoe   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
12698214e71cSJoe   PetscCall(DMGetApplicationContext(sw, (void *)&user));
12708214e71cSJoe 
12718214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
12728214e71cSJoe   PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
12738214e71cSJoe   for (PetscInt p = 0; p < Np; ++p) {
12748214e71cSJoe     PetscReal *pcoord = &coords[p * dim];
12758214e71cSJoe     PetscReal  pE[3]  = {0., 0., 0.};
12768214e71cSJoe 
12778214e71cSJoe     /* Calculate field at particle p due to particle q */
12788214e71cSJoe     for (PetscInt q = 0; q < Np; ++q) {
12798214e71cSJoe       PetscReal *qcoord = &coords[q * dim];
12808214e71cSJoe       PetscReal  rpq[3], r, r3, q_q;
12818214e71cSJoe 
12828214e71cSJoe       if (p == q) continue;
12838214e71cSJoe       q_q = user->charges[species[q]] * 1.;
12848214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) rpq[d] = pcoord[d] - qcoord[d];
12858214e71cSJoe       r = DMPlex_NormD_Internal(dim, rpq);
12868214e71cSJoe       if (r < PETSC_SQRT_MACHINE_EPSILON) continue;
12878214e71cSJoe       r3 = PetscPowRealInt(r, 3);
12888214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pE[d] += q_q * rpq[d] / r3;
12898214e71cSJoe     }
12908214e71cSJoe     for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = pE[d];
12918214e71cSJoe   }
12928214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
12938214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
12948214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
12958214e71cSJoe }
12968214e71cSJoe 
12978214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Primal(SNES snes, DM sw, PetscReal E[])
12988214e71cSJoe {
1299b80bf5b1SJoe Pusztay   DM         dm;
13008214e71cSJoe   AppCtx    *user;
13018214e71cSJoe   PetscDS    ds;
13028214e71cSJoe   PetscFE    fe;
1303*f1e6e573SMatthew G. Knepley   Mat        M_p;
13048214e71cSJoe   Vec        phi, locPhi, rho, f;
13058214e71cSJoe   PetscReal *coords;
13068214e71cSJoe   PetscInt   dim, cStart, cEnd, Np;
13078214e71cSJoe 
13088214e71cSJoe   PetscFunctionBegin;
130984467f86SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, (void *)&user));
131084467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
13118214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
13128214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
13138214e71cSJoe 
13148214e71cSJoe   KSP          ksp;
13158214e71cSJoe   Vec          rho0;
131684467f86SMatthew G. Knepley   const char **oldFields;
131784467f86SMatthew G. Knepley   PetscInt     Nf;
131884467f86SMatthew G. Knepley   const char **tmp;
13198214e71cSJoe 
13208214e71cSJoe   /* Create the charges rho */
13218214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
132284467f86SMatthew G. Knepley   PetscCall(DMSwarmVectorGetField(sw, &Nf, &tmp));
132384467f86SMatthew G. Knepley   PetscCall(PetscMalloc1(Nf, &oldFields));
132484467f86SMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscStrallocpy(tmp[f], (char **)&oldFields[f]));
1325*f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmVectorDefineField(sw, "w_q"));
13268214e71cSJoe   PetscCall(DMCreateMassMatrix(sw, dm, &M_p));
1327*f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmVectorDefineFields(sw, Nf, oldFields));
132884467f86SMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscFree(oldFields[f]));
132984467f86SMatthew G. Knepley   PetscCall(PetscFree(oldFields));
13308214e71cSJoe 
13318214e71cSJoe   PetscCall(DMGetGlobalVector(dm, &rho0));
13328214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)rho0, "Charge density (rho0) from Primal Compute"));
13338214e71cSJoe   PetscCall(DMGetGlobalVector(dm, &rho));
13348214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)rho, "rho"));
13358214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
13368214e71cSJoe 
13378214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
13388214e71cSJoe   PetscCall(MatMultTranspose(M_p, f, rho));
13398214e71cSJoe   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
1340*f1e6e573SMatthew G. Knepley   PetscCall(MatViewFromOptions(user->M, NULL, "-m_view"));
13418214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
13428214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
13438214e71cSJoe 
13448214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
13458214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj_"));
1346*f1e6e573SMatthew G. Knepley   PetscCall(KSPSetOperators(ksp, user->M, user->M));
13478214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
13488214e71cSJoe   PetscCall(KSPSolve(ksp, rho, rho0));
13498214e71cSJoe   PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view"));
13508214e71cSJoe 
13518214e71cSJoe   PetscInt           rhosize;
13528214e71cSJoe   PetscReal         *charges;
13538214e71cSJoe   const PetscScalar *rho_vals;
13548214e71cSJoe   PetscCall(DMSwarmGetField(sw, "charges", NULL, NULL, (void **)&charges));
13558214e71cSJoe   PetscCall(VecGetLocalSize(rho0, &rhosize));
13568214e71cSJoe   PetscCall(VecGetArrayRead(rho0, &rho_vals));
13578214e71cSJoe   for (PetscInt c = 0; c < rhosize; ++c) charges[c] = rho_vals[c];
13588214e71cSJoe   PetscCall(VecRestoreArrayRead(rho0, &rho_vals));
13598214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "charges", NULL, NULL, (void **)&charges));
13608214e71cSJoe 
13618214e71cSJoe   PetscCall(VecScale(rho, -1.0));
13628214e71cSJoe 
13638214e71cSJoe   PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view"));
13648214e71cSJoe   PetscCall(VecViewFromOptions(rho, NULL, "-rho_view"));
13658214e71cSJoe   PetscCall(DMRestoreGlobalVector(dm, &rho0));
13668214e71cSJoe   PetscCall(KSPDestroy(&ksp));
13678214e71cSJoe   PetscCall(MatDestroy(&M_p));
13688214e71cSJoe 
13698214e71cSJoe   PetscCall(DMGetGlobalVector(dm, &phi));
13708214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)phi, "potential"));
13718214e71cSJoe   PetscCall(VecSet(phi, 0.0));
13728214e71cSJoe   PetscCall(SNESSolve(snes, rho, phi));
13738214e71cSJoe   PetscCall(DMRestoreGlobalVector(dm, &rho));
13748214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
13758214e71cSJoe 
13768214e71cSJoe   PetscInt           phisize;
13778214e71cSJoe   PetscReal         *pot;
13788214e71cSJoe   const PetscScalar *phi_vals;
13798214e71cSJoe   PetscCall(DMSwarmGetField(sw, "potential", NULL, NULL, (void **)&pot));
13808214e71cSJoe   PetscCall(VecGetLocalSize(phi, &phisize));
13818214e71cSJoe   PetscCall(VecGetArrayRead(phi, &phi_vals));
13828214e71cSJoe   for (PetscInt c = 0; c < phisize; ++c) pot[c] = phi_vals[c];
13838214e71cSJoe   PetscCall(VecRestoreArrayRead(phi, &phi_vals));
13848214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "potential", NULL, NULL, (void **)&pot));
13858214e71cSJoe 
13868214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
13878214e71cSJoe   PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi));
13888214e71cSJoe   PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi));
13898214e71cSJoe   PetscCall(DMRestoreGlobalVector(dm, &phi));
139084467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
13918214e71cSJoe 
13928214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
13938214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
13948214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
13958214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
13968214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
13978214e71cSJoe 
139884467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
1399*f1e6e573SMatthew G. Knepley   PetscFEGeom *chunkgeom = NULL;
14008214e71cSJoe   for (PetscInt c = cStart; c < cEnd; ++c) {
14018214e71cSJoe     PetscTabulation tab;
14028214e71cSJoe     PetscScalar    *clPhi = NULL;
14038214e71cSJoe     PetscReal      *pcoord, *refcoord;
14048214e71cSJoe     PetscInt       *points;
14058214e71cSJoe     PetscInt        Ncp;
14068214e71cSJoe 
14078214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
14088214e71cSJoe     PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord));
14098214e71cSJoe     PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord));
14108214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
14118214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1412*f1e6e573SMatthew G. Knepley     {
1413*f1e6e573SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1414*f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1415*f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1416*f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1417*f1e6e573SMatthew G. Knepley       }
1418*f1e6e573SMatthew G. Knepley     }
14198214e71cSJoe     PetscCall(PetscFECreateTabulation(fe, 1, Ncp, refcoord, 1, &tab));
14208214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
14218214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
14228214e71cSJoe       const PetscReal *basisDer = tab->T[1];
14238214e71cSJoe       const PetscInt   p        = points[cp];
14248214e71cSJoe 
14258214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1426*f1e6e573SMatthew G. Knepley       PetscCall(PetscFEFreeInterpolateGradient_Static(fe, basisDer, clPhi, dim, chunkgeom->invJ, NULL, cp, &E[p * dim]));
14278214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) {
14288214e71cSJoe         E[p * dim + d] *= -1.0;
14298214e71cSJoe         if (user->fake_1D && d > 0) E[p * dim + d] = 0;
14308214e71cSJoe       }
14318214e71cSJoe     }
14328214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
1433*f1e6e573SMatthew G. Knepley     PetscCall(PetscTabulationDestroy(&tab));
14348214e71cSJoe     PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord));
14358214e71cSJoe     PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord));
143684467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
14378214e71cSJoe   }
14388214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
14398214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
14408214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1441*f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
144284467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
14438214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
14448214e71cSJoe }
14458214e71cSJoe 
14468214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Mixed(SNES snes, DM sw, PetscReal E[])
14478214e71cSJoe {
14488214e71cSJoe   AppCtx         *user;
14498214e71cSJoe   DM              dm, potential_dm;
14508214e71cSJoe   KSP             ksp;
14518214e71cSJoe   IS              potential_IS;
14528214e71cSJoe   PetscDS         ds;
14538214e71cSJoe   PetscFE         fe;
14548214e71cSJoe   Mat             M_p, M;
14558214e71cSJoe   Vec             phi, locPhi, rho, f, temp_rho, rho0;
14568214e71cSJoe   PetscQuadrature q;
14578214e71cSJoe   PetscReal      *coords, *pot;
145884467f86SMatthew G. Knepley   PetscInt        dim, cStart, cEnd, Np, pot_field = 1;
145984467f86SMatthew G. Knepley   const char    **oldFields;
146084467f86SMatthew G. Knepley   PetscInt        Nf;
146184467f86SMatthew G. Knepley   const char    **tmp;
14628214e71cSJoe 
14638214e71cSJoe   PetscFunctionBegin;
146484467f86SMatthew G. Knepley   PetscCall(DMGetApplicationContext(sw, &user));
146584467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0));
14668214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
14678214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
14688214e71cSJoe 
14698214e71cSJoe   /* Create the charges rho */
14708214e71cSJoe   PetscCall(SNESGetDM(snes, &dm));
14718214e71cSJoe   PetscCall(DMGetGlobalVector(dm, &rho));
14728214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)rho, "rho"));
14738214e71cSJoe 
147484467f86SMatthew G. Knepley   PetscCall(DMCreateSubDM(dm, 1, &pot_field, &potential_IS, &potential_dm));
14758214e71cSJoe 
147684467f86SMatthew G. Knepley   PetscCall(DMSwarmVectorGetField(sw, &Nf, &tmp));
147784467f86SMatthew G. Knepley   PetscCall(PetscMalloc1(Nf, &oldFields));
147884467f86SMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscStrallocpy(tmp[f], (char **)&oldFields[f]));
1479*f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmVectorDefineField(sw, "w_q"));
14808214e71cSJoe   PetscCall(DMCreateMassMatrix(sw, potential_dm, &M_p));
1481*f1e6e573SMatthew G. Knepley   PetscCall(DMSwarmVectorDefineFields(sw, Nf, oldFields));
148284467f86SMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscFree(oldFields[f]));
148384467f86SMatthew G. Knepley   PetscCall(PetscFree(oldFields));
14848214e71cSJoe 
14858214e71cSJoe   PetscCall(DMCreateMassMatrix(potential_dm, potential_dm, &M));
14868214e71cSJoe   PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view"));
14878214e71cSJoe   PetscCall(MatViewFromOptions(M, NULL, "-m_view"));
14888214e71cSJoe   PetscCall(DMGetGlobalVector(potential_dm, &temp_rho));
14898214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)temp_rho, "Mf"));
14908214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f));
14918214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)f, "particle weight"));
14928214e71cSJoe   PetscCall(VecViewFromOptions(f, NULL, "-weights_view"));
14938214e71cSJoe   PetscCall(MatMultTranspose(M_p, f, temp_rho));
14948214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f));
14958214e71cSJoe   PetscCall(DMGetGlobalVector(potential_dm, &rho0));
14968214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)rho0, "Charge density (rho0) from Mixed Compute"));
14978214e71cSJoe 
14988214e71cSJoe   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
14998214e71cSJoe   PetscCall(KSPSetOptionsPrefix(ksp, "em_proj"));
15008214e71cSJoe   PetscCall(KSPSetOperators(ksp, M, M));
15018214e71cSJoe   PetscCall(KSPSetFromOptions(ksp));
15028214e71cSJoe   PetscCall(KSPSolve(ksp, temp_rho, rho0));
15038214e71cSJoe   PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view"));
15048214e71cSJoe 
15058214e71cSJoe   PetscInt           rhosize;
15068214e71cSJoe   PetscReal         *charges;
15078214e71cSJoe   const PetscScalar *rho_vals;
15088214e71cSJoe   Parameter         *param;
15098214e71cSJoe   PetscCall(PetscBagGetData(user->bag, (void **)&param));
15108214e71cSJoe   PetscCall(DMSwarmGetField(sw, "charges", NULL, NULL, (void **)&charges));
15118214e71cSJoe   PetscCall(VecGetLocalSize(rho0, &rhosize));
15128214e71cSJoe 
15138214e71cSJoe   /* Integral over reference element is size 1.  Reference element area is 4.  Scale rho0 by 1/4 because the basis function is 1/4 */
15148214e71cSJoe   PetscCall(VecScale(rho0, 0.25));
15158214e71cSJoe   PetscCall(VecGetArrayRead(rho0, &rho_vals));
15168214e71cSJoe   for (PetscInt c = 0; c < rhosize; ++c) charges[c] = rho_vals[c];
15178214e71cSJoe   PetscCall(VecRestoreArrayRead(rho0, &rho_vals));
15188214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "charges", NULL, NULL, (void **)&charges));
15198214e71cSJoe 
15208214e71cSJoe   PetscCall(VecISCopy(rho, potential_IS, SCATTER_FORWARD, temp_rho));
15218214e71cSJoe   PetscCall(VecScale(rho, 0.25));
15228214e71cSJoe   PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view"));
15238214e71cSJoe   PetscCall(VecViewFromOptions(temp_rho, NULL, "-temprho_view"));
15248214e71cSJoe   PetscCall(VecViewFromOptions(rho, NULL, "-rho_view"));
15258214e71cSJoe   PetscCall(DMRestoreGlobalVector(potential_dm, &temp_rho));
15268214e71cSJoe   PetscCall(DMRestoreGlobalVector(potential_dm, &rho0));
15278214e71cSJoe 
15288214e71cSJoe   PetscCall(MatDestroy(&M_p));
15298214e71cSJoe   PetscCall(MatDestroy(&M));
15308214e71cSJoe   PetscCall(KSPDestroy(&ksp));
15318214e71cSJoe   PetscCall(DMDestroy(&potential_dm));
15328214e71cSJoe   PetscCall(ISDestroy(&potential_IS));
15338214e71cSJoe 
15348214e71cSJoe   PetscCall(DMGetGlobalVector(dm, &phi));
15358214e71cSJoe   PetscCall(PetscObjectSetName((PetscObject)phi, "potential"));
15368214e71cSJoe   PetscCall(VecSet(phi, 0.0));
15378214e71cSJoe   PetscCall(SNESSolve(snes, rho, phi));
15388214e71cSJoe   PetscCall(DMRestoreGlobalVector(dm, &rho));
15398214e71cSJoe 
15408214e71cSJoe   PetscInt           phisize;
15418214e71cSJoe   const PetscScalar *phi_vals;
15428214e71cSJoe   PetscCall(DMSwarmGetField(sw, "potential", NULL, NULL, (void **)&pot));
15438214e71cSJoe   PetscCall(VecGetLocalSize(phi, &phisize));
15448214e71cSJoe   PetscCall(VecViewFromOptions(phi, NULL, "-phi_view"));
15458214e71cSJoe   PetscCall(VecGetArrayRead(phi, &phi_vals));
15468214e71cSJoe   for (PetscInt c = 0; c < phisize; ++c) pot[c] = phi_vals[c];
15478214e71cSJoe   PetscCall(VecRestoreArrayRead(phi, &phi_vals));
15488214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "potential", NULL, NULL, (void **)&pot));
15498214e71cSJoe 
15508214e71cSJoe   PetscCall(DMGetLocalVector(dm, &locPhi));
15518214e71cSJoe   PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi));
15528214e71cSJoe   PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi));
15538214e71cSJoe   PetscCall(DMRestoreGlobalVector(dm, &phi));
155484467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0));
15558214e71cSJoe 
155684467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0));
15578214e71cSJoe   PetscCall(DMGetDS(dm, &ds));
15588214e71cSJoe   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
15598214e71cSJoe   PetscCall(DMSwarmSortGetAccess(sw));
15608214e71cSJoe   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
15618214e71cSJoe   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
15628214e71cSJoe   PetscCall(PetscFEGetQuadrature(fe, &q));
1563*f1e6e573SMatthew G. Knepley   PetscFEGeom *chunkgeom = NULL;
15648214e71cSJoe   for (PetscInt c = cStart; c < cEnd; ++c) {
15658214e71cSJoe     PetscTabulation tab;
15668214e71cSJoe     PetscScalar    *clPhi = NULL;
15678214e71cSJoe     PetscReal      *pcoord, *refcoord;
15688214e71cSJoe     PetscInt       *points;
15698214e71cSJoe     PetscInt        Ncp;
15708214e71cSJoe 
15718214e71cSJoe     PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points));
15728214e71cSJoe     PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord));
15738214e71cSJoe     PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord));
15748214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp)
15758214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d];
1576*f1e6e573SMatthew G. Knepley     {
1577*f1e6e573SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom));
1578*f1e6e573SMatthew G. Knepley       for (PetscInt i = 0; i < Ncp; ++i) {
1579*f1e6e573SMatthew G. Knepley         // Apply the inverse affine transformation for each point
1580*f1e6e573SMatthew G. Knepley         const PetscReal x0[3] = {-1., -1., -1.};
1581*f1e6e573SMatthew G. Knepley         CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]);
1582*f1e6e573SMatthew G. Knepley       }
1583*f1e6e573SMatthew G. Knepley     }
15848214e71cSJoe     PetscCall(PetscFECreateTabulation(fe, 1, Ncp, refcoord, 1, &tab));
15858214e71cSJoe     PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi));
15868214e71cSJoe 
15878214e71cSJoe     for (PetscInt cp = 0; cp < Ncp; ++cp) {
15888214e71cSJoe       const PetscInt p = points[cp];
15898214e71cSJoe 
15908214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.;
1591*f1e6e573SMatthew G. Knepley       PetscCall(PetscFEInterpolateAtPoints_Static(fe, tab, clPhi, chunkgeom, cp, &E[p * dim]));
1592*f1e6e573SMatthew G. Knepley       PetscCall(PetscFEPushforward(fe, chunkgeom, 1, &E[p * dim]));
15938214e71cSJoe       for (PetscInt d = 0; d < dim; ++d) {
15948214e71cSJoe         E[p * dim + d] *= -2.0;
15958214e71cSJoe         if (user->fake_1D && d > 0) E[p * dim + d] = 0;
15968214e71cSJoe       }
15978214e71cSJoe     }
15988214e71cSJoe     PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi));
1599*f1e6e573SMatthew G. Knepley     PetscCall(PetscTabulationDestroy(&tab));
16008214e71cSJoe     PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord));
16018214e71cSJoe     PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord));
160284467f86SMatthew G. Knepley     PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points));
16038214e71cSJoe   }
16048214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
16058214e71cSJoe   PetscCall(DMSwarmSortRestoreAccess(sw));
16068214e71cSJoe   PetscCall(DMRestoreLocalVector(dm, &locPhi));
1607*f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom));
160884467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0));
16098214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16108214e71cSJoe }
16118214e71cSJoe 
16128214e71cSJoe static PetscErrorCode ComputeFieldAtParticles(SNES snes, DM sw, PetscReal E[])
16138214e71cSJoe {
16148214e71cSJoe   AppCtx  *ctx;
16158214e71cSJoe   PetscInt dim, Np;
16168214e71cSJoe 
16178214e71cSJoe   PetscFunctionBegin;
16188214e71cSJoe   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
16198214e71cSJoe   PetscValidHeaderSpecific(sw, DM_CLASSID, 2);
16208214e71cSJoe   PetscAssertPointer(E, 3);
16218214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16228214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
16238214e71cSJoe   PetscCall(DMGetApplicationContext(sw, &ctx));
16248214e71cSJoe   PetscCall(PetscArrayzero(E, Np * dim));
16258214e71cSJoe 
16268214e71cSJoe   switch (ctx->em) {
16278214e71cSJoe   case EM_PRIMAL:
16288214e71cSJoe     PetscCall(ComputeFieldAtParticles_Primal(snes, sw, E));
16298214e71cSJoe     break;
16308214e71cSJoe   case EM_COULOMB:
16318214e71cSJoe     PetscCall(ComputeFieldAtParticles_Coulomb(snes, sw, E));
16328214e71cSJoe     break;
16338214e71cSJoe   case EM_MIXED:
16348214e71cSJoe     PetscCall(ComputeFieldAtParticles_Mixed(snes, sw, E));
16358214e71cSJoe     break;
16368214e71cSJoe   case EM_NONE:
16378214e71cSJoe     break;
16388214e71cSJoe   default:
16398214e71cSJoe     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No solver for electrostatic model %s", EMTypes[ctx->em]);
16408214e71cSJoe   }
16418214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16428214e71cSJoe }
16438214e71cSJoe 
16448214e71cSJoe static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec G, void *ctx)
16458214e71cSJoe {
16468214e71cSJoe   DM                 sw;
16478214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
16488214e71cSJoe   const PetscReal   *coords, *vel;
16498214e71cSJoe   const PetscScalar *u;
16508214e71cSJoe   PetscScalar       *g;
16518214e71cSJoe   PetscReal         *E, m_p = 1., q_p = -1.;
16528214e71cSJoe   PetscInt           dim, d, Np, p;
1653b80bf5b1SJoe Pusztay 
1654b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
16558214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
16568214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16578214e71cSJoe   PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords));
16588214e71cSJoe   PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel));
16598214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
16608214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
16618214e71cSJoe   PetscCall(VecGetArrayRead(U, &u));
16628214e71cSJoe   PetscCall(VecGetArray(G, &g));
16638214e71cSJoe 
16648214e71cSJoe   PetscCall(ComputeFieldAtParticles(snes, sw, E));
16658214e71cSJoe 
16668214e71cSJoe   Np /= 2 * dim;
16678214e71cSJoe   for (p = 0; p < Np; ++p) {
16688214e71cSJoe     for (d = 0; d < dim; ++d) {
16698214e71cSJoe       g[(p * 2 + 0) * dim + d] = u[(p * 2 + 1) * dim + d];
16708214e71cSJoe       g[(p * 2 + 1) * dim + d] = q_p * E[p * dim + d] / m_p;
16718214e71cSJoe     }
16728214e71cSJoe   }
16738214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords));
16748214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel));
16758214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
16768214e71cSJoe   PetscCall(VecRestoreArrayRead(U, &u));
16778214e71cSJoe   PetscCall(VecRestoreArray(G, &g));
16788214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
16798214e71cSJoe }
16808214e71cSJoe 
16818214e71cSJoe /* J_{ij} = dF_i/dx_j
16828214e71cSJoe    J_p = (  0   1)
16838214e71cSJoe          (-w^2  0)
16848214e71cSJoe    TODO Now there is another term with w^2 from the electric field. I think we will need to invert the operator.
16858214e71cSJoe         Perhaps we can approximate the Jacobian using only the cellwise P-P gradient from Coulomb
16868214e71cSJoe */
16878214e71cSJoe static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat P, void *ctx)
16888214e71cSJoe {
16898214e71cSJoe   DM               sw;
16908214e71cSJoe   const PetscReal *coords, *vel;
16918214e71cSJoe   PetscInt         dim, d, Np, p, rStart;
16928214e71cSJoe 
16938214e71cSJoe   PetscFunctionBeginUser;
16948214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
16958214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
16968214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
16978214e71cSJoe   PetscCall(MatGetOwnershipRange(J, &rStart, NULL));
16988214e71cSJoe   PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords));
16998214e71cSJoe   PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel));
17008214e71cSJoe   Np /= 2 * dim;
17018214e71cSJoe   for (p = 0; p < Np; ++p) {
17028214e71cSJoe     const PetscReal x0      = coords[p * dim + 0];
17038214e71cSJoe     const PetscReal vy0     = vel[p * dim + 1];
17048214e71cSJoe     const PetscReal omega   = vy0 / x0;
17058214e71cSJoe     PetscScalar     vals[4] = {0., 1., -PetscSqr(omega), 0.};
17068214e71cSJoe 
17078214e71cSJoe     for (d = 0; d < dim; ++d) {
17088214e71cSJoe       const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart};
17098214e71cSJoe       PetscCall(MatSetValues(J, 2, rows, 2, rows, vals, INSERT_VALUES));
17108214e71cSJoe     }
17118214e71cSJoe   }
17128214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords));
17138214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel));
17148214e71cSJoe   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
17158214e71cSJoe   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
17168214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
17178214e71cSJoe }
17188214e71cSJoe 
17198214e71cSJoe static PetscErrorCode RHSFunctionX(TS ts, PetscReal t, Vec V, Vec Xres, void *ctx)
17208214e71cSJoe {
17218214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
17228214e71cSJoe   DM                 sw;
17238214e71cSJoe   const PetscScalar *v;
17248214e71cSJoe   PetscScalar       *xres;
17258214e71cSJoe   PetscInt           Np, p, d, dim;
17268214e71cSJoe 
17278214e71cSJoe   PetscFunctionBeginUser;
172884467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsXEvent, ts, 0, 0, 0));
17298214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
17308214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
17318214e71cSJoe   PetscCall(VecGetLocalSize(Xres, &Np));
17329566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(V, &v));
17338214e71cSJoe   PetscCall(VecGetArray(Xres, &xres));
1734b80bf5b1SJoe Pusztay   Np /= dim;
1735b80bf5b1SJoe Pusztay   for (p = 0; p < Np; ++p) {
17368214e71cSJoe     for (d = 0; d < dim; ++d) {
17378214e71cSJoe       xres[p * dim + d] = v[p * dim + d];
17388214e71cSJoe       if (user->fake_1D && d > 0) xres[p * dim + d] = 0;
17398214e71cSJoe     }
1740b80bf5b1SJoe Pusztay   }
17419566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(V, &v));
17428214e71cSJoe   PetscCall(VecRestoreArray(Xres, &xres));
174384467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsXEvent, ts, 0, 0, 0));
17443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1745b80bf5b1SJoe Pusztay }
1746b80bf5b1SJoe Pusztay 
17478214e71cSJoe static PetscErrorCode RHSFunctionV(TS ts, PetscReal t, Vec X, Vec Vres, void *ctx)
17488214e71cSJoe {
17498214e71cSJoe   DM                 sw;
17508214e71cSJoe   AppCtx            *user = (AppCtx *)ctx;
17518214e71cSJoe   SNES               snes = ((AppCtx *)ctx)->snes;
17528214e71cSJoe   const PetscScalar *x;
17538214e71cSJoe   const PetscReal   *coords, *vel;
17548214e71cSJoe   PetscReal         *E, m_p, q_p;
17558214e71cSJoe   PetscScalar       *vres;
17568214e71cSJoe   PetscInt           Np, p, dim, d;
17578214e71cSJoe   Parameter         *param;
17588214e71cSJoe 
17598214e71cSJoe   PetscFunctionBeginUser;
176084467f86SMatthew G. Knepley   PetscCall(PetscLogEventBegin(user->RhsVEvent, ts, 0, 0, 0));
17618214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
17628214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
17638214e71cSJoe   PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords));
17648214e71cSJoe   PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel));
17658214e71cSJoe   PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E));
17668214e71cSJoe   PetscCall(PetscBagGetData(user->bag, (void **)&param));
17678214e71cSJoe   m_p = user->masses[0] * param->m0;
17688214e71cSJoe   q_p = user->charges[0] * param->q0;
17698214e71cSJoe   PetscCall(VecGetLocalSize(Vres, &Np));
17708214e71cSJoe   PetscCall(VecGetArrayRead(X, &x));
17718214e71cSJoe   PetscCall(VecGetArray(Vres, &vres));
17728214e71cSJoe   PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension must be 2");
17738214e71cSJoe   PetscCall(ComputeFieldAtParticles(snes, sw, E));
17748214e71cSJoe 
17758214e71cSJoe   Np /= dim;
17768214e71cSJoe   for (p = 0; p < Np; ++p) {
17778214e71cSJoe     for (d = 0; d < dim; ++d) {
17788214e71cSJoe       vres[p * dim + d] = q_p * E[p * dim + d] / m_p;
17798214e71cSJoe       if (user->fake_1D && d > 0) vres[p * dim + d] = 0.;
17808214e71cSJoe     }
17818214e71cSJoe   }
17828214e71cSJoe   PetscCall(VecRestoreArrayRead(X, &x));
17838214e71cSJoe   /*
1784d7c1f440SPierre Jolivet     Synchronized, ordered output for parallel/sequential test cases.
17858214e71cSJoe     In the 1D (on the 2D mesh) case, every y component should be zero.
17868214e71cSJoe   */
17878214e71cSJoe   if (user->checkVRes) {
17888214e71cSJoe     PetscBool pr = user->checkVRes > 1 ? PETSC_TRUE : PETSC_FALSE;
17898214e71cSJoe     PetscInt  step;
17908214e71cSJoe 
17918214e71cSJoe     PetscCall(TSGetStepNumber(ts, &step));
17928214e71cSJoe     if (pr) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step: %" PetscInt_FMT "\n", step));
17938214e71cSJoe     for (PetscInt p = 0; p < Np; ++p) {
17948214e71cSJoe       if (pr) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Residual: %.12g %.12g\n", (double)PetscRealPart(vres[p * dim + 0]), (double)PetscRealPart(vres[p * dim + 1])));
17958214e71cSJoe       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]));
17968214e71cSJoe     }
17978214e71cSJoe     if (pr) PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
17988214e71cSJoe   }
17998214e71cSJoe   PetscCall(VecRestoreArray(Vres, &vres));
18008214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords));
18018214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel));
18028214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E));
180384467f86SMatthew G. Knepley   PetscCall(PetscLogEventEnd(user->RhsVEvent, ts, 0, 0, 0));
18048214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18058214e71cSJoe }
18068214e71cSJoe 
18078214e71cSJoe static PetscErrorCode CreateSolution(TS ts)
18088214e71cSJoe {
18098214e71cSJoe   DM       sw;
18108214e71cSJoe   Vec      u;
18118214e71cSJoe   PetscInt dim, Np;
18128214e71cSJoe 
18138214e71cSJoe   PetscFunctionBegin;
18148214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
18158214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
18168214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
18178214e71cSJoe   PetscCall(VecCreate(PETSC_COMM_WORLD, &u));
18188214e71cSJoe   PetscCall(VecSetBlockSize(u, dim));
18198214e71cSJoe   PetscCall(VecSetSizes(u, 2 * Np * dim, PETSC_DECIDE));
18208214e71cSJoe   PetscCall(VecSetUp(u));
18218214e71cSJoe   PetscCall(TSSetSolution(ts, u));
18228214e71cSJoe   PetscCall(VecDestroy(&u));
18238214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18248214e71cSJoe }
18258214e71cSJoe 
18268214e71cSJoe static PetscErrorCode SetProblem(TS ts)
18278214e71cSJoe {
18288214e71cSJoe   AppCtx *user;
18298214e71cSJoe   DM      sw;
18308214e71cSJoe 
18318214e71cSJoe   PetscFunctionBegin;
18328214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
18338214e71cSJoe   PetscCall(DMGetApplicationContext(sw, (void **)&user));
18348214e71cSJoe   // Define unified system for (X, V)
18358214e71cSJoe   {
18368214e71cSJoe     Mat      J;
18378214e71cSJoe     PetscInt dim, Np;
18388214e71cSJoe 
18398214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
18408214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
18418214e71cSJoe     PetscCall(MatCreate(PETSC_COMM_WORLD, &J));
18428214e71cSJoe     PetscCall(MatSetSizes(J, 2 * Np * dim, 2 * Np * dim, PETSC_DECIDE, PETSC_DECIDE));
18438214e71cSJoe     PetscCall(MatSetBlockSize(J, 2 * dim));
18448214e71cSJoe     PetscCall(MatSetFromOptions(J));
18458214e71cSJoe     PetscCall(MatSetUp(J));
18468214e71cSJoe     PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, user));
18478214e71cSJoe     PetscCall(TSSetRHSJacobian(ts, J, J, RHSJacobian, user));
18488214e71cSJoe     PetscCall(MatDestroy(&J));
18498214e71cSJoe   }
18508214e71cSJoe   /* Define split system for X and V */
18518214e71cSJoe   {
18528214e71cSJoe     Vec             u;
18538214e71cSJoe     IS              isx, isv, istmp;
18548214e71cSJoe     const PetscInt *idx;
18558214e71cSJoe     PetscInt        dim, Np, rstart;
18568214e71cSJoe 
18578214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
18588214e71cSJoe     PetscCall(DMGetDimension(sw, &dim));
18598214e71cSJoe     PetscCall(DMSwarmGetLocalSize(sw, &Np));
18608214e71cSJoe     PetscCall(VecGetOwnershipRange(u, &rstart, NULL));
18618214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 0, 2, &istmp));
18628214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
18638214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isx));
18648214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
18658214e71cSJoe     PetscCall(ISDestroy(&istmp));
18668214e71cSJoe     PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 1, 2, &istmp));
18678214e71cSJoe     PetscCall(ISGetIndices(istmp, &idx));
18688214e71cSJoe     PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isv));
18698214e71cSJoe     PetscCall(ISRestoreIndices(istmp, &idx));
18708214e71cSJoe     PetscCall(ISDestroy(&istmp));
18718214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "position", isx));
18728214e71cSJoe     PetscCall(TSRHSSplitSetIS(ts, "momentum", isv));
18738214e71cSJoe     PetscCall(ISDestroy(&isx));
18748214e71cSJoe     PetscCall(ISDestroy(&isv));
18758214e71cSJoe     PetscCall(TSRHSSplitSetRHSFunction(ts, "position", NULL, RHSFunctionX, user));
18768214e71cSJoe     PetscCall(TSRHSSplitSetRHSFunction(ts, "momentum", NULL, RHSFunctionV, user));
18778214e71cSJoe   }
18788214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
18798214e71cSJoe }
18808214e71cSJoe 
18818214e71cSJoe static PetscErrorCode DMSwarmTSRedistribute(TS ts)
18828214e71cSJoe {
18838214e71cSJoe   DM        sw;
18848214e71cSJoe   Vec       u;
18858214e71cSJoe   PetscReal t, maxt, dt;
18868214e71cSJoe   PetscInt  n, maxn;
18878214e71cSJoe 
18888214e71cSJoe   PetscFunctionBegin;
18898214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
18908214e71cSJoe   PetscCall(TSGetTime(ts, &t));
18918214e71cSJoe   PetscCall(TSGetMaxTime(ts, &maxt));
18928214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
18938214e71cSJoe   PetscCall(TSGetStepNumber(ts, &n));
18948214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
18958214e71cSJoe 
18968214e71cSJoe   PetscCall(TSReset(ts));
18978214e71cSJoe   PetscCall(TSSetDM(ts, sw));
18988214e71cSJoe   PetscCall(TSSetFromOptions(ts));
18998214e71cSJoe   PetscCall(TSSetTime(ts, t));
19008214e71cSJoe   PetscCall(TSSetMaxTime(ts, maxt));
19018214e71cSJoe   PetscCall(TSSetTimeStep(ts, dt));
19028214e71cSJoe   PetscCall(TSSetStepNumber(ts, n));
19038214e71cSJoe   PetscCall(TSSetMaxSteps(ts, maxn));
19048214e71cSJoe 
19058214e71cSJoe   PetscCall(CreateSolution(ts));
19068214e71cSJoe   PetscCall(SetProblem(ts));
19078214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
19088214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
19098214e71cSJoe }
19108214e71cSJoe 
19118214e71cSJoe PetscErrorCode line(PetscInt dim, PetscReal time, const PetscReal dummy[], PetscInt p, PetscScalar x[], void *ctx)
19128214e71cSJoe {
19138214e71cSJoe   DM        sw, cdm;
19148214e71cSJoe   PetscInt  Np;
19158214e71cSJoe   PetscReal low[2], high[2];
19168214e71cSJoe   AppCtx   *user = (AppCtx *)ctx;
19178214e71cSJoe 
19188214e71cSJoe   sw = user->swarm;
19198214e71cSJoe   PetscCall(DMSwarmGetCellDM(sw, &cdm));
19208214e71cSJoe   // Get the bounding box so we can equally space the particles
19218214e71cSJoe   PetscCall(DMGetLocalBoundingBox(cdm, low, high));
19228214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
19238214e71cSJoe   // shift it by h/2 so nothing is initialized directly on a boundary
19248214e71cSJoe   x[0] = ((high[0] - low[0]) / Np) * (p + 0.5);
19258214e71cSJoe   x[1] = 0.;
19268214e71cSJoe   return PETSC_SUCCESS;
19278214e71cSJoe }
19288214e71cSJoe 
1929b80bf5b1SJoe Pusztay /*
19308214e71cSJoe   InitializeSolveAndSwarm - Set the solution values to the swarm coordinates and velocities, and also possibly set the initial values.
19318214e71cSJoe 
19328214e71cSJoe   Input Parameters:
19338214e71cSJoe + ts         - The TS
1934d7c1f440SPierre Jolivet - useInitial - Flag to also set the initial conditions to the current coordinates and velocities and setup the problem
19358214e71cSJoe 
19368214e71cSJoe   Output Parameters:
19378214e71cSJoe . u - The initialized solution vector
19388214e71cSJoe 
19398214e71cSJoe   Level: advanced
19408214e71cSJoe 
19418214e71cSJoe .seealso: InitializeSolve()
1942b80bf5b1SJoe Pusztay */
19438214e71cSJoe static PetscErrorCode InitializeSolveAndSwarm(TS ts, PetscBool useInitial)
1944d71ae5a4SJacob Faibussowitsch {
19458214e71cSJoe   DM       sw;
19468214e71cSJoe   Vec      u, gc, gv, gc0, gv0;
19478214e71cSJoe   IS       isx, isv;
19488214e71cSJoe   PetscInt dim;
19498214e71cSJoe   AppCtx  *user;
1950b80bf5b1SJoe Pusztay 
1951b80bf5b1SJoe Pusztay   PetscFunctionBeginUser;
19528214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
19538214e71cSJoe   PetscCall(DMGetApplicationContext(sw, &user));
19548214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
19558214e71cSJoe   if (useInitial) {
19568214e71cSJoe     PetscReal v0[2] = {1., 0.};
19578214e71cSJoe     if (user->perturbed_weights) {
19588214e71cSJoe       PetscCall(InitializeParticles_PerturbedWeights(sw, user));
19598214e71cSJoe     } else {
19608214e71cSJoe       PetscCall(DMSwarmComputeLocalSizeFromOptions(sw));
19618214e71cSJoe       PetscCall(DMSwarmInitializeCoordinates(sw));
19628214e71cSJoe       if (user->fake_1D) {
19638214e71cSJoe         PetscCall(InitializeVelocities_Fake1D(sw, user));
19648214e71cSJoe       } else {
19658214e71cSJoe         PetscCall(DMSwarmInitializeVelocitiesFromOptions(sw, v0));
19668214e71cSJoe       }
19678214e71cSJoe     }
19688214e71cSJoe     PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
19698214e71cSJoe     PetscCall(DMSwarmTSRedistribute(ts));
19708214e71cSJoe   }
19718214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
19728214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
19738214e71cSJoe   PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
19748214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19758214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "initCoordinates", &gc0));
19768214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
19778214e71cSJoe   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "initVelocity", &gv0));
19788214e71cSJoe   if (useInitial) {
19798214e71cSJoe     PetscCall(VecCopy(gc, gc0));
19808214e71cSJoe     PetscCall(VecCopy(gv, gv0));
19818214e71cSJoe   }
19828214e71cSJoe   PetscCall(VecISCopy(u, isx, SCATTER_FORWARD, gc));
19838214e71cSJoe   PetscCall(VecISCopy(u, isv, SCATTER_FORWARD, gv));
19848214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
19858214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "initCoordinates", &gc0));
19868214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
19878214e71cSJoe   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "initVelocity", &gv0));
19888214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
19898214e71cSJoe }
19908214e71cSJoe 
19918214e71cSJoe static PetscErrorCode InitializeSolve(TS ts, Vec u)
1992b80bf5b1SJoe Pusztay {
19938214e71cSJoe   PetscFunctionBegin;
19948214e71cSJoe   PetscCall(TSSetSolution(ts, u));
19958214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_TRUE));
19968214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
1997b80bf5b1SJoe Pusztay }
1998b80bf5b1SJoe Pusztay 
19998214e71cSJoe static PetscErrorCode ComputeError(TS ts, Vec U, Vec E)
20008214e71cSJoe {
20018214e71cSJoe   MPI_Comm           comm;
20028214e71cSJoe   DM                 sw;
20038214e71cSJoe   AppCtx            *user;
20048214e71cSJoe   const PetscScalar *u;
20058214e71cSJoe   const PetscReal   *coords, *vel;
20068214e71cSJoe   PetscScalar       *e;
20078214e71cSJoe   PetscReal          t;
20088214e71cSJoe   PetscInt           dim, Np, p;
2009b80bf5b1SJoe Pusztay 
20108214e71cSJoe   PetscFunctionBeginUser;
20118214e71cSJoe   PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
20128214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
20138214e71cSJoe   PetscCall(DMGetApplicationContext(sw, &user));
20148214e71cSJoe   PetscCall(DMGetDimension(sw, &dim));
20158214e71cSJoe   PetscCall(TSGetSolveTime(ts, &t));
20168214e71cSJoe   PetscCall(VecGetArray(E, &e));
20178214e71cSJoe   PetscCall(VecGetArrayRead(U, &u));
20188214e71cSJoe   PetscCall(DMSwarmGetLocalSize(sw, &Np));
20198214e71cSJoe   PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords));
20208214e71cSJoe   PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel));
20218214e71cSJoe   Np /= 2 * dim;
20228214e71cSJoe   for (p = 0; p < Np; ++p) {
20238214e71cSJoe     /* TODO generalize initial conditions and project into plane instead of assuming x-y */
20248214e71cSJoe     const PetscReal    r0    = DMPlex_NormD_Internal(dim, &coords[p * dim]);
20258214e71cSJoe     const PetscReal    th0   = PetscAtan2Real(coords[p * dim + 1], coords[p * dim + 0]);
20268214e71cSJoe     const PetscReal    v0    = DMPlex_NormD_Internal(dim, &vel[p * dim]);
20278214e71cSJoe     const PetscReal    omega = v0 / r0;
20288214e71cSJoe     const PetscReal    ct    = PetscCosReal(omega * t + th0);
20298214e71cSJoe     const PetscReal    st    = PetscSinReal(omega * t + th0);
20308214e71cSJoe     const PetscScalar *x     = &u[(p * 2 + 0) * dim];
20318214e71cSJoe     const PetscScalar *v     = &u[(p * 2 + 1) * dim];
20328214e71cSJoe     const PetscReal    xe[3] = {r0 * ct, r0 * st, 0.0};
20338214e71cSJoe     const PetscReal    ve[3] = {-v0 * st, v0 * ct, 0.0};
20348214e71cSJoe     PetscInt           d;
20358214e71cSJoe 
20368214e71cSJoe     for (d = 0; d < dim; ++d) {
20378214e71cSJoe       e[(p * 2 + 0) * dim + d] = x[d] - xe[d];
20388214e71cSJoe       e[(p * 2 + 1) * dim + d] = v[d] - ve[d];
2039b80bf5b1SJoe Pusztay     }
20408214e71cSJoe     if (user->error) {
20418214e71cSJoe       const PetscReal en   = 0.5 * DMPlex_DotRealD_Internal(dim, v, v);
20428214e71cSJoe       const PetscReal exen = 0.5 * PetscSqr(v0);
20438214e71cSJoe       PetscCall(PetscPrintf(comm, "t %.4g: p%" PetscInt_FMT " error [%.2g %.2g] sol [(%.6lf %.6lf) (%.6lf %.6lf)] exact [(%.6lf %.6lf) (%.6lf %.6lf)] energy/exact energy %g / %g (%.10lf%%)\n", (double)t, p, (double)DMPlex_NormD_Internal(dim, &e[(p * 2 + 0) * dim]), (double)DMPlex_NormD_Internal(dim, &e[(p * 2 + 1) * dim]), (double)x[0], (double)x[1], (double)v[0], (double)v[1], (double)xe[0], (double)xe[1], (double)ve[0], (double)ve[1], (double)en, (double)exen, (double)(PetscAbsReal(exen - en) * 100. / exen)));
2044b80bf5b1SJoe Pusztay     }
20458214e71cSJoe   }
20468214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords));
20478214e71cSJoe   PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel));
20488214e71cSJoe   PetscCall(VecRestoreArrayRead(U, &u));
20498214e71cSJoe   PetscCall(VecRestoreArray(E, &e));
20508214e71cSJoe   PetscFunctionReturn(PETSC_SUCCESS);
20518214e71cSJoe }
20528214e71cSJoe 
20538214e71cSJoe static PetscErrorCode MigrateParticles(TS ts)
20548214e71cSJoe {
20558214e71cSJoe   DM               sw, cdm;
20568214e71cSJoe   const PetscReal *L;
20578214e71cSJoe 
20588214e71cSJoe   PetscFunctionBeginUser;
20598214e71cSJoe   PetscCall(TSGetDM(ts, &sw));
20608214e71cSJoe   PetscCall(DMViewFromOptions(sw, NULL, "-migrate_view_pre"));
20618214e71cSJoe   {
20628214e71cSJoe     Vec        u, gc, gv, position, momentum;
20638214e71cSJoe     IS         isx, isv;
20648214e71cSJoe     PetscReal *pos, *mom;
20658214e71cSJoe 
20668214e71cSJoe     PetscCall(TSGetSolution(ts, &u));
20678214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "position", &isx));
20688214e71cSJoe     PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv));
20698214e71cSJoe     PetscCall(VecGetSubVector(u, isx, &position));
20708214e71cSJoe     PetscCall(VecGetSubVector(u, isv, &momentum));
20718214e71cSJoe     PetscCall(VecGetArray(position, &pos));
20728214e71cSJoe     PetscCall(VecGetArray(momentum, &mom));
20738214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
20748214e71cSJoe     PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv));
20758214e71cSJoe     PetscCall(VecISCopy(u, isx, SCATTER_REVERSE, gc));
20768214e71cSJoe     PetscCall(VecISCopy(u, isv, SCATTER_REVERSE, gv));
20778214e71cSJoe 
20788214e71cSJoe     PetscCall(DMSwarmGetCellDM(sw, &cdm));
20798214e71cSJoe     PetscCall(DMGetPeriodicity(cdm, NULL, NULL, &L));
20808214e71cSJoe     if ((L[0] || L[1]) >= 0.) {
20818214e71cSJoe       PetscReal *x, *v, upper[3], lower[3];
20828214e71cSJoe       PetscInt   Np, dim;
20838214e71cSJoe 
20848214e71cSJoe       PetscCall(DMSwarmGetLocalSize(sw, &Np));
20858214e71cSJoe       PetscCall(DMGetDimension(cdm, &dim));
20868214e71cSJoe       PetscCall(DMGetBoundingBox(cdm, lower, upper));
20878214e71cSJoe       PetscCall(VecGetArray(gc, &x));
20888214e71cSJoe       PetscCall(VecGetArray(gv, &v));
20898214e71cSJoe       for (PetscInt p = 0; p < Np; ++p) {
20908214e71cSJoe         for (PetscInt d = 0; d < dim; ++d) {
20918214e71cSJoe           if (pos[p * dim + d] < lower[d]) {
20928214e71cSJoe             x[p * dim + d] = pos[p * dim + d] + (upper[d] - lower[d]);
20938214e71cSJoe           } else if (pos[p * dim + d] > upper[d]) {
20948214e71cSJoe             x[p * dim + d] = pos[p * dim + d] - (upper[d] - lower[d]);
20958214e71cSJoe           } else {
20968214e71cSJoe             x[p * dim + d] = pos[p * dim + d];
20978214e71cSJoe           }
20988214e71cSJoe           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]);
20998214e71cSJoe           v[p * dim + d] = mom[p * dim + d];
21008214e71cSJoe         }
21018214e71cSJoe       }
21028214e71cSJoe       PetscCall(VecRestoreArray(gc, &x));
21038214e71cSJoe       PetscCall(VecRestoreArray(gv, &v));
21048214e71cSJoe     }
21058214e71cSJoe     PetscCall(VecRestoreArray(position, &pos));
21068214e71cSJoe     PetscCall(VecRestoreArray(momentum, &mom));
21078214e71cSJoe     PetscCall(VecRestoreSubVector(u, isx, &position));
21088214e71cSJoe     PetscCall(VecRestoreSubVector(u, isv, &momentum));
21098214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv));
21108214e71cSJoe     PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc));
21118214e71cSJoe   }
21128214e71cSJoe   PetscCall(DMSwarmMigrate(sw, PETSC_TRUE));
21138214e71cSJoe   PetscCall(DMSwarmTSRedistribute(ts));
21148214e71cSJoe   PetscCall(InitializeSolveAndSwarm(ts, PETSC_FALSE));
21153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2116b80bf5b1SJoe Pusztay }
2117b80bf5b1SJoe Pusztay 
2118d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
2119d71ae5a4SJacob Faibussowitsch {
2120b80bf5b1SJoe Pusztay   DM        dm, sw;
21218214e71cSJoe   TS        ts;
21228214e71cSJoe   Vec       u;
21238214e71cSJoe   PetscReal dt;
21248214e71cSJoe   PetscInt  maxn;
2125b80bf5b1SJoe Pusztay   AppCtx    user;
2126b80bf5b1SJoe Pusztay 
21279566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
21288214e71cSJoe   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
21298214e71cSJoe   PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &user.bag));
21308214e71cSJoe   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
21318214e71cSJoe   PetscCall(CreatePoisson(dm, &user));
21328214e71cSJoe   PetscCall(CreateSwarm(dm, &user, &sw));
21338214e71cSJoe   PetscCall(SetupParameters(PETSC_COMM_WORLD, &user));
21348214e71cSJoe   PetscCall(InitializeConstants(sw, &user));
21358214e71cSJoe   PetscCall(DMSetApplicationContext(sw, &user));
2136b80bf5b1SJoe Pusztay 
21378214e71cSJoe   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
21388214e71cSJoe   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
21399566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts, sw));
21408214e71cSJoe   PetscCall(TSSetMaxTime(ts, 0.1));
21418214e71cSJoe   PetscCall(TSSetTimeStep(ts, 0.00001));
21428214e71cSJoe   PetscCall(TSSetMaxSteps(ts, 100));
21438214e71cSJoe   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
21448214e71cSJoe 
21458214e71cSJoe   if (user.efield_monitor) PetscCall(TSMonitorSet(ts, MonitorEField, &user, NULL));
2146*f1e6e573SMatthew G. Knepley   if (user.moment_monitor) PetscCall(TSMonitorSet(ts, MonitorMoments, &user, NULL));
21478214e71cSJoe   if (user.initial_monitor) PetscCall(TSMonitorSet(ts, MonitorInitialConditions, &user, NULL));
21488214e71cSJoe   if (user.monitor_positions) PetscCall(TSMonitorSet(ts, MonitorPositions_2D, &user, NULL));
21498214e71cSJoe   if (user.poisson_monitor) PetscCall(TSMonitorSet(ts, MonitorPoisson, &user, NULL));
21508214e71cSJoe 
21518214e71cSJoe   PetscCall(TSSetFromOptions(ts));
21528214e71cSJoe   PetscCall(TSGetTimeStep(ts, &dt));
21538214e71cSJoe   PetscCall(TSGetMaxSteps(ts, &maxn));
21548214e71cSJoe   user.steps    = maxn;
21558214e71cSJoe   user.stepSize = dt;
21568214e71cSJoe   PetscCall(SetupContext(dm, sw, &user));
21578214e71cSJoe   PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve));
21588214e71cSJoe   PetscCall(TSSetComputeExactError(ts, ComputeError));
21598214e71cSJoe   PetscCall(TSSetPostStep(ts, MigrateParticles));
21608214e71cSJoe   PetscCall(CreateSolution(ts));
21618214e71cSJoe   PetscCall(TSGetSolution(ts, &u));
21628214e71cSJoe   PetscCall(TSComputeInitialCondition(ts, u));
21638214e71cSJoe   PetscCall(CheckNonNegativeWeights(sw, &user));
21648214e71cSJoe   PetscCall(TSSolve(ts, NULL));
21658214e71cSJoe 
21669566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&user.snes));
2167*f1e6e573SMatthew G. Knepley   PetscCall(MatDestroy(&user.M));
2168*f1e6e573SMatthew G. Knepley   PetscCall(PetscFEGeomDestroy(&user.fegeom));
21699566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
21709566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sw));
21719566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
21728214e71cSJoe   PetscCall(DestroyContext(&user));
21739566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
2174b122ec5aSJacob Faibussowitsch   return 0;
2175b80bf5b1SJoe Pusztay }
2176b80bf5b1SJoe Pusztay 
2177b80bf5b1SJoe Pusztay /*TEST
2178b80bf5b1SJoe Pusztay 
2179b80bf5b1SJoe Pusztay    build:
21808214e71cSJoe     requires: !complex double
21818214e71cSJoe 
21828214e71cSJoe   # This tests that we can put particles in a box and compute the Coulomb force
21838214e71cSJoe   # Recommend -draw_size 500,500
21848214e71cSJoe    testset:
21858214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
21868214e71cSJoe      args: -dm_plex_dim 2 -fake_1D -dm_plex_simplex 0 -dm_plex_box_faces 20,1 \
21878214e71cSJoe              -dm_plex_box_lower 0,-1 -dm_plex_box_upper 12.5664,1 \
2188b80bf5b1SJoe Pusztay              -dm_plex_box_bd periodic,none \
21898214e71cSJoe            -dm_swarm_coordinate_density constant -dm_swarm_num_particles 100 \
21908214e71cSJoe            -sigma 1.0e-8 -timeScale 2.0e-14 \
21918214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
21928214e71cSJoe              -ts_monitor_sp_swarm -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 0 \
21938214e71cSJoe            -output_step 50 -check_vel_res
21948214e71cSJoe      test:
21958214e71cSJoe        suffix: none_1d
21968214e71cSJoe        args: -em_type none -error
21978214e71cSJoe      test:
21988214e71cSJoe        suffix: coulomb_1d
21998214e71cSJoe        args: -em_type coulomb
22008214e71cSJoe 
22018214e71cSJoe    # for viewers
22028214e71cSJoe    #-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
22038214e71cSJoe    testset:
22048214e71cSJoe      nsize: {{1 2}}
22058214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
22068214e71cSJoe      args: -dm_plex_dim 2 -fake_1D -dm_plex_simplex 0 -dm_plex_box_faces 36,1 \
22078214e71cSJoe              -dm_plex_box_lower 0.,-0.5 -dm_plex_box_upper 12.5664,0.5 \
22088214e71cSJoe              -dm_plex_box_bd periodic,none \
22098214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
22108214e71cSJoe              -vdm_plex_box_lower -3 -vdm_plex_box_upper 3 \
221184467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -twostream -charges -1.,1. -sigma 1.0e-8 \
22128214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
22138214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 2 \
22148214e71cSJoe              -ts_dt 0.01 -ts_max_time 5 -ts_max_steps 10 \
22158214e71cSJoe            -em_snes_atol 1.e-15 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
221684467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
22178214e71cSJoe      test:
22188214e71cSJoe        suffix: two_stream_c0
22198214e71cSJoe        args: -em_type primal -petscfe_default_quadrature_order 2 -petscspace_degree 2 -em_pc_type svd
22208214e71cSJoe      test:
22218214e71cSJoe        suffix: two_stream_rt
22228214e71cSJoe        requires: superlu_dist
22238214e71cSJoe        args: -em_type mixed \
22248214e71cSJoe                -potential_petscspace_degree 0 \
22258214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
22268214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
22278214e71cSJoe                -field_petscspace_degree 2 -field_petscfe_default_quadrature_order 1 \
22288214e71cSJoe                -field_petscspace_type sum \
22298214e71cSJoe                  -field_petscspace_variables 2 \
22308214e71cSJoe                  -field_petscspace_components 2 \
22318214e71cSJoe                  -field_petscspace_sum_spaces 2 \
22328214e71cSJoe                  -field_petscspace_sum_concatenate true \
22338214e71cSJoe                  -field_sumcomp_0_petscspace_variables 2 \
22348214e71cSJoe                  -field_sumcomp_0_petscspace_type tensor \
22358214e71cSJoe                  -field_sumcomp_0_petscspace_tensor_spaces 2 \
22368214e71cSJoe                  -field_sumcomp_0_petscspace_tensor_uniform false \
22378214e71cSJoe                  -field_sumcomp_0_tensorcomp_0_petscspace_degree 1 \
22388214e71cSJoe                  -field_sumcomp_0_tensorcomp_1_petscspace_degree 0 \
22398214e71cSJoe                  -field_sumcomp_1_petscspace_variables 2 \
22408214e71cSJoe                  -field_sumcomp_1_petscspace_type tensor \
22418214e71cSJoe                  -field_sumcomp_1_petscspace_tensor_spaces 2 \
22428214e71cSJoe                  -field_sumcomp_1_petscspace_tensor_uniform false \
22438214e71cSJoe                  -field_sumcomp_1_tensorcomp_0_petscspace_degree 0 \
22448214e71cSJoe                  -field_sumcomp_1_tensorcomp_1_petscspace_degree 1 \
22458214e71cSJoe                -field_petscdualspace_form_degree -1 \
22468214e71cSJoe                -field_petscdualspace_order 1 \
22478214e71cSJoe                -field_petscdualspace_lagrange_trimmed true \
22488214e71cSJoe              -em_snes_error_if_not_converged \
22498214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
22508214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
22518214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
22528214e71cSJoe                -em_fieldsplit_field_pc_type lu \
22538214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
22548214e71cSJoe                -em_fieldsplit_potential_pc_type svd
22558214e71cSJoe 
225684467f86SMatthew G. Knepley    # For an eyeball check, we use
225784467f86SMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 10,1 -vdm_plex_box_faces 2000 -monitor_efield
22588214e71cSJoe    # For verification, we use
225984467f86SMatthew G. Knepley    # -ts_max_steps 1000 -dm_plex_box_faces 100,1 -vdm_plex_box_faces 8000 -dm_swarm_num_particles 800000 -monitor_efield
22608214e71cSJoe    # -ts_monitor_sp_swarm_multi_species 0 -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500
22618214e71cSJoe    testset:
22628214e71cSJoe      nsize: {{1 2}}
22638214e71cSJoe      requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT)
22648214e71cSJoe      args: -dm_plex_dim 2 -fake_1D -dm_plex_simplex 0 -dm_plex_box_faces 10,1 \
22658214e71cSJoe              -dm_plex_box_lower 0.,-0.5 -dm_plex_box_upper 12.5664,0.5 \
22668214e71cSJoe              -dm_plex_box_bd periodic,none \
22678214e71cSJoe            -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \
22688214e71cSJoe              -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \
2269*f1e6e573SMatthew G. Knepley              -vpetscspace_degree 2 -vdm_plex_hash_location \
227084467f86SMatthew G. Knepley            -dm_swarm_num_species 1 -charges -1.,1. \
22718214e71cSJoe              -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \
22728214e71cSJoe            -ts_type basicsymplectic -ts_basicsymplectic_type 1 \
22738214e71cSJoe              -ts_dt 0.03 -ts_max_time 500 -ts_max_steps 1 \
22748214e71cSJoe            -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \
227584467f86SMatthew G. Knepley            -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1
22768214e71cSJoe 
22778214e71cSJoe      test:
22788214e71cSJoe        suffix: uniform_equilibrium_1d
22798214e71cSJoe        args: -cosine_coefficients 0.0,0.5 -em_type primal -petscspace_degree 1 -em_pc_type svd
22808214e71cSJoe      test:
22818214e71cSJoe        suffix: uniform_primal_1d
22828214e71cSJoe        args: -em_type primal -petscspace_degree 1 -em_pc_type svd
22838214e71cSJoe      test:
22848214e71cSJoe        requires: superlu_dist
22858214e71cSJoe        suffix: uniform_mixed_1d
22868214e71cSJoe        args: -em_type mixed \
22878214e71cSJoe                -potential_petscspace_degree 0 \
22888214e71cSJoe                -potential_petscdualspace_lagrange_use_moments \
22898214e71cSJoe                -potential_petscdualspace_lagrange_moment_order 2 \
22908214e71cSJoe                -field_petscspace_degree 2 -field_petscfe_default_quadrature_order 1 \
22918214e71cSJoe                -field_petscspace_type sum \
22928214e71cSJoe                  -field_petscspace_variables 2 \
22938214e71cSJoe                  -field_petscspace_components 2 \
22948214e71cSJoe                  -field_petscspace_sum_spaces 2 \
22958214e71cSJoe                  -field_petscspace_sum_concatenate true \
22968214e71cSJoe                  -field_sumcomp_0_petscspace_variables 2 \
22978214e71cSJoe                  -field_sumcomp_0_petscspace_type tensor \
22988214e71cSJoe                  -field_sumcomp_0_petscspace_tensor_spaces 2 \
22998214e71cSJoe                  -field_sumcomp_0_petscspace_tensor_uniform false \
23008214e71cSJoe                  -field_sumcomp_0_tensorcomp_0_petscspace_degree 1 \
23018214e71cSJoe                  -field_sumcomp_0_tensorcomp_1_petscspace_degree 0 \
23028214e71cSJoe                  -field_sumcomp_1_petscspace_variables 2 \
23038214e71cSJoe                  -field_sumcomp_1_petscspace_type tensor \
23048214e71cSJoe                  -field_sumcomp_1_petscspace_tensor_spaces 2 \
23058214e71cSJoe                  -field_sumcomp_1_petscspace_tensor_uniform false \
23068214e71cSJoe                  -field_sumcomp_1_tensorcomp_0_petscspace_degree 0 \
23078214e71cSJoe                  -field_sumcomp_1_tensorcomp_1_petscspace_degree 1 \
23088214e71cSJoe                -field_petscdualspace_form_degree -1 \
23098214e71cSJoe                -field_petscdualspace_order 1 \
23108214e71cSJoe                -field_petscdualspace_lagrange_trimmed true \
23118214e71cSJoe              -em_snes_error_if_not_converged \
23128214e71cSJoe              -em_ksp_type preonly -em_ksp_error_if_not_converged \
23138214e71cSJoe              -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \
23148214e71cSJoe                -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \
23158214e71cSJoe                -em_fieldsplit_field_pc_type lu \
23168214e71cSJoe                  -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \
23178214e71cSJoe                -em_fieldsplit_potential_pc_type svd
23188214e71cSJoe 
2319b80bf5b1SJoe Pusztay TEST*/
2320