18214e71cSJoe static char help[] = "Landau Damping/Two Stream instability test using Vlasov-Poisson equations\n"; 2b80bf5b1SJoe Pusztay 38214e71cSJoe /* 49072cb8bSMatthew G. Knepley TODO: 59072cb8bSMatthew G. Knepley - Cache mesh geometry 69072cb8bSMatthew G. Knepley - Move electrostatic solver to MG+SVD 79072cb8bSMatthew G. Knepley 88214e71cSJoe To run the code with particles sinusoidally perturbed in x space use the test "pp_poisson_bsi_1d_4" or "pp_poisson_bsi_2d_4" 98214e71cSJoe According to Lukas, good damping results come at ~16k particles per cell 108214e71cSJoe 119072cb8bSMatthew G. Knepley To visualize the maximum electric field use 128214e71cSJoe 139072cb8bSMatthew G. Knepley -efield_monitor 148214e71cSJoe 159072cb8bSMatthew G. Knepley To monitor velocity moments of the distribution use 16f1e6e573SMatthew G. Knepley 179072cb8bSMatthew G. Knepley -ptof_pc_type lu -moments_monitor 189072cb8bSMatthew G. Knepley 199072cb8bSMatthew G. Knepley To monitor the particle positions in phase space use 209072cb8bSMatthew G. Knepley 219072cb8bSMatthew G. Knepley -positions_monitor 229072cb8bSMatthew G. Knepley 239072cb8bSMatthew G. Knepley To monitor the charge density, E field, and potential use 249072cb8bSMatthew G. Knepley 259072cb8bSMatthew G. Knepley -poisson_monitor 269072cb8bSMatthew G. Knepley 279072cb8bSMatthew G. Knepley To monitor the remapping field use 289072cb8bSMatthew G. Knepley 299072cb8bSMatthew G. Knepley -remap_uf_view draw 30f1e6e573SMatthew G. Knepley 318214e71cSJoe To visualize the swarm distribution use 328214e71cSJoe 338214e71cSJoe -ts_monitor_hg_swarm 348214e71cSJoe 358214e71cSJoe To visualize the particles, we can use 368214e71cSJoe 378214e71cSJoe -ts_monitor_sp_swarm -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500 388214e71cSJoe 3984467f86SMatthew G. Knepley For a Landau Damping verification run, we use 4084467f86SMatthew G. Knepley 41045208b8SMatthew G. Knepley # Physics 42045208b8SMatthew G. Knepley -cosine_coefficients 0.01 -dm_swarm_num_species 1 -charges -1. -perturbed_weights -total_weight 1. 43045208b8SMatthew G. Knepley # Spatial Mesh 44045208b8SMatthew G. Knepley -dm_plex_dim 1 -dm_plex_box_faces 40 -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic -dm_plex_hash_location 45045208b8SMatthew G. Knepley # Velocity Mesh 46045208b8SMatthew G. Knepley -vdm_plex_dim 1 -vdm_plex_box_faces 40 -vdm_plex_box_lower -6 -vdm_plex_box_upper 6 -vpetscspace_degree 2 -vdm_plex_hash_location 47045208b8SMatthew G. Knepley # Remap Space 48045208b8SMatthew G. Knepley -dm_swarm_remap_type pfak -remap_freq 100 49045208b8SMatthew G. Knepley -remap_dm_plex_dim 2 -remap_dm_plex_simplex 0 -remap_dm_plex_box_faces 20,20 -remap_dm_plex_box_bd periodic,none -remap_dm_plex_box_lower 0.,-6. 50045208b8SMatthew G. Knepley -remap_dm_plex_box_upper 12.5664,6. -remap_petscspace_degree 1 -remap_dm_plex_hash_location 51045208b8SMatthew G. Knepley # Remap Solve 52045208b8SMatthew G. Knepley -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 -ptof_pc_type lu 53045208b8SMatthew G. Knepley # EM Solve 54045208b8SMatthew G. Knepley -em_type primal -petscspace_degree 1 -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged -em_pc_type svd -em_proj_pc_type lu 55045208b8SMatthew G. Knepley # Timestepping 56045208b8SMatthew G. Knepley -ts_type basicsymplectic -ts_basicsymplectic_type 1 -ts_dt 0.03 -ts_max_steps 1500 -ts_max_time 100 57045208b8SMatthew G. Knepley # Monitoring 58045208b8SMatthew G. Knepley -output_step 1 -check_vel_res -efield_monitor -poisson_monitor -positions_monitor -dm_swarm_print_coords 0 -remap_uf_view draw 59045208b8SMatthew G. Knepley -ftop_ksp_lsqr_monitor -ftop_ksp_converged_reason 6084467f86SMatthew G. Knepley 618214e71cSJoe */ 62b80bf5b1SJoe Pusztay #include <petscts.h> 638214e71cSJoe #include <petscdmplex.h> 648214e71cSJoe #include <petscdmswarm.h> 658214e71cSJoe #include <petscfe.h> 668214e71cSJoe #include <petscds.h> 678214e71cSJoe #include <petscbag.h> 688214e71cSJoe #include <petscdraw.h> 698214e71cSJoe #include <petsc/private/dmpleximpl.h> /* For norm and dot */ 708214e71cSJoe #include <petsc/private/petscfeimpl.h> /* For interpolation */ 7184467f86SMatthew G. Knepley #include <petsc/private/dmswarmimpl.h> /* For swarm debugging */ 728214e71cSJoe #include "petscdm.h" 738214e71cSJoe #include "petscdmlabel.h" 748214e71cSJoe 758214e71cSJoe PETSC_EXTERN PetscErrorCode stream(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 768214e71cSJoe PETSC_EXTERN PetscErrorCode line(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 778214e71cSJoe 788214e71cSJoe const char *EMTypes[] = {"primal", "mixed", "coulomb", "none", "EMType", "EM_", NULL}; 798214e71cSJoe typedef enum { 808214e71cSJoe EM_PRIMAL, 818214e71cSJoe EM_MIXED, 828214e71cSJoe EM_COULOMB, 838214e71cSJoe EM_NONE 848214e71cSJoe } EMType; 858214e71cSJoe 868214e71cSJoe typedef enum { 878214e71cSJoe V0, 888214e71cSJoe X0, 898214e71cSJoe T0, 908214e71cSJoe M0, 918214e71cSJoe Q0, 928214e71cSJoe PHI0, 938214e71cSJoe POISSON, 948214e71cSJoe VLASOV, 958214e71cSJoe SIGMA, 968214e71cSJoe NUM_CONSTANTS 978214e71cSJoe } ConstantType; 988214e71cSJoe typedef struct { 998214e71cSJoe PetscScalar v0; /* Velocity scale, often the thermal velocity */ 1008214e71cSJoe PetscScalar t0; /* Time scale */ 1018214e71cSJoe PetscScalar x0; /* Space scale */ 1028214e71cSJoe PetscScalar m0; /* Mass scale */ 1038214e71cSJoe PetscScalar q0; /* Charge scale */ 1048214e71cSJoe PetscScalar kb; 1058214e71cSJoe PetscScalar epsi0; 1068214e71cSJoe PetscScalar phi0; /* Potential scale */ 1078214e71cSJoe PetscScalar poissonNumber; /* Non-Dimensional Poisson Number */ 1088214e71cSJoe PetscScalar vlasovNumber; /* Non-Dimensional Vlasov Number */ 1098214e71cSJoe PetscReal sigma; /* Nondimensional charge per length in x */ 1108214e71cSJoe } Parameter; 111b80bf5b1SJoe Pusztay 112b80bf5b1SJoe Pusztay typedef struct { 1139072cb8bSMatthew G. Knepley PetscBag bag; // Problem parameters 1149072cb8bSMatthew G. Knepley PetscBool error; // Flag for printing the error 1159072cb8bSMatthew G. Knepley PetscInt remapFreq; // Number of timesteps between remapping 1169072cb8bSMatthew G. Knepley PetscBool efield_monitor; // Flag to show electric field monitor 1179072cb8bSMatthew G. Knepley PetscBool moment_monitor; // Flag to show distribution moment monitor 1189072cb8bSMatthew G. Knepley PetscBool positions_monitor; // Flag to show particle positins at each time step 1199072cb8bSMatthew G. Knepley PetscBool poisson_monitor; // Flag to display charge, E field, and potential at each solve 1209072cb8bSMatthew G. Knepley PetscBool initial_monitor; // Flag to monitor the initial conditions 1219072cb8bSMatthew G. Knepley PetscBool perturbed_weights; // Uniformly sample x,v space with gaussian weights 1229072cb8bSMatthew G. Knepley PetscInt ostep; // Print the energy at each ostep time steps 1238214e71cSJoe PetscInt numParticles; 1248214e71cSJoe PetscReal timeScale; /* Nondimensionalizing time scale */ 1258214e71cSJoe PetscReal charges[2]; /* The charges of each species */ 1268214e71cSJoe PetscReal masses[2]; /* The masses of each species */ 1278214e71cSJoe PetscReal thermal_energy[2]; /* Thermal Energy (used to get other constants)*/ 1288214e71cSJoe PetscReal cosine_coefficients[2]; /*(alpha, k)*/ 1298214e71cSJoe PetscReal totalWeight; 1308214e71cSJoe PetscReal stepSize; 1318214e71cSJoe PetscInt steps; 1328214e71cSJoe PetscReal initVel; 133f1e6e573SMatthew G. Knepley EMType em; // Type of electrostatic model 134f1e6e573SMatthew G. Knepley SNES snes; // EM solver 1354a0cbf56SMatthew G. Knepley DM dmPot; // The DM for potential 136b02f317dSMatthew G. Knepley Mat fftPot; // Fourier Transform operator for the potential 1374a0cbf56SMatthew G. Knepley IS isPot; // The IS for potential, or NULL in primal 1384a0cbf56SMatthew G. Knepley Mat M; // The finite element mass matrix for potential 139f1e6e573SMatthew G. Knepley PetscFEGeom *fegeom; // Geometric information for the DM cells 140b02f317dSMatthew G. Knepley PetscDrawHG drawhgic_x; // Histogram of the particle weight in each X cell 141b02f317dSMatthew G. Knepley PetscDraw drawic_x; // Draw context for histogram 142b02f317dSMatthew G. Knepley PetscDrawHG drawhgic_v; // Histogram of the particle weight in each X cell 143b02f317dSMatthew G. Knepley PetscDraw drawic_v; // Draw context for histogram 1449072cb8bSMatthew G. Knepley PetscBool validE; // Flag to indicate E-field in swarm is valid 14575155f48SMatthew G. Knepley PetscReal drawlgEmin; // The minimum lg(E) to plot 14675155f48SMatthew G. Knepley PetscDrawLG drawlgE; // Logarithm of maximum electric field 14775155f48SMatthew G. Knepley PetscDrawSP drawspE; // Electric field at particle positions 14875155f48SMatthew G. Knepley PetscDrawSP drawspX; // Particle positions 14975155f48SMatthew G. Knepley PetscViewer viewerRho; // Charge density viewer 150b02f317dSMatthew G. Knepley PetscViewer viewerRhoHat; // Charge density Fourier Transform viewer 15175155f48SMatthew G. Knepley PetscViewer viewerPhi; // Potential viewer 1528214e71cSJoe DM swarm; 1538214e71cSJoe PetscRandom random; 1548214e71cSJoe PetscBool twostream; 1558214e71cSJoe PetscBool checkweights; 156b02f317dSMatthew G. Knepley PetscInt checkVRes; // Flag to check/output velocity residuals for nightly tests 15784467f86SMatthew G. Knepley 15884467f86SMatthew G. Knepley PetscLogEvent RhsXEvent, RhsVEvent, ESolveEvent, ETabEvent; 159b80bf5b1SJoe Pusztay } AppCtx; 160b80bf5b1SJoe Pusztay 161d71ae5a4SJacob Faibussowitsch static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) 162d71ae5a4SJacob Faibussowitsch { 163b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 1648214e71cSJoe PetscInt d = 2; 1658214e71cSJoe PetscInt maxSpecies = 2; 1668214e71cSJoe options->error = PETSC_FALSE; 1679072cb8bSMatthew G. Knepley options->remapFreq = 1; 1688214e71cSJoe options->efield_monitor = PETSC_FALSE; 169f1e6e573SMatthew G. Knepley options->moment_monitor = PETSC_FALSE; 1708214e71cSJoe options->initial_monitor = PETSC_FALSE; 1718214e71cSJoe options->perturbed_weights = PETSC_FALSE; 1728214e71cSJoe options->poisson_monitor = PETSC_FALSE; 1739072cb8bSMatthew G. Knepley options->positions_monitor = PETSC_FALSE; 1748214e71cSJoe options->ostep = 100; 1758214e71cSJoe options->timeScale = 2.0e-14; 1768214e71cSJoe options->charges[0] = -1.0; 1778214e71cSJoe options->charges[1] = 1.0; 1788214e71cSJoe options->masses[0] = 1.0; 1798214e71cSJoe options->masses[1] = 1000.0; 1808214e71cSJoe options->thermal_energy[0] = 1.0; 1818214e71cSJoe options->thermal_energy[1] = 1.0; 1828214e71cSJoe options->cosine_coefficients[0] = 0.01; 1838214e71cSJoe options->cosine_coefficients[1] = 0.5; 1848214e71cSJoe options->initVel = 1; 1858214e71cSJoe options->totalWeight = 1.0; 1868214e71cSJoe options->drawic_x = NULL; 1878214e71cSJoe options->drawhgic_x = NULL; 188b02f317dSMatthew G. Knepley options->drawic_v = NULL; 1898214e71cSJoe options->drawhgic_v = NULL; 19075155f48SMatthew G. Knepley options->drawlgEmin = -6; 19175155f48SMatthew G. Knepley options->drawlgE = NULL; 19275155f48SMatthew G. Knepley options->drawspE = NULL; 19375155f48SMatthew G. Knepley options->drawspX = NULL; 19475155f48SMatthew G. Knepley options->viewerRho = NULL; 195b02f317dSMatthew G. Knepley options->viewerRhoHat = NULL; 19675155f48SMatthew G. Knepley options->viewerPhi = NULL; 1978214e71cSJoe options->em = EM_COULOMB; 1984a0cbf56SMatthew G. Knepley options->snes = NULL; 1994a0cbf56SMatthew G. Knepley options->dmPot = NULL; 200b02f317dSMatthew G. Knepley options->fftPot = NULL; 2014a0cbf56SMatthew G. Knepley options->isPot = NULL; 2024a0cbf56SMatthew G. Knepley options->M = NULL; 2038214e71cSJoe options->numParticles = 32768; 2048214e71cSJoe options->twostream = PETSC_FALSE; 2058214e71cSJoe options->checkweights = PETSC_FALSE; 2068214e71cSJoe options->checkVRes = 0; 207b80bf5b1SJoe Pusztay 2088214e71cSJoe PetscOptionsBegin(comm, "", "Landau Damping and Two Stream options", "DMSWARM"); 2098214e71cSJoe PetscCall(PetscOptionsBool("-error", "Flag to print the error", "ex2.c", options->error, &options->error, NULL)); 2109072cb8bSMatthew G. Knepley PetscCall(PetscOptionsInt("-remap_freq", "Number", "ex2.c", options->remapFreq, &options->remapFreq, NULL)); 2119072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-efield_monitor", "Flag to plot log(max E) over time", "ex2.c", options->efield_monitor, &options->efield_monitor, NULL)); 2129072cb8bSMatthew G. Knepley PetscCall(PetscOptionsReal("-efield_min_monitor", "Minimum E field to plot", "ex2.c", options->drawlgEmin, &options->drawlgEmin, NULL)); 2139072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-moments_monitor", "Flag to show moments table", "ex2.c", options->moment_monitor, &options->moment_monitor, NULL)); 2149072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-ics_monitor", "Flag to show initial condition histograms", "ex2.c", options->initial_monitor, &options->initial_monitor, NULL)); 2159072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-positions_monitor", "The flag to show particle positions", "ex2.c", options->positions_monitor, &options->positions_monitor, NULL)); 2169072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-poisson_monitor", "The flag to show charges, Efield and potential solve", "ex2.c", options->poisson_monitor, &options->poisson_monitor, NULL)); 2178214e71cSJoe PetscCall(PetscOptionsBool("-twostream", "Run two stream instability", "ex2.c", options->twostream, &options->twostream, NULL)); 2188214e71cSJoe PetscCall(PetscOptionsBool("-perturbed_weights", "Flag to run uniform sampling with perturbed weights", "ex2.c", options->perturbed_weights, &options->perturbed_weights, NULL)); 2198214e71cSJoe PetscCall(PetscOptionsBool("-check_weights", "Ensure all particle weights are positive", "ex2.c", options->checkweights, &options->checkweights, NULL)); 2208214e71cSJoe PetscCall(PetscOptionsInt("-check_vel_res", "Check particle velocity residuals for nightly tests", "ex2.c", options->checkVRes, &options->checkVRes, NULL)); 2218214e71cSJoe PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", "ex2.c", options->ostep, &options->ostep, NULL)); 2228214e71cSJoe PetscCall(PetscOptionsReal("-timeScale", "Nondimensionalizing time scale", "ex2.c", options->timeScale, &options->timeScale, NULL)); 2238214e71cSJoe PetscCall(PetscOptionsReal("-initial_velocity", "Initial velocity of perturbed particle", "ex2.c", options->initVel, &options->initVel, NULL)); 2248214e71cSJoe PetscCall(PetscOptionsReal("-total_weight", "Total weight of all particles", "ex2.c", options->totalWeight, &options->totalWeight, NULL)); 2258214e71cSJoe PetscCall(PetscOptionsRealArray("-cosine_coefficients", "Amplitude and frequency of cosine equation used in initialization", "ex2.c", options->cosine_coefficients, &d, NULL)); 2268214e71cSJoe PetscCall(PetscOptionsRealArray("-charges", "Species charges", "ex2.c", options->charges, &maxSpecies, NULL)); 2278214e71cSJoe PetscCall(PetscOptionsEnum("-em_type", "Type of electrostatic solver", "ex2.c", EMTypes, (PetscEnum)options->em, (PetscEnum *)&options->em, NULL)); 228d0609cedSBarry Smith PetscOptionsEnd(); 22984467f86SMatthew G. Knepley 23084467f86SMatthew G. Knepley PetscCall(PetscLogEventRegister("RhsX", TS_CLASSID, &options->RhsXEvent)); 23184467f86SMatthew G. Knepley PetscCall(PetscLogEventRegister("RhsV", TS_CLASSID, &options->RhsVEvent)); 23284467f86SMatthew G. Knepley PetscCall(PetscLogEventRegister("ESolve", TS_CLASSID, &options->ESolveEvent)); 23384467f86SMatthew G. Knepley PetscCall(PetscLogEventRegister("ETab", TS_CLASSID, &options->ETabEvent)); 2343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 235b80bf5b1SJoe Pusztay } 236b80bf5b1SJoe Pusztay 2378214e71cSJoe static PetscErrorCode SetupContext(DM dm, DM sw, AppCtx *user) 2388214e71cSJoe { 239b02f317dSMatthew G. Knepley MPI_Comm comm; 240b02f317dSMatthew G. Knepley 2418214e71cSJoe PetscFunctionBeginUser; 242b02f317dSMatthew G. Knepley PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2438214e71cSJoe if (user->efield_monitor) { 24475155f48SMatthew G. Knepley PetscDraw draw; 24575155f48SMatthew G. Knepley PetscDrawAxis axis; 24675155f48SMatthew G. Knepley 247b02f317dSMatthew G. Knepley PetscCall(PetscDrawCreate(comm, NULL, "Max Electric Field", 0, 300, 400, 300, &draw)); 24875155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(draw, "ex9_Efield")); 24975155f48SMatthew G. Knepley PetscCall(PetscDrawSetFromOptions(draw)); 25075155f48SMatthew G. Knepley PetscCall(PetscDrawLGCreate(draw, 1, &user->drawlgE)); 25175155f48SMatthew G. Knepley PetscCall(PetscDrawDestroy(&draw)); 25275155f48SMatthew G. Knepley PetscCall(PetscDrawLGGetAxis(user->drawlgE, &axis)); 25375155f48SMatthew G. Knepley PetscCall(PetscDrawAxisSetLabels(axis, "Electron Electric Field", "time", "E_max")); 25475155f48SMatthew G. Knepley PetscCall(PetscDrawLGSetLimits(user->drawlgE, 0., user->steps * user->stepSize, user->drawlgEmin, 0.)); 2558214e71cSJoe } 256b02f317dSMatthew G. Knepley 2578214e71cSJoe if (user->initial_monitor) { 258b02f317dSMatthew G. Knepley PetscDrawAxis axis1, axis2; 2598214e71cSJoe PetscReal dmboxlower[2], dmboxupper[2]; 2608214e71cSJoe PetscInt dim, cStart, cEnd; 261b02f317dSMatthew G. Knepley 2628214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 2638214e71cSJoe PetscCall(DMGetBoundingBox(dm, dmboxlower, dmboxupper)); 2648214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2658214e71cSJoe 266b02f317dSMatthew G. Knepley PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_x", 0, 300, 400, 300, &user->drawic_x)); 26775155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(user->drawic_x, "ex9_ic_x")); 2688214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->drawic_x)); 2696497c311SBarry Smith PetscCall(PetscDrawHGCreate(user->drawic_x, (int)dim, &user->drawhgic_x)); 270b02f317dSMatthew G. Knepley PetscCall(PetscDrawHGCalcStats(user->drawhgic_x, PETSC_TRUE)); 2718214e71cSJoe PetscCall(PetscDrawHGGetAxis(user->drawhgic_x, &axis1)); 2726497c311SBarry Smith PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_x, (int)(cEnd - cStart))); 2738214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis1, "Initial X Distribution", "X", "counts")); 274b02f317dSMatthew G. Knepley PetscCall(PetscDrawAxisSetLimits(axis1, dmboxlower[0], dmboxupper[0], 0, 0)); 2758214e71cSJoe 276b02f317dSMatthew G. Knepley PetscCall(PetscDrawCreate(comm, NULL, "monitor_initial_conditions_v", 400, 300, 400, 300, &user->drawic_v)); 27775155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(user->drawic_v, "ex9_ic_v")); 2788214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->drawic_v)); 2796497c311SBarry Smith PetscCall(PetscDrawHGCreate(user->drawic_v, (int)dim, &user->drawhgic_v)); 280b02f317dSMatthew G. Knepley PetscCall(PetscDrawHGCalcStats(user->drawhgic_v, PETSC_TRUE)); 2818214e71cSJoe PetscCall(PetscDrawHGGetAxis(user->drawhgic_v, &axis2)); 282b02f317dSMatthew G. Knepley PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_v, 21)); 2838214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis2, "Initial V_x Distribution", "V", "counts")); 284b02f317dSMatthew G. Knepley PetscCall(PetscDrawAxisSetLimits(axis2, -6, 6, 0, 0)); 2858214e71cSJoe } 286b02f317dSMatthew G. Knepley 2879072cb8bSMatthew G. Knepley if (user->positions_monitor) { 28875155f48SMatthew G. Knepley PetscDraw draw; 2898214e71cSJoe PetscDrawAxis axis; 2908214e71cSJoe 291b02f317dSMatthew G. Knepley PetscCall(PetscDrawCreate(comm, NULL, "Particle Position", 0, 0, 400, 300, &draw)); 29275155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(draw, "ex9_pos")); 29375155f48SMatthew G. Knepley PetscCall(PetscDrawSetFromOptions(draw)); 29475155f48SMatthew G. Knepley PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspX)); 29575155f48SMatthew G. Knepley PetscCall(PetscDrawDestroy(&draw)); 29675155f48SMatthew G. Knepley PetscCall(PetscDrawSPSetDimension(user->drawspX, 1)); 29775155f48SMatthew G. Knepley PetscCall(PetscDrawSPGetAxis(user->drawspX, &axis)); 2988214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "v")); 29975155f48SMatthew G. Knepley PetscCall(PetscDrawSPReset(user->drawspX)); 3008214e71cSJoe } 3018214e71cSJoe if (user->poisson_monitor) { 302b02f317dSMatthew G. Knepley Vec rho, rhohat, phi; 30375155f48SMatthew G. Knepley PetscDraw draw; 30475155f48SMatthew G. Knepley PetscDrawAxis axis; 3058214e71cSJoe 306b02f317dSMatthew G. Knepley PetscCall(PetscDrawCreate(comm, NULL, "Electric_Field", 0, 0, 400, 300, &draw)); 30775155f48SMatthew G. Knepley PetscCall(PetscDrawSetFromOptions(draw)); 30875155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(draw, "ex9_E_spatial")); 30975155f48SMatthew G. Knepley PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspE)); 31075155f48SMatthew G. Knepley PetscCall(PetscDrawDestroy(&draw)); 31175155f48SMatthew G. Knepley PetscCall(PetscDrawSPSetDimension(user->drawspE, 1)); 31275155f48SMatthew G. Knepley PetscCall(PetscDrawSPGetAxis(user->drawspE, &axis)); 31375155f48SMatthew G. Knepley PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "E")); 31475155f48SMatthew G. Knepley PetscCall(PetscDrawSPReset(user->drawspE)); 3158214e71cSJoe 316b02f317dSMatthew G. Knepley PetscCall(PetscViewerDrawOpen(comm, NULL, "Charge Density", 0, 0, 400, 300, &user->viewerRho)); 31775155f48SMatthew G. Knepley PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerRho, "rho_")); 31875155f48SMatthew G. Knepley PetscCall(PetscViewerDrawGetDraw(user->viewerRho, 0, &draw)); 31975155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(draw, "ex9_rho_spatial")); 32075155f48SMatthew G. Knepley PetscCall(PetscViewerSetFromOptions(user->viewerRho)); 3214a0cbf56SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho)); 32275155f48SMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)rho, "charge_density")); 3234a0cbf56SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho)); 3248214e71cSJoe 325b02f317dSMatthew G. Knepley PetscInt dim, N; 326b02f317dSMatthew G. Knepley 327b02f317dSMatthew G. Knepley PetscCall(DMGetDimension(user->dmPot, &dim)); 328b02f317dSMatthew G. Knepley if (dim == 1) { 329b02f317dSMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat)); 330b02f317dSMatthew G. Knepley PetscCall(VecGetSize(rhohat, &N)); 331b02f317dSMatthew G. Knepley PetscCall(MatCreateFFT(comm, dim, &N, MATFFTW, &user->fftPot)); 332b02f317dSMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat)); 333b02f317dSMatthew G. Knepley } 334b02f317dSMatthew G. Knepley 335b02f317dSMatthew G. Knepley PetscCall(PetscViewerDrawOpen(comm, NULL, "Charge Density FT", 0, 0, 400, 300, &user->viewerRhoHat)); 336b02f317dSMatthew G. Knepley PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerRhoHat, "rhohat_")); 337b02f317dSMatthew G. Knepley PetscCall(PetscViewerDrawGetDraw(user->viewerRhoHat, 0, &draw)); 338b02f317dSMatthew G. Knepley PetscCall(PetscDrawSetSave(draw, "ex9_rho_ft")); 339b02f317dSMatthew G. Knepley PetscCall(PetscViewerSetFromOptions(user->viewerRhoHat)); 340b02f317dSMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat)); 341b02f317dSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)rhohat, "charge_density_ft")); 342b02f317dSMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat)); 343b02f317dSMatthew G. Knepley 344b02f317dSMatthew G. Knepley PetscCall(PetscViewerDrawOpen(comm, NULL, "Potential", 400, 0, 400, 300, &user->viewerPhi)); 34575155f48SMatthew G. Knepley PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerPhi, "phi_")); 34675155f48SMatthew G. Knepley PetscCall(PetscViewerDrawGetDraw(user->viewerPhi, 0, &draw)); 34775155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(draw, "ex9_phi_spatial")); 34875155f48SMatthew G. Knepley PetscCall(PetscViewerSetFromOptions(user->viewerPhi)); 3494a0cbf56SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi)); 35075155f48SMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)phi, "potential")); 3514a0cbf56SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi)); 3528214e71cSJoe } 3538214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 3548214e71cSJoe } 3558214e71cSJoe 3568214e71cSJoe static PetscErrorCode DestroyContext(AppCtx *user) 3578214e71cSJoe { 3588214e71cSJoe PetscFunctionBeginUser; 3598214e71cSJoe PetscCall(PetscDrawHGDestroy(&user->drawhgic_x)); 3608214e71cSJoe PetscCall(PetscDrawDestroy(&user->drawic_x)); 3618214e71cSJoe PetscCall(PetscDrawHGDestroy(&user->drawhgic_v)); 3628214e71cSJoe PetscCall(PetscDrawDestroy(&user->drawic_v)); 3638214e71cSJoe 36475155f48SMatthew G. Knepley PetscCall(PetscDrawLGDestroy(&user->drawlgE)); 36575155f48SMatthew G. Knepley PetscCall(PetscDrawSPDestroy(&user->drawspE)); 36675155f48SMatthew G. Knepley PetscCall(PetscDrawSPDestroy(&user->drawspX)); 36775155f48SMatthew G. Knepley PetscCall(PetscViewerDestroy(&user->viewerRho)); 368b02f317dSMatthew G. Knepley PetscCall(PetscViewerDestroy(&user->viewerRhoHat)); 369b02f317dSMatthew G. Knepley PetscCall(MatDestroy(&user->fftPot)); 37075155f48SMatthew G. Knepley PetscCall(PetscViewerDestroy(&user->viewerPhi)); 3718214e71cSJoe 3728214e71cSJoe PetscCall(PetscBagDestroy(&user->bag)); 3738214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 3748214e71cSJoe } 3758214e71cSJoe 3768214e71cSJoe static PetscErrorCode CheckNonNegativeWeights(DM sw, AppCtx *user) 3778214e71cSJoe { 3788214e71cSJoe const PetscScalar *w; 3798214e71cSJoe PetscInt Np; 3808214e71cSJoe 3818214e71cSJoe PetscFunctionBeginUser; 3828214e71cSJoe if (!user->checkweights) PetscFunctionReturn(PETSC_SUCCESS); 3838214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w)); 3848214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 3858214e71cSJoe 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]); 3868214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w)); 3878214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 3888214e71cSJoe } 3898214e71cSJoe 3909072cb8bSMatthew G. Knepley static PetscErrorCode computeVelocityFEMMoments(DM sw, PetscReal moments[], AppCtx *user) 3918214e71cSJoe { 3929072cb8bSMatthew G. Knepley DMSwarmCellDM celldm; 393f1e6e573SMatthew G. Knepley DM vdm; 394f1e6e573SMatthew G. Knepley Vec u[1]; 395f1e6e573SMatthew G. Knepley const char *fields[1] = {"w_q"}; 3968214e71cSJoe 397f1e6e573SMatthew G. Knepley PetscFunctionBegin; 3989072cb8bSMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(sw, "velocity")); 3999072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 4009072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMGetDM(celldm, &vdm)); 401f1e6e573SMatthew G. Knepley PetscCall(DMGetGlobalVector(vdm, &u[0])); 402f1e6e573SMatthew G. Knepley PetscCall(DMSwarmProjectFields(sw, vdm, 1, fields, u, SCATTER_FORWARD)); 403f1e6e573SMatthew G. Knepley PetscCall(DMPlexComputeMoments(vdm, u[0], moments)); 404f1e6e573SMatthew G. Knepley PetscCall(DMRestoreGlobalVector(vdm, &u[0])); 4059072cb8bSMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(sw, "space")); 4068214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 4078214e71cSJoe } 4088214e71cSJoe 4098214e71cSJoe static PetscErrorCode MonitorEField(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 4108214e71cSJoe { 4118214e71cSJoe AppCtx *user = (AppCtx *)ctx; 412f1e6e573SMatthew G. Knepley DM sw; 413f1e6e573SMatthew G. Knepley PetscReal *E, *x, *weight; 414f1e6e573SMatthew G. Knepley PetscReal Enorm = 0., lgEnorm, lgEmax, sum = 0., Emax = 0., chargesum = 0.; 415f1e6e573SMatthew G. Knepley PetscReal pmoments[4]; /* \int f, \int v f, \int v^2 f */ 416f1e6e573SMatthew G. Knepley PetscInt *species, dim, Np; 4178214e71cSJoe 4188214e71cSJoe PetscFunctionBeginUser; 4199072cb8bSMatthew G. Knepley if (step < 0 || !user->validE) PetscFunctionReturn(PETSC_SUCCESS); 4208214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 4218214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 4228214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 4238214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 4248214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 4258214e71cSJoe PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 4268214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 4278214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 4288214e71cSJoe 429f1e6e573SMatthew G. Knepley for (PetscInt p = 0; p < Np; ++p) { 430f1e6e573SMatthew G. Knepley for (PetscInt d = 0; d < 1; ++d) { 431f1e6e573SMatthew G. Knepley PetscReal temp = PetscAbsReal(E[p * dim + d]); 4328214e71cSJoe if (temp > Emax) Emax = temp; 4338214e71cSJoe } 4348214e71cSJoe Enorm += PetscSqrtReal(E[p * dim] * E[p * dim]); 4358214e71cSJoe sum += E[p * dim]; 4368214e71cSJoe chargesum += user->charges[0] * weight[p]; 4378214e71cSJoe } 4388214e71cSJoe lgEnorm = Enorm != 0 ? PetscLog10Real(Enorm) : -16.; 43975155f48SMatthew G. Knepley lgEmax = Emax != 0 ? PetscLog10Real(Emax) : user->drawlgEmin; 4408214e71cSJoe 4418214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 4428214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 4438214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 4448214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 44575155f48SMatthew G. Knepley PetscCall(PetscDrawLGAddPoint(user->drawlgE, &t, &lgEmax)); 44675155f48SMatthew G. Knepley PetscCall(PetscDrawLGDraw(user->drawlgE)); 44775155f48SMatthew G. Knepley PetscDraw draw; 44875155f48SMatthew G. Knepley PetscCall(PetscDrawLGGetDraw(user->drawlgE, &draw)); 44975155f48SMatthew G. Knepley PetscCall(PetscDrawSave(draw)); 450f1e6e573SMatthew G. Knepley 451f1e6e573SMatthew G. Knepley PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments)); 45275155f48SMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%f\t%+e\t%e\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n", (double)t, (double)sum, (double)Enorm, (double)lgEnorm, (double)Emax, (double)lgEmax, (double)chargesum, (double)pmoments[0], (double)pmoments[1], (double)pmoments[1 + dim])); 45375155f48SMatthew G. Knepley PetscCall(DMViewFromOptions(sw, NULL, "-sw_efield_view")); 454f1e6e573SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 455f1e6e573SMatthew G. Knepley } 456f1e6e573SMatthew G. Knepley 457f1e6e573SMatthew G. Knepley static PetscErrorCode MonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 458f1e6e573SMatthew G. Knepley { 459f1e6e573SMatthew G. Knepley AppCtx *user = (AppCtx *)ctx; 460f1e6e573SMatthew G. Knepley DM sw; 461f1e6e573SMatthew G. Knepley PetscReal pmoments[4], fmoments[4]; /* \int f, \int v f, \int v^2 f */ 462f1e6e573SMatthew G. Knepley 463f1e6e573SMatthew G. Knepley PetscFunctionBeginUser; 464f1e6e573SMatthew G. Knepley if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); 465f1e6e573SMatthew G. Knepley PetscCall(TSGetDM(ts, &sw)); 466f1e6e573SMatthew G. Knepley 467f1e6e573SMatthew G. Knepley PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments)); 468f1e6e573SMatthew G. Knepley PetscCall(computeVelocityFEMMoments(sw, fmoments, user)); 469f1e6e573SMatthew G. Knepley 470f1e6e573SMatthew 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])); 4718214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 4728214e71cSJoe } 4738214e71cSJoe 4748214e71cSJoe PetscErrorCode MonitorInitialConditions(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 4758214e71cSJoe { 4768214e71cSJoe AppCtx *user = (AppCtx *)ctx; 477b02f317dSMatthew G. Knepley DM sw; 4788214e71cSJoe const PetscScalar *u; 4798214e71cSJoe PetscReal *weight, *pos, *vel; 480b02f317dSMatthew G. Knepley PetscInt dim, Np; 4818214e71cSJoe 4828214e71cSJoe PetscFunctionBegin; 4838214e71cSJoe if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */ 484b02f317dSMatthew G. Knepley if (step == 0) { 4858214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 4868214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 4878214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 4888214e71cSJoe 4898214e71cSJoe PetscCall(PetscDrawHGReset(user->drawhgic_x)); 4908214e71cSJoe PetscCall(PetscDrawHGGetDraw(user->drawhgic_x, &user->drawic_x)); 4918214e71cSJoe PetscCall(PetscDrawClear(user->drawic_x)); 4928214e71cSJoe PetscCall(PetscDrawFlush(user->drawic_x)); 4938214e71cSJoe 4948214e71cSJoe PetscCall(PetscDrawHGReset(user->drawhgic_v)); 4958214e71cSJoe PetscCall(PetscDrawHGGetDraw(user->drawhgic_v, &user->drawic_v)); 4968214e71cSJoe PetscCall(PetscDrawClear(user->drawic_v)); 4978214e71cSJoe PetscCall(PetscDrawFlush(user->drawic_v)); 4988214e71cSJoe 4998214e71cSJoe PetscCall(VecGetArrayRead(U, &u)); 500b02f317dSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos)); 5018214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel)); 5028214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 503b02f317dSMatthew G. Knepley for (PetscInt p = 0; p < Np; ++p) { 504b02f317dSMatthew G. Knepley PetscCall(PetscDrawHGAddWeightedValue(user->drawhgic_x, pos[p * dim], weight[p])); 505b02f317dSMatthew G. Knepley PetscCall(PetscDrawHGAddWeightedValue(user->drawhgic_v, vel[p * dim], weight[p])); 5068214e71cSJoe } 5078214e71cSJoe PetscCall(VecRestoreArrayRead(U, &u)); 5088214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos)); 5098214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel)); 5108214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 511b02f317dSMatthew G. Knepley 512b02f317dSMatthew G. Knepley PetscCall(PetscDrawHGDraw(user->drawhgic_x)); 513b02f317dSMatthew G. Knepley PetscCall(PetscDrawHGSave(user->drawhgic_x)); 514b02f317dSMatthew G. Knepley PetscCall(PetscDrawHGDraw(user->drawhgic_v)); 515b02f317dSMatthew G. Knepley PetscCall(PetscDrawHGSave(user->drawhgic_v)); 5168214e71cSJoe } 5178214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 5188214e71cSJoe } 5198214e71cSJoe 5208214e71cSJoe static PetscErrorCode MonitorPositions_2D(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 5218214e71cSJoe { 5228214e71cSJoe AppCtx *user = (AppCtx *)ctx; 5238214e71cSJoe DM dm, sw; 5248214e71cSJoe PetscScalar *x, *v, *weight; 5258214e71cSJoe PetscReal lower[3], upper[3], speed; 5268214e71cSJoe const PetscInt *s; 5278214e71cSJoe PetscInt dim, cStart, cEnd, c; 5288214e71cSJoe 5298214e71cSJoe PetscFunctionBeginUser; 5308214e71cSJoe if (step > 0 && step % user->ostep == 0) { 5318214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 5328214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 5338214e71cSJoe PetscCall(DMGetDimension(dm, &dim)); 5348214e71cSJoe PetscCall(DMGetBoundingBox(dm, lower, upper)); 5358214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 5368214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 5378214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v)); 5388214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 5398214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&s)); 5408214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 54175155f48SMatthew G. Knepley PetscCall(PetscDrawSPReset(user->drawspX)); 54275155f48SMatthew G. Knepley PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], lower[1], upper[1])); 54375155f48SMatthew G. Knepley PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], -12, 12)); 5448214e71cSJoe for (c = 0; c < cEnd - cStart; ++c) { 5458214e71cSJoe PetscInt *pidx, Npc, q; 5468214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 5478214e71cSJoe for (q = 0; q < Npc; ++q) { 5488214e71cSJoe const PetscInt p = pidx[q]; 5498214e71cSJoe if (s[p] == 0) { 5509072cb8bSMatthew G. Knepley speed = 0.; 5519072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) speed += PetscSqr(v[p * dim + d]); 5529072cb8bSMatthew G. Knepley speed = PetscSqrtReal(speed); 553045208b8SMatthew G. Knepley if (dim == 1) { 55475155f48SMatthew G. Knepley PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &v[p * dim], &speed)); 5558214e71cSJoe } else { 55675155f48SMatthew G. Knepley PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &x[p * dim + 1], &speed)); 5578214e71cSJoe } 5588214e71cSJoe } else if (s[p] == 1) { 55975155f48SMatthew G. Knepley PetscCall(PetscDrawSPAddPoint(user->drawspX, &x[p * dim], &v[p * dim])); 5608214e71cSJoe } 5618214e71cSJoe } 56284467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx)); 5638214e71cSJoe } 56475155f48SMatthew G. Knepley PetscCall(PetscDrawSPDraw(user->drawspX, PETSC_TRUE)); 56575155f48SMatthew G. Knepley PetscDraw draw; 56675155f48SMatthew G. Knepley PetscCall(PetscDrawSPGetDraw(user->drawspX, &draw)); 56775155f48SMatthew G. Knepley PetscCall(PetscDrawSave(draw)); 5688214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 5698214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 5708214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 5718214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v)); 5728214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&s)); 5738214e71cSJoe } 5748214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 5758214e71cSJoe } 5768214e71cSJoe 5778214e71cSJoe static PetscErrorCode MonitorPoisson(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 5788214e71cSJoe { 5798214e71cSJoe AppCtx *user = (AppCtx *)ctx; 5808214e71cSJoe DM dm, sw; 5818214e71cSJoe 5828214e71cSJoe PetscFunctionBeginUser; 5838214e71cSJoe if (step > 0 && step % user->ostep == 0) { 5848214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 5858214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 5869072cb8bSMatthew G. Knepley 5879072cb8bSMatthew G. Knepley if (user->validE) { 5889072cb8bSMatthew G. Knepley PetscScalar *x, *E, *weight; 5899072cb8bSMatthew G. Knepley PetscReal lower[3], upper[3], xval; 5909072cb8bSMatthew G. Knepley PetscDraw draw; 5919072cb8bSMatthew G. Knepley PetscInt dim, cStart, cEnd; 5929072cb8bSMatthew G. Knepley 5938214e71cSJoe PetscCall(DMGetDimension(dm, &dim)); 5948214e71cSJoe PetscCall(DMGetBoundingBox(dm, lower, upper)); 5958214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 5968214e71cSJoe 59775155f48SMatthew G. Knepley PetscCall(PetscDrawSPReset(user->drawspE)); 5988214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 5998214e71cSJoe PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 6008214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 6018214e71cSJoe 6028214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 6039072cb8bSMatthew G. Knepley for (PetscInt c = 0; c < cEnd - cStart; ++c) { 60475155f48SMatthew G. Knepley PetscReal Eavg = 0.0; 6059072cb8bSMatthew G. Knepley PetscInt *pidx, Npc; 6069072cb8bSMatthew G. Knepley 6078214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 6089072cb8bSMatthew G. Knepley for (PetscInt q = 0; q < Npc; ++q) { 6098214e71cSJoe const PetscInt p = pidx[q]; 61075155f48SMatthew G. Knepley Eavg += E[p * dim]; 6118214e71cSJoe } 61275155f48SMatthew G. Knepley Eavg /= Npc; 6138214e71cSJoe xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart)); 61475155f48SMatthew G. Knepley PetscCall(PetscDrawSPAddPoint(user->drawspE, &xval, &Eavg)); 61584467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx)); 6168214e71cSJoe } 61775155f48SMatthew G. Knepley PetscCall(PetscDrawSPDraw(user->drawspE, PETSC_TRUE)); 61875155f48SMatthew G. Knepley PetscCall(PetscDrawSPGetDraw(user->drawspE, &draw)); 61975155f48SMatthew G. Knepley PetscCall(PetscDrawSave(draw)); 6208214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 6218214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 6228214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 6238214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 6249072cb8bSMatthew G. Knepley } 62575155f48SMatthew G. Knepley 626b02f317dSMatthew G. Knepley Vec rho, rhohat, phi; 62775155f48SMatthew G. Knepley 6284a0cbf56SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho)); 62975155f48SMatthew G. Knepley PetscCall(VecView(rho, user->viewerRho)); 6304a0cbf56SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho)); 63175155f48SMatthew G. Knepley 632b02f317dSMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(user->dmPot, "rhohat", &rhohat)); 633b02f317dSMatthew G. Knepley PetscCall(MatMult(user->fftPot, rho, rhohat)); 634b02f317dSMatthew G. Knepley PetscCall(VecView(rhohat, user->viewerRhoHat)); 635b02f317dSMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rhohat", &rhohat)); 636b02f317dSMatthew G. Knepley 6374a0cbf56SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi)); 63875155f48SMatthew G. Knepley PetscCall(VecView(phi, user->viewerPhi)); 6394a0cbf56SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi)); 6408214e71cSJoe } 6418214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 6428214e71cSJoe } 6438214e71cSJoe 6448214e71cSJoe static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx) 6458214e71cSJoe { 6468214e71cSJoe PetscBag bag; 6478214e71cSJoe Parameter *p; 6488214e71cSJoe 6498214e71cSJoe PetscFunctionBeginUser; 6508214e71cSJoe /* setup PETSc parameter bag */ 6518214e71cSJoe PetscCall(PetscBagGetData(ctx->bag, (void **)&p)); 6528214e71cSJoe PetscCall(PetscBagSetName(ctx->bag, "par", "Vlasov-Poisson Parameters")); 6538214e71cSJoe bag = ctx->bag; 6548214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "v0", "Velocity scale, m/s")); 6558214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->t0, 1.0, "t0", "Time scale, s")); 6568214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->x0, 1.0, "x0", "Space scale, m")); 6578214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "phi0", "Potential scale, kg*m^2/A*s^3")); 6588214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->q0, 1.0, "q0", "Charge Scale, A*s")); 6598214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->m0, 1.0, "m0", "Mass Scale, kg")); 6608214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->epsi0, 1.0, "epsi0", "Permittivity of Free Space, kg")); 6618214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->kb, 1.0, "kb", "Boltzmann Constant, m^2 kg/s^2 K^1")); 6628214e71cSJoe 6638214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->sigma, 1.0, "sigma", "Charge per unit area, C/m^3")); 6648214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->poissonNumber, 1.0, "poissonNumber", "Non-Dimensional Poisson Number")); 6658214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->vlasovNumber, 1.0, "vlasovNumber", "Non-Dimensional Vlasov Number")); 6668214e71cSJoe PetscCall(PetscBagSetFromOptions(bag)); 6678214e71cSJoe { 6688214e71cSJoe PetscViewer viewer; 6698214e71cSJoe PetscViewerFormat format; 6708214e71cSJoe PetscBool flg; 6718214e71cSJoe 672648c30bcSBarry Smith PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg)); 6738214e71cSJoe if (flg) { 6748214e71cSJoe PetscCall(PetscViewerPushFormat(viewer, format)); 6758214e71cSJoe PetscCall(PetscBagView(bag, viewer)); 6768214e71cSJoe PetscCall(PetscViewerFlush(viewer)); 6778214e71cSJoe PetscCall(PetscViewerPopFormat(viewer)); 6788214e71cSJoe PetscCall(PetscViewerDestroy(&viewer)); 6798214e71cSJoe } 6808214e71cSJoe } 6818214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 6828214e71cSJoe } 6838214e71cSJoe 6848214e71cSJoe static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm) 685d71ae5a4SJacob Faibussowitsch { 686b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 6879566063dSJacob Faibussowitsch PetscCall(DMCreate(comm, dm)); 6889566063dSJacob Faibussowitsch PetscCall(DMSetType(*dm, DMPLEX)); 6899566063dSJacob Faibussowitsch PetscCall(DMSetFromOptions(*dm)); 6909072cb8bSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)*dm, "space")); 6919566063dSJacob Faibussowitsch PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view")); 692f1e6e573SMatthew G. Knepley 693f1e6e573SMatthew G. Knepley // Cache the mesh geometry 694f1e6e573SMatthew G. Knepley DMField coordField; 695f1e6e573SMatthew G. Knepley IS cellIS; 696f1e6e573SMatthew G. Knepley PetscQuadrature quad; 697f1e6e573SMatthew G. Knepley PetscReal *wt, *pt; 698f1e6e573SMatthew G. Knepley PetscInt cdim, cStart, cEnd; 699f1e6e573SMatthew G. Knepley 700f1e6e573SMatthew G. Knepley PetscCall(DMGetCoordinateField(*dm, &coordField)); 701f1e6e573SMatthew G. Knepley PetscCheck(coordField, comm, PETSC_ERR_USER, "DM must have a coordinate field"); 702f1e6e573SMatthew G. Knepley PetscCall(DMGetCoordinateDim(*dm, &cdim)); 703f1e6e573SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd)); 704f1e6e573SMatthew G. Knepley PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cellIS)); 705f1e6e573SMatthew G. Knepley PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad)); 706f1e6e573SMatthew G. Knepley PetscCall(PetscMalloc1(1, &wt)); 707f1e6e573SMatthew G. Knepley PetscCall(PetscMalloc1(2, &pt)); 708f1e6e573SMatthew G. Knepley wt[0] = 1.; 709f1e6e573SMatthew G. Knepley pt[0] = -1.; 710f1e6e573SMatthew G. Knepley pt[1] = -1.; 711f1e6e573SMatthew G. Knepley PetscCall(PetscQuadratureSetData(quad, cdim, 1, 1, pt, wt)); 712*ac9d17c7SMatthew G. Knepley PetscCall(DMFieldCreateFEGeom(coordField, cellIS, quad, PETSC_FEGEOM_BASIC, &user->fegeom)); 713f1e6e573SMatthew G. Knepley PetscCall(PetscQuadratureDestroy(&quad)); 714f1e6e573SMatthew G. Knepley PetscCall(ISDestroy(&cellIS)); 7153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 716b80bf5b1SJoe Pusztay } 717b80bf5b1SJoe Pusztay 7188214e71cSJoe 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[]) 7198214e71cSJoe { 7208214e71cSJoe f0[0] = -constants[SIGMA]; 7218214e71cSJoe } 7228214e71cSJoe 723d71ae5a4SJacob 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[]) 724d71ae5a4SJacob Faibussowitsch { 725b80bf5b1SJoe Pusztay PetscInt d; 726ad540459SPierre Jolivet for (d = 0; d < dim; ++d) f1[d] = u_x[d]; 727b80bf5b1SJoe Pusztay } 728b80bf5b1SJoe Pusztay 7298214e71cSJoe 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[]) 730d71ae5a4SJacob Faibussowitsch { 731b80bf5b1SJoe Pusztay PetscInt d; 732ad540459SPierre Jolivet for (d = 0; d < dim; ++d) g3[d * dim + d] = 1.0; 733b80bf5b1SJoe Pusztay } 734b80bf5b1SJoe Pusztay 7358214e71cSJoe static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 736d71ae5a4SJacob Faibussowitsch { 7378214e71cSJoe *u = 0.0; 7388214e71cSJoe return PETSC_SUCCESS; 739b80bf5b1SJoe Pusztay } 740b80bf5b1SJoe Pusztay 741b80bf5b1SJoe Pusztay /* 7428214e71cSJoe / I -grad\ / q \ = /0\ 7438214e71cSJoe \-div 0 / \phi/ \f/ 744b80bf5b1SJoe Pusztay */ 7458214e71cSJoe 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[]) 746d71ae5a4SJacob Faibussowitsch { 7478214e71cSJoe for (PetscInt d = 0; d < dim; ++d) f0[d] += u[uOff[0] + d]; 7488214e71cSJoe } 7498214e71cSJoe 7508214e71cSJoe 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[]) 7518214e71cSJoe { 7528214e71cSJoe for (PetscInt d = 0; d < dim; ++d) f1[d * dim + d] = u[uOff[1]]; 7538214e71cSJoe } 7548214e71cSJoe 7558214e71cSJoe 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[]) 7568214e71cSJoe { 7578214e71cSJoe f0[0] += constants[SIGMA]; 7588214e71cSJoe for (PetscInt d = 0; d < dim; ++d) f0[0] += u_x[uOff_x[0] + d * dim + d]; 7598214e71cSJoe } 7608214e71cSJoe 7618214e71cSJoe /* Boundary residual. Dirichlet boundary for u means u_bdy=p*n */ 7628214e71cSJoe 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[]) 7638214e71cSJoe { 7648214e71cSJoe for (PetscInt d = 0; d < dim; ++d) g0[d * dim + d] = 1.0; 7658214e71cSJoe } 7668214e71cSJoe 7678214e71cSJoe 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[]) 7688214e71cSJoe { 7698214e71cSJoe for (PetscInt d = 0; d < dim; ++d) g2[d * dim + d] = 1.0; 7708214e71cSJoe } 7718214e71cSJoe 7728214e71cSJoe 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[]) 7738214e71cSJoe { 7748214e71cSJoe for (PetscInt d = 0; d < dim; ++d) g1[d * dim + d] = 1.0; 7758214e71cSJoe } 7768214e71cSJoe 7778214e71cSJoe static PetscErrorCode CreateFEM(DM dm, AppCtx *user) 7788214e71cSJoe { 7798214e71cSJoe PetscFE fephi, feq; 7808214e71cSJoe PetscDS ds; 7818214e71cSJoe PetscBool simplex; 7828214e71cSJoe PetscInt dim; 7838214e71cSJoe 7848214e71cSJoe PetscFunctionBeginUser; 7858214e71cSJoe PetscCall(DMGetDimension(dm, &dim)); 7868214e71cSJoe PetscCall(DMPlexIsSimplex(dm, &simplex)); 7878214e71cSJoe if (user->em == EM_MIXED) { 7888214e71cSJoe DMLabel label; 7898214e71cSJoe const PetscInt id = 1; 7908214e71cSJoe 7918214e71cSJoe PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "field_", PETSC_DETERMINE, &feq)); 7928214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)feq, "field")); 7938214e71cSJoe PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "potential_", PETSC_DETERMINE, &fephi)); 7948214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)fephi, "potential")); 7958214e71cSJoe PetscCall(PetscFECopyQuadrature(feq, fephi)); 7968214e71cSJoe PetscCall(DMSetField(dm, 0, NULL, (PetscObject)feq)); 7978214e71cSJoe PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fephi)); 7988214e71cSJoe PetscCall(DMCreateDS(dm)); 7998214e71cSJoe PetscCall(PetscFEDestroy(&fephi)); 8008214e71cSJoe PetscCall(PetscFEDestroy(&feq)); 8018214e71cSJoe 8028214e71cSJoe PetscCall(DMGetLabel(dm, "marker", &label)); 8038214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 8048214e71cSJoe 8058214e71cSJoe PetscCall(PetscDSSetResidual(ds, 0, f0_q, f1_q)); 8068214e71cSJoe PetscCall(PetscDSSetResidual(ds, 1, f0_phi_backgroundCharge, NULL)); 8078214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_qq, NULL, NULL, NULL)); 8088214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_qphi, NULL)); 8098214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_phiq, NULL, NULL)); 8108214e71cSJoe 8118214e71cSJoe PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void))zero, NULL, NULL, NULL)); 8128214e71cSJoe 813f1e6e573SMatthew G. Knepley } else { 8148214e71cSJoe MatNullSpace nullsp; 8158214e71cSJoe PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, PETSC_DETERMINE, &fephi)); 8168214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)fephi, "potential")); 8178214e71cSJoe PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fephi)); 8188214e71cSJoe PetscCall(DMCreateDS(dm)); 8198214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 8208214e71cSJoe PetscCall(PetscDSSetResidual(ds, 0, ion_f0, laplacian_f1)); 8218214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, laplacian_g3)); 8228214e71cSJoe PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullsp)); 8238214e71cSJoe PetscCall(PetscObjectCompose((PetscObject)fephi, "nullspace", (PetscObject)nullsp)); 8248214e71cSJoe PetscCall(MatNullSpaceDestroy(&nullsp)); 8258214e71cSJoe PetscCall(PetscFEDestroy(&fephi)); 8268214e71cSJoe } 8278214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 8288214e71cSJoe } 8298214e71cSJoe 8308214e71cSJoe static PetscErrorCode CreatePoisson(DM dm, AppCtx *user) 8318214e71cSJoe { 8328214e71cSJoe SNES snes; 8338214e71cSJoe Mat J; 8348214e71cSJoe MatNullSpace nullSpace; 8358214e71cSJoe 8368214e71cSJoe PetscFunctionBeginUser; 8378214e71cSJoe PetscCall(CreateFEM(dm, user)); 8388214e71cSJoe PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes)); 8398214e71cSJoe PetscCall(SNESSetOptionsPrefix(snes, "em_")); 8408214e71cSJoe PetscCall(SNESSetDM(snes, dm)); 8418214e71cSJoe PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, user)); 8428214e71cSJoe PetscCall(SNESSetFromOptions(snes)); 8438214e71cSJoe 8448214e71cSJoe PetscCall(DMCreateMatrix(dm, &J)); 8458214e71cSJoe PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullSpace)); 8468214e71cSJoe PetscCall(MatSetNullSpace(J, nullSpace)); 8478214e71cSJoe PetscCall(MatNullSpaceDestroy(&nullSpace)); 8488214e71cSJoe PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL)); 8498214e71cSJoe PetscCall(MatDestroy(&J)); 8504a0cbf56SMatthew G. Knepley if (user->em == EM_MIXED) { 8514a0cbf56SMatthew G. Knepley const PetscInt potential = 1; 8524a0cbf56SMatthew G. Knepley 8534a0cbf56SMatthew G. Knepley PetscCall(DMCreateSubDM(dm, 1, &potential, &user->isPot, &user->dmPot)); 8544a0cbf56SMatthew G. Knepley } else { 8554a0cbf56SMatthew G. Knepley user->dmPot = dm; 8564a0cbf56SMatthew G. Knepley PetscCall(PetscObjectReference((PetscObject)user->dmPot)); 8574a0cbf56SMatthew G. Knepley } 8584a0cbf56SMatthew G. Knepley PetscCall(DMCreateMassMatrix(user->dmPot, user->dmPot, &user->M)); 859f1e6e573SMatthew G. Knepley PetscCall(DMPlexCreateClosureIndex(dm, NULL)); 8608214e71cSJoe user->snes = snes; 8618214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 8628214e71cSJoe } 8638214e71cSJoe 8648214e71cSJoe PetscErrorCode PetscPDFPertubedConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 8658214e71cSJoe { 8668214e71cSJoe p[0] = (1 + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI); 8678214e71cSJoe p[1] = (1 + 0.01 * PetscCosReal(0.5 * x[1])) / (2 * PETSC_PI); 8688214e71cSJoe return PETSC_SUCCESS; 8698214e71cSJoe } 8708214e71cSJoe PetscErrorCode PetscPDFPertubedConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 8718214e71cSJoe { 8728214e71cSJoe p[0] = (1. + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI); 8738214e71cSJoe return PETSC_SUCCESS; 8748214e71cSJoe } 8758214e71cSJoe 8768214e71cSJoe PetscErrorCode PetscPDFCosine1D(const PetscReal x[], const PetscReal scale[], PetscReal p[]) 8778214e71cSJoe { 8788214e71cSJoe const PetscReal alpha = scale ? scale[0] : 0.0; 8798214e71cSJoe const PetscReal k = scale ? scale[1] : 1.; 8808214e71cSJoe p[0] = (1 + alpha * PetscCosReal(k * x[0])); 8818214e71cSJoe return PETSC_SUCCESS; 8828214e71cSJoe } 8838214e71cSJoe 8848214e71cSJoe PetscErrorCode PetscPDFCosine2D(const PetscReal x[], const PetscReal scale[], PetscReal p[]) 8858214e71cSJoe { 8868214e71cSJoe const PetscReal alpha = scale ? scale[0] : 0.; 8878214e71cSJoe const PetscReal k = scale ? scale[0] : 1.; 8888214e71cSJoe p[0] = (1 + alpha * PetscCosReal(k * (x[0] + x[1]))); 8898214e71cSJoe return PETSC_SUCCESS; 8908214e71cSJoe } 8918214e71cSJoe 89284467f86SMatthew G. Knepley static PetscErrorCode CreateVelocityDM(DM sw, DM *vdm) 8938214e71cSJoe { 894f1e6e573SMatthew G. Knepley PetscFE fe; 895f1e6e573SMatthew G. Knepley DMPolytopeType ct; 896f1e6e573SMatthew G. Knepley PetscInt dim, cStart; 897f1e6e573SMatthew G. Knepley const char *prefix = "v"; 898f1e6e573SMatthew G. Knepley 89984467f86SMatthew G. Knepley PetscFunctionBegin; 90084467f86SMatthew G. Knepley PetscCall(DMCreate(PETSC_COMM_SELF, vdm)); 90184467f86SMatthew G. Knepley PetscCall(DMSetType(*vdm, DMPLEX)); 902f1e6e573SMatthew G. Knepley PetscCall(DMPlexSetOptionsPrefix(*vdm, prefix)); 90384467f86SMatthew G. Knepley PetscCall(DMSetFromOptions(*vdm)); 9049072cb8bSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)*vdm, "velocity")); 90584467f86SMatthew G. Knepley PetscCall(DMViewFromOptions(*vdm, NULL, "-dm_view")); 906f1e6e573SMatthew G. Knepley 907f1e6e573SMatthew G. Knepley PetscCall(DMGetDimension(*vdm, &dim)); 908f1e6e573SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(*vdm, 0, &cStart, NULL)); 909f1e6e573SMatthew G. Knepley PetscCall(DMPlexGetCellType(*vdm, cStart, &ct)); 910f1e6e573SMatthew G. Knepley PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe)); 911f1e6e573SMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)fe, "distribution")); 912f1e6e573SMatthew G. Knepley PetscCall(DMSetField(*vdm, 0, NULL, (PetscObject)fe)); 913f1e6e573SMatthew G. Knepley PetscCall(DMCreateDS(*vdm)); 914f1e6e573SMatthew G. Knepley PetscCall(PetscFEDestroy(&fe)); 91584467f86SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 9168214e71cSJoe } 9178214e71cSJoe 9189072cb8bSMatthew G. Knepley /* 9199072cb8bSMatthew G. Knepley InitializeParticles_Centroid - Initialize a regular grid of particles. 9209072cb8bSMatthew G. Knepley 9219072cb8bSMatthew G. Knepley Input Parameters: 9229072cb8bSMatthew G. Knepley + sw - The `DMSWARM` 9239072cb8bSMatthew G. Knepley - force1D - Treat the spatial domain as 1D 9249072cb8bSMatthew G. Knepley 9259072cb8bSMatthew G. Knepley Notes: 9269072cb8bSMatthew G. Knepley This functions sets the species, cellid, spatial coordinate, and velocity fields for all particles. 9279072cb8bSMatthew G. Knepley 9289072cb8bSMatthew G. Knepley It places one particle in the centroid of each cell in the implicit tensor product of the spatial 9299072cb8bSMatthew G. Knepley and velocity meshes. 9309072cb8bSMatthew G. Knepley */ 931045208b8SMatthew G. Knepley static PetscErrorCode InitializeParticles_Centroid(DM sw) 9328214e71cSJoe { 93384467f86SMatthew G. Knepley DM_Swarm *swarm = (DM_Swarm *)sw->data; 9349072cb8bSMatthew G. Knepley DMSwarmCellDM celldm; 93584467f86SMatthew G. Knepley DM xdm, vdm; 93684467f86SMatthew G. Knepley PetscReal vmin[3], vmax[3]; 93784467f86SMatthew G. Knepley PetscReal *x, *v; 93884467f86SMatthew G. Knepley PetscInt *species, *cellid; 93984467f86SMatthew G. Knepley PetscInt dim, xcStart, xcEnd, vcStart, vcEnd, Ns, Np, Npc, debug; 9408214e71cSJoe PetscBool flg; 94184467f86SMatthew G. Knepley MPI_Comm comm; 9429072cb8bSMatthew G. Knepley const char *cellidname; 9438214e71cSJoe 9448214e71cSJoe PetscFunctionBegin; 94584467f86SMatthew G. Knepley PetscCall(PetscObjectGetComm((PetscObject)sw, &comm)); 94684467f86SMatthew G. Knepley 94784467f86SMatthew G. Knepley PetscOptionsBegin(comm, "", "DMSwarm Options", "DMSWARM"); 9488214e71cSJoe PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 9498214e71cSJoe PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg)); 9508214e71cSJoe if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns)); 95184467f86SMatthew G. Knepley PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_coords", "Debug output level for particle coordinate computations", "InitializeParticles", 0, &swarm->printCoords, NULL, 0)); 95284467f86SMatthew G. Knepley PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_weights", "Debug output level for particle weight computations", "InitializeWeights", 0, &swarm->printWeights, NULL, 0)); 9538214e71cSJoe PetscOptionsEnd(); 95484467f86SMatthew G. Knepley debug = swarm->printCoords; 9558214e71cSJoe 9568214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 95784467f86SMatthew G. Knepley PetscCall(DMSwarmGetCellDM(sw, &xdm)); 95884467f86SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd)); 9598214e71cSJoe 960045208b8SMatthew G. Knepley PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm)); 961045208b8SMatthew G. Knepley PetscCall(DMSwarmCellDMGetDM(celldm, &vdm)); 96284467f86SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd)); 9638214e71cSJoe 96484467f86SMatthew G. Knepley // One particle per centroid on the tensor product grid 96584467f86SMatthew G. Knepley Npc = (vcEnd - vcStart) * Ns; 96684467f86SMatthew G. Knepley Np = (xcEnd - xcStart) * Npc; 9678214e71cSJoe PetscCall(DMSwarmSetLocalSizes(sw, Np, 0)); 96884467f86SMatthew G. Knepley if (debug) { 96984467f86SMatthew G. Knepley PetscInt gNp; 97084467f86SMatthew G. Knepley PetscCallMPI(MPIU_Allreduce(&Np, &gNp, 1, MPIU_INT, MPIU_SUM, comm)); 97184467f86SMatthew G. Knepley PetscCall(PetscPrintf(comm, "Global Np = %" PetscInt_FMT "\n", gNp)); 9728214e71cSJoe } 9738214e71cSJoe 97484467f86SMatthew G. Knepley // Set species and cellid 9759072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 9769072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMGetCellID(celldm, &cellidname)); 97784467f86SMatthew G. Knepley PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 9789072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, cellidname, NULL, NULL, (void **)&cellid)); 97984467f86SMatthew G. Knepley for (PetscInt c = 0, p = 0; c < xcEnd - xcStart; ++c) { 98084467f86SMatthew G. Knepley for (PetscInt s = 0; s < Ns; ++s) { 98184467f86SMatthew G. Knepley for (PetscInt q = 0; q < Npc / Ns; ++q, ++p) { 98284467f86SMatthew G. Knepley species[p] = s; 98384467f86SMatthew G. Knepley cellid[p] = c; 98484467f86SMatthew G. Knepley } 98584467f86SMatthew G. Knepley } 98684467f86SMatthew G. Knepley } 98784467f86SMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 9889072cb8bSMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, cellidname, NULL, NULL, (void **)&cellid)); 98984467f86SMatthew G. Knepley 99084467f86SMatthew G. Knepley // Set particle coordinates 9918214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 9928214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v)); 9938214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 99484467f86SMatthew G. Knepley PetscCall(DMGetBoundingBox(vdm, vmin, vmax)); 99584467f86SMatthew G. Knepley PetscCall(DMGetCoordinatesLocalSetUp(xdm)); 99684467f86SMatthew G. Knepley for (PetscInt c = 0; c < xcEnd - xcStart; ++c) { 99784467f86SMatthew G. Knepley const PetscInt cell = c + xcStart; 9988214e71cSJoe PetscInt *pidx, Npc; 9998214e71cSJoe PetscReal centroid[3], volume; 10008214e71cSJoe 10018214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 100284467f86SMatthew G. Knepley PetscCall(DMPlexComputeCellGeometryFVM(xdm, cell, &volume, centroid, NULL)); 100384467f86SMatthew G. Knepley for (PetscInt s = 0; s < Ns; ++s) { 100484467f86SMatthew G. Knepley for (PetscInt q = 0; q < Npc / Ns; ++q) { 100584467f86SMatthew G. Knepley const PetscInt p = pidx[q * Ns + s]; 10068214e71cSJoe 100784467f86SMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) { 10088214e71cSJoe x[p * dim + d] = centroid[d]; 100984467f86SMatthew G. Knepley v[p * dim + d] = vmin[0] + (q + 0.5) * ((vmax[0] - vmin[0]) / (Npc / Ns)); 10108214e71cSJoe } 10119072cb8bSMatthew G. Knepley if (debug > 1) { 10129072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "Particle %4" PetscInt_FMT " ", p)); 10139072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, " x: (")); 10149072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) { 10159072cb8bSMatthew G. Knepley if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 10169072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", x[p * dim + d])); 10179072cb8bSMatthew G. Knepley } 10189072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, ") v:(")); 10199072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) { 10209072cb8bSMatthew G. Knepley if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 10219072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", v[p * dim + d])); 10229072cb8bSMatthew G. Knepley } 10239072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n")); 10249072cb8bSMatthew G. Knepley } 10258214e71cSJoe } 10268214e71cSJoe } 102784467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx)); 10288214e71cSJoe } 10298214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 10308214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 10318214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v)); 103284467f86SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 103384467f86SMatthew G. Knepley } 103484467f86SMatthew G. Knepley 103584467f86SMatthew G. Knepley /* 103684467f86SMatthew G. Knepley InitializeWeights - Compute weight for each local particle 103784467f86SMatthew G. Knepley 103884467f86SMatthew G. Knepley Input Parameters: 103984467f86SMatthew G. Knepley + sw - The `DMSwarm` 104084467f86SMatthew G. Knepley . totalWeight - The sum of all particle weights 104184467f86SMatthew G. Knepley . func - The PDF for the particle spatial distribution 104284467f86SMatthew G. Knepley - param - The PDF parameters 104384467f86SMatthew G. Knepley 104484467f86SMatthew G. Knepley Notes: 104584467f86SMatthew G. Knepley The PDF for velocity is assumed to be a Gaussian 104684467f86SMatthew G. Knepley 104784467f86SMatthew G. Knepley The particle weights are returned in the `w_q` field of `sw`. 104884467f86SMatthew G. Knepley */ 1049045208b8SMatthew G. Knepley static PetscErrorCode InitializeWeights(DM sw, PetscReal totalWeight, PetscProbFunc func, const PetscReal param[]) 105084467f86SMatthew G. Knepley { 105184467f86SMatthew G. Knepley DM xdm, vdm; 1052045208b8SMatthew G. Knepley DMSwarmCellDM celldm; 105384467f86SMatthew G. Knepley PetscScalar *weight; 105484467f86SMatthew G. Knepley PetscQuadrature xquad; 105584467f86SMatthew G. Knepley const PetscReal *xq, *xwq; 105684467f86SMatthew G. Knepley const PetscInt order = 5; 1057045208b8SMatthew G. Knepley PetscReal xi0[3]; 105884467f86SMatthew G. Knepley PetscReal xwtot = 0., pwtot = 0.; 105984467f86SMatthew G. Knepley PetscInt xNq; 106084467f86SMatthew G. Knepley PetscInt dim, Ns, xcStart, xcEnd, vcStart, vcEnd, debug = ((DM_Swarm *)sw->data)->printWeights; 106184467f86SMatthew G. Knepley MPI_Comm comm; 106284467f86SMatthew G. Knepley PetscMPIInt rank; 106384467f86SMatthew G. Knepley 106484467f86SMatthew G. Knepley PetscFunctionBegin; 106584467f86SMatthew G. Knepley PetscCall(PetscObjectGetComm((PetscObject)sw, &comm)); 106684467f86SMatthew G. Knepley PetscCallMPI(MPI_Comm_rank(comm, &rank)); 106784467f86SMatthew G. Knepley PetscCall(DMGetDimension(sw, &dim)); 106884467f86SMatthew G. Knepley PetscCall(DMSwarmGetCellDM(sw, &xdm)); 106984467f86SMatthew G. Knepley PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 107084467f86SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd)); 1071045208b8SMatthew G. Knepley PetscCall(DMSwarmGetCellDMByName(sw, "velocity", &celldm)); 1072045208b8SMatthew G. Knepley PetscCall(DMSwarmCellDMGetDM(celldm, &vdm)); 107384467f86SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd)); 107484467f86SMatthew G. Knepley 107584467f86SMatthew G. Knepley // Setup Quadrature for spatial and velocity weight calculations 1076045208b8SMatthew G. Knepley PetscCall(PetscDTGaussTensorQuadrature(dim, 1, order, -1.0, 1.0, &xquad)); 107784467f86SMatthew G. Knepley PetscCall(PetscQuadratureGetData(xquad, NULL, NULL, &xNq, &xq, &xwq)); 107884467f86SMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) xi0[d] = -1.0; 107984467f86SMatthew G. Knepley 108084467f86SMatthew G. Knepley // Integrate the density function to get the weights of particles in each cell 108184467f86SMatthew G. Knepley PetscCall(DMGetCoordinatesLocalSetUp(vdm)); 108284467f86SMatthew G. Knepley PetscCall(DMSwarmSortGetAccess(sw)); 108384467f86SMatthew G. Knepley PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 108484467f86SMatthew G. Knepley for (PetscInt c = xcStart; c < xcEnd; ++c) { 108584467f86SMatthew G. Knepley PetscReal xv0[3], xJ[9], xinvJ[9], xdetJ, xqr[3], xden, xw = 0.; 108684467f86SMatthew G. Knepley PetscInt *pidx, Npc; 108784467f86SMatthew G. Knepley PetscInt xNc; 108884467f86SMatthew G. Knepley const PetscScalar *xarray; 108984467f86SMatthew G. Knepley PetscScalar *xcoords = NULL; 109084467f86SMatthew G. Knepley PetscBool xisDG; 109184467f86SMatthew G. Knepley 109284467f86SMatthew G. Knepley PetscCall(DMPlexGetCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords)); 109384467f86SMatthew G. Knepley PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 109484467f86SMatthew 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); 109584467f86SMatthew G. Knepley PetscCall(DMPlexComputeCellGeometryFEM(xdm, c, NULL, xv0, xJ, xinvJ, &xdetJ)); 109684467f86SMatthew G. Knepley for (PetscInt q = 0; q < xNq; ++q) { 109784467f86SMatthew G. Knepley // Transform quadrature points from ref space to real space 1098045208b8SMatthew G. Knepley CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xq[q * dim], xqr); 109984467f86SMatthew G. Knepley // Get probability density at quad point 110084467f86SMatthew G. Knepley // No need to scale xqr since PDF will be periodic 110184467f86SMatthew G. Knepley PetscCall((*func)(xqr, param, &xden)); 110284467f86SMatthew G. Knepley xw += xden * (xwq[q] * xdetJ); 110384467f86SMatthew G. Knepley } 110484467f86SMatthew G. Knepley xwtot += xw; 110584467f86SMatthew G. Knepley if (debug) { 110684467f86SMatthew G. Knepley IS globalOrdering; 110784467f86SMatthew G. Knepley const PetscInt *ordering; 110884467f86SMatthew G. Knepley 110984467f86SMatthew G. Knepley PetscCall(DMPlexGetCellNumbering(xdm, &globalOrdering)); 111084467f86SMatthew G. Knepley PetscCall(ISGetIndices(globalOrdering, &ordering)); 111175155f48SMatthew 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)); 111284467f86SMatthew G. Knepley PetscCall(ISRestoreIndices(globalOrdering, &ordering)); 111384467f86SMatthew G. Knepley } 111484467f86SMatthew G. Knepley // Set weights to be Gaussian in velocity cells 111584467f86SMatthew G. Knepley for (PetscInt vc = vcStart; vc < vcEnd; ++vc) { 111684467f86SMatthew G. Knepley const PetscInt p = pidx[vc * Ns + 0]; 111784467f86SMatthew G. Knepley PetscReal vw = 0.; 111884467f86SMatthew G. Knepley PetscInt vNc; 111984467f86SMatthew G. Knepley const PetscScalar *varray; 112084467f86SMatthew G. Knepley PetscScalar *vcoords = NULL; 112184467f86SMatthew G. Knepley PetscBool visDG; 112284467f86SMatthew G. Knepley 112384467f86SMatthew G. Knepley PetscCall(DMPlexGetCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords)); 112484467f86SMatthew G. Knepley // TODO: Fix 2 stream Ask Joe 112584467f86SMatthew G. Knepley // Two stream function from 1/2pi v^2 e^(-v^2/2) 112684467f86SMatthew 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.))); 112784467f86SMatthew G. Knepley vw = 0.5 * (PetscErfReal(vcoords[1] / PetscSqrtReal(2.)) - PetscErfReal(vcoords[0] / PetscSqrtReal(2.))); 112884467f86SMatthew G. Knepley 112984467f86SMatthew G. Knepley weight[p] = totalWeight * vw * xw; 113084467f86SMatthew G. Knepley pwtot += weight[p]; 11319072cb8bSMatthew G. Knepley PetscCheck(weight[p] <= 10., PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Particle %" PetscInt_FMT " weight exceeeded 1: %g, %g, %g", p, xw, vw, totalWeight); 113284467f86SMatthew G. Knepley PetscCall(DMPlexRestoreCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords)); 113384467f86SMatthew G. Knepley if (debug > 1) PetscCall(PetscPrintf(comm, "particle %" PetscInt_FMT ": %g, vw: %g xw: %g\n", p, weight[p], vw, xw)); 113484467f86SMatthew G. Knepley } 113584467f86SMatthew G. Knepley PetscCall(DMPlexRestoreCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords)); 113684467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx)); 113784467f86SMatthew G. Knepley } 113884467f86SMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 113984467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestoreAccess(sw)); 114084467f86SMatthew G. Knepley PetscCall(PetscQuadratureDestroy(&xquad)); 114184467f86SMatthew G. Knepley 114284467f86SMatthew G. Knepley if (debug) { 114384467f86SMatthew G. Knepley PetscReal wtot[2] = {pwtot, xwtot}, gwtot[2]; 114484467f86SMatthew G. Knepley 114584467f86SMatthew G. Knepley PetscCall(PetscSynchronizedFlush(comm, NULL)); 114684467f86SMatthew G. Knepley PetscCallMPI(MPIU_Allreduce(wtot, gwtot, 2, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD)); 114784467f86SMatthew G. Knepley PetscCall(PetscPrintf(comm, "particle weight sum = %1.10f cell weight sum = %1.10f\n", (double)gwtot[0], (double)gwtot[1])); 114884467f86SMatthew G. Knepley } 114984467f86SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 115084467f86SMatthew G. Knepley } 115184467f86SMatthew G. Knepley 115284467f86SMatthew G. Knepley static PetscErrorCode InitializeParticles_PerturbedWeights(DM sw, AppCtx *user) 115384467f86SMatthew G. Knepley { 115484467f86SMatthew G. Knepley PetscReal scale[2] = {user->cosine_coefficients[0], user->cosine_coefficients[1]}; 115575155f48SMatthew G. Knepley PetscInt dim; 115684467f86SMatthew G. Knepley 115784467f86SMatthew G. Knepley PetscFunctionBegin; 115875155f48SMatthew G. Knepley PetscCall(DMGetDimension(sw, &dim)); 1159045208b8SMatthew G. Knepley PetscCall(InitializeParticles_Centroid(sw)); 1160045208b8SMatthew G. Knepley PetscCall(InitializeWeights(sw, user->totalWeight, dim == 1 ? PetscPDFCosine1D : PetscPDFCosine2D, scale)); 11618214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 11628214e71cSJoe } 11638214e71cSJoe 11648214e71cSJoe static PetscErrorCode InitializeConstants(DM sw, AppCtx *user) 11658214e71cSJoe { 11668214e71cSJoe DM dm; 11678214e71cSJoe PetscInt *species; 11688214e71cSJoe PetscReal *weight, totalCharge = 0., totalWeight = 0., gmin[3], gmax[3], global_charge, global_weight; 11698214e71cSJoe PetscInt Np, dim; 11708214e71cSJoe 11718214e71cSJoe PetscFunctionBegin; 11728214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 11738214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 11748214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 11758214e71cSJoe PetscCall(DMGetBoundingBox(dm, gmin, gmax)); 11768214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 11778214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 11788214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 11798214e71cSJoe totalWeight += weight[p]; 11808214e71cSJoe totalCharge += user->charges[species[p]] * weight[p]; 11818214e71cSJoe } 11828214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 11838214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 11848214e71cSJoe { 11858214e71cSJoe Parameter *param; 11868214e71cSJoe PetscReal Area; 11878214e71cSJoe 11888214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 11898214e71cSJoe switch (dim) { 11908214e71cSJoe case 1: 11918214e71cSJoe Area = (gmax[0] - gmin[0]); 11928214e71cSJoe break; 11938214e71cSJoe case 2: 11948214e71cSJoe Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]); 11958214e71cSJoe break; 11968214e71cSJoe case 3: 11978214e71cSJoe Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]) * (gmax[2] - gmin[2]); 11988214e71cSJoe break; 11998214e71cSJoe default: 12008214e71cSJoe SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", dim); 12018214e71cSJoe } 1202462c564dSBarry Smith PetscCallMPI(MPIU_Allreduce(&totalWeight, &global_weight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD)); 1203462c564dSBarry Smith PetscCallMPI(MPIU_Allreduce(&totalCharge, &global_charge, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD)); 12048214e71cSJoe 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)); 12058214e71cSJoe param->sigma = PetscAbsReal(global_charge / (Area)); 12068214e71cSJoe 12078214e71cSJoe PetscCall(PetscPrintf(PETSC_COMM_WORLD, "sigma: %g\n", (double)param->sigma)); 12088214e71cSJoe 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, 12098214e71cSJoe (double)param->vlasovNumber)); 12108214e71cSJoe } 12118214e71cSJoe /* Setup Constants */ 12128214e71cSJoe { 12138214e71cSJoe PetscDS ds; 12148214e71cSJoe Parameter *param; 12158214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 12168214e71cSJoe PetscScalar constants[NUM_CONSTANTS]; 12178214e71cSJoe constants[SIGMA] = param->sigma; 12188214e71cSJoe constants[V0] = param->v0; 12198214e71cSJoe constants[T0] = param->t0; 12208214e71cSJoe constants[X0] = param->x0; 12218214e71cSJoe constants[M0] = param->m0; 12228214e71cSJoe constants[Q0] = param->q0; 12238214e71cSJoe constants[PHI0] = param->phi0; 12248214e71cSJoe constants[POISSON] = param->poissonNumber; 12258214e71cSJoe constants[VLASOV] = param->vlasovNumber; 12268214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 12278214e71cSJoe PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants)); 12288214e71cSJoe } 12298214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 12308214e71cSJoe } 12318214e71cSJoe 12328214e71cSJoe static PetscErrorCode CreateSwarm(DM dm, AppCtx *user, DM *sw) 12338214e71cSJoe { 12349072cb8bSMatthew G. Knepley DMSwarmCellDM celldm; 12359072cb8bSMatthew G. Knepley DM vdm; 12368214e71cSJoe PetscReal v0[2] = {1., 0.}; 12378214e71cSJoe PetscInt dim; 1238b80bf5b1SJoe Pusztay 1239b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 12409566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 12419566063dSJacob Faibussowitsch PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw)); 12429566063dSJacob Faibussowitsch PetscCall(DMSetType(*sw, DMSWARM)); 12439566063dSJacob Faibussowitsch PetscCall(DMSetDimension(*sw, dim)); 12449566063dSJacob Faibussowitsch PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC)); 1245045208b8SMatthew G. Knepley PetscCall(DMSetApplicationContext(*sw, user)); 12469072cb8bSMatthew G. Knepley 12479566063dSJacob Faibussowitsch PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR)); 12488214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL)); 12498214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "species", 1, PETSC_INT)); 12508214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "E_field", dim, PETSC_REAL)); 12519072cb8bSMatthew G. Knepley 12529072cb8bSMatthew G. Knepley const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"}; 12539072cb8bSMatthew G. Knepley 12549072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMCreate(dm, 2, fieldnames, 1, fieldnames, &celldm)); 12559072cb8bSMatthew G. Knepley PetscCall(DMSwarmAddCellDM(*sw, celldm)); 12569072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMDestroy(&celldm)); 12579072cb8bSMatthew G. Knepley 12589072cb8bSMatthew G. Knepley const char *vfieldnames[1] = {"w_q"}; 12599072cb8bSMatthew G. Knepley 12609072cb8bSMatthew G. Knepley PetscCall(CreateVelocityDM(*sw, &vdm)); 12619072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMCreate(vdm, 1, vfieldnames, 1, &fieldnames[1], &celldm)); 12629072cb8bSMatthew G. Knepley PetscCall(DMSwarmAddCellDM(*sw, celldm)); 12639072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMDestroy(&celldm)); 12649072cb8bSMatthew G. Knepley PetscCall(DMDestroy(&vdm)); 12659072cb8bSMatthew G. Knepley 12664a0cbf56SMatthew G. Knepley DM mdm; 12674a0cbf56SMatthew G. Knepley 12684a0cbf56SMatthew G. Knepley PetscCall(DMClone(dm, &mdm)); 12694a0cbf56SMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)mdm, "moments")); 12704a0cbf56SMatthew G. Knepley PetscCall(DMCopyDisc(dm, mdm)); 12714a0cbf56SMatthew G. Knepley PetscCall(DMSwarmCellDMCreate(mdm, 1, vfieldnames, 1, fieldnames, &celldm)); 12724a0cbf56SMatthew G. Knepley PetscCall(DMDestroy(&mdm)); 12734a0cbf56SMatthew G. Knepley PetscCall(DMSwarmAddCellDM(*sw, celldm)); 12744a0cbf56SMatthew G. Knepley PetscCall(DMSwarmCellDMDestroy(&celldm)); 12754a0cbf56SMatthew G. Knepley 12769566063dSJacob Faibussowitsch PetscCall(DMSetFromOptions(*sw)); 1277045208b8SMatthew G. Knepley PetscCall(DMSetUp(*sw)); 1278045208b8SMatthew G. Knepley 12799072cb8bSMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(*sw, "space")); 12808214e71cSJoe user->swarm = *sw; 1281045208b8SMatthew G. Knepley // TODO: This is redundant init since it is done in InitializeSolveAndSwarm, however DMSetUp() requires the local size be set 12828214e71cSJoe if (user->perturbed_weights) { 12838214e71cSJoe PetscCall(InitializeParticles_PerturbedWeights(*sw, user)); 1284b80bf5b1SJoe Pusztay } else { 12858214e71cSJoe PetscCall(DMSwarmComputeLocalSizeFromOptions(*sw)); 12868214e71cSJoe PetscCall(DMSwarmInitializeCoordinates(*sw)); 12878214e71cSJoe PetscCall(DMSwarmInitializeVelocitiesFromOptions(*sw, v0)); 1288b80bf5b1SJoe Pusztay } 12899566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles")); 12909566063dSJacob Faibussowitsch PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view")); 12913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1292b80bf5b1SJoe Pusztay } 1293b80bf5b1SJoe Pusztay 12948214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Coulomb(SNES snes, DM sw, PetscReal E[]) 1295d71ae5a4SJacob Faibussowitsch { 12968214e71cSJoe AppCtx *user; 12978214e71cSJoe PetscReal *coords; 12988214e71cSJoe PetscInt *species, dim, Np, Ns; 12998214e71cSJoe PetscMPIInt size; 13008214e71cSJoe 13018214e71cSJoe PetscFunctionBegin; 13028214e71cSJoe PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)snes), &size)); 13038214e71cSJoe PetscCheck(size == 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Coulomb code only works in serial"); 13048214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 13058214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 13068214e71cSJoe PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 13078214e71cSJoe PetscCall(DMGetApplicationContext(sw, (void *)&user)); 13088214e71cSJoe 13098214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 13108214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 13118214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 13128214e71cSJoe PetscReal *pcoord = &coords[p * dim]; 13138214e71cSJoe PetscReal pE[3] = {0., 0., 0.}; 13148214e71cSJoe 13158214e71cSJoe /* Calculate field at particle p due to particle q */ 13168214e71cSJoe for (PetscInt q = 0; q < Np; ++q) { 13178214e71cSJoe PetscReal *qcoord = &coords[q * dim]; 13188214e71cSJoe PetscReal rpq[3], r, r3, q_q; 13198214e71cSJoe 13208214e71cSJoe if (p == q) continue; 13218214e71cSJoe q_q = user->charges[species[q]] * 1.; 13228214e71cSJoe for (PetscInt d = 0; d < dim; ++d) rpq[d] = pcoord[d] - qcoord[d]; 13238214e71cSJoe r = DMPlex_NormD_Internal(dim, rpq); 13248214e71cSJoe if (r < PETSC_SQRT_MACHINE_EPSILON) continue; 13258214e71cSJoe r3 = PetscPowRealInt(r, 3); 13268214e71cSJoe for (PetscInt d = 0; d < dim; ++d) pE[d] += q_q * rpq[d] / r3; 13278214e71cSJoe } 13288214e71cSJoe for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = pE[d]; 13298214e71cSJoe } 13308214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 13318214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 13328214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 13338214e71cSJoe } 13348214e71cSJoe 13354a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Primal(SNES snes, DM sw, Mat M_p, PetscReal E[]) 13368214e71cSJoe { 1337b80bf5b1SJoe Pusztay DM dm; 13388214e71cSJoe AppCtx *user; 13398214e71cSJoe PetscDS ds; 13408214e71cSJoe PetscFE fe; 13414a0cbf56SMatthew G. Knepley KSP ksp; 134275155f48SMatthew G. Knepley Vec rhoRhs; // Weak charge density, \int phi_i rho 134375155f48SMatthew G. Knepley Vec rho; // Charge density, M^{-1} rhoRhs 134475155f48SMatthew G. Knepley Vec phi, locPhi; // Potential 134575155f48SMatthew G. Knepley Vec f; // Particle weights 13468214e71cSJoe PetscReal *coords; 13478214e71cSJoe PetscInt dim, cStart, cEnd, Np; 13488214e71cSJoe 13498214e71cSJoe PetscFunctionBegin; 135084467f86SMatthew G. Knepley PetscCall(DMGetApplicationContext(sw, (void *)&user)); 135184467f86SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0)); 13528214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 13538214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 13548214e71cSJoe 13558214e71cSJoe PetscCall(SNESGetDM(snes, &dm)); 135675155f48SMatthew G. Knepley PetscCall(DMGetGlobalVector(dm, &rhoRhs)); 135775155f48SMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density")); 13584a0cbf56SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho)); 13598214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f)); 13608214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)f, "particle weight")); 136175155f48SMatthew G. Knepley 13628214e71cSJoe PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view")); 1363f1e6e573SMatthew G. Knepley PetscCall(MatViewFromOptions(user->M, NULL, "-m_view")); 13648214e71cSJoe PetscCall(VecViewFromOptions(f, NULL, "-weights_view")); 136575155f48SMatthew G. Knepley 136675155f48SMatthew G. Knepley PetscCall(MatMultTranspose(M_p, f, rhoRhs)); 13678214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f)); 13688214e71cSJoe 13698214e71cSJoe PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp)); 13708214e71cSJoe PetscCall(KSPSetOptionsPrefix(ksp, "em_proj_")); 1371f1e6e573SMatthew G. Knepley PetscCall(KSPSetOperators(ksp, user->M, user->M)); 13728214e71cSJoe PetscCall(KSPSetFromOptions(ksp)); 137375155f48SMatthew G. Knepley PetscCall(KSPSolve(ksp, rhoRhs, rho)); 13748214e71cSJoe 137575155f48SMatthew G. Knepley PetscCall(VecScale(rhoRhs, -1.0)); 13768214e71cSJoe 137775155f48SMatthew G. Knepley PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view")); 13784a0cbf56SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho)); 13798214e71cSJoe PetscCall(KSPDestroy(&ksp)); 13808214e71cSJoe 13814a0cbf56SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi)); 13828214e71cSJoe PetscCall(VecSet(phi, 0.0)); 138375155f48SMatthew G. Knepley PetscCall(SNESSolve(snes, rhoRhs, phi)); 138475155f48SMatthew G. Knepley PetscCall(DMRestoreGlobalVector(dm, &rhoRhs)); 13858214e71cSJoe PetscCall(VecViewFromOptions(phi, NULL, "-phi_view")); 13868214e71cSJoe 13878214e71cSJoe PetscCall(DMGetLocalVector(dm, &locPhi)); 13888214e71cSJoe PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi)); 13898214e71cSJoe PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi)); 13904a0cbf56SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi)); 139184467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0)); 13928214e71cSJoe 13938214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 13948214e71cSJoe PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe)); 13958214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 13968214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 13978214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 13988214e71cSJoe 139984467f86SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0)); 14008214e71cSJoe PetscTabulation tab; 14018214e71cSJoe PetscReal *pcoord, *refcoord; 1402045208b8SMatthew G. Knepley PetscFEGeom *chunkgeom = NULL; 1403045208b8SMatthew G. Knepley PetscInt maxNcp = 0; 1404045208b8SMatthew G. Knepley 1405045208b8SMatthew G. Knepley for (PetscInt c = cStart; c < cEnd; ++c) { 1406045208b8SMatthew G. Knepley PetscInt Ncp; 1407045208b8SMatthew G. Knepley 1408045208b8SMatthew G. Knepley PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp)); 1409045208b8SMatthew G. Knepley maxNcp = PetscMax(maxNcp, Ncp); 1410045208b8SMatthew G. Knepley } 1411045208b8SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord)); 1412045208b8SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord)); 1413045208b8SMatthew G. Knepley PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab)); 1414045208b8SMatthew G. Knepley for (PetscInt c = cStart; c < cEnd; ++c) { 1415045208b8SMatthew G. Knepley PetscScalar *clPhi = NULL; 14168214e71cSJoe PetscInt *points; 14178214e71cSJoe PetscInt Ncp; 14188214e71cSJoe 14198214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points)); 14208214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) 14218214e71cSJoe for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d]; 1422f1e6e573SMatthew G. Knepley { 1423f1e6e573SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom)); 1424f1e6e573SMatthew G. Knepley for (PetscInt i = 0; i < Ncp; ++i) { 1425f1e6e573SMatthew G. Knepley const PetscReal x0[3] = {-1., -1., -1.}; 1426f1e6e573SMatthew G. Knepley CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]); 1427f1e6e573SMatthew G. Knepley } 1428f1e6e573SMatthew G. Knepley } 1429045208b8SMatthew G. Knepley PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab)); 14308214e71cSJoe PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 14318214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) { 14328214e71cSJoe const PetscReal *basisDer = tab->T[1]; 14338214e71cSJoe const PetscInt p = points[cp]; 14348214e71cSJoe 14358214e71cSJoe for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.; 1436f1e6e573SMatthew G. Knepley PetscCall(PetscFEFreeInterpolateGradient_Static(fe, basisDer, clPhi, dim, chunkgeom->invJ, NULL, cp, &E[p * dim])); 1437045208b8SMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0; 14388214e71cSJoe } 14398214e71cSJoe PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 144084467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points)); 14418214e71cSJoe } 1442045208b8SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord)); 1443045208b8SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord)); 1444045208b8SMatthew G. Knepley PetscCall(PetscTabulationDestroy(&tab)); 14458214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 14468214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 14478214e71cSJoe PetscCall(DMRestoreLocalVector(dm, &locPhi)); 1448f1e6e573SMatthew G. Knepley PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom)); 144984467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0)); 14508214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 14518214e71cSJoe } 14528214e71cSJoe 14534a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles_Mixed(SNES snes, DM sw, Mat M_p, PetscReal E[]) 14548214e71cSJoe { 14554a0cbf56SMatthew G. Knepley DM dm; 14568214e71cSJoe AppCtx *user; 14578214e71cSJoe PetscDS ds; 14588214e71cSJoe PetscFE fe; 14594a0cbf56SMatthew G. Knepley KSP ksp; 14604a0cbf56SMatthew G. Knepley Vec rhoRhs, rhoRhsFull; // Weak charge density, \int phi_i rho, and embedding in mixed problem 14614a0cbf56SMatthew G. Knepley Vec rho; // Charge density, M^{-1} rhoRhs 14624a0cbf56SMatthew G. Knepley Vec phi, locPhi, phiFull; // Potential and embedding in mixed problem 14634a0cbf56SMatthew G. Knepley Vec f; // Particle weights 146475155f48SMatthew G. Knepley PetscReal *coords; 14654a0cbf56SMatthew G. Knepley PetscInt dim, cStart, cEnd, Np; 14668214e71cSJoe 14678214e71cSJoe PetscFunctionBegin; 146884467f86SMatthew G. Knepley PetscCall(DMGetApplicationContext(sw, &user)); 146984467f86SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0)); 14708214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 14718214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 14728214e71cSJoe 14738214e71cSJoe PetscCall(SNESGetDM(snes, &dm)); 14744a0cbf56SMatthew G. Knepley PetscCall(DMGetGlobalVector(user->dmPot, &rhoRhs)); 14754a0cbf56SMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density")); 14764a0cbf56SMatthew G. Knepley PetscCall(DMGetGlobalVector(dm, &rhoRhsFull)); 14774a0cbf56SMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)rhoRhsFull, "Weak charge density")); 14784a0cbf56SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(user->dmPot, "rho", &rho)); 14798214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f)); 14808214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)f, "particle weight")); 14814a0cbf56SMatthew G. Knepley 14824a0cbf56SMatthew G. Knepley PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view")); 14834a0cbf56SMatthew G. Knepley PetscCall(MatViewFromOptions(user->M, NULL, "-m_view")); 14848214e71cSJoe PetscCall(VecViewFromOptions(f, NULL, "-weights_view")); 14854a0cbf56SMatthew G. Knepley 14864a0cbf56SMatthew G. Knepley PetscCall(MatMultTranspose(M_p, f, rhoRhs)); 14878214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f)); 14888214e71cSJoe 14898214e71cSJoe PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp)); 14908214e71cSJoe PetscCall(KSPSetOptionsPrefix(ksp, "em_proj")); 14914a0cbf56SMatthew G. Knepley PetscCall(KSPSetOperators(ksp, user->M, user->M)); 14928214e71cSJoe PetscCall(KSPSetFromOptions(ksp)); 14934a0cbf56SMatthew G. Knepley PetscCall(KSPSolve(ksp, rhoRhs, rho)); 14948214e71cSJoe 14954a0cbf56SMatthew G. Knepley PetscCall(VecISCopy(rhoRhsFull, user->isPot, SCATTER_FORWARD, rhoRhs)); 14964a0cbf56SMatthew G. Knepley //PetscCall(VecScale(rhoRhsFull, -1.0)); 14978214e71cSJoe 14984a0cbf56SMatthew G. Knepley PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view")); 14994a0cbf56SMatthew G. Knepley PetscCall(VecViewFromOptions(rhoRhsFull, NULL, "-rho_full_view")); 15004a0cbf56SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "rho", &rho)); 15014a0cbf56SMatthew G. Knepley PetscCall(DMRestoreGlobalVector(user->dmPot, &rhoRhs)); 15028214e71cSJoe PetscCall(KSPDestroy(&ksp)); 15038214e71cSJoe 15044a0cbf56SMatthew G. Knepley PetscCall(DMGetGlobalVector(dm, &phiFull)); 15054a0cbf56SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(user->dmPot, "phi", &phi)); 15064a0cbf56SMatthew G. Knepley PetscCall(VecSet(phiFull, 0.0)); 15074a0cbf56SMatthew G. Knepley PetscCall(SNESSolve(snes, rhoRhsFull, phiFull)); 15084a0cbf56SMatthew G. Knepley PetscCall(DMRestoreGlobalVector(dm, &rhoRhsFull)); 15098214e71cSJoe PetscCall(VecViewFromOptions(phi, NULL, "-phi_view")); 15108214e71cSJoe 15114a0cbf56SMatthew G. Knepley PetscCall(VecISCopy(phiFull, user->isPot, SCATTER_REVERSE, phi)); 15124a0cbf56SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(user->dmPot, "phi", &phi)); 15134a0cbf56SMatthew G. Knepley 15148214e71cSJoe PetscCall(DMGetLocalVector(dm, &locPhi)); 15154a0cbf56SMatthew G. Knepley PetscCall(DMGlobalToLocalBegin(dm, phiFull, INSERT_VALUES, locPhi)); 15164a0cbf56SMatthew G. Knepley PetscCall(DMGlobalToLocalEnd(dm, phiFull, INSERT_VALUES, locPhi)); 15174a0cbf56SMatthew G. Knepley PetscCall(DMRestoreGlobalVector(dm, &phiFull)); 151884467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0)); 15198214e71cSJoe 15208214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 15218214e71cSJoe PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe)); 15228214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 15238214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 15248214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 15254a0cbf56SMatthew G. Knepley 15264a0cbf56SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0)); 15278214e71cSJoe PetscTabulation tab; 15288214e71cSJoe PetscReal *pcoord, *refcoord; 15294a0cbf56SMatthew G. Knepley PetscFEGeom *chunkgeom = NULL; 15304a0cbf56SMatthew G. Knepley PetscInt maxNcp = 0; 15314a0cbf56SMatthew G. Knepley 15324a0cbf56SMatthew G. Knepley for (PetscInt c = cStart; c < cEnd; ++c) { 15334a0cbf56SMatthew G. Knepley PetscInt Ncp; 15344a0cbf56SMatthew G. Knepley 15354a0cbf56SMatthew G. Knepley PetscCall(DMSwarmSortGetNumberOfPointsPerCell(sw, c, &Ncp)); 15364a0cbf56SMatthew G. Knepley maxNcp = PetscMax(maxNcp, Ncp); 15374a0cbf56SMatthew G. Knepley } 15384a0cbf56SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord)); 15394a0cbf56SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord)); 15404a0cbf56SMatthew G. Knepley PetscCall(PetscFECreateTabulation(fe, 1, maxNcp, refcoord, 1, &tab)); 15414a0cbf56SMatthew G. Knepley for (PetscInt c = cStart; c < cEnd; ++c) { 15424a0cbf56SMatthew G. Knepley PetscScalar *clPhi = NULL; 15438214e71cSJoe PetscInt *points; 15448214e71cSJoe PetscInt Ncp; 15458214e71cSJoe 15468214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points)); 15478214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) 15488214e71cSJoe for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d]; 1549f1e6e573SMatthew G. Knepley { 1550f1e6e573SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom)); 1551f1e6e573SMatthew G. Knepley for (PetscInt i = 0; i < Ncp; ++i) { 1552f1e6e573SMatthew G. Knepley const PetscReal x0[3] = {-1., -1., -1.}; 1553f1e6e573SMatthew G. Knepley CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]); 1554f1e6e573SMatthew G. Knepley } 1555f1e6e573SMatthew G. Knepley } 15564a0cbf56SMatthew G. Knepley PetscCall(PetscFEComputeTabulation(fe, Ncp, refcoord, 1, tab)); 15578214e71cSJoe PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 15588214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) { 15598214e71cSJoe const PetscInt p = points[cp]; 15608214e71cSJoe 15618214e71cSJoe for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.; 1562f1e6e573SMatthew G. Knepley PetscCall(PetscFEInterpolateAtPoints_Static(fe, tab, clPhi, chunkgeom, cp, &E[p * dim])); 1563f1e6e573SMatthew G. Knepley PetscCall(PetscFEPushforward(fe, chunkgeom, 1, &E[p * dim])); 15644a0cbf56SMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] *= -1.0; 15658214e71cSJoe } 15668214e71cSJoe PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 156784467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points)); 15688214e71cSJoe } 15694a0cbf56SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &pcoord)); 15704a0cbf56SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, maxNcp * dim, MPIU_REAL, &refcoord)); 15714a0cbf56SMatthew G. Knepley PetscCall(PetscTabulationDestroy(&tab)); 15728214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 15738214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 15748214e71cSJoe PetscCall(DMRestoreLocalVector(dm, &locPhi)); 1575f1e6e573SMatthew G. Knepley PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom)); 157684467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0)); 15778214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 15788214e71cSJoe } 15798214e71cSJoe 15804a0cbf56SMatthew G. Knepley static PetscErrorCode ComputeFieldAtParticles(SNES snes, DM sw) 15818214e71cSJoe { 15824a0cbf56SMatthew G. Knepley AppCtx *user; 15834a0cbf56SMatthew G. Knepley Mat M_p; 15844a0cbf56SMatthew G. Knepley PetscReal *E; 15858214e71cSJoe PetscInt dim, Np; 15868214e71cSJoe 15878214e71cSJoe PetscFunctionBegin; 15888214e71cSJoe PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 15898214e71cSJoe PetscValidHeaderSpecific(sw, DM_CLASSID, 2); 15908214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 15918214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 15924a0cbf56SMatthew G. Knepley PetscCall(DMGetApplicationContext(sw, &user)); 15938214e71cSJoe 15944a0cbf56SMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(sw, "moments")); 15954a0cbf56SMatthew G. Knepley // TODO: Could share sort context with space cellDM 15964a0cbf56SMatthew G. Knepley PetscCall(DMSwarmMigrate(sw, PETSC_FALSE)); 15974a0cbf56SMatthew G. Knepley PetscCall(DMCreateMassMatrix(sw, user->dmPot, &M_p)); 15984a0cbf56SMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(sw, "space")); 15994a0cbf56SMatthew G. Knepley 16004a0cbf56SMatthew G. Knepley PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 16014a0cbf56SMatthew G. Knepley PetscCall(PetscArrayzero(E, Np * dim)); 16024a0cbf56SMatthew G. Knepley user->validE = PETSC_TRUE; 16034a0cbf56SMatthew G. Knepley 16044a0cbf56SMatthew G. Knepley switch (user->em) { 16058214e71cSJoe case EM_COULOMB: 16068214e71cSJoe PetscCall(ComputeFieldAtParticles_Coulomb(snes, sw, E)); 16078214e71cSJoe break; 16084a0cbf56SMatthew G. Knepley case EM_PRIMAL: 16094a0cbf56SMatthew G. Knepley PetscCall(ComputeFieldAtParticles_Primal(snes, sw, M_p, E)); 16104a0cbf56SMatthew G. Knepley break; 16118214e71cSJoe case EM_MIXED: 16124a0cbf56SMatthew G. Knepley PetscCall(ComputeFieldAtParticles_Mixed(snes, sw, M_p, E)); 16138214e71cSJoe break; 16148214e71cSJoe case EM_NONE: 16158214e71cSJoe break; 16168214e71cSJoe default: 16174a0cbf56SMatthew G. Knepley SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No solver for electrostatic model %s", EMTypes[user->em]); 16188214e71cSJoe } 16194a0cbf56SMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 16204a0cbf56SMatthew G. Knepley PetscCall(MatDestroy(&M_p)); 16218214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 16228214e71cSJoe } 16238214e71cSJoe 16248214e71cSJoe static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec G, void *ctx) 16258214e71cSJoe { 16268214e71cSJoe DM sw; 16278214e71cSJoe SNES snes = ((AppCtx *)ctx)->snes; 16288214e71cSJoe const PetscScalar *u; 16298214e71cSJoe PetscScalar *g; 16308214e71cSJoe PetscReal *E, m_p = 1., q_p = -1.; 16318214e71cSJoe PetscInt dim, d, Np, p; 1632b80bf5b1SJoe Pusztay 1633b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 16348214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 16354a0cbf56SMatthew G. Knepley PetscCall(ComputeFieldAtParticles(snes, sw)); 16364a0cbf56SMatthew G. Knepley 16378214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 16388214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 16394a0cbf56SMatthew G. Knepley PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 16408214e71cSJoe PetscCall(VecGetArrayRead(U, &u)); 16418214e71cSJoe PetscCall(VecGetArray(G, &g)); 16428214e71cSJoe Np /= 2 * dim; 16438214e71cSJoe for (p = 0; p < Np; ++p) { 16448214e71cSJoe for (d = 0; d < dim; ++d) { 16458214e71cSJoe g[(p * 2 + 0) * dim + d] = u[(p * 2 + 1) * dim + d]; 16468214e71cSJoe g[(p * 2 + 1) * dim + d] = q_p * E[p * dim + d] / m_p; 16478214e71cSJoe } 16488214e71cSJoe } 16498214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 16508214e71cSJoe PetscCall(VecRestoreArrayRead(U, &u)); 16518214e71cSJoe PetscCall(VecRestoreArray(G, &g)); 16528214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 16538214e71cSJoe } 16548214e71cSJoe 16558214e71cSJoe /* J_{ij} = dF_i/dx_j 16568214e71cSJoe J_p = ( 0 1) 16578214e71cSJoe (-w^2 0) 16588214e71cSJoe TODO Now there is another term with w^2 from the electric field. I think we will need to invert the operator. 16598214e71cSJoe Perhaps we can approximate the Jacobian using only the cellwise P-P gradient from Coulomb 16608214e71cSJoe */ 16618214e71cSJoe static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat P, void *ctx) 16628214e71cSJoe { 16638214e71cSJoe DM sw; 16648214e71cSJoe const PetscReal *coords, *vel; 16658214e71cSJoe PetscInt dim, d, Np, p, rStart; 16668214e71cSJoe 16678214e71cSJoe PetscFunctionBeginUser; 16688214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 16698214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 16708214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 16718214e71cSJoe PetscCall(MatGetOwnershipRange(J, &rStart, NULL)); 1672045208b8SMatthew G. Knepley PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 1673045208b8SMatthew G. Knepley PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel)); 16748214e71cSJoe Np /= 2 * dim; 16758214e71cSJoe for (p = 0; p < Np; ++p) { 16768214e71cSJoe const PetscReal x0 = coords[p * dim + 0]; 16778214e71cSJoe const PetscReal vy0 = vel[p * dim + 1]; 16788214e71cSJoe const PetscReal omega = vy0 / x0; 16798214e71cSJoe PetscScalar vals[4] = {0., 1., -PetscSqr(omega), 0.}; 16808214e71cSJoe 16818214e71cSJoe for (d = 0; d < dim; ++d) { 16828214e71cSJoe const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart}; 16838214e71cSJoe PetscCall(MatSetValues(J, 2, rows, 2, rows, vals, INSERT_VALUES)); 16848214e71cSJoe } 16858214e71cSJoe } 1686045208b8SMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 1687045208b8SMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel)); 16888214e71cSJoe PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 16898214e71cSJoe PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 16908214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 16918214e71cSJoe } 16928214e71cSJoe 16938214e71cSJoe static PetscErrorCode RHSFunctionX(TS ts, PetscReal t, Vec V, Vec Xres, void *ctx) 16948214e71cSJoe { 16958214e71cSJoe AppCtx *user = (AppCtx *)ctx; 16968214e71cSJoe DM sw; 16978214e71cSJoe const PetscScalar *v; 16988214e71cSJoe PetscScalar *xres; 16998214e71cSJoe PetscInt Np, p, d, dim; 17008214e71cSJoe 17018214e71cSJoe PetscFunctionBeginUser; 170284467f86SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->RhsXEvent, ts, 0, 0, 0)); 17038214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 17048214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 17058214e71cSJoe PetscCall(VecGetLocalSize(Xres, &Np)); 17069566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(V, &v)); 17078214e71cSJoe PetscCall(VecGetArray(Xres, &xres)); 1708b80bf5b1SJoe Pusztay Np /= dim; 1709b80bf5b1SJoe Pusztay for (p = 0; p < Np; ++p) { 1710045208b8SMatthew G. Knepley for (d = 0; d < dim; ++d) xres[p * dim + d] = v[p * dim + d]; 1711b80bf5b1SJoe Pusztay } 17129566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(V, &v)); 17138214e71cSJoe PetscCall(VecRestoreArray(Xres, &xres)); 171484467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->RhsXEvent, ts, 0, 0, 0)); 17153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1716b80bf5b1SJoe Pusztay } 1717b80bf5b1SJoe Pusztay 17188214e71cSJoe static PetscErrorCode RHSFunctionV(TS ts, PetscReal t, Vec X, Vec Vres, void *ctx) 17198214e71cSJoe { 17208214e71cSJoe DM sw; 17218214e71cSJoe AppCtx *user = (AppCtx *)ctx; 17228214e71cSJoe SNES snes = ((AppCtx *)ctx)->snes; 17238214e71cSJoe const PetscScalar *x; 17248214e71cSJoe PetscScalar *vres; 17254a0cbf56SMatthew G. Knepley PetscReal *E, m_p, q_p; 17268214e71cSJoe PetscInt Np, p, dim, d; 17278214e71cSJoe Parameter *param; 17288214e71cSJoe 17298214e71cSJoe PetscFunctionBeginUser; 173084467f86SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->RhsVEvent, ts, 0, 0, 0)); 17318214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 17324a0cbf56SMatthew G. Knepley PetscCall(ComputeFieldAtParticles(snes, sw)); 17334a0cbf56SMatthew G. Knepley 17348214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 17358214e71cSJoe PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 17368214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 17378214e71cSJoe m_p = user->masses[0] * param->m0; 17388214e71cSJoe q_p = user->charges[0] * param->q0; 17398214e71cSJoe PetscCall(VecGetLocalSize(Vres, &Np)); 17408214e71cSJoe PetscCall(VecGetArrayRead(X, &x)); 17418214e71cSJoe PetscCall(VecGetArray(Vres, &vres)); 17428214e71cSJoe Np /= dim; 17438214e71cSJoe for (p = 0; p < Np; ++p) { 1744045208b8SMatthew G. Knepley for (d = 0; d < dim; ++d) vres[p * dim + d] = q_p * E[p * dim + d] / m_p; 17458214e71cSJoe } 17468214e71cSJoe PetscCall(VecRestoreArrayRead(X, &x)); 17478214e71cSJoe /* 1748d7c1f440SPierre Jolivet Synchronized, ordered output for parallel/sequential test cases. 17498214e71cSJoe In the 1D (on the 2D mesh) case, every y component should be zero. 17508214e71cSJoe */ 17518214e71cSJoe if (user->checkVRes) { 17528214e71cSJoe PetscBool pr = user->checkVRes > 1 ? PETSC_TRUE : PETSC_FALSE; 17538214e71cSJoe PetscInt step; 17548214e71cSJoe 17558214e71cSJoe PetscCall(TSGetStepNumber(ts, &step)); 17568214e71cSJoe if (pr) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step: %" PetscInt_FMT "\n", step)); 17578214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 17588214e71cSJoe if (pr) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Residual: %.12g %.12g\n", (double)PetscRealPart(vres[p * dim + 0]), (double)PetscRealPart(vres[p * dim + 1]))); 17598214e71cSJoe 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])); 17608214e71cSJoe } 17618214e71cSJoe if (pr) PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT)); 17628214e71cSJoe } 17638214e71cSJoe PetscCall(VecRestoreArray(Vres, &vres)); 17648214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 176584467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->RhsVEvent, ts, 0, 0, 0)); 17668214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 17678214e71cSJoe } 17688214e71cSJoe 17698214e71cSJoe static PetscErrorCode CreateSolution(TS ts) 17708214e71cSJoe { 17718214e71cSJoe DM sw; 17728214e71cSJoe Vec u; 17738214e71cSJoe PetscInt dim, Np; 17748214e71cSJoe 17758214e71cSJoe PetscFunctionBegin; 17768214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 17778214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 17788214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 17798214e71cSJoe PetscCall(VecCreate(PETSC_COMM_WORLD, &u)); 17808214e71cSJoe PetscCall(VecSetBlockSize(u, dim)); 17818214e71cSJoe PetscCall(VecSetSizes(u, 2 * Np * dim, PETSC_DECIDE)); 17828214e71cSJoe PetscCall(VecSetUp(u)); 17838214e71cSJoe PetscCall(TSSetSolution(ts, u)); 17848214e71cSJoe PetscCall(VecDestroy(&u)); 17858214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 17868214e71cSJoe } 17878214e71cSJoe 17888214e71cSJoe static PetscErrorCode SetProblem(TS ts) 17898214e71cSJoe { 17908214e71cSJoe AppCtx *user; 17918214e71cSJoe DM sw; 17928214e71cSJoe 17938214e71cSJoe PetscFunctionBegin; 17948214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 17958214e71cSJoe PetscCall(DMGetApplicationContext(sw, (void **)&user)); 17968214e71cSJoe // Define unified system for (X, V) 17978214e71cSJoe { 17988214e71cSJoe Mat J; 17998214e71cSJoe PetscInt dim, Np; 18008214e71cSJoe 18018214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 18028214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 18038214e71cSJoe PetscCall(MatCreate(PETSC_COMM_WORLD, &J)); 18048214e71cSJoe PetscCall(MatSetSizes(J, 2 * Np * dim, 2 * Np * dim, PETSC_DECIDE, PETSC_DECIDE)); 18058214e71cSJoe PetscCall(MatSetBlockSize(J, 2 * dim)); 18068214e71cSJoe PetscCall(MatSetFromOptions(J)); 18078214e71cSJoe PetscCall(MatSetUp(J)); 18088214e71cSJoe PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, user)); 18098214e71cSJoe PetscCall(TSSetRHSJacobian(ts, J, J, RHSJacobian, user)); 18108214e71cSJoe PetscCall(MatDestroy(&J)); 18118214e71cSJoe } 18128214e71cSJoe /* Define split system for X and V */ 18138214e71cSJoe { 18148214e71cSJoe Vec u; 18158214e71cSJoe IS isx, isv, istmp; 18168214e71cSJoe const PetscInt *idx; 18178214e71cSJoe PetscInt dim, Np, rstart; 18188214e71cSJoe 18198214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 18208214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 18218214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 18228214e71cSJoe PetscCall(VecGetOwnershipRange(u, &rstart, NULL)); 18238214e71cSJoe PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 0, 2, &istmp)); 18248214e71cSJoe PetscCall(ISGetIndices(istmp, &idx)); 18258214e71cSJoe PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isx)); 18268214e71cSJoe PetscCall(ISRestoreIndices(istmp, &idx)); 18278214e71cSJoe PetscCall(ISDestroy(&istmp)); 18288214e71cSJoe PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 1, 2, &istmp)); 18298214e71cSJoe PetscCall(ISGetIndices(istmp, &idx)); 18308214e71cSJoe PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isv)); 18318214e71cSJoe PetscCall(ISRestoreIndices(istmp, &idx)); 18328214e71cSJoe PetscCall(ISDestroy(&istmp)); 18338214e71cSJoe PetscCall(TSRHSSplitSetIS(ts, "position", isx)); 18348214e71cSJoe PetscCall(TSRHSSplitSetIS(ts, "momentum", isv)); 18358214e71cSJoe PetscCall(ISDestroy(&isx)); 18368214e71cSJoe PetscCall(ISDestroy(&isv)); 18378214e71cSJoe PetscCall(TSRHSSplitSetRHSFunction(ts, "position", NULL, RHSFunctionX, user)); 18388214e71cSJoe PetscCall(TSRHSSplitSetRHSFunction(ts, "momentum", NULL, RHSFunctionV, user)); 18398214e71cSJoe } 18408214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 18418214e71cSJoe } 18428214e71cSJoe 18438214e71cSJoe static PetscErrorCode DMSwarmTSRedistribute(TS ts) 18448214e71cSJoe { 18458214e71cSJoe DM sw; 18468214e71cSJoe Vec u; 18478214e71cSJoe PetscReal t, maxt, dt; 18488214e71cSJoe PetscInt n, maxn; 18498214e71cSJoe 18508214e71cSJoe PetscFunctionBegin; 18518214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 18528214e71cSJoe PetscCall(TSGetTime(ts, &t)); 18538214e71cSJoe PetscCall(TSGetMaxTime(ts, &maxt)); 18548214e71cSJoe PetscCall(TSGetTimeStep(ts, &dt)); 18558214e71cSJoe PetscCall(TSGetStepNumber(ts, &n)); 18568214e71cSJoe PetscCall(TSGetMaxSteps(ts, &maxn)); 18578214e71cSJoe 18588214e71cSJoe PetscCall(TSReset(ts)); 18598214e71cSJoe PetscCall(TSSetDM(ts, sw)); 18608214e71cSJoe PetscCall(TSSetFromOptions(ts)); 18618214e71cSJoe PetscCall(TSSetTime(ts, t)); 18628214e71cSJoe PetscCall(TSSetMaxTime(ts, maxt)); 18638214e71cSJoe PetscCall(TSSetTimeStep(ts, dt)); 18648214e71cSJoe PetscCall(TSSetStepNumber(ts, n)); 18658214e71cSJoe PetscCall(TSSetMaxSteps(ts, maxn)); 18668214e71cSJoe 18678214e71cSJoe PetscCall(CreateSolution(ts)); 18688214e71cSJoe PetscCall(SetProblem(ts)); 18698214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 18708214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 18718214e71cSJoe } 18728214e71cSJoe 18738214e71cSJoe PetscErrorCode line(PetscInt dim, PetscReal time, const PetscReal dummy[], PetscInt p, PetscScalar x[], void *ctx) 18748214e71cSJoe { 18758214e71cSJoe DM sw, cdm; 18768214e71cSJoe PetscInt Np; 18778214e71cSJoe PetscReal low[2], high[2]; 18788214e71cSJoe AppCtx *user = (AppCtx *)ctx; 18798214e71cSJoe 18808214e71cSJoe sw = user->swarm; 18818214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &cdm)); 18828214e71cSJoe // Get the bounding box so we can equally space the particles 18838214e71cSJoe PetscCall(DMGetLocalBoundingBox(cdm, low, high)); 18848214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 18858214e71cSJoe // shift it by h/2 so nothing is initialized directly on a boundary 18868214e71cSJoe x[0] = ((high[0] - low[0]) / Np) * (p + 0.5); 18878214e71cSJoe x[1] = 0.; 18888214e71cSJoe return PETSC_SUCCESS; 18898214e71cSJoe } 18908214e71cSJoe 1891b80bf5b1SJoe Pusztay /* 18928214e71cSJoe InitializeSolveAndSwarm - Set the solution values to the swarm coordinates and velocities, and also possibly set the initial values. 18938214e71cSJoe 18948214e71cSJoe Input Parameters: 18958214e71cSJoe + ts - The TS 1896d7c1f440SPierre Jolivet - useInitial - Flag to also set the initial conditions to the current coordinates and velocities and setup the problem 18978214e71cSJoe 18988214e71cSJoe Output Parameters: 18998214e71cSJoe . u - The initialized solution vector 19008214e71cSJoe 19018214e71cSJoe Level: advanced 19028214e71cSJoe 19038214e71cSJoe .seealso: InitializeSolve() 1904b80bf5b1SJoe Pusztay */ 19058214e71cSJoe static PetscErrorCode InitializeSolveAndSwarm(TS ts, PetscBool useInitial) 1906d71ae5a4SJacob Faibussowitsch { 19078214e71cSJoe DM sw; 1908045208b8SMatthew G. Knepley Vec u, gc, gv; 19098214e71cSJoe IS isx, isv; 19108214e71cSJoe PetscInt dim; 19118214e71cSJoe AppCtx *user; 1912b80bf5b1SJoe Pusztay 1913b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 19148214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 19158214e71cSJoe PetscCall(DMGetApplicationContext(sw, &user)); 19168214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 19178214e71cSJoe if (useInitial) { 19188214e71cSJoe PetscReal v0[2] = {1., 0.}; 19198214e71cSJoe if (user->perturbed_weights) { 19208214e71cSJoe PetscCall(InitializeParticles_PerturbedWeights(sw, user)); 19218214e71cSJoe } else { 19228214e71cSJoe PetscCall(DMSwarmComputeLocalSizeFromOptions(sw)); 19238214e71cSJoe PetscCall(DMSwarmInitializeCoordinates(sw)); 19248214e71cSJoe PetscCall(DMSwarmInitializeVelocitiesFromOptions(sw, v0)); 19258214e71cSJoe } 19268214e71cSJoe PetscCall(DMSwarmMigrate(sw, PETSC_TRUE)); 19278214e71cSJoe PetscCall(DMSwarmTSRedistribute(ts)); 19288214e71cSJoe } 1929045208b8SMatthew G. Knepley PetscCall(DMSetUp(sw)); 19308214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 19318214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "position", &isx)); 19328214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv)); 19338214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 19348214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv)); 19358214e71cSJoe PetscCall(VecISCopy(u, isx, SCATTER_FORWARD, gc)); 19368214e71cSJoe PetscCall(VecISCopy(u, isv, SCATTER_FORWARD, gv)); 19378214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 19388214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv)); 19398214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 19408214e71cSJoe } 19418214e71cSJoe 19428214e71cSJoe static PetscErrorCode InitializeSolve(TS ts, Vec u) 1943b80bf5b1SJoe Pusztay { 19448214e71cSJoe PetscFunctionBegin; 19458214e71cSJoe PetscCall(TSSetSolution(ts, u)); 19468214e71cSJoe PetscCall(InitializeSolveAndSwarm(ts, PETSC_TRUE)); 19478214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1948b80bf5b1SJoe Pusztay } 1949b80bf5b1SJoe Pusztay 19508214e71cSJoe static PetscErrorCode MigrateParticles(TS ts) 19518214e71cSJoe { 19528214e71cSJoe DM sw, cdm; 19538214e71cSJoe const PetscReal *L; 19549072cb8bSMatthew G. Knepley AppCtx *ctx; 19558214e71cSJoe 19568214e71cSJoe PetscFunctionBeginUser; 19578214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 19589072cb8bSMatthew G. Knepley PetscCall(DMGetApplicationContext(sw, &ctx)); 19598214e71cSJoe PetscCall(DMViewFromOptions(sw, NULL, "-migrate_view_pre")); 19608214e71cSJoe { 19618214e71cSJoe Vec u, gc, gv, position, momentum; 19628214e71cSJoe IS isx, isv; 19638214e71cSJoe PetscReal *pos, *mom; 19648214e71cSJoe 19658214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 19668214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "position", &isx)); 19678214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv)); 19688214e71cSJoe PetscCall(VecGetSubVector(u, isx, &position)); 19698214e71cSJoe PetscCall(VecGetSubVector(u, isv, &momentum)); 19708214e71cSJoe PetscCall(VecGetArray(position, &pos)); 19718214e71cSJoe PetscCall(VecGetArray(momentum, &mom)); 19728214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 19738214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv)); 19748214e71cSJoe PetscCall(VecISCopy(u, isx, SCATTER_REVERSE, gc)); 19758214e71cSJoe PetscCall(VecISCopy(u, isv, SCATTER_REVERSE, gv)); 19768214e71cSJoe 19778214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &cdm)); 19788214e71cSJoe PetscCall(DMGetPeriodicity(cdm, NULL, NULL, &L)); 19798214e71cSJoe if ((L[0] || L[1]) >= 0.) { 19808214e71cSJoe PetscReal *x, *v, upper[3], lower[3]; 19818214e71cSJoe PetscInt Np, dim; 19828214e71cSJoe 19838214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 19848214e71cSJoe PetscCall(DMGetDimension(cdm, &dim)); 19858214e71cSJoe PetscCall(DMGetBoundingBox(cdm, lower, upper)); 19868214e71cSJoe PetscCall(VecGetArray(gc, &x)); 19878214e71cSJoe PetscCall(VecGetArray(gv, &v)); 19888214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 19898214e71cSJoe for (PetscInt d = 0; d < dim; ++d) { 19908214e71cSJoe if (pos[p * dim + d] < lower[d]) { 19918214e71cSJoe x[p * dim + d] = pos[p * dim + d] + (upper[d] - lower[d]); 19928214e71cSJoe } else if (pos[p * dim + d] > upper[d]) { 19938214e71cSJoe x[p * dim + d] = pos[p * dim + d] - (upper[d] - lower[d]); 19948214e71cSJoe } else { 19958214e71cSJoe x[p * dim + d] = pos[p * dim + d]; 19968214e71cSJoe } 19978214e71cSJoe 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]); 19988214e71cSJoe v[p * dim + d] = mom[p * dim + d]; 19998214e71cSJoe } 20008214e71cSJoe } 20018214e71cSJoe PetscCall(VecRestoreArray(gc, &x)); 20028214e71cSJoe PetscCall(VecRestoreArray(gv, &v)); 20038214e71cSJoe } 20048214e71cSJoe PetscCall(VecRestoreArray(position, &pos)); 20058214e71cSJoe PetscCall(VecRestoreArray(momentum, &mom)); 20068214e71cSJoe PetscCall(VecRestoreSubVector(u, isx, &position)); 20078214e71cSJoe PetscCall(VecRestoreSubVector(u, isv, &momentum)); 20088214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv)); 20098214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 20108214e71cSJoe } 20118214e71cSJoe PetscCall(DMSwarmMigrate(sw, PETSC_TRUE)); 20129072cb8bSMatthew G. Knepley PetscInt step; 20139072cb8bSMatthew G. Knepley 20149072cb8bSMatthew G. Knepley PetscCall(TSGetStepNumber(ts, &step)); 2015045208b8SMatthew G. Knepley if (!(step % ctx->remapFreq)) { 20169072cb8bSMatthew G. Knepley // Monitor electric field before we destroy it 20179072cb8bSMatthew G. Knepley PetscReal ptime; 20189072cb8bSMatthew G. Knepley PetscInt step; 20199072cb8bSMatthew G. Knepley 20209072cb8bSMatthew G. Knepley PetscCall(TSGetStepNumber(ts, &step)); 20219072cb8bSMatthew G. Knepley PetscCall(TSGetTime(ts, &ptime)); 20229072cb8bSMatthew G. Knepley if (ctx->efield_monitor) PetscCall(MonitorEField(ts, step, ptime, NULL, ctx)); 20239072cb8bSMatthew G. Knepley if (ctx->poisson_monitor) PetscCall(MonitorPoisson(ts, step, ptime, NULL, ctx)); 20249072cb8bSMatthew G. Knepley PetscCall(DMSwarmRemap(sw)); 20259072cb8bSMatthew G. Knepley ctx->validE = PETSC_FALSE; 20269072cb8bSMatthew G. Knepley } 20279072cb8bSMatthew G. Knepley // This MUST come last, since it recreates the subswarms and they must DMClone() the new swarm 20288214e71cSJoe PetscCall(DMSwarmTSRedistribute(ts)); 20298214e71cSJoe PetscCall(InitializeSolveAndSwarm(ts, PETSC_FALSE)); 20303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2031b80bf5b1SJoe Pusztay } 2032b80bf5b1SJoe Pusztay 2033d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv) 2034d71ae5a4SJacob Faibussowitsch { 2035b80bf5b1SJoe Pusztay DM dm, sw; 20368214e71cSJoe TS ts; 20378214e71cSJoe Vec u; 20388214e71cSJoe PetscReal dt; 20398214e71cSJoe PetscInt maxn; 2040b80bf5b1SJoe Pusztay AppCtx user; 2041b80bf5b1SJoe Pusztay 20429566063dSJacob Faibussowitsch PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 20438214e71cSJoe PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user)); 20448214e71cSJoe PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &user.bag)); 20458214e71cSJoe PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm)); 20468214e71cSJoe PetscCall(CreatePoisson(dm, &user)); 20478214e71cSJoe PetscCall(CreateSwarm(dm, &user, &sw)); 20488214e71cSJoe PetscCall(SetupParameters(PETSC_COMM_WORLD, &user)); 20498214e71cSJoe PetscCall(InitializeConstants(sw, &user)); 20508214e71cSJoe PetscCall(DMSetApplicationContext(sw, &user)); 2051b80bf5b1SJoe Pusztay 20528214e71cSJoe PetscCall(TSCreate(PETSC_COMM_WORLD, &ts)); 20538214e71cSJoe PetscCall(TSSetProblemType(ts, TS_NONLINEAR)); 20549566063dSJacob Faibussowitsch PetscCall(TSSetDM(ts, sw)); 20558214e71cSJoe PetscCall(TSSetMaxTime(ts, 0.1)); 20568214e71cSJoe PetscCall(TSSetTimeStep(ts, 0.00001)); 20578214e71cSJoe PetscCall(TSSetMaxSteps(ts, 100)); 20588214e71cSJoe PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP)); 20598214e71cSJoe 20608214e71cSJoe if (user.efield_monitor) PetscCall(TSMonitorSet(ts, MonitorEField, &user, NULL)); 2061f1e6e573SMatthew G. Knepley if (user.moment_monitor) PetscCall(TSMonitorSet(ts, MonitorMoments, &user, NULL)); 20628214e71cSJoe if (user.initial_monitor) PetscCall(TSMonitorSet(ts, MonitorInitialConditions, &user, NULL)); 20639072cb8bSMatthew G. Knepley if (user.positions_monitor) PetscCall(TSMonitorSet(ts, MonitorPositions_2D, &user, NULL)); 20648214e71cSJoe if (user.poisson_monitor) PetscCall(TSMonitorSet(ts, MonitorPoisson, &user, NULL)); 20658214e71cSJoe 20668214e71cSJoe PetscCall(TSSetFromOptions(ts)); 20678214e71cSJoe PetscCall(TSGetTimeStep(ts, &dt)); 20688214e71cSJoe PetscCall(TSGetMaxSteps(ts, &maxn)); 20698214e71cSJoe user.steps = maxn; 20708214e71cSJoe user.stepSize = dt; 20718214e71cSJoe PetscCall(SetupContext(dm, sw, &user)); 20728214e71cSJoe PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve)); 20738214e71cSJoe PetscCall(TSSetPostStep(ts, MigrateParticles)); 20748214e71cSJoe PetscCall(CreateSolution(ts)); 20758214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 20768214e71cSJoe PetscCall(TSComputeInitialCondition(ts, u)); 20778214e71cSJoe PetscCall(CheckNonNegativeWeights(sw, &user)); 20788214e71cSJoe PetscCall(TSSolve(ts, NULL)); 20798214e71cSJoe 20809566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&user.snes)); 20814a0cbf56SMatthew G. Knepley PetscCall(DMDestroy(&user.dmPot)); 20824a0cbf56SMatthew G. Knepley PetscCall(ISDestroy(&user.isPot)); 2083f1e6e573SMatthew G. Knepley PetscCall(MatDestroy(&user.M)); 2084f1e6e573SMatthew G. Knepley PetscCall(PetscFEGeomDestroy(&user.fegeom)); 20859566063dSJacob Faibussowitsch PetscCall(TSDestroy(&ts)); 20869566063dSJacob Faibussowitsch PetscCall(DMDestroy(&sw)); 20879566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dm)); 20888214e71cSJoe PetscCall(DestroyContext(&user)); 20899566063dSJacob Faibussowitsch PetscCall(PetscFinalize()); 2090b122ec5aSJacob Faibussowitsch return 0; 2091b80bf5b1SJoe Pusztay } 2092b80bf5b1SJoe Pusztay 2093b80bf5b1SJoe Pusztay /*TEST 2094b80bf5b1SJoe Pusztay 2095b80bf5b1SJoe Pusztay build: 20968214e71cSJoe requires: !complex double 20978214e71cSJoe 20988214e71cSJoe # This tests that we can put particles in a box and compute the Coulomb force 20998214e71cSJoe # Recommend -draw_size 500,500 21008214e71cSJoe testset: 21018214e71cSJoe requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT) 2102045208b8SMatthew G. Knepley args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 20 \ 2103045208b8SMatthew G. Knepley -dm_plex_box_lower 0 -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \ 21049072cb8bSMatthew G. Knepley -vdm_plex_simplex 0 \ 21058214e71cSJoe -dm_swarm_coordinate_density constant -dm_swarm_num_particles 100 \ 21068214e71cSJoe -sigma 1.0e-8 -timeScale 2.0e-14 \ 21078214e71cSJoe -ts_type basicsymplectic -ts_basicsymplectic_type 1 \ 21088214e71cSJoe -output_step 50 -check_vel_res 21098214e71cSJoe test: 21108214e71cSJoe suffix: none_1d 21119072cb8bSMatthew G. Knepley requires: 21128214e71cSJoe args: -em_type none -error 21138214e71cSJoe test: 21148214e71cSJoe suffix: coulomb_1d 21158214e71cSJoe args: -em_type coulomb 21168214e71cSJoe 21178214e71cSJoe # for viewers 21188214e71cSJoe #-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 21198214e71cSJoe testset: 21208214e71cSJoe nsize: {{1 2}} 21218214e71cSJoe requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT) 2122045208b8SMatthew G. Knepley args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 36 \ 2123045208b8SMatthew G. Knepley -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \ 21248214e71cSJoe -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \ 21258214e71cSJoe -vdm_plex_box_lower -3 -vdm_plex_box_upper 3 \ 212684467f86SMatthew G. Knepley -dm_swarm_num_species 1 -twostream -charges -1.,1. -sigma 1.0e-8 \ 21278214e71cSJoe -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \ 21288214e71cSJoe -ts_type basicsymplectic -ts_basicsymplectic_type 2 \ 21298214e71cSJoe -ts_dt 0.01 -ts_max_time 5 -ts_max_steps 10 \ 21308214e71cSJoe -em_snes_atol 1.e-15 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \ 213184467f86SMatthew G. Knepley -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1 21328214e71cSJoe test: 21338214e71cSJoe suffix: two_stream_c0 21348214e71cSJoe args: -em_type primal -petscfe_default_quadrature_order 2 -petscspace_degree 2 -em_pc_type svd 21358214e71cSJoe test: 21368214e71cSJoe suffix: two_stream_rt 21378214e71cSJoe requires: superlu_dist 21388214e71cSJoe args: -em_type mixed \ 21398214e71cSJoe -potential_petscspace_degree 0 \ 21408214e71cSJoe -potential_petscdualspace_lagrange_use_moments \ 21418214e71cSJoe -potential_petscdualspace_lagrange_moment_order 2 \ 2142045208b8SMatthew G. Knepley -field_petscspace_degree 1 -field_petscfe_default_quadrature_order 1 \ 21438214e71cSJoe -em_snes_error_if_not_converged \ 21448214e71cSJoe -em_ksp_type preonly -em_ksp_error_if_not_converged \ 21458214e71cSJoe -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \ 21468214e71cSJoe -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \ 21478214e71cSJoe -em_fieldsplit_field_pc_type lu \ 21488214e71cSJoe -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \ 21498214e71cSJoe -em_fieldsplit_potential_pc_type svd 21508214e71cSJoe 215184467f86SMatthew G. Knepley # For an eyeball check, we use 21529072cb8bSMatthew G. Knepley # -ts_max_steps 1000 -dm_plex_box_faces 10,1 -vdm_plex_box_faces 2000 -efield_monitor 21538214e71cSJoe # For verification, we use 215484467f86SMatthew G. Knepley # -ts_max_steps 1000 -dm_plex_box_faces 100,1 -vdm_plex_box_faces 8000 -dm_swarm_num_particles 800000 -monitor_efield 21558214e71cSJoe # -ts_monitor_sp_swarm_multi_species 0 -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500 21568214e71cSJoe testset: 21578214e71cSJoe nsize: {{1 2}} 21588214e71cSJoe requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT) 2159045208b8SMatthew G. Knepley args: -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 10 \ 2160045208b8SMatthew G. Knepley -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \ 21618214e71cSJoe -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \ 21628214e71cSJoe -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \ 2163f1e6e573SMatthew G. Knepley -vpetscspace_degree 2 -vdm_plex_hash_location \ 216484467f86SMatthew G. Knepley -dm_swarm_num_species 1 -charges -1.,1. \ 21658214e71cSJoe -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \ 21668214e71cSJoe -ts_type basicsymplectic -ts_basicsymplectic_type 1 \ 21678214e71cSJoe -ts_dt 0.03 -ts_max_time 500 -ts_max_steps 1 \ 21688214e71cSJoe -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \ 216984467f86SMatthew G. Knepley -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1 21708214e71cSJoe 21718214e71cSJoe test: 21728214e71cSJoe suffix: uniform_equilibrium_1d 21738214e71cSJoe args: -cosine_coefficients 0.0,0.5 -em_type primal -petscspace_degree 1 -em_pc_type svd 21748214e71cSJoe test: 217575155f48SMatthew G. Knepley suffix: uniform_equilibrium_1d_real 2176045208b8SMatthew G. Knepley args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \ 217775155f48SMatthew G. Knepley -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \ 217875155f48SMatthew G. Knepley -cosine_coefficients 0.0 -em_type primal -petscspace_degree 1 -em_pc_type svd 217975155f48SMatthew G. Knepley test: 21808214e71cSJoe suffix: uniform_primal_1d 21818214e71cSJoe args: -em_type primal -petscspace_degree 1 -em_pc_type svd 21828214e71cSJoe test: 218375155f48SMatthew G. Knepley suffix: uniform_primal_1d_real 2184045208b8SMatthew G. Knepley args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \ 218575155f48SMatthew G. Knepley -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \ 218675155f48SMatthew G. Knepley -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd 21879072cb8bSMatthew G. Knepley # NOT WORKING -ftop_pc_type bjacobi -ftop_sub_pc_type lu -ftop_sub_pc_factor_shift_type nonzero 21889072cb8bSMatthew G. Knepley test: 21899072cb8bSMatthew G. Knepley suffix: uniform_primal_1d_real_pfak 21909072cb8bSMatthew G. Knepley nsize: 1 2191045208b8SMatthew G. Knepley args: -dm_plex_dim 1 -dm_plex_simplex 1 -dm_plex_box_faces 10 \ 21929072cb8bSMatthew G. Knepley -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \ 21939072cb8bSMatthew 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 \ 21949072cb8bSMatthew G. Knepley -remap_dm_plex_box_lower 0.,-10. -remap_dm_plex_box_upper 12.5664,10. \ 21959072cb8bSMatthew G. Knepley -remap_petscspace_degree 2 -remap_dm_plex_hash_location \ 2196045208b8SMatthew G. Knepley -remap_freq 1 -dm_swarm_remap_type pfak \ 21979072cb8bSMatthew G. Knepley -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 \ 21989072cb8bSMatthew G. Knepley -ptof_pc_type lu \ 21999072cb8bSMatthew G. Knepley -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd -em_proj_pc_type lu 220075155f48SMatthew G. Knepley test: 22018214e71cSJoe requires: superlu_dist 22028214e71cSJoe suffix: uniform_mixed_1d 22038214e71cSJoe args: -em_type mixed \ 22048214e71cSJoe -potential_petscspace_degree 0 \ 22058214e71cSJoe -potential_petscdualspace_lagrange_use_moments \ 22068214e71cSJoe -potential_petscdualspace_lagrange_moment_order 2 \ 2207045208b8SMatthew G. Knepley -field_petscspace_degree 1 \ 22088214e71cSJoe -em_snes_error_if_not_converged \ 22098214e71cSJoe -em_ksp_type preonly -em_ksp_error_if_not_converged \ 22108214e71cSJoe -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \ 22118214e71cSJoe -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \ 22128214e71cSJoe -em_fieldsplit_field_pc_type lu \ 22138214e71cSJoe -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \ 22148214e71cSJoe -em_fieldsplit_potential_pc_type svd 22158214e71cSJoe 2216b80bf5b1SJoe Pusztay TEST*/ 2217