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