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