18214e71cSJoe static char help[] = "Landau Damping/Two Stream instability test using Vlasov-Poisson equations\n"; 2b80bf5b1SJoe Pusztay 38214e71cSJoe /* 4*9072cb8bSMatthew G. Knepley TODO: 5*9072cb8bSMatthew G. Knepley - Cache mesh geometry 6*9072cb8bSMatthew G. Knepley - Move electrostatic solver to MG+SVD 7*9072cb8bSMatthew 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 11*9072cb8bSMatthew G. Knepley To visualize the maximum electric field use 128214e71cSJoe 13*9072cb8bSMatthew G. Knepley -efield_monitor 148214e71cSJoe 15*9072cb8bSMatthew G. Knepley To monitor velocity moments of the distribution use 16f1e6e573SMatthew G. Knepley 17*9072cb8bSMatthew G. Knepley -ptof_pc_type lu -moments_monitor 18*9072cb8bSMatthew G. Knepley 19*9072cb8bSMatthew G. Knepley To monitor the particle positions in phase space use 20*9072cb8bSMatthew G. Knepley 21*9072cb8bSMatthew G. Knepley -positions_monitor 22*9072cb8bSMatthew G. Knepley 23*9072cb8bSMatthew G. Knepley To monitor the charge density, E field, and potential use 24*9072cb8bSMatthew G. Knepley 25*9072cb8bSMatthew G. Knepley -poisson_monitor 26*9072cb8bSMatthew G. Knepley 27*9072cb8bSMatthew G. Knepley To monitor the remapping field use 28*9072cb8bSMatthew G. Knepley 29*9072cb8bSMatthew 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 4184467f86SMatthew G. Knepley -dm_plex_dim 2 -fake_1D -dm_plex_simplex 0 -dm_plex_box_faces 10,1 \ 4284467f86SMatthew G. Knepley -dm_plex_box_lower 0.,-0.5 -dm_plex_box_upper 12.5664,0.5 -dm_plex_box_bd periodic,none \ 4384467f86SMatthew G. Knepley -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 2000 -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \ 4484467f86SMatthew G. Knepley -dm_swarm_num_species 1 -charges -1.,1. \ 4584467f86SMatthew G. Knepley -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \ 4684467f86SMatthew G. Knepley -ts_type basicsymplectic -ts_basicsymplectic_type 1 -ts_dt 0.03 -ts_max_time 500 -ts_max_steps 500 \ 4784467f86SMatthew 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 \ 48*9072cb8bSMatthew G. Knepley -output_step 100 -check_vel_res -efield_monitor -ts_monitor -log_view 4984467f86SMatthew G. Knepley 508214e71cSJoe */ 51b80bf5b1SJoe Pusztay #include <petscts.h> 528214e71cSJoe #include <petscdmplex.h> 538214e71cSJoe #include <petscdmswarm.h> 548214e71cSJoe #include <petscfe.h> 558214e71cSJoe #include <petscds.h> 568214e71cSJoe #include <petscbag.h> 578214e71cSJoe #include <petscdraw.h> 588214e71cSJoe #include <petsc/private/dmpleximpl.h> /* For norm and dot */ 598214e71cSJoe #include <petsc/private/petscfeimpl.h> /* For interpolation */ 6084467f86SMatthew G. Knepley #include <petsc/private/dmswarmimpl.h> /* For swarm debugging */ 618214e71cSJoe #include "petscdm.h" 628214e71cSJoe #include "petscdmlabel.h" 638214e71cSJoe 648214e71cSJoe PETSC_EXTERN PetscErrorCode stream(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 658214e71cSJoe PETSC_EXTERN PetscErrorCode line(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 668214e71cSJoe 678214e71cSJoe const char *EMTypes[] = {"primal", "mixed", "coulomb", "none", "EMType", "EM_", NULL}; 688214e71cSJoe typedef enum { 698214e71cSJoe EM_PRIMAL, 708214e71cSJoe EM_MIXED, 718214e71cSJoe EM_COULOMB, 728214e71cSJoe EM_NONE 738214e71cSJoe } EMType; 748214e71cSJoe 75*9072cb8bSMatthew G. Knepley const char *RemapTypes[] = {"colella", "pfak", "RemapType", "RM_", NULL}; 76*9072cb8bSMatthew G. Knepley typedef enum { 77*9072cb8bSMatthew G. Knepley RM_COLELLA, 78*9072cb8bSMatthew G. Knepley RM_PFAK, 79*9072cb8bSMatthew G. Knepley } RemapType; 80*9072cb8bSMatthew G. Knepley 818214e71cSJoe typedef enum { 828214e71cSJoe V0, 838214e71cSJoe X0, 848214e71cSJoe T0, 858214e71cSJoe M0, 868214e71cSJoe Q0, 878214e71cSJoe PHI0, 888214e71cSJoe POISSON, 898214e71cSJoe VLASOV, 908214e71cSJoe SIGMA, 918214e71cSJoe NUM_CONSTANTS 928214e71cSJoe } ConstantType; 938214e71cSJoe typedef struct { 948214e71cSJoe PetscScalar v0; /* Velocity scale, often the thermal velocity */ 958214e71cSJoe PetscScalar t0; /* Time scale */ 968214e71cSJoe PetscScalar x0; /* Space scale */ 978214e71cSJoe PetscScalar m0; /* Mass scale */ 988214e71cSJoe PetscScalar q0; /* Charge scale */ 998214e71cSJoe PetscScalar kb; 1008214e71cSJoe PetscScalar epsi0; 1018214e71cSJoe PetscScalar phi0; /* Potential scale */ 1028214e71cSJoe PetscScalar poissonNumber; /* Non-Dimensional Poisson Number */ 1038214e71cSJoe PetscScalar vlasovNumber; /* Non-Dimensional Vlasov Number */ 1048214e71cSJoe PetscReal sigma; /* Nondimensional charge per length in x */ 1058214e71cSJoe } Parameter; 106b80bf5b1SJoe Pusztay 107b80bf5b1SJoe Pusztay typedef struct { 108*9072cb8bSMatthew G. Knepley PetscBag bag; // Problem parameters 109*9072cb8bSMatthew G. Knepley PetscBool error; // Flag for printing the error 110*9072cb8bSMatthew G. Knepley PetscBool remap; // Flag to remap particles 111*9072cb8bSMatthew G. Knepley RemapType remapType; // Remap algorithm 112*9072cb8bSMatthew G. Knepley PetscInt remapFreq; // Number of timesteps between remapping 113*9072cb8bSMatthew G. Knepley PetscBool efield_monitor; // Flag to show electric field monitor 114*9072cb8bSMatthew G. Knepley PetscBool moment_monitor; // Flag to show distribution moment monitor 115*9072cb8bSMatthew G. Knepley PetscBool weight_monitor; // Flag to show weight monitor 116*9072cb8bSMatthew G. Knepley PetscBool positions_monitor; // Flag to show particle positins at each time step 117*9072cb8bSMatthew G. Knepley PetscBool poisson_monitor; // Flag to display charge, E field, and potential at each solve 118*9072cb8bSMatthew G. Knepley PetscBool initial_monitor; // Flag to monitor the initial conditions 119*9072cb8bSMatthew G. Knepley PetscBool fake_1D; // Run simulation in 2D but zeroing second dimension 120*9072cb8bSMatthew G. Knepley PetscBool perturbed_weights; // Uniformly sample x,v space with gaussian weights 121*9072cb8bSMatthew G. Knepley PetscInt ostep; // Print the energy at each ostep time steps 1228214e71cSJoe PetscInt numParticles; 1238214e71cSJoe PetscReal timeScale; /* Nondimensionalizing time scale */ 1248214e71cSJoe PetscReal charges[2]; /* The charges of each species */ 1258214e71cSJoe PetscReal masses[2]; /* The masses of each species */ 1268214e71cSJoe PetscReal thermal_energy[2]; /* Thermal Energy (used to get other constants)*/ 1278214e71cSJoe PetscReal cosine_coefficients[2]; /*(alpha, k)*/ 1288214e71cSJoe PetscReal totalWeight; 1298214e71cSJoe PetscReal stepSize; 1308214e71cSJoe PetscInt steps; 1318214e71cSJoe PetscReal initVel; 132f1e6e573SMatthew G. Knepley EMType em; // Type of electrostatic model 133f1e6e573SMatthew G. Knepley SNES snes; // EM solver 134f1e6e573SMatthew G. Knepley Mat M; // The finite element mass matrix 135f1e6e573SMatthew G. Knepley PetscFEGeom *fegeom; // Geometric information for the DM cells 1368214e71cSJoe PetscDraw drawic_x; 1378214e71cSJoe PetscDraw drawic_v; 1388214e71cSJoe PetscDraw drawic_w; 1398214e71cSJoe PetscDrawHG drawhgic_x; 1408214e71cSJoe PetscDrawHG drawhgic_v; 1418214e71cSJoe PetscDrawHG drawhgic_w; 142*9072cb8bSMatthew G. Knepley PetscBool validE; // Flag to indicate E-field in swarm is valid 14375155f48SMatthew G. Knepley PetscReal drawlgEmin; // The minimum lg(E) to plot 14475155f48SMatthew G. Knepley PetscDrawLG drawlgE; // Logarithm of maximum electric field 14575155f48SMatthew G. Knepley PetscDrawSP drawspE; // Electric field at particle positions 14675155f48SMatthew G. Knepley PetscDrawSP drawspX; // Particle positions 14775155f48SMatthew G. Knepley PetscViewer viewerRho; // Charge density viewer 14875155f48SMatthew G. Knepley PetscViewer viewerPhi; // Potential viewer 1498214e71cSJoe DM swarm; 1508214e71cSJoe PetscRandom random; 1518214e71cSJoe PetscBool twostream; 1528214e71cSJoe PetscBool checkweights; 1538214e71cSJoe PetscInt checkVRes; /* Flag to check/output velocity residuals for nightly tests */ 15484467f86SMatthew G. Knepley 15584467f86SMatthew G. Knepley PetscLogEvent RhsXEvent, RhsVEvent, ESolveEvent, ETabEvent; 156b80bf5b1SJoe Pusztay } AppCtx; 157b80bf5b1SJoe Pusztay 158d71ae5a4SJacob Faibussowitsch static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) 159d71ae5a4SJacob Faibussowitsch { 160b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 1618214e71cSJoe PetscInt d = 2; 1628214e71cSJoe PetscInt maxSpecies = 2; 1638214e71cSJoe options->error = PETSC_FALSE; 164*9072cb8bSMatthew G. Knepley options->remap = PETSC_FALSE; 165*9072cb8bSMatthew G. Knepley options->remapType = RM_COLELLA; 166*9072cb8bSMatthew G. Knepley options->remapFreq = 1; 1678214e71cSJoe options->efield_monitor = PETSC_FALSE; 168f1e6e573SMatthew G. Knepley options->moment_monitor = PETSC_FALSE; 169*9072cb8bSMatthew G. Knepley options->weight_monitor = PETSC_FALSE; 1708214e71cSJoe options->initial_monitor = PETSC_FALSE; 1718214e71cSJoe options->fake_1D = PETSC_FALSE; 1728214e71cSJoe options->perturbed_weights = PETSC_FALSE; 1738214e71cSJoe options->poisson_monitor = PETSC_FALSE; 174*9072cb8bSMatthew G. Knepley options->positions_monitor = PETSC_FALSE; 1758214e71cSJoe options->ostep = 100; 1768214e71cSJoe options->timeScale = 2.0e-14; 1778214e71cSJoe options->charges[0] = -1.0; 1788214e71cSJoe options->charges[1] = 1.0; 1798214e71cSJoe options->masses[0] = 1.0; 1808214e71cSJoe options->masses[1] = 1000.0; 1818214e71cSJoe options->thermal_energy[0] = 1.0; 1828214e71cSJoe options->thermal_energy[1] = 1.0; 1838214e71cSJoe options->cosine_coefficients[0] = 0.01; 1848214e71cSJoe options->cosine_coefficients[1] = 0.5; 1858214e71cSJoe options->initVel = 1; 1868214e71cSJoe options->totalWeight = 1.0; 1878214e71cSJoe options->drawic_x = NULL; 1888214e71cSJoe options->drawic_v = NULL; 1898214e71cSJoe options->drawic_w = NULL; 1908214e71cSJoe options->drawhgic_x = NULL; 1918214e71cSJoe options->drawhgic_v = NULL; 1928214e71cSJoe options->drawhgic_w = NULL; 19375155f48SMatthew G. Knepley options->drawlgEmin = -6; 19475155f48SMatthew G. Knepley options->drawlgE = NULL; 19575155f48SMatthew G. Knepley options->drawspE = NULL; 19675155f48SMatthew G. Knepley options->drawspX = NULL; 19775155f48SMatthew G. Knepley options->viewerRho = NULL; 19875155f48SMatthew G. Knepley options->viewerPhi = NULL; 1998214e71cSJoe options->em = EM_COULOMB; 2008214e71cSJoe options->numParticles = 32768; 2018214e71cSJoe options->twostream = PETSC_FALSE; 2028214e71cSJoe options->checkweights = PETSC_FALSE; 2038214e71cSJoe options->checkVRes = 0; 204b80bf5b1SJoe Pusztay 2058214e71cSJoe PetscOptionsBegin(comm, "", "Landau Damping and Two Stream options", "DMSWARM"); 2068214e71cSJoe PetscCall(PetscOptionsBool("-error", "Flag to print the error", "ex2.c", options->error, &options->error, NULL)); 207*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-remap", "Flag to remap the particles", "ex2.c", options->remap, &options->remap, NULL)); 208*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsInt("-remap_freq", "Number", "ex2.c", options->remapFreq, &options->remapFreq, NULL)); 209*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsEnum("-remap_type", "Remap algorithm", "ex2.c", RemapTypes, (PetscEnum)options->remapType, (PetscEnum *)&options->remapType, NULL)); 210*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-efield_monitor", "Flag to plot log(max E) over time", "ex2.c", options->efield_monitor, &options->efield_monitor, NULL)); 211*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsReal("-efield_min_monitor", "Minimum E field to plot", "ex2.c", options->drawlgEmin, &options->drawlgEmin, NULL)); 212*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-moments_monitor", "Flag to show moments table", "ex2.c", options->moment_monitor, &options->moment_monitor, NULL)); 213*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-weight_monitor", "The flag to show particle weights", "ex2.c", options->weight_monitor, &options->weight_monitor, NULL)); 214*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-ics_monitor", "Flag to show initial condition histograms", "ex2.c", options->initial_monitor, &options->initial_monitor, NULL)); 215*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-positions_monitor", "The flag to show particle positions", "ex2.c", options->positions_monitor, &options->positions_monitor, NULL)); 216*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBool("-poisson_monitor", "The flag to show charges, Efield and potential solve", "ex2.c", options->poisson_monitor, &options->poisson_monitor, NULL)); 2178214e71cSJoe PetscCall(PetscOptionsBool("-fake_1D", "Flag to run a 1D simulation (but really in 2D)", "ex2.c", options->fake_1D, &options->fake_1D, NULL)); 2188214e71cSJoe PetscCall(PetscOptionsBool("-twostream", "Run two stream instability", "ex2.c", options->twostream, &options->twostream, NULL)); 2198214e71cSJoe PetscCall(PetscOptionsBool("-perturbed_weights", "Flag to run uniform sampling with perturbed weights", "ex2.c", options->perturbed_weights, &options->perturbed_weights, NULL)); 2208214e71cSJoe PetscCall(PetscOptionsBool("-check_weights", "Ensure all particle weights are positive", "ex2.c", options->checkweights, &options->checkweights, NULL)); 2218214e71cSJoe PetscCall(PetscOptionsInt("-check_vel_res", "Check particle velocity residuals for nightly tests", "ex2.c", options->checkVRes, &options->checkVRes, NULL)); 2228214e71cSJoe PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", "ex2.c", options->ostep, &options->ostep, NULL)); 2238214e71cSJoe PetscCall(PetscOptionsReal("-timeScale", "Nondimensionalizing time scale", "ex2.c", options->timeScale, &options->timeScale, NULL)); 2248214e71cSJoe PetscCall(PetscOptionsReal("-initial_velocity", "Initial velocity of perturbed particle", "ex2.c", options->initVel, &options->initVel, NULL)); 2258214e71cSJoe PetscCall(PetscOptionsReal("-total_weight", "Total weight of all particles", "ex2.c", options->totalWeight, &options->totalWeight, NULL)); 2268214e71cSJoe PetscCall(PetscOptionsRealArray("-cosine_coefficients", "Amplitude and frequency of cosine equation used in initialization", "ex2.c", options->cosine_coefficients, &d, NULL)); 2278214e71cSJoe PetscCall(PetscOptionsRealArray("-charges", "Species charges", "ex2.c", options->charges, &maxSpecies, NULL)); 2288214e71cSJoe PetscCall(PetscOptionsEnum("-em_type", "Type of electrostatic solver", "ex2.c", EMTypes, (PetscEnum)options->em, (PetscEnum *)&options->em, NULL)); 229d0609cedSBarry Smith PetscOptionsEnd(); 23084467f86SMatthew G. Knepley 23184467f86SMatthew G. Knepley PetscCall(PetscLogEventRegister("RhsX", TS_CLASSID, &options->RhsXEvent)); 23284467f86SMatthew G. Knepley PetscCall(PetscLogEventRegister("RhsV", TS_CLASSID, &options->RhsVEvent)); 23384467f86SMatthew G. Knepley PetscCall(PetscLogEventRegister("ESolve", TS_CLASSID, &options->ESolveEvent)); 23484467f86SMatthew G. Knepley PetscCall(PetscLogEventRegister("ETab", TS_CLASSID, &options->ETabEvent)); 2353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 236b80bf5b1SJoe Pusztay } 237b80bf5b1SJoe Pusztay 2388214e71cSJoe static PetscErrorCode SetupContext(DM dm, DM sw, AppCtx *user) 2398214e71cSJoe { 2408214e71cSJoe PetscFunctionBeginUser; 2418214e71cSJoe if (user->efield_monitor) { 24275155f48SMatthew G. Knepley PetscDraw draw; 24375155f48SMatthew G. Knepley PetscDrawAxis axis; 24475155f48SMatthew G. Knepley 24575155f48SMatthew G. Knepley PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "Max Electric Field", 0, 300, 400, 300, &draw)); 24675155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(draw, "ex9_Efield")); 24775155f48SMatthew G. Knepley PetscCall(PetscDrawSetFromOptions(draw)); 24875155f48SMatthew G. Knepley PetscCall(PetscDrawLGCreate(draw, 1, &user->drawlgE)); 24975155f48SMatthew G. Knepley PetscCall(PetscDrawDestroy(&draw)); 25075155f48SMatthew G. Knepley PetscCall(PetscDrawLGGetAxis(user->drawlgE, &axis)); 25175155f48SMatthew G. Knepley PetscCall(PetscDrawAxisSetLabels(axis, "Electron Electric Field", "time", "E_max")); 25275155f48SMatthew G. Knepley PetscCall(PetscDrawLGSetLimits(user->drawlgE, 0., user->steps * user->stepSize, user->drawlgEmin, 0.)); 2538214e71cSJoe } 2548214e71cSJoe if (user->initial_monitor) { 2558214e71cSJoe PetscDrawAxis axis1, axis2, axis3; 2568214e71cSJoe PetscReal dmboxlower[2], dmboxupper[2]; 2578214e71cSJoe PetscInt dim, cStart, cEnd; 2588214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 2598214e71cSJoe PetscCall(DMGetBoundingBox(dm, dmboxlower, dmboxupper)); 2608214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2618214e71cSJoe 2628214e71cSJoe PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_x", 0, 300, 400, 300, &user->drawic_x)); 26375155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(user->drawic_x, "ex9_ic_x")); 2648214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->drawic_x)); 2656497c311SBarry Smith PetscCall(PetscDrawHGCreate(user->drawic_x, (int)dim, &user->drawhgic_x)); 2668214e71cSJoe PetscCall(PetscDrawHGGetAxis(user->drawhgic_x, &axis1)); 2676497c311SBarry Smith PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_x, (int)(cEnd - cStart))); 2688214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis1, "Initial X Distribution", "X", "counts")); 2698214e71cSJoe PetscCall(PetscDrawAxisSetLimits(axis1, dmboxlower[0], dmboxupper[0], 0, 1500)); 2708214e71cSJoe 2718214e71cSJoe PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_v", 400, 300, 400, 300, &user->drawic_v)); 27275155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(user->drawic_v, "ex9_ic_v")); 2738214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->drawic_v)); 2746497c311SBarry Smith PetscCall(PetscDrawHGCreate(user->drawic_v, (int)dim, &user->drawhgic_v)); 2758214e71cSJoe PetscCall(PetscDrawHGGetAxis(user->drawhgic_v, &axis2)); 2768214e71cSJoe PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_v, 1000)); 2778214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis2, "Initial V_x Distribution", "V", "counts")); 2788214e71cSJoe PetscCall(PetscDrawAxisSetLimits(axis2, -1, 1, 0, 1500)); 2798214e71cSJoe 2808214e71cSJoe PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_w", 800, 300, 400, 300, &user->drawic_w)); 28175155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(user->drawic_w, "ex9_ic_w")); 2828214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->drawic_w)); 2836497c311SBarry Smith PetscCall(PetscDrawHGCreate(user->drawic_w, (int)dim, &user->drawhgic_w)); 2848214e71cSJoe PetscCall(PetscDrawHGGetAxis(user->drawhgic_w, &axis3)); 2858214e71cSJoe PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_w, 10)); 2868214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis3, "Initial W Distribution", "weight", "counts")); 2878214e71cSJoe PetscCall(PetscDrawAxisSetLimits(axis3, 0, 0.01, 0, 5000)); 2888214e71cSJoe } 289*9072cb8bSMatthew G. Knepley if (user->positions_monitor) { 29075155f48SMatthew G. Knepley PetscDraw draw; 2918214e71cSJoe PetscDrawAxis axis; 2928214e71cSJoe 29375155f48SMatthew G. Knepley PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "Particle Position", 0, 0, 400, 300, &draw)); 29475155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(draw, "ex9_pos")); 29575155f48SMatthew G. Knepley PetscCall(PetscDrawSetFromOptions(draw)); 29675155f48SMatthew G. Knepley PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspX)); 29775155f48SMatthew G. Knepley PetscCall(PetscDrawDestroy(&draw)); 29875155f48SMatthew G. Knepley PetscCall(PetscDrawSPSetDimension(user->drawspX, 1)); 29975155f48SMatthew G. Knepley PetscCall(PetscDrawSPGetAxis(user->drawspX, &axis)); 3008214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "v")); 30175155f48SMatthew G. Knepley PetscCall(PetscDrawSPReset(user->drawspX)); 3028214e71cSJoe } 3038214e71cSJoe if (user->poisson_monitor) { 30475155f48SMatthew G. Knepley Vec rho, phi; 30575155f48SMatthew G. Knepley PetscDraw draw; 30675155f48SMatthew G. Knepley PetscDrawAxis axis; 3078214e71cSJoe 30875155f48SMatthew G. Knepley PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "Electric_Field", 0, 0, 400, 300, &draw)); 30975155f48SMatthew G. Knepley PetscCall(PetscDrawSetFromOptions(draw)); 31075155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(draw, "ex9_E_spatial")); 31175155f48SMatthew G. Knepley PetscCall(PetscDrawSPCreate(draw, 10, &user->drawspE)); 31275155f48SMatthew G. Knepley PetscCall(PetscDrawDestroy(&draw)); 31375155f48SMatthew G. Knepley PetscCall(PetscDrawSPSetDimension(user->drawspE, 1)); 31475155f48SMatthew G. Knepley PetscCall(PetscDrawSPGetAxis(user->drawspE, &axis)); 31575155f48SMatthew G. Knepley PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "E")); 31675155f48SMatthew G. Knepley PetscCall(PetscDrawSPReset(user->drawspE)); 3178214e71cSJoe 31875155f48SMatthew G. Knepley PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, NULL, "Charge Density", 0, 0, 400, 300, &user->viewerRho)); 31975155f48SMatthew G. Knepley PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerRho, "rho_")); 32075155f48SMatthew G. Knepley PetscCall(PetscViewerDrawGetDraw(user->viewerRho, 0, &draw)); 32175155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(draw, "ex9_rho_spatial")); 32275155f48SMatthew G. Knepley PetscCall(PetscViewerSetFromOptions(user->viewerRho)); 32375155f48SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(dm, "rho", &rho)); 32475155f48SMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)rho, "charge_density")); 32575155f48SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(dm, "rho", &rho)); 3268214e71cSJoe 32775155f48SMatthew G. Knepley PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, NULL, "Potential", 400, 0, 400, 300, &user->viewerPhi)); 32875155f48SMatthew G. Knepley PetscCall(PetscObjectSetOptionsPrefix((PetscObject)user->viewerPhi, "phi_")); 32975155f48SMatthew G. Knepley PetscCall(PetscViewerDrawGetDraw(user->viewerPhi, 0, &draw)); 33075155f48SMatthew G. Knepley PetscCall(PetscDrawSetSave(draw, "ex9_phi_spatial")); 33175155f48SMatthew G. Knepley PetscCall(PetscViewerSetFromOptions(user->viewerPhi)); 33275155f48SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(dm, "phi", &phi)); 33375155f48SMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)phi, "potential")); 33475155f48SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(dm, "phi", &phi)); 3358214e71cSJoe } 3368214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 3378214e71cSJoe } 3388214e71cSJoe 3398214e71cSJoe static PetscErrorCode DestroyContext(AppCtx *user) 3408214e71cSJoe { 3418214e71cSJoe PetscFunctionBeginUser; 3428214e71cSJoe PetscCall(PetscDrawHGDestroy(&user->drawhgic_x)); 3438214e71cSJoe PetscCall(PetscDrawDestroy(&user->drawic_x)); 3448214e71cSJoe PetscCall(PetscDrawHGDestroy(&user->drawhgic_v)); 3458214e71cSJoe PetscCall(PetscDrawDestroy(&user->drawic_v)); 3468214e71cSJoe PetscCall(PetscDrawHGDestroy(&user->drawhgic_w)); 3478214e71cSJoe PetscCall(PetscDrawDestroy(&user->drawic_w)); 3488214e71cSJoe 34975155f48SMatthew G. Knepley PetscCall(PetscDrawLGDestroy(&user->drawlgE)); 35075155f48SMatthew G. Knepley PetscCall(PetscDrawSPDestroy(&user->drawspE)); 35175155f48SMatthew G. Knepley PetscCall(PetscDrawSPDestroy(&user->drawspX)); 35275155f48SMatthew G. Knepley PetscCall(PetscViewerDestroy(&user->viewerRho)); 35375155f48SMatthew G. Knepley PetscCall(PetscViewerDestroy(&user->viewerPhi)); 3548214e71cSJoe 3558214e71cSJoe PetscCall(PetscBagDestroy(&user->bag)); 3568214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 3578214e71cSJoe } 3588214e71cSJoe 3598214e71cSJoe static PetscErrorCode CheckNonNegativeWeights(DM sw, AppCtx *user) 3608214e71cSJoe { 3618214e71cSJoe const PetscScalar *w; 3628214e71cSJoe PetscInt Np; 3638214e71cSJoe 3648214e71cSJoe PetscFunctionBeginUser; 3658214e71cSJoe if (!user->checkweights) PetscFunctionReturn(PETSC_SUCCESS); 3668214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w)); 3678214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 3688214e71cSJoe 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]); 3698214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w)); 3708214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 3718214e71cSJoe } 3728214e71cSJoe 373*9072cb8bSMatthew G. Knepley static PetscErrorCode computeVelocityFEMMoments(DM sw, PetscReal moments[], AppCtx *user) 3748214e71cSJoe { 375*9072cb8bSMatthew G. Knepley DMSwarmCellDM celldm; 376f1e6e573SMatthew G. Knepley DM vdm; 377f1e6e573SMatthew G. Knepley Vec u[1]; 378f1e6e573SMatthew G. Knepley const char *fields[1] = {"w_q"}; 3798214e71cSJoe 380f1e6e573SMatthew G. Knepley PetscFunctionBegin; 381*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(sw, "velocity")); 382*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 383*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMGetDM(celldm, &vdm)); 384f1e6e573SMatthew G. Knepley PetscCall(DMGetGlobalVector(vdm, &u[0])); 385f1e6e573SMatthew G. Knepley PetscCall(DMSwarmProjectFields(sw, vdm, 1, fields, u, SCATTER_FORWARD)); 386f1e6e573SMatthew G. Knepley PetscCall(DMPlexComputeMoments(vdm, u[0], moments)); 387f1e6e573SMatthew G. Knepley PetscCall(DMRestoreGlobalVector(vdm, &u[0])); 388*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(sw, "space")); 3898214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 3908214e71cSJoe } 3918214e71cSJoe 3928214e71cSJoe static PetscErrorCode MonitorEField(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 3938214e71cSJoe { 3948214e71cSJoe AppCtx *user = (AppCtx *)ctx; 395f1e6e573SMatthew G. Knepley DM sw; 396f1e6e573SMatthew G. Knepley PetscReal *E, *x, *weight; 397f1e6e573SMatthew G. Knepley PetscReal Enorm = 0., lgEnorm, lgEmax, sum = 0., Emax = 0., chargesum = 0.; 398f1e6e573SMatthew G. Knepley PetscReal pmoments[4]; /* \int f, \int v f, \int v^2 f */ 399f1e6e573SMatthew G. Knepley PetscInt *species, dim, Np; 4008214e71cSJoe 4018214e71cSJoe PetscFunctionBeginUser; 402*9072cb8bSMatthew G. Knepley if (step < 0 || !user->validE) PetscFunctionReturn(PETSC_SUCCESS); 4038214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 4048214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 4058214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 4068214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 4078214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 4088214e71cSJoe PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 4098214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 4108214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 4118214e71cSJoe 412f1e6e573SMatthew G. Knepley for (PetscInt p = 0; p < Np; ++p) { 413f1e6e573SMatthew G. Knepley for (PetscInt d = 0; d < 1; ++d) { 414f1e6e573SMatthew G. Knepley PetscReal temp = PetscAbsReal(E[p * dim + d]); 4158214e71cSJoe if (temp > Emax) Emax = temp; 4168214e71cSJoe } 4178214e71cSJoe Enorm += PetscSqrtReal(E[p * dim] * E[p * dim]); 4188214e71cSJoe sum += E[p * dim]; 4198214e71cSJoe chargesum += user->charges[0] * weight[p]; 4208214e71cSJoe } 4218214e71cSJoe lgEnorm = Enorm != 0 ? PetscLog10Real(Enorm) : -16.; 42275155f48SMatthew G. Knepley lgEmax = Emax != 0 ? PetscLog10Real(Emax) : user->drawlgEmin; 4238214e71cSJoe 4248214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 4258214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 4268214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 4278214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 42875155f48SMatthew G. Knepley PetscCall(PetscDrawLGAddPoint(user->drawlgE, &t, &lgEmax)); 42975155f48SMatthew G. Knepley PetscCall(PetscDrawLGDraw(user->drawlgE)); 43075155f48SMatthew G. Knepley PetscDraw draw; 43175155f48SMatthew G. Knepley PetscCall(PetscDrawLGGetDraw(user->drawlgE, &draw)); 43275155f48SMatthew G. Knepley PetscCall(PetscDrawSave(draw)); 433f1e6e573SMatthew G. Knepley 434f1e6e573SMatthew G. Knepley PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments)); 43575155f48SMatthew 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])); 43675155f48SMatthew G. Knepley PetscCall(DMViewFromOptions(sw, NULL, "-sw_efield_view")); 437f1e6e573SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 438f1e6e573SMatthew G. Knepley } 439f1e6e573SMatthew G. Knepley 440f1e6e573SMatthew G. Knepley static PetscErrorCode MonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 441f1e6e573SMatthew G. Knepley { 442f1e6e573SMatthew G. Knepley AppCtx *user = (AppCtx *)ctx; 443f1e6e573SMatthew G. Knepley DM sw; 444f1e6e573SMatthew G. Knepley PetscReal pmoments[4], fmoments[4]; /* \int f, \int v f, \int v^2 f */ 445f1e6e573SMatthew G. Knepley 446f1e6e573SMatthew G. Knepley PetscFunctionBeginUser; 447f1e6e573SMatthew G. Knepley if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); 448f1e6e573SMatthew G. Knepley PetscCall(TSGetDM(ts, &sw)); 449f1e6e573SMatthew G. Knepley 450f1e6e573SMatthew G. Knepley PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", pmoments)); 451f1e6e573SMatthew G. Knepley PetscCall(computeVelocityFEMMoments(sw, fmoments, user)); 452f1e6e573SMatthew G. Knepley 453f1e6e573SMatthew 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])); 4548214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 4558214e71cSJoe } 4568214e71cSJoe 4578214e71cSJoe PetscErrorCode MonitorInitialConditions(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 4588214e71cSJoe { 4598214e71cSJoe AppCtx *user = (AppCtx *)ctx; 4608214e71cSJoe DM dm, sw; 4618214e71cSJoe const PetscScalar *u; 4628214e71cSJoe PetscReal *weight, *pos, *vel; 4638214e71cSJoe PetscInt dim, p, Np, cStart, cEnd; 4648214e71cSJoe 4658214e71cSJoe PetscFunctionBegin; 4668214e71cSJoe if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */ 4678214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 4688214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 4698214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 4708214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 4718214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 4728214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 4738214e71cSJoe 4748214e71cSJoe if (step == 0) { 4758214e71cSJoe PetscCall(PetscDrawHGReset(user->drawhgic_x)); 4768214e71cSJoe PetscCall(PetscDrawHGGetDraw(user->drawhgic_x, &user->drawic_x)); 4778214e71cSJoe PetscCall(PetscDrawClear(user->drawic_x)); 4788214e71cSJoe PetscCall(PetscDrawFlush(user->drawic_x)); 4798214e71cSJoe 4808214e71cSJoe PetscCall(PetscDrawHGReset(user->drawhgic_v)); 4818214e71cSJoe PetscCall(PetscDrawHGGetDraw(user->drawhgic_v, &user->drawic_v)); 4828214e71cSJoe PetscCall(PetscDrawClear(user->drawic_v)); 4838214e71cSJoe PetscCall(PetscDrawFlush(user->drawic_v)); 4848214e71cSJoe 4858214e71cSJoe PetscCall(PetscDrawHGReset(user->drawhgic_w)); 4868214e71cSJoe PetscCall(PetscDrawHGGetDraw(user->drawhgic_w, &user->drawic_w)); 4878214e71cSJoe PetscCall(PetscDrawClear(user->drawic_w)); 4888214e71cSJoe PetscCall(PetscDrawFlush(user->drawic_w)); 4898214e71cSJoe 4908214e71cSJoe PetscCall(VecGetArrayRead(U, &u)); 4918214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel)); 4928214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 4938214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos)); 4948214e71cSJoe 4958214e71cSJoe PetscCall(VecGetLocalSize(U, &Np)); 4968214e71cSJoe Np /= dim * 2; 4978214e71cSJoe for (p = 0; p < Np; ++p) { 4988214e71cSJoe PetscCall(PetscDrawHGAddValue(user->drawhgic_x, pos[p * dim])); 4998214e71cSJoe PetscCall(PetscDrawHGAddValue(user->drawhgic_v, vel[p * dim])); 5008214e71cSJoe PetscCall(PetscDrawHGAddValue(user->drawhgic_w, weight[p])); 5018214e71cSJoe } 5028214e71cSJoe 5038214e71cSJoe PetscCall(VecRestoreArrayRead(U, &u)); 5048214e71cSJoe PetscCall(PetscDrawHGDraw(user->drawhgic_x)); 5058214e71cSJoe PetscCall(PetscDrawHGSave(user->drawhgic_x)); 5068214e71cSJoe 5078214e71cSJoe PetscCall(PetscDrawHGDraw(user->drawhgic_v)); 5088214e71cSJoe PetscCall(PetscDrawHGSave(user->drawhgic_v)); 5098214e71cSJoe 5108214e71cSJoe PetscCall(PetscDrawHGDraw(user->drawhgic_w)); 5118214e71cSJoe PetscCall(PetscDrawHGSave(user->drawhgic_w)); 5128214e71cSJoe 5138214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos)); 5148214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel)); 5158214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 5168214e71cSJoe } 5178214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 5188214e71cSJoe } 5198214e71cSJoe 5208214e71cSJoe static PetscErrorCode MonitorPositions_2D(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 5218214e71cSJoe { 5228214e71cSJoe AppCtx *user = (AppCtx *)ctx; 5238214e71cSJoe DM dm, sw; 5248214e71cSJoe PetscScalar *x, *v, *weight; 5258214e71cSJoe PetscReal lower[3], upper[3], speed; 5268214e71cSJoe const PetscInt *s; 5278214e71cSJoe PetscInt dim, cStart, cEnd, c; 5288214e71cSJoe 5298214e71cSJoe PetscFunctionBeginUser; 5308214e71cSJoe if (step > 0 && step % user->ostep == 0) { 5318214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 5328214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 5338214e71cSJoe PetscCall(DMGetDimension(dm, &dim)); 5348214e71cSJoe PetscCall(DMGetBoundingBox(dm, lower, upper)); 5358214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 5368214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 5378214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v)); 5388214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 5398214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&s)); 5408214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 54175155f48SMatthew G. Knepley PetscCall(PetscDrawSPReset(user->drawspX)); 54275155f48SMatthew G. Knepley PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], lower[1], upper[1])); 54375155f48SMatthew G. Knepley PetscCall(PetscDrawSPSetLimits(user->drawspX, lower[0], upper[0], -12, 12)); 5448214e71cSJoe for (c = 0; c < cEnd - cStart; ++c) { 5458214e71cSJoe PetscInt *pidx, Npc, q; 5468214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 5478214e71cSJoe for (q = 0; q < Npc; ++q) { 5488214e71cSJoe const PetscInt p = pidx[q]; 5498214e71cSJoe if (s[p] == 0) { 550*9072cb8bSMatthew G. Knepley speed = 0.; 551*9072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) speed += PetscSqr(v[p * dim + d]); 552*9072cb8bSMatthew G. Knepley speed = PetscSqrtReal(speed); 5538214e71cSJoe if (dim == 1 || user->fake_1D) { 55475155f48SMatthew G. Knepley PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &v[p * dim], &speed)); 5558214e71cSJoe } else { 55675155f48SMatthew G. Knepley PetscCall(PetscDrawSPAddPointColorized(user->drawspX, &x[p * dim], &x[p * dim + 1], &speed)); 5578214e71cSJoe } 5588214e71cSJoe } else if (s[p] == 1) { 55975155f48SMatthew G. Knepley PetscCall(PetscDrawSPAddPoint(user->drawspX, &x[p * dim], &v[p * dim])); 5608214e71cSJoe } 5618214e71cSJoe } 56284467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx)); 5638214e71cSJoe } 56475155f48SMatthew G. Knepley PetscCall(PetscDrawSPDraw(user->drawspX, PETSC_TRUE)); 56575155f48SMatthew G. Knepley PetscDraw draw; 56675155f48SMatthew G. Knepley PetscCall(PetscDrawSPGetDraw(user->drawspX, &draw)); 56775155f48SMatthew G. Knepley PetscCall(PetscDrawSave(draw)); 5688214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 5698214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 5708214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 5718214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v)); 5728214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&s)); 5738214e71cSJoe } 5748214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 5758214e71cSJoe } 5768214e71cSJoe 5778214e71cSJoe static PetscErrorCode MonitorPoisson(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 5788214e71cSJoe { 5798214e71cSJoe AppCtx *user = (AppCtx *)ctx; 5808214e71cSJoe DM dm, sw; 5818214e71cSJoe 5828214e71cSJoe PetscFunctionBeginUser; 5838214e71cSJoe if (step > 0 && step % user->ostep == 0) { 5848214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 5858214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 586*9072cb8bSMatthew G. Knepley 587*9072cb8bSMatthew G. Knepley if (user->validE) { 588*9072cb8bSMatthew G. Knepley PetscScalar *x, *E, *weight; 589*9072cb8bSMatthew G. Knepley PetscReal lower[3], upper[3], xval; 590*9072cb8bSMatthew G. Knepley PetscDraw draw; 591*9072cb8bSMatthew G. Knepley PetscInt dim, cStart, cEnd; 592*9072cb8bSMatthew G. Knepley 5938214e71cSJoe PetscCall(DMGetDimension(dm, &dim)); 5948214e71cSJoe PetscCall(DMGetBoundingBox(dm, lower, upper)); 5958214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 5968214e71cSJoe 59775155f48SMatthew G. Knepley PetscCall(PetscDrawSPReset(user->drawspE)); 5988214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 5998214e71cSJoe PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 6008214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 6018214e71cSJoe 6028214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 603*9072cb8bSMatthew G. Knepley for (PetscInt c = 0; c < cEnd - cStart; ++c) { 60475155f48SMatthew G. Knepley PetscReal Eavg = 0.0; 605*9072cb8bSMatthew G. Knepley PetscInt *pidx, Npc; 606*9072cb8bSMatthew G. Knepley 6078214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 608*9072cb8bSMatthew G. Knepley for (PetscInt q = 0; q < Npc; ++q) { 6098214e71cSJoe const PetscInt p = pidx[q]; 61075155f48SMatthew G. Knepley Eavg += E[p * dim]; 6118214e71cSJoe } 61275155f48SMatthew G. Knepley Eavg /= Npc; 6138214e71cSJoe xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart)); 61475155f48SMatthew G. Knepley PetscCall(PetscDrawSPAddPoint(user->drawspE, &xval, &Eavg)); 61584467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx)); 6168214e71cSJoe } 61775155f48SMatthew G. Knepley PetscCall(PetscDrawSPDraw(user->drawspE, PETSC_TRUE)); 61875155f48SMatthew G. Knepley PetscCall(PetscDrawSPGetDraw(user->drawspE, &draw)); 61975155f48SMatthew G. Knepley PetscCall(PetscDrawSave(draw)); 6208214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 6218214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 6228214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 6238214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 624*9072cb8bSMatthew G. Knepley } 62575155f48SMatthew G. Knepley 62675155f48SMatthew G. Knepley Vec rho, phi; 62775155f48SMatthew G. Knepley 62875155f48SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(dm, "rho", &rho)); 62975155f48SMatthew G. Knepley PetscCall(VecView(rho, user->viewerRho)); 63075155f48SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(dm, "rho", &rho)); 63175155f48SMatthew G. Knepley 63275155f48SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(dm, "phi", &phi)); 63375155f48SMatthew G. Knepley PetscCall(VecView(phi, user->viewerPhi)); 63475155f48SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(dm, "phi", &phi)); 6358214e71cSJoe } 6368214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 6378214e71cSJoe } 6388214e71cSJoe 639*9072cb8bSMatthew G. Knepley static PetscErrorCode MonitorSwarmWeights(DM sw, const char field[]) 640*9072cb8bSMatthew G. Knepley { 641*9072cb8bSMatthew G. Knepley PetscReal *w; 642*9072cb8bSMatthew G. Knepley PetscInt bs; 643*9072cb8bSMatthew G. Knepley 644*9072cb8bSMatthew G. Knepley PetscFunctionBegin; 645*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, field, &bs, NULL, (void **)&w)); 646*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, field, &bs, NULL, (void **)&w)); 647*9072cb8bSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 648*9072cb8bSMatthew G. Knepley } 649*9072cb8bSMatthew G. Knepley 6508214e71cSJoe static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx) 6518214e71cSJoe { 6528214e71cSJoe PetscBag bag; 6538214e71cSJoe Parameter *p; 6548214e71cSJoe 6558214e71cSJoe PetscFunctionBeginUser; 6568214e71cSJoe /* setup PETSc parameter bag */ 6578214e71cSJoe PetscCall(PetscBagGetData(ctx->bag, (void **)&p)); 6588214e71cSJoe PetscCall(PetscBagSetName(ctx->bag, "par", "Vlasov-Poisson Parameters")); 6598214e71cSJoe bag = ctx->bag; 6608214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "v0", "Velocity scale, m/s")); 6618214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->t0, 1.0, "t0", "Time scale, s")); 6628214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->x0, 1.0, "x0", "Space scale, m")); 6638214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "phi0", "Potential scale, kg*m^2/A*s^3")); 6648214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->q0, 1.0, "q0", "Charge Scale, A*s")); 6658214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->m0, 1.0, "m0", "Mass Scale, kg")); 6668214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->epsi0, 1.0, "epsi0", "Permittivity of Free Space, kg")); 6678214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->kb, 1.0, "kb", "Boltzmann Constant, m^2 kg/s^2 K^1")); 6688214e71cSJoe 6698214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->sigma, 1.0, "sigma", "Charge per unit area, C/m^3")); 6708214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->poissonNumber, 1.0, "poissonNumber", "Non-Dimensional Poisson Number")); 6718214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->vlasovNumber, 1.0, "vlasovNumber", "Non-Dimensional Vlasov Number")); 6728214e71cSJoe PetscCall(PetscBagSetFromOptions(bag)); 6738214e71cSJoe { 6748214e71cSJoe PetscViewer viewer; 6758214e71cSJoe PetscViewerFormat format; 6768214e71cSJoe PetscBool flg; 6778214e71cSJoe 678648c30bcSBarry Smith PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg)); 6798214e71cSJoe if (flg) { 6808214e71cSJoe PetscCall(PetscViewerPushFormat(viewer, format)); 6818214e71cSJoe PetscCall(PetscBagView(bag, viewer)); 6828214e71cSJoe PetscCall(PetscViewerFlush(viewer)); 6838214e71cSJoe PetscCall(PetscViewerPopFormat(viewer)); 6848214e71cSJoe PetscCall(PetscViewerDestroy(&viewer)); 6858214e71cSJoe } 6868214e71cSJoe } 6878214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 6888214e71cSJoe } 6898214e71cSJoe 6908214e71cSJoe static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm) 691d71ae5a4SJacob Faibussowitsch { 692b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 6939566063dSJacob Faibussowitsch PetscCall(DMCreate(comm, dm)); 6949566063dSJacob Faibussowitsch PetscCall(DMSetType(*dm, DMPLEX)); 6959566063dSJacob Faibussowitsch PetscCall(DMSetFromOptions(*dm)); 696*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)*dm, "space")); 6979566063dSJacob Faibussowitsch PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view")); 698f1e6e573SMatthew G. Knepley 699f1e6e573SMatthew G. Knepley // Cache the mesh geometry 700f1e6e573SMatthew G. Knepley DMField coordField; 701f1e6e573SMatthew G. Knepley IS cellIS; 702f1e6e573SMatthew G. Knepley PetscQuadrature quad; 703f1e6e573SMatthew G. Knepley PetscReal *wt, *pt; 704f1e6e573SMatthew G. Knepley PetscInt cdim, cStart, cEnd; 705f1e6e573SMatthew G. Knepley 706f1e6e573SMatthew G. Knepley PetscCall(DMGetCoordinateField(*dm, &coordField)); 707f1e6e573SMatthew G. Knepley PetscCheck(coordField, comm, PETSC_ERR_USER, "DM must have a coordinate field"); 708f1e6e573SMatthew G. Knepley PetscCall(DMGetCoordinateDim(*dm, &cdim)); 709f1e6e573SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd)); 710f1e6e573SMatthew G. Knepley PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cellIS)); 711f1e6e573SMatthew G. Knepley PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad)); 712f1e6e573SMatthew G. Knepley PetscCall(PetscMalloc1(1, &wt)); 713f1e6e573SMatthew G. Knepley PetscCall(PetscMalloc1(2, &pt)); 714f1e6e573SMatthew G. Knepley wt[0] = 1.; 715f1e6e573SMatthew G. Knepley pt[0] = -1.; 716f1e6e573SMatthew G. Knepley pt[1] = -1.; 717f1e6e573SMatthew G. Knepley PetscCall(PetscQuadratureSetData(quad, cdim, 1, 1, pt, wt)); 718f1e6e573SMatthew G. Knepley PetscCall(DMFieldCreateFEGeom(coordField, cellIS, quad, PETSC_FALSE, &user->fegeom)); 719f1e6e573SMatthew G. Knepley PetscCall(PetscQuadratureDestroy(&quad)); 720f1e6e573SMatthew G. Knepley PetscCall(ISDestroy(&cellIS)); 7213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 722b80bf5b1SJoe Pusztay } 723b80bf5b1SJoe Pusztay 7248214e71cSJoe 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[]) 7258214e71cSJoe { 7268214e71cSJoe f0[0] = -constants[SIGMA]; 7278214e71cSJoe } 7288214e71cSJoe 729d71ae5a4SJacob 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[]) 730d71ae5a4SJacob Faibussowitsch { 731b80bf5b1SJoe Pusztay PetscInt d; 732ad540459SPierre Jolivet for (d = 0; d < dim; ++d) f1[d] = u_x[d]; 733b80bf5b1SJoe Pusztay } 734b80bf5b1SJoe Pusztay 7358214e71cSJoe 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[]) 736d71ae5a4SJacob Faibussowitsch { 737b80bf5b1SJoe Pusztay PetscInt d; 738ad540459SPierre Jolivet for (d = 0; d < dim; ++d) g3[d * dim + d] = 1.0; 739b80bf5b1SJoe Pusztay } 740b80bf5b1SJoe Pusztay 7418214e71cSJoe static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 742d71ae5a4SJacob Faibussowitsch { 7438214e71cSJoe *u = 0.0; 7448214e71cSJoe return PETSC_SUCCESS; 745b80bf5b1SJoe Pusztay } 746b80bf5b1SJoe Pusztay 747b80bf5b1SJoe Pusztay /* 7488214e71cSJoe / I -grad\ / q \ = /0\ 7498214e71cSJoe \-div 0 / \phi/ \f/ 750b80bf5b1SJoe Pusztay */ 7518214e71cSJoe 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[]) 752d71ae5a4SJacob Faibussowitsch { 7538214e71cSJoe for (PetscInt d = 0; d < dim; ++d) f0[d] += u[uOff[0] + d]; 7548214e71cSJoe } 7558214e71cSJoe 7568214e71cSJoe 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[]) 7578214e71cSJoe { 7588214e71cSJoe for (PetscInt d = 0; d < dim; ++d) f1[d * dim + d] = u[uOff[1]]; 7598214e71cSJoe } 7608214e71cSJoe 7618214e71cSJoe 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[]) 7628214e71cSJoe { 7638214e71cSJoe f0[0] += constants[SIGMA]; 7648214e71cSJoe for (PetscInt d = 0; d < dim; ++d) f0[0] += u_x[uOff_x[0] + d * dim + d]; 7658214e71cSJoe } 7668214e71cSJoe 7678214e71cSJoe /* Boundary residual. Dirichlet boundary for u means u_bdy=p*n */ 7688214e71cSJoe 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[]) 7698214e71cSJoe { 7708214e71cSJoe for (PetscInt d = 0; d < dim; ++d) g0[d * dim + d] = 1.0; 7718214e71cSJoe } 7728214e71cSJoe 7738214e71cSJoe 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[]) 7748214e71cSJoe { 7758214e71cSJoe for (PetscInt d = 0; d < dim; ++d) g2[d * dim + d] = 1.0; 7768214e71cSJoe } 7778214e71cSJoe 7788214e71cSJoe 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[]) 7798214e71cSJoe { 7808214e71cSJoe for (PetscInt d = 0; d < dim; ++d) g1[d * dim + d] = 1.0; 7818214e71cSJoe } 7828214e71cSJoe 7838214e71cSJoe static PetscErrorCode CreateFEM(DM dm, AppCtx *user) 7848214e71cSJoe { 7858214e71cSJoe PetscFE fephi, feq; 7868214e71cSJoe PetscDS ds; 7878214e71cSJoe PetscBool simplex; 7888214e71cSJoe PetscInt dim; 7898214e71cSJoe 7908214e71cSJoe PetscFunctionBeginUser; 7918214e71cSJoe PetscCall(DMGetDimension(dm, &dim)); 7928214e71cSJoe PetscCall(DMPlexIsSimplex(dm, &simplex)); 7938214e71cSJoe if (user->em == EM_MIXED) { 7948214e71cSJoe DMLabel label; 7958214e71cSJoe const PetscInt id = 1; 7968214e71cSJoe 7978214e71cSJoe PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "field_", PETSC_DETERMINE, &feq)); 7988214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)feq, "field")); 7998214e71cSJoe PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "potential_", PETSC_DETERMINE, &fephi)); 8008214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)fephi, "potential")); 8018214e71cSJoe PetscCall(PetscFECopyQuadrature(feq, fephi)); 8028214e71cSJoe PetscCall(DMSetField(dm, 0, NULL, (PetscObject)feq)); 8038214e71cSJoe PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fephi)); 8048214e71cSJoe PetscCall(DMCreateDS(dm)); 8058214e71cSJoe PetscCall(PetscFEDestroy(&fephi)); 8068214e71cSJoe PetscCall(PetscFEDestroy(&feq)); 8078214e71cSJoe 8088214e71cSJoe PetscCall(DMGetLabel(dm, "marker", &label)); 8098214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 8108214e71cSJoe 8118214e71cSJoe PetscCall(PetscDSSetResidual(ds, 0, f0_q, f1_q)); 8128214e71cSJoe PetscCall(PetscDSSetResidual(ds, 1, f0_phi_backgroundCharge, NULL)); 8138214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_qq, NULL, NULL, NULL)); 8148214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_qphi, NULL)); 8158214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_phiq, NULL, NULL)); 8168214e71cSJoe 8178214e71cSJoe PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void))zero, NULL, NULL, NULL)); 8188214e71cSJoe 819f1e6e573SMatthew G. Knepley } else { 8208214e71cSJoe MatNullSpace nullsp; 8218214e71cSJoe PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, PETSC_DETERMINE, &fephi)); 8228214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)fephi, "potential")); 8238214e71cSJoe PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fephi)); 8248214e71cSJoe PetscCall(DMCreateDS(dm)); 8258214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 8268214e71cSJoe PetscCall(PetscDSSetResidual(ds, 0, ion_f0, laplacian_f1)); 8278214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, laplacian_g3)); 8288214e71cSJoe PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullsp)); 8298214e71cSJoe PetscCall(PetscObjectCompose((PetscObject)fephi, "nullspace", (PetscObject)nullsp)); 8308214e71cSJoe PetscCall(MatNullSpaceDestroy(&nullsp)); 8318214e71cSJoe PetscCall(PetscFEDestroy(&fephi)); 8328214e71cSJoe } 8338214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 8348214e71cSJoe } 8358214e71cSJoe 8368214e71cSJoe static PetscErrorCode CreatePoisson(DM dm, AppCtx *user) 8378214e71cSJoe { 8388214e71cSJoe SNES snes; 8398214e71cSJoe Mat J; 8408214e71cSJoe MatNullSpace nullSpace; 8418214e71cSJoe 8428214e71cSJoe PetscFunctionBeginUser; 8438214e71cSJoe PetscCall(CreateFEM(dm, user)); 8448214e71cSJoe PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes)); 8458214e71cSJoe PetscCall(SNESSetOptionsPrefix(snes, "em_")); 8468214e71cSJoe PetscCall(SNESSetDM(snes, dm)); 8478214e71cSJoe PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, user)); 8488214e71cSJoe PetscCall(SNESSetFromOptions(snes)); 8498214e71cSJoe 8508214e71cSJoe PetscCall(DMCreateMatrix(dm, &J)); 8518214e71cSJoe PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullSpace)); 8528214e71cSJoe PetscCall(MatSetNullSpace(J, nullSpace)); 8538214e71cSJoe PetscCall(MatNullSpaceDestroy(&nullSpace)); 8548214e71cSJoe PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL)); 8558214e71cSJoe PetscCall(MatDestroy(&J)); 856f1e6e573SMatthew G. Knepley PetscCall(DMCreateMassMatrix(dm, dm, &user->M)); 857f1e6e573SMatthew G. Knepley PetscCall(DMPlexCreateClosureIndex(dm, NULL)); 8588214e71cSJoe user->snes = snes; 8598214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 8608214e71cSJoe } 8618214e71cSJoe 8628214e71cSJoe PetscErrorCode PetscPDFPertubedConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 8638214e71cSJoe { 8648214e71cSJoe p[0] = (1 + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI); 8658214e71cSJoe p[1] = (1 + 0.01 * PetscCosReal(0.5 * x[1])) / (2 * PETSC_PI); 8668214e71cSJoe return PETSC_SUCCESS; 8678214e71cSJoe } 8688214e71cSJoe PetscErrorCode PetscPDFPertubedConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 8698214e71cSJoe { 8708214e71cSJoe p[0] = (1. + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI); 8718214e71cSJoe return PETSC_SUCCESS; 8728214e71cSJoe } 8738214e71cSJoe 8748214e71cSJoe PetscErrorCode PetscPDFCosine1D(const PetscReal x[], const PetscReal scale[], PetscReal p[]) 8758214e71cSJoe { 8768214e71cSJoe const PetscReal alpha = scale ? scale[0] : 0.0; 8778214e71cSJoe const PetscReal k = scale ? scale[1] : 1.; 8788214e71cSJoe p[0] = (1 + alpha * PetscCosReal(k * x[0])); 8798214e71cSJoe return PETSC_SUCCESS; 8808214e71cSJoe } 8818214e71cSJoe 8828214e71cSJoe PetscErrorCode PetscPDFCosine2D(const PetscReal x[], const PetscReal scale[], PetscReal p[]) 8838214e71cSJoe { 8848214e71cSJoe const PetscReal alpha = scale ? scale[0] : 0.; 8858214e71cSJoe const PetscReal k = scale ? scale[0] : 1.; 8868214e71cSJoe p[0] = (1 + alpha * PetscCosReal(k * (x[0] + x[1]))); 8878214e71cSJoe return PETSC_SUCCESS; 8888214e71cSJoe } 8898214e71cSJoe 89084467f86SMatthew G. Knepley static PetscErrorCode CreateVelocityDM(DM sw, DM *vdm) 8918214e71cSJoe { 892f1e6e573SMatthew G. Knepley PetscFE fe; 893f1e6e573SMatthew G. Knepley DMPolytopeType ct; 894f1e6e573SMatthew G. Knepley PetscInt dim, cStart; 895f1e6e573SMatthew G. Knepley const char *prefix = "v"; 896f1e6e573SMatthew G. Knepley 89784467f86SMatthew G. Knepley PetscFunctionBegin; 89884467f86SMatthew G. Knepley PetscCall(DMCreate(PETSC_COMM_SELF, vdm)); 89984467f86SMatthew G. Knepley PetscCall(DMSetType(*vdm, DMPLEX)); 900f1e6e573SMatthew G. Knepley PetscCall(DMPlexSetOptionsPrefix(*vdm, prefix)); 90184467f86SMatthew G. Knepley PetscCall(DMSetFromOptions(*vdm)); 902*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)*vdm, "velocity")); 90384467f86SMatthew G. Knepley PetscCall(DMViewFromOptions(*vdm, NULL, "-dm_view")); 904f1e6e573SMatthew G. Knepley 905f1e6e573SMatthew G. Knepley PetscCall(DMGetDimension(*vdm, &dim)); 906f1e6e573SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(*vdm, 0, &cStart, NULL)); 907f1e6e573SMatthew G. Knepley PetscCall(DMPlexGetCellType(*vdm, cStart, &ct)); 908f1e6e573SMatthew G. Knepley PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe)); 909f1e6e573SMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)fe, "distribution")); 910f1e6e573SMatthew G. Knepley PetscCall(DMSetField(*vdm, 0, NULL, (PetscObject)fe)); 911f1e6e573SMatthew G. Knepley PetscCall(DMCreateDS(*vdm)); 912f1e6e573SMatthew G. Knepley PetscCall(PetscFEDestroy(&fe)); 91384467f86SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 9148214e71cSJoe } 9158214e71cSJoe 916*9072cb8bSMatthew G. Knepley static PetscErrorCode CreateRemapDM(DM sw, DM *rdm) 917*9072cb8bSMatthew G. Knepley { 918*9072cb8bSMatthew G. Knepley PetscFE fe; 919*9072cb8bSMatthew G. Knepley DMPolytopeType ct; 920*9072cb8bSMatthew G. Knepley PetscInt dim, cStart; 921*9072cb8bSMatthew G. Knepley const char *prefix = "remap_"; 922*9072cb8bSMatthew G. Knepley 923*9072cb8bSMatthew G. Knepley PetscFunctionBegin; 924*9072cb8bSMatthew G. Knepley PetscCall(DMCreate(PetscObjectComm((PetscObject)sw), rdm)); 925*9072cb8bSMatthew G. Knepley PetscCall(DMSetType(*rdm, DMPLEX)); 926*9072cb8bSMatthew G. Knepley PetscCall(DMPlexSetOptionsPrefix(*rdm, prefix)); 927*9072cb8bSMatthew G. Knepley PetscCall(DMSetFromOptions(*rdm)); 928*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)*rdm, "remap")); 929*9072cb8bSMatthew G. Knepley PetscCall(DMViewFromOptions(*rdm, NULL, "-dm_view")); 930*9072cb8bSMatthew G. Knepley 931*9072cb8bSMatthew G. Knepley PetscCall(DMGetDimension(*rdm, &dim)); 932*9072cb8bSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(*rdm, 0, &cStart, NULL)); 933*9072cb8bSMatthew G. Knepley PetscCall(DMPlexGetCellType(*rdm, cStart, &ct)); 934*9072cb8bSMatthew G. Knepley PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, prefix, PETSC_DETERMINE, &fe)); 935*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)fe, "distribution")); 936*9072cb8bSMatthew G. Knepley PetscCall(DMSetField(*rdm, 0, NULL, (PetscObject)fe)); 937*9072cb8bSMatthew G. Knepley PetscCall(DMCreateDS(*rdm)); 938*9072cb8bSMatthew G. Knepley PetscCall(PetscFEDestroy(&fe)); 939*9072cb8bSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 940*9072cb8bSMatthew G. Knepley } 941*9072cb8bSMatthew G. Knepley 942*9072cb8bSMatthew G. Knepley /* 943*9072cb8bSMatthew G. Knepley InitializeParticles_Regular - Initialize a regular grid of particles in each cell 944*9072cb8bSMatthew G. Knepley 945*9072cb8bSMatthew G. Knepley Input Parameters: 946*9072cb8bSMatthew G. Knepley + sw - The `DMSWARM` 947*9072cb8bSMatthew G. Knepley - n - The number of particles per dimension per species 948*9072cb8bSMatthew G. Knepley 949*9072cb8bSMatthew G. Knepley Notes: 950*9072cb8bSMatthew G. Knepley This functions sets the species, cellid, and cell DM coordinates. 951*9072cb8bSMatthew G. Knepley 952*9072cb8bSMatthew G. Knepley It places n^d particles per species in each cell of the cell DM. 953*9072cb8bSMatthew G. Knepley */ 954*9072cb8bSMatthew G. Knepley static PetscErrorCode InitializeParticles_Regular(DM sw, PetscInt n) 955*9072cb8bSMatthew G. Knepley { 956*9072cb8bSMatthew G. Knepley DM_Swarm *swarm = (DM_Swarm *)sw->data; 957*9072cb8bSMatthew G. Knepley DM dm; 958*9072cb8bSMatthew G. Knepley DMSwarmCellDM celldm; 959*9072cb8bSMatthew G. Knepley PetscInt dim, Ns, Npc, Np, cStart, cEnd, debug; 960*9072cb8bSMatthew G. Knepley PetscBool flg; 961*9072cb8bSMatthew G. Knepley MPI_Comm comm; 962*9072cb8bSMatthew G. Knepley 963*9072cb8bSMatthew G. Knepley PetscFunctionBegin; 964*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectGetComm((PetscObject)sw, &comm)); 965*9072cb8bSMatthew G. Knepley 966*9072cb8bSMatthew G. Knepley PetscOptionsBegin(comm, "", "DMSwarm Options", "DMSWARM"); 967*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 968*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg)); 969*9072cb8bSMatthew G. Knepley if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns)); 970*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_coords", "Debug output level for particle coordinate computations", "InitializeParticles", 0, &swarm->printCoords, NULL, 0)); 971*9072cb8bSMatthew G. Knepley PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_weights", "Debug output level for particle weight computations", "InitializeWeights", 0, &swarm->printWeights, NULL, 0)); 972*9072cb8bSMatthew G. Knepley PetscOptionsEnd(); 973*9072cb8bSMatthew G. Knepley debug = swarm->printCoords; 974*9072cb8bSMatthew G. Knepley 975*9072cb8bSMatthew G. Knepley // n^d particle per cell on the grid 976*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetCellDM(sw, &dm)); 977*9072cb8bSMatthew G. Knepley PetscCall(DMGetDimension(dm, &dim)); 978*9072cb8bSMatthew G. Knepley PetscCheck(!(dim % 2), comm, PETSC_ERR_SUP, "We only support even dimension, not %" PetscInt_FMT, dim); 979*9072cb8bSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 980*9072cb8bSMatthew G. Knepley Npc = Ns * PetscPowInt(n, dim); 981*9072cb8bSMatthew G. Knepley Np = (cEnd - cStart) * Npc; 982*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSetLocalSizes(sw, Np, 0)); 983*9072cb8bSMatthew G. Knepley if (debug) { 984*9072cb8bSMatthew G. Knepley PetscInt gNp; 985*9072cb8bSMatthew G. Knepley PetscCallMPI(MPIU_Allreduce(&Np, &gNp, 1, MPIU_INT, MPIU_SUM, comm)); 986*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(comm, "Global Np = %" PetscInt_FMT "\n", gNp)); 987*9072cb8bSMatthew G. Knepley } 988*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(comm, "Regular layout using %" PetscInt_FMT " particles per cell\n", Npc)); 989*9072cb8bSMatthew G. Knepley 990*9072cb8bSMatthew G. Knepley // Set species and cellid 991*9072cb8bSMatthew G. Knepley { 992*9072cb8bSMatthew G. Knepley const char *cellidName; 993*9072cb8bSMatthew G. Knepley PetscInt *species, *cellid; 994*9072cb8bSMatthew G. Knepley 995*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 996*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMGetCellID(celldm, &cellidName)); 997*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 998*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, cellidName, NULL, NULL, (void **)&cellid)); 999*9072cb8bSMatthew G. Knepley for (PetscInt c = 0, p = 0; c < cEnd - cStart; ++c) { 1000*9072cb8bSMatthew G. Knepley for (PetscInt s = 0; s < Ns; ++s) { 1001*9072cb8bSMatthew G. Knepley for (PetscInt q = 0; q < Npc / Ns; ++q, ++p) { 1002*9072cb8bSMatthew G. Knepley species[p] = s; 1003*9072cb8bSMatthew G. Knepley cellid[p] = c; 1004*9072cb8bSMatthew G. Knepley } 1005*9072cb8bSMatthew G. Knepley } 1006*9072cb8bSMatthew G. Knepley } 1007*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 1008*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, cellidName, NULL, NULL, (void **)&cellid)); 1009*9072cb8bSMatthew G. Knepley } 1010*9072cb8bSMatthew G. Knepley 1011*9072cb8bSMatthew G. Knepley // Set particle coordinates 1012*9072cb8bSMatthew G. Knepley { 1013*9072cb8bSMatthew G. Knepley PetscReal *x, *v; 1014*9072cb8bSMatthew G. Knepley const char **coordNames; 1015*9072cb8bSMatthew G. Knepley PetscInt Ncoord; 1016*9072cb8bSMatthew G. Knepley const PetscInt xdim = dim / 2, vdim = dim / 2; 1017*9072cb8bSMatthew G. Knepley 1018*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Ncoord, &coordNames)); 1019*9072cb8bSMatthew G. Knepley PetscCheck(Ncoord == 2, comm, PETSC_ERR_SUP, "We only support regular layout for 2 coordinate fields, not %" PetscInt_FMT, Ncoord); 1020*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, coordNames[0], NULL, NULL, (void **)&x)); 1021*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, coordNames[1], NULL, NULL, (void **)&v)); 1022*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortGetAccess(sw)); 1023*9072cb8bSMatthew G. Knepley PetscCall(DMGetCoordinatesLocalSetUp(dm)); 1024*9072cb8bSMatthew G. Knepley for (PetscInt c = 0; c < cEnd - cStart; ++c) { 1025*9072cb8bSMatthew G. Knepley const PetscInt cell = c + cStart; 1026*9072cb8bSMatthew G. Knepley const PetscScalar *a; 1027*9072cb8bSMatthew G. Knepley PetscScalar *coords; 1028*9072cb8bSMatthew G. Knepley PetscReal lower[6], upper[6]; 1029*9072cb8bSMatthew G. Knepley PetscBool isDG; 1030*9072cb8bSMatthew G. Knepley PetscInt *pidx, npc, Nc; 1031*9072cb8bSMatthew G. Knepley 1032*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &npc, &pidx)); 1033*9072cb8bSMatthew G. Knepley PetscCheck(Npc == npc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of points per cell %" PetscInt_FMT " != %" PetscInt_FMT, npc, Npc); 1034*9072cb8bSMatthew G. Knepley PetscCall(DMPlexGetCellCoordinates(dm, cell, &isDG, &Nc, &a, &coords)); 1035*9072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) { 1036*9072cb8bSMatthew G. Knepley lower[d] = coords[0 * dim + d]; 1037*9072cb8bSMatthew G. Knepley upper[d] = coords[0 * dim + d]; 1038*9072cb8bSMatthew G. Knepley } 1039*9072cb8bSMatthew G. Knepley for (PetscInt i = 1; i < Nc / dim; ++i) { 1040*9072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) { 1041*9072cb8bSMatthew G. Knepley lower[d] = PetscMin(lower[d], coords[i * dim + d]); 1042*9072cb8bSMatthew G. Knepley upper[d] = PetscMax(upper[d], coords[i * dim + d]); 1043*9072cb8bSMatthew G. Knepley } 1044*9072cb8bSMatthew G. Knepley } 1045*9072cb8bSMatthew G. Knepley for (PetscInt s = 0; s < Ns; ++s) { 1046*9072cb8bSMatthew G. Knepley for (PetscInt q = 0; q < Npc / Ns; ++q) { 1047*9072cb8bSMatthew G. Knepley const PetscInt p = pidx[q * Ns + s]; 1048*9072cb8bSMatthew G. Knepley PetscInt xi[3], vi[3]; 1049*9072cb8bSMatthew G. Knepley 1050*9072cb8bSMatthew G. Knepley xi[0] = q % n; 1051*9072cb8bSMatthew G. Knepley xi[1] = (q / n) % n; 1052*9072cb8bSMatthew G. Knepley xi[2] = (q / PetscSqr(n)) % n; 1053*9072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < xdim; ++d) x[p * xdim + d] = lower[d] + (xi[d] + 0.5) * (upper[d] - lower[d]) / n; 1054*9072cb8bSMatthew G. Knepley vi[0] = (q / PetscPowInt(n, xdim)) % n; 1055*9072cb8bSMatthew G. Knepley vi[1] = (q / PetscPowInt(n, xdim + 1)) % n; 1056*9072cb8bSMatthew G. Knepley vi[2] = (q / PetscPowInt(n, xdim + 2)); 1057*9072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < vdim; ++d) v[p * vdim + d] = lower[xdim + d] + (vi[d] + 0.5) * (upper[xdim + d] - lower[xdim + d]) / n; 1058*9072cb8bSMatthew G. Knepley if (debug > 1) { 1059*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "Particle %4" PetscInt_FMT " ", p)); 1060*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, " x: (")); 1061*9072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < xdim; ++d) { 1062*9072cb8bSMatthew G. Knepley if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 1063*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", x[p * xdim + d])); 1064*9072cb8bSMatthew G. Knepley } 1065*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, ") v:(")); 1066*9072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < vdim; ++d) { 1067*9072cb8bSMatthew G. Knepley if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 1068*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", v[p * vdim + d])); 1069*9072cb8bSMatthew G. Knepley } 1070*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n")); 1071*9072cb8bSMatthew G. Knepley } 1072*9072cb8bSMatthew G. Knepley } 1073*9072cb8bSMatthew G. Knepley } 1074*9072cb8bSMatthew G. Knepley PetscCall(DMPlexRestoreCellCoordinates(dm, cell, &isDG, &Nc, &a, &coords)); 1075*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx)); 1076*9072cb8bSMatthew G. Knepley } 1077*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortRestoreAccess(sw)); 1078*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, coordNames[0], NULL, NULL, (void **)&x)); 1079*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, coordNames[1], NULL, NULL, (void **)&v)); 1080*9072cb8bSMatthew G. Knepley } 1081*9072cb8bSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 1082*9072cb8bSMatthew G. Knepley } 1083*9072cb8bSMatthew G. Knepley 1084*9072cb8bSMatthew G. Knepley /* 1085*9072cb8bSMatthew G. Knepley InitializeParticles_Centroid - Initialize a regular grid of particles. 1086*9072cb8bSMatthew G. Knepley 1087*9072cb8bSMatthew G. Knepley Input Parameters: 1088*9072cb8bSMatthew G. Knepley + sw - The `DMSWARM` 1089*9072cb8bSMatthew G. Knepley - force1D - Treat the spatial domain as 1D 1090*9072cb8bSMatthew G. Knepley 1091*9072cb8bSMatthew G. Knepley Notes: 1092*9072cb8bSMatthew G. Knepley This functions sets the species, cellid, spatial coordinate, and velocity fields for all particles. 1093*9072cb8bSMatthew G. Knepley 1094*9072cb8bSMatthew G. Knepley It places one particle in the centroid of each cell in the implicit tensor product of the spatial 1095*9072cb8bSMatthew G. Knepley and velocity meshes. 1096*9072cb8bSMatthew G. Knepley */ 109784467f86SMatthew G. Knepley static PetscErrorCode InitializeParticles_Centroid(DM sw, PetscBool force1D) 10988214e71cSJoe { 109984467f86SMatthew G. Knepley DM_Swarm *swarm = (DM_Swarm *)sw->data; 1100*9072cb8bSMatthew G. Knepley DMSwarmCellDM celldm; 110184467f86SMatthew G. Knepley DM xdm, vdm; 110284467f86SMatthew G. Knepley PetscReal vmin[3], vmax[3]; 110384467f86SMatthew G. Knepley PetscReal *x, *v; 110484467f86SMatthew G. Knepley PetscInt *species, *cellid; 110584467f86SMatthew G. Knepley PetscInt dim, xcStart, xcEnd, vcStart, vcEnd, Ns, Np, Npc, debug; 11068214e71cSJoe PetscBool flg; 110784467f86SMatthew G. Knepley MPI_Comm comm; 1108*9072cb8bSMatthew G. Knepley const char *cellidname; 11098214e71cSJoe 11108214e71cSJoe PetscFunctionBegin; 111184467f86SMatthew G. Knepley PetscCall(PetscObjectGetComm((PetscObject)sw, &comm)); 111284467f86SMatthew G. Knepley 111384467f86SMatthew G. Knepley PetscOptionsBegin(comm, "", "DMSwarm Options", "DMSWARM"); 11148214e71cSJoe PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 11158214e71cSJoe PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg)); 11168214e71cSJoe if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns)); 111784467f86SMatthew G. Knepley PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_coords", "Debug output level for particle coordinate computations", "InitializeParticles", 0, &swarm->printCoords, NULL, 0)); 111884467f86SMatthew G. Knepley PetscCall(PetscOptionsBoundedInt("-dm_swarm_print_weights", "Debug output level for particle weight computations", "InitializeWeights", 0, &swarm->printWeights, NULL, 0)); 11198214e71cSJoe PetscOptionsEnd(); 112084467f86SMatthew G. Knepley debug = swarm->printCoords; 11218214e71cSJoe 11228214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 112384467f86SMatthew G. Knepley PetscCall(DMSwarmGetCellDM(sw, &xdm)); 112484467f86SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd)); 11258214e71cSJoe 112684467f86SMatthew G. Knepley PetscCall(PetscObjectQuery((PetscObject)sw, "__vdm__", (PetscObject *)&vdm)); 112784467f86SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd)); 11288214e71cSJoe 112984467f86SMatthew G. Knepley // One particle per centroid on the tensor product grid 113084467f86SMatthew G. Knepley Npc = (vcEnd - vcStart) * Ns; 113184467f86SMatthew G. Knepley Np = (xcEnd - xcStart) * Npc; 11328214e71cSJoe PetscCall(DMSwarmSetLocalSizes(sw, Np, 0)); 113384467f86SMatthew G. Knepley if (debug) { 113484467f86SMatthew G. Knepley PetscInt gNp; 113584467f86SMatthew G. Knepley PetscCallMPI(MPIU_Allreduce(&Np, &gNp, 1, MPIU_INT, MPIU_SUM, comm)); 113684467f86SMatthew G. Knepley PetscCall(PetscPrintf(comm, "Global Np = %" PetscInt_FMT "\n", gNp)); 11378214e71cSJoe } 11388214e71cSJoe 113984467f86SMatthew G. Knepley // Set species and cellid 1140*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 1141*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMGetCellID(celldm, &cellidname)); 114284467f86SMatthew G. Knepley PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 1143*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, cellidname, NULL, NULL, (void **)&cellid)); 114484467f86SMatthew G. Knepley for (PetscInt c = 0, p = 0; c < xcEnd - xcStart; ++c) { 114584467f86SMatthew G. Knepley for (PetscInt s = 0; s < Ns; ++s) { 114684467f86SMatthew G. Knepley for (PetscInt q = 0; q < Npc / Ns; ++q, ++p) { 114784467f86SMatthew G. Knepley species[p] = s; 114884467f86SMatthew G. Knepley cellid[p] = c; 114984467f86SMatthew G. Knepley } 115084467f86SMatthew G. Knepley } 115184467f86SMatthew G. Knepley } 115284467f86SMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 1153*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, cellidname, NULL, NULL, (void **)&cellid)); 115484467f86SMatthew G. Knepley 115584467f86SMatthew G. Knepley // Set particle coordinates 11568214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 11578214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v)); 11588214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 115984467f86SMatthew G. Knepley PetscCall(DMGetBoundingBox(vdm, vmin, vmax)); 116084467f86SMatthew G. Knepley PetscCall(DMGetCoordinatesLocalSetUp(xdm)); 116184467f86SMatthew G. Knepley for (PetscInt c = 0; c < xcEnd - xcStart; ++c) { 116284467f86SMatthew G. Knepley const PetscInt cell = c + xcStart; 11638214e71cSJoe PetscInt *pidx, Npc; 11648214e71cSJoe PetscReal centroid[3], volume; 11658214e71cSJoe 11668214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 116784467f86SMatthew G. Knepley PetscCall(DMPlexComputeCellGeometryFVM(xdm, cell, &volume, centroid, NULL)); 116884467f86SMatthew G. Knepley for (PetscInt s = 0; s < Ns; ++s) { 116984467f86SMatthew G. Knepley for (PetscInt q = 0; q < Npc / Ns; ++q) { 117084467f86SMatthew G. Knepley const PetscInt p = pidx[q * Ns + s]; 11718214e71cSJoe 117284467f86SMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) { 11738214e71cSJoe x[p * dim + d] = centroid[d]; 117484467f86SMatthew G. Knepley v[p * dim + d] = vmin[0] + (q + 0.5) * ((vmax[0] - vmin[0]) / (Npc / Ns)); 117584467f86SMatthew G. Knepley if (force1D && d > 0) v[p * dim + d] = 0.; 11768214e71cSJoe } 1177*9072cb8bSMatthew G. Knepley if (debug > 1) { 1178*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "Particle %4" PetscInt_FMT " ", p)); 1179*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, " x: (")); 1180*9072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) { 1181*9072cb8bSMatthew G. Knepley if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 1182*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", x[p * dim + d])); 1183*9072cb8bSMatthew G. Knepley } 1184*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, ") v:(")); 1185*9072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) { 1186*9072cb8bSMatthew G. Knepley if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 1187*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", v[p * dim + d])); 1188*9072cb8bSMatthew G. Knepley } 1189*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n")); 1190*9072cb8bSMatthew G. Knepley } 11918214e71cSJoe } 11928214e71cSJoe } 119384467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx)); 11948214e71cSJoe } 11958214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 11968214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 11978214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v)); 119884467f86SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 119984467f86SMatthew G. Knepley } 120084467f86SMatthew G. Knepley 120184467f86SMatthew G. Knepley /* 120284467f86SMatthew G. Knepley InitializeWeights - Compute weight for each local particle 120384467f86SMatthew G. Knepley 120484467f86SMatthew G. Knepley Input Parameters: 120584467f86SMatthew G. Knepley + sw - The `DMSwarm` 120684467f86SMatthew G. Knepley . totalWeight - The sum of all particle weights 120784467f86SMatthew G. Knepley . force1D - Flag to treat the problem as 1D 120884467f86SMatthew G. Knepley . func - The PDF for the particle spatial distribution 120984467f86SMatthew G. Knepley - param - The PDF parameters 121084467f86SMatthew G. Knepley 121184467f86SMatthew G. Knepley Notes: 121284467f86SMatthew G. Knepley The PDF for velocity is assumed to be a Gaussian 121384467f86SMatthew G. Knepley 121484467f86SMatthew G. Knepley The particle weights are returned in the `w_q` field of `sw`. 121584467f86SMatthew G. Knepley */ 121684467f86SMatthew G. Knepley static PetscErrorCode InitializeWeights(DM sw, PetscReal totalWeight, PetscBool force1D, PetscProbFunc func, const PetscReal param[]) 121784467f86SMatthew G. Knepley { 121884467f86SMatthew G. Knepley DM xdm, vdm; 121984467f86SMatthew G. Knepley PetscScalar *weight; 122084467f86SMatthew G. Knepley PetscQuadrature xquad; 122184467f86SMatthew G. Knepley const PetscReal *xq, *xwq; 122284467f86SMatthew G. Knepley const PetscInt order = 5; 122384467f86SMatthew G. Knepley PetscReal *xqd = NULL, xi0[3]; 122484467f86SMatthew G. Knepley PetscReal xwtot = 0., pwtot = 0.; 122584467f86SMatthew G. Knepley PetscInt xNq; 122684467f86SMatthew G. Knepley PetscInt dim, Ns, xcStart, xcEnd, vcStart, vcEnd, debug = ((DM_Swarm *)sw->data)->printWeights; 122784467f86SMatthew G. Knepley MPI_Comm comm; 122884467f86SMatthew G. Knepley PetscMPIInt rank; 122984467f86SMatthew G. Knepley 123084467f86SMatthew G. Knepley PetscFunctionBegin; 123184467f86SMatthew G. Knepley PetscCall(PetscObjectGetComm((PetscObject)sw, &comm)); 123284467f86SMatthew G. Knepley PetscCallMPI(MPI_Comm_rank(comm, &rank)); 123384467f86SMatthew G. Knepley PetscCall(DMGetDimension(sw, &dim)); 123484467f86SMatthew G. Knepley PetscCall(DMSwarmGetCellDM(sw, &xdm)); 123584467f86SMatthew G. Knepley PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 123684467f86SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd)); 123784467f86SMatthew G. Knepley PetscCall(PetscObjectQuery((PetscObject)sw, "__vdm__", (PetscObject *)&vdm)); 123884467f86SMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd)); 123984467f86SMatthew G. Knepley 124084467f86SMatthew G. Knepley // Setup Quadrature for spatial and velocity weight calculations 124184467f86SMatthew G. Knepley if (force1D) PetscCall(PetscDTGaussTensorQuadrature(1, 1, order, -1.0, 1.0, &xquad)); 124284467f86SMatthew G. Knepley else PetscCall(PetscDTGaussTensorQuadrature(dim, 1, order, -1.0, 1.0, &xquad)); 124384467f86SMatthew G. Knepley PetscCall(PetscQuadratureGetData(xquad, NULL, NULL, &xNq, &xq, &xwq)); 124484467f86SMatthew G. Knepley if (force1D) { 124584467f86SMatthew G. Knepley PetscCall(PetscCalloc1(xNq * dim, &xqd)); 124684467f86SMatthew G. Knepley for (PetscInt q = 0; q < xNq; ++q) xqd[q * dim] = xq[q]; 124784467f86SMatthew G. Knepley } 124884467f86SMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) xi0[d] = -1.0; 124984467f86SMatthew G. Knepley 125084467f86SMatthew G. Knepley // Integrate the density function to get the weights of particles in each cell 125184467f86SMatthew G. Knepley PetscCall(DMGetCoordinatesLocalSetUp(vdm)); 125284467f86SMatthew G. Knepley PetscCall(DMSwarmSortGetAccess(sw)); 125384467f86SMatthew G. Knepley PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 125484467f86SMatthew G. Knepley for (PetscInt c = xcStart; c < xcEnd; ++c) { 125584467f86SMatthew G. Knepley PetscReal xv0[3], xJ[9], xinvJ[9], xdetJ, xqr[3], xden, xw = 0.; 125684467f86SMatthew G. Knepley PetscInt *pidx, Npc; 125784467f86SMatthew G. Knepley PetscInt xNc; 125884467f86SMatthew G. Knepley const PetscScalar *xarray; 125984467f86SMatthew G. Knepley PetscScalar *xcoords = NULL; 126084467f86SMatthew G. Knepley PetscBool xisDG; 126184467f86SMatthew G. Knepley 126284467f86SMatthew G. Knepley PetscCall(DMPlexGetCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords)); 126384467f86SMatthew G. Knepley PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 126484467f86SMatthew 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); 126584467f86SMatthew G. Knepley PetscCall(DMPlexComputeCellGeometryFEM(xdm, c, NULL, xv0, xJ, xinvJ, &xdetJ)); 126684467f86SMatthew G. Knepley for (PetscInt q = 0; q < xNq; ++q) { 126784467f86SMatthew G. Knepley // Transform quadrature points from ref space to real space 126884467f86SMatthew G. Knepley if (force1D) CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xqd[q * dim], xqr); 126984467f86SMatthew G. Knepley else CoordinatesRefToReal(dim, dim, xi0, xv0, xJ, &xq[q * dim], xqr); 127084467f86SMatthew G. Knepley // Get probability density at quad point 127184467f86SMatthew G. Knepley // No need to scale xqr since PDF will be periodic 127284467f86SMatthew G. Knepley PetscCall((*func)(xqr, param, &xden)); 127384467f86SMatthew G. Knepley if (force1D) xdetJ = xJ[0]; // Only want x contribution 127484467f86SMatthew G. Knepley xw += xden * (xwq[q] * xdetJ); 127584467f86SMatthew G. Knepley } 127684467f86SMatthew G. Knepley xwtot += xw; 127784467f86SMatthew G. Knepley if (debug) { 127884467f86SMatthew G. Knepley IS globalOrdering; 127984467f86SMatthew G. Knepley const PetscInt *ordering; 128084467f86SMatthew G. Knepley 128184467f86SMatthew G. Knepley PetscCall(DMPlexGetCellNumbering(xdm, &globalOrdering)); 128284467f86SMatthew G. Knepley PetscCall(ISGetIndices(globalOrdering, &ordering)); 128375155f48SMatthew 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)); 128484467f86SMatthew G. Knepley PetscCall(ISRestoreIndices(globalOrdering, &ordering)); 128584467f86SMatthew G. Knepley } 128684467f86SMatthew G. Knepley // Set weights to be Gaussian in velocity cells 128784467f86SMatthew G. Knepley for (PetscInt vc = vcStart; vc < vcEnd; ++vc) { 128884467f86SMatthew G. Knepley const PetscInt p = pidx[vc * Ns + 0]; 128984467f86SMatthew G. Knepley PetscReal vw = 0.; 129084467f86SMatthew G. Knepley PetscInt vNc; 129184467f86SMatthew G. Knepley const PetscScalar *varray; 129284467f86SMatthew G. Knepley PetscScalar *vcoords = NULL; 129384467f86SMatthew G. Knepley PetscBool visDG; 129484467f86SMatthew G. Knepley 129584467f86SMatthew G. Knepley PetscCall(DMPlexGetCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords)); 129684467f86SMatthew G. Knepley // TODO: Fix 2 stream Ask Joe 129784467f86SMatthew G. Knepley // Two stream function from 1/2pi v^2 e^(-v^2/2) 129884467f86SMatthew 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.))); 129984467f86SMatthew G. Knepley vw = 0.5 * (PetscErfReal(vcoords[1] / PetscSqrtReal(2.)) - PetscErfReal(vcoords[0] / PetscSqrtReal(2.))); 130084467f86SMatthew G. Knepley 130184467f86SMatthew G. Knepley weight[p] = totalWeight * vw * xw; 130284467f86SMatthew G. Knepley pwtot += weight[p]; 1303*9072cb8bSMatthew 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); 130484467f86SMatthew G. Knepley PetscCall(DMPlexRestoreCellCoordinates(vdm, vc, &visDG, &vNc, &varray, &vcoords)); 130584467f86SMatthew G. Knepley if (debug > 1) PetscCall(PetscPrintf(comm, "particle %" PetscInt_FMT ": %g, vw: %g xw: %g\n", p, weight[p], vw, xw)); 130684467f86SMatthew G. Knepley } 130784467f86SMatthew G. Knepley PetscCall(DMPlexRestoreCellCoordinates(xdm, c, &xisDG, &xNc, &xarray, &xcoords)); 130884467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx)); 130984467f86SMatthew G. Knepley } 131084467f86SMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 131184467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestoreAccess(sw)); 131284467f86SMatthew G. Knepley PetscCall(PetscQuadratureDestroy(&xquad)); 131384467f86SMatthew G. Knepley if (force1D) PetscCall(PetscFree(xqd)); 131484467f86SMatthew G. Knepley 131584467f86SMatthew G. Knepley if (debug) { 131684467f86SMatthew G. Knepley PetscReal wtot[2] = {pwtot, xwtot}, gwtot[2]; 131784467f86SMatthew G. Knepley 131884467f86SMatthew G. Knepley PetscCall(PetscSynchronizedFlush(comm, NULL)); 131984467f86SMatthew G. Knepley PetscCallMPI(MPIU_Allreduce(wtot, gwtot, 2, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD)); 132084467f86SMatthew G. Knepley PetscCall(PetscPrintf(comm, "particle weight sum = %1.10f cell weight sum = %1.10f\n", (double)gwtot[0], (double)gwtot[1])); 132184467f86SMatthew G. Knepley } 132284467f86SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 132384467f86SMatthew G. Knepley } 132484467f86SMatthew G. Knepley 132584467f86SMatthew G. Knepley static PetscErrorCode InitializeParticles_PerturbedWeights(DM sw, AppCtx *user) 132684467f86SMatthew G. Knepley { 132784467f86SMatthew G. Knepley PetscReal scale[2] = {user->cosine_coefficients[0], user->cosine_coefficients[1]}; 132875155f48SMatthew G. Knepley PetscInt dim; 132984467f86SMatthew G. Knepley 133084467f86SMatthew G. Knepley PetscFunctionBegin; 133175155f48SMatthew G. Knepley PetscCall(DMGetDimension(sw, &dim)); 133284467f86SMatthew G. Knepley PetscCall(InitializeParticles_Centroid(sw, user->fake_1D)); 133375155f48SMatthew G. Knepley PetscCall(InitializeWeights(sw, user->totalWeight, user->fake_1D, dim == 1 || user->fake_1D ? PetscPDFCosine1D : PetscPDFCosine2D, scale)); 13348214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 13358214e71cSJoe } 13368214e71cSJoe 13378214e71cSJoe static PetscErrorCode InitializeConstants(DM sw, AppCtx *user) 13388214e71cSJoe { 13398214e71cSJoe DM dm; 13408214e71cSJoe PetscInt *species; 13418214e71cSJoe PetscReal *weight, totalCharge = 0., totalWeight = 0., gmin[3], gmax[3], global_charge, global_weight; 13428214e71cSJoe PetscInt Np, dim; 13438214e71cSJoe 13448214e71cSJoe PetscFunctionBegin; 13458214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 13468214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 13478214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 13488214e71cSJoe PetscCall(DMGetBoundingBox(dm, gmin, gmax)); 13498214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 13508214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 13518214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 13528214e71cSJoe totalWeight += weight[p]; 13538214e71cSJoe totalCharge += user->charges[species[p]] * weight[p]; 13548214e71cSJoe } 13558214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 13568214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 13578214e71cSJoe { 13588214e71cSJoe Parameter *param; 13598214e71cSJoe PetscReal Area; 13608214e71cSJoe 13618214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 13628214e71cSJoe switch (dim) { 13638214e71cSJoe case 1: 13648214e71cSJoe Area = (gmax[0] - gmin[0]); 13658214e71cSJoe break; 13668214e71cSJoe case 2: 13678214e71cSJoe if (user->fake_1D) { 13688214e71cSJoe Area = (gmax[0] - gmin[0]); 13698214e71cSJoe } else { 13708214e71cSJoe Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]); 13718214e71cSJoe } 13728214e71cSJoe break; 13738214e71cSJoe case 3: 13748214e71cSJoe Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]) * (gmax[2] - gmin[2]); 13758214e71cSJoe break; 13768214e71cSJoe default: 13778214e71cSJoe SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", dim); 13788214e71cSJoe } 1379462c564dSBarry Smith PetscCallMPI(MPIU_Allreduce(&totalWeight, &global_weight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD)); 1380462c564dSBarry Smith PetscCallMPI(MPIU_Allreduce(&totalCharge, &global_charge, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD)); 13818214e71cSJoe 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)); 13828214e71cSJoe param->sigma = PetscAbsReal(global_charge / (Area)); 13838214e71cSJoe 13848214e71cSJoe PetscCall(PetscPrintf(PETSC_COMM_WORLD, "sigma: %g\n", (double)param->sigma)); 13858214e71cSJoe 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, 13868214e71cSJoe (double)param->vlasovNumber)); 13878214e71cSJoe } 13888214e71cSJoe /* Setup Constants */ 13898214e71cSJoe { 13908214e71cSJoe PetscDS ds; 13918214e71cSJoe Parameter *param; 13928214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 13938214e71cSJoe PetscScalar constants[NUM_CONSTANTS]; 13948214e71cSJoe constants[SIGMA] = param->sigma; 13958214e71cSJoe constants[V0] = param->v0; 13968214e71cSJoe constants[T0] = param->t0; 13978214e71cSJoe constants[X0] = param->x0; 13988214e71cSJoe constants[M0] = param->m0; 13998214e71cSJoe constants[Q0] = param->q0; 14008214e71cSJoe constants[PHI0] = param->phi0; 14018214e71cSJoe constants[POISSON] = param->poissonNumber; 14028214e71cSJoe constants[VLASOV] = param->vlasovNumber; 14038214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 14048214e71cSJoe PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants)); 14058214e71cSJoe } 14068214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 14078214e71cSJoe } 14088214e71cSJoe 14098214e71cSJoe static PetscErrorCode InitializeVelocities_Fake1D(DM sw, AppCtx *user) 14108214e71cSJoe { 14118214e71cSJoe DM dm; 14128214e71cSJoe PetscReal *v; 14138214e71cSJoe PetscInt *species, cStart, cEnd; 14148214e71cSJoe PetscInt dim, Np; 14158214e71cSJoe 14168214e71cSJoe PetscFunctionBegin; 14178214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 14188214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 14198214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v)); 14208214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 14218214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 14228214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 14238214e71cSJoe PetscRandom rnd; 14248214e71cSJoe PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)sw), &rnd)); 14258214e71cSJoe PetscCall(PetscRandomSetInterval(rnd, 0, 1.)); 14268214e71cSJoe PetscCall(PetscRandomSetFromOptions(rnd)); 14278214e71cSJoe 14288214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 14298214e71cSJoe PetscReal a[3] = {0., 0., 0.}, vel[3] = {0., 0., 0.}; 14308214e71cSJoe 14318214e71cSJoe PetscCall(PetscRandomGetValueReal(rnd, &a[0])); 14328214e71cSJoe if (user->perturbed_weights) { 14338214e71cSJoe PetscCall(PetscPDFSampleConstant1D(a, NULL, vel)); 14348214e71cSJoe } else { 14358214e71cSJoe PetscCall(PetscPDFSampleGaussian1D(a, NULL, vel)); 14368214e71cSJoe } 14378214e71cSJoe v[p * dim] = vel[0]; 14388214e71cSJoe } 14398214e71cSJoe PetscCall(PetscRandomDestroy(&rnd)); 14408214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v)); 14418214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 14428214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 14438214e71cSJoe } 14448214e71cSJoe 14458214e71cSJoe static PetscErrorCode CreateSwarm(DM dm, AppCtx *user, DM *sw) 14468214e71cSJoe { 1447*9072cb8bSMatthew G. Knepley DMSwarmCellDM celldm; 1448*9072cb8bSMatthew G. Knepley DM vdm; 14498214e71cSJoe PetscReal v0[2] = {1., 0.}; 14508214e71cSJoe PetscInt dim; 1451b80bf5b1SJoe Pusztay 1452b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 14539566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 14549566063dSJacob Faibussowitsch PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw)); 14559566063dSJacob Faibussowitsch PetscCall(DMSetType(*sw, DMSWARM)); 14569566063dSJacob Faibussowitsch PetscCall(DMSetDimension(*sw, dim)); 14579566063dSJacob Faibussowitsch PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC)); 1458*9072cb8bSMatthew G. Knepley 14599566063dSJacob Faibussowitsch PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR)); 14608214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL)); 14618214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "species", 1, PETSC_INT)); 14628214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "initCoordinates", dim, PETSC_REAL)); 14638214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "initVelocity", dim, PETSC_REAL)); 14648214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "E_field", dim, PETSC_REAL)); 1465*9072cb8bSMatthew G. Knepley 1466*9072cb8bSMatthew G. Knepley const char *fieldnames[2] = {DMSwarmPICField_coor, "velocity"}; 1467*9072cb8bSMatthew G. Knepley 1468*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMCreate(dm, 2, fieldnames, 1, fieldnames, &celldm)); 1469*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmAddCellDM(*sw, celldm)); 1470*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMDestroy(&celldm)); 1471*9072cb8bSMatthew G. Knepley 1472*9072cb8bSMatthew G. Knepley const char *vfieldnames[1] = {"w_q"}; 1473*9072cb8bSMatthew G. Knepley 1474*9072cb8bSMatthew G. Knepley PetscCall(CreateVelocityDM(*sw, &vdm)); 1475*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectCompose((PetscObject)*sw, "__vdm__", (PetscObject)vdm)); 1476*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMCreate(vdm, 1, vfieldnames, 1, &fieldnames[1], &celldm)); 1477*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmAddCellDM(*sw, celldm)); 1478*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMDestroy(&celldm)); 1479*9072cb8bSMatthew G. Knepley PetscCall(DMDestroy(&vdm)); 1480*9072cb8bSMatthew G. Knepley 1481*9072cb8bSMatthew G. Knepley if (user->remap && user->remapType == RM_PFAK) { 1482*9072cb8bSMatthew G. Knepley DM rdm; 1483*9072cb8bSMatthew G. Knepley 1484*9072cb8bSMatthew G. Knepley PetscCall(CreateRemapDM(*sw, &rdm)); 1485*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMCreate(rdm, 1, vfieldnames, 2, fieldnames, &celldm)); 1486*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmAddCellDM(*sw, celldm)); 1487*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMDestroy(&celldm)); 1488*9072cb8bSMatthew G. Knepley PetscCall(DMDestroy(&rdm)); 1489*9072cb8bSMatthew G. Knepley } 1490*9072cb8bSMatthew G. Knepley 14919566063dSJacob Faibussowitsch PetscCall(DMSwarmFinalizeFieldRegister(*sw)); 14928214e71cSJoe PetscCall(DMSetApplicationContext(*sw, user)); 14939566063dSJacob Faibussowitsch PetscCall(DMSetFromOptions(*sw)); 1494*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(*sw, "space")); 14958214e71cSJoe user->swarm = *sw; 1496*9072cb8bSMatthew G. Knepley // TODO: This is redundant init since it is done in InitializeSolveAndSwarm. To remove it, we need to move the 1497*9072cb8bSMatthew G. Knepley // creation of initCoordinates and initVelocity 14988214e71cSJoe if (user->perturbed_weights) { 14998214e71cSJoe PetscCall(InitializeParticles_PerturbedWeights(*sw, user)); 1500b80bf5b1SJoe Pusztay } else { 15018214e71cSJoe PetscCall(DMSwarmComputeLocalSizeFromOptions(*sw)); 15028214e71cSJoe PetscCall(DMSwarmInitializeCoordinates(*sw)); 15038214e71cSJoe if (user->fake_1D) { 15048214e71cSJoe PetscCall(InitializeVelocities_Fake1D(*sw, user)); 15059371c9d4SSatish Balay } else { 15068214e71cSJoe PetscCall(DMSwarmInitializeVelocitiesFromOptions(*sw, v0)); 1507b80bf5b1SJoe Pusztay } 1508b80bf5b1SJoe Pusztay } 15099566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles")); 15109566063dSJacob Faibussowitsch PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view")); 15118214e71cSJoe { 15128214e71cSJoe Vec gc, gc0, gv, gv0; 15138214e71cSJoe 15148214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, DMSwarmPICField_coor, &gc)); 15158214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, "initCoordinates", &gc0)); 15168214e71cSJoe PetscCall(VecCopy(gc, gc0)); 15178214e71cSJoe PetscCall(VecViewFromOptions(gc, NULL, "-ic_x_view")); 15188214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, DMSwarmPICField_coor, &gc)); 15198214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, "initCoordinates", &gc0)); 15208214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, "velocity", &gv)); 15218214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, "initVelocity", &gv0)); 15228214e71cSJoe PetscCall(VecCopy(gv, gv0)); 15238214e71cSJoe PetscCall(VecViewFromOptions(gv, NULL, "-ic_v_view")); 15248214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, "velocity", &gv)); 15258214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, "initVelocity", &gv0)); 15268214e71cSJoe } 1527*9072cb8bSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 152884467f86SMatthew G. Knepley } 1529*9072cb8bSMatthew G. Knepley 1530*9072cb8bSMatthew G. Knepley /* 1531*9072cb8bSMatthew G. Knepley @article{MyersColellaVanStraalen2017, 1532*9072cb8bSMatthew G. Knepley title = {A 4th-order particle-in-cell method with phase-space remapping for the {Vlasov-Poisson} equation}, 1533*9072cb8bSMatthew G. Knepley author = {Andrew Myers and Phillip Colella and Brian Van Straalen}, 1534*9072cb8bSMatthew G. Knepley journal = {SIAM Journal on Scientific Computing}, 1535*9072cb8bSMatthew G. Knepley volume = {39}, 1536*9072cb8bSMatthew G. Knepley issue = {3}, 1537*9072cb8bSMatthew G. Knepley pages = {B467-B485}, 1538*9072cb8bSMatthew G. Knepley doi = {10.1137/16M105962X}, 1539*9072cb8bSMatthew G. Knepley issn = {10957197}, 1540*9072cb8bSMatthew G. Knepley year = {2017}, 1541*9072cb8bSMatthew G. Knepley } 1542*9072cb8bSMatthew G. Knepley */ 1543*9072cb8bSMatthew G. Knepley static PetscErrorCode W_3_Interpolation_Private(PetscReal x, PetscReal *w) 1544*9072cb8bSMatthew G. Knepley { 1545*9072cb8bSMatthew G. Knepley const PetscReal ax = PetscAbsReal(x); 1546*9072cb8bSMatthew G. Knepley 1547*9072cb8bSMatthew G. Knepley PetscFunctionBegin; 1548*9072cb8bSMatthew G. Knepley *w = 0.; 1549*9072cb8bSMatthew G. Knepley // W_3(x) = 1 - 5/2 |x|^2 + 3/2 |x|^3 0 \le |x| \e 1 1550*9072cb8bSMatthew G. Knepley if (ax <= 1.) *w = 1. - 2.5 * PetscSqr(ax) + 1.5 * PetscSqr(ax) * ax; 1551*9072cb8bSMatthew G. Knepley // 1/2 (2 - |x|)^2 (1 - |x|) 1 \le |x| \le 2 1552*9072cb8bSMatthew G. Knepley else if (ax <= 2.) *w = 0.5 * PetscSqr(2. - ax) * (1. - ax); 1553*9072cb8bSMatthew G. Knepley //PetscCall(PetscPrintf(PETSC_COMM_SELF, " W_3 %g --> %g\n", x, *w)); 1554*9072cb8bSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 1555*9072cb8bSMatthew G. Knepley } 1556*9072cb8bSMatthew G. Knepley 1557*9072cb8bSMatthew G. Knepley // Right now, we will assume that the spatial and velocity grids are regular, which will speed up point location immensely 1558*9072cb8bSMatthew G. Knepley static PetscErrorCode DMSwarmRemap_Colella(DM sw, DM *rsw) 1559*9072cb8bSMatthew G. Knepley { 1560*9072cb8bSMatthew G. Knepley DM xdm, vdm; 1561*9072cb8bSMatthew G. Knepley DMSwarmCellDM celldm; 1562*9072cb8bSMatthew G. Knepley AppCtx *user; 1563*9072cb8bSMatthew G. Knepley PetscReal xmin[3], xmax[3], vmin[3], vmax[3]; 1564*9072cb8bSMatthew G. Knepley PetscInt xend[3], vend[3]; 1565*9072cb8bSMatthew G. Knepley PetscReal *x, *v, *w, *rw; 1566*9072cb8bSMatthew G. Knepley PetscReal hx[3], hv[3]; 1567*9072cb8bSMatthew G. Knepley PetscInt dim, xcdim, vcdim, xcStart, xcEnd, vcStart, vcEnd, Np, Nfc; 1568*9072cb8bSMatthew G. Knepley PetscInt debug = ((DM_Swarm *)sw->data)->printWeights; 1569*9072cb8bSMatthew G. Knepley const char **coordFields; 1570*9072cb8bSMatthew G. Knepley 1571*9072cb8bSMatthew G. Knepley PetscFunctionBegin; 1572*9072cb8bSMatthew G. Knepley PetscCall(DMGetApplicationContext(sw, (void **)&user)); 1573*9072cb8bSMatthew G. Knepley PetscCall(DMGetDimension(sw, &dim)); 1574*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetCellDM(sw, &xdm)); 1575*9072cb8bSMatthew G. Knepley PetscCall(DMGetCoordinateDim(xdm, &xcdim)); 1576*9072cb8bSMatthew G. Knepley // Create a new centroid swarm without weights 1577*9072cb8bSMatthew G. Knepley PetscCall(CreateSwarm(xdm, user, rsw)); 1578*9072cb8bSMatthew G. Knepley PetscCall(InitializeParticles_Centroid(*rsw, user->fake_1D)); 1579*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetLocalSize(*rsw, &Np)); 1580*9072cb8bSMatthew G. Knepley // Assume quad mesh and calculate cell diameters (TODO this could be more robust) 1581*9072cb8bSMatthew G. Knepley { 1582*9072cb8bSMatthew G. Knepley const PetscScalar *array; 1583*9072cb8bSMatthew G. Knepley PetscScalar *coords; 1584*9072cb8bSMatthew G. Knepley PetscBool isDG; 1585*9072cb8bSMatthew G. Knepley PetscInt Nc; 1586*9072cb8bSMatthew G. Knepley 1587*9072cb8bSMatthew G. Knepley PetscCall(DMGetBoundingBox(xdm, xmin, xmax)); 1588*9072cb8bSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd)); 1589*9072cb8bSMatthew G. Knepley PetscCall(DMPlexGetCellCoordinates(xdm, xcStart, &isDG, &Nc, &array, &coords)); 1590*9072cb8bSMatthew G. Knepley hx[0] = coords[1 * xcdim + 0] - coords[0 * xcdim + 0]; 1591*9072cb8bSMatthew G. Knepley hx[1] = xcdim > 1 ? coords[2 * xcdim + 1] - coords[1 * xcdim + 1] : 1.; 1592*9072cb8bSMatthew G. Knepley PetscCall(DMPlexRestoreCellCoordinates(xdm, xcStart, &isDG, &Nc, &array, &coords)); 1593*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectQuery((PetscObject)sw, "__vdm__", (PetscObject *)&vdm)); 1594*9072cb8bSMatthew G. Knepley PetscCall(DMGetCoordinateDim(vdm, &vcdim)); 1595*9072cb8bSMatthew G. Knepley PetscCall(DMGetBoundingBox(vdm, vmin, vmax)); 1596*9072cb8bSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd)); 1597*9072cb8bSMatthew G. Knepley PetscCall(DMPlexGetCellCoordinates(vdm, vcStart, &isDG, &Nc, &array, &coords)); 1598*9072cb8bSMatthew G. Knepley hv[0] = coords[1 * vcdim + 0] - coords[0 * vcdim + 0]; 1599*9072cb8bSMatthew G. Knepley hv[1] = vcdim > 1 ? coords[2 * vcdim + 1] - coords[1 * vcdim + 1] : 1.; 1600*9072cb8bSMatthew G. Knepley PetscCall(DMPlexRestoreCellCoordinates(vdm, vcStart, &isDG, &Nc, &array, &coords)); 1601*9072cb8bSMatthew G. Knepley 1602*9072cb8bSMatthew G. Knepley PetscCheck(dim == 1 || user->fake_1D, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONG, "Only support 1D distributions at this time"); 1603*9072cb8bSMatthew G. Knepley xend[0] = xcEnd - xcStart; 1604*9072cb8bSMatthew G. Knepley xend[1] = 1; 1605*9072cb8bSMatthew G. Knepley vend[0] = vcEnd - vcStart; 1606*9072cb8bSMatthew G. Knepley vend[1] = 1; 1607*9072cb8bSMatthew G. Knepley if (debug > 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Phase Grid (%g, %g, %g, %g) (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ")\n", hx[0], hx[1], hv[0], hv[1], xend[0], xend[1], vend[0], vend[1])); 1608*9072cb8bSMatthew G. Knepley } 1609*9072cb8bSMatthew G. Knepley // Iterate over particles in the original swarm 1610*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetCellDMActive(sw, &celldm)); 1611*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMGetCoordinateFields(celldm, &Nfc, &coordFields)); 1612*9072cb8bSMatthew G. Knepley PetscCheck(Nfc == 1, PetscObjectComm((PetscObject)sw), PETSC_ERR_SUP, "We only support a single coordinate field right now, not %" PetscInt_FMT, Nfc); 1613*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, coordFields[0], NULL, NULL, (void **)&x)); 1614*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v)); 1615*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w)); 1616*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetField(*rsw, "w_q", NULL, NULL, (void **)&rw)); 1617*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortGetAccess(sw)); 1618*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortGetAccess(*rsw)); 1619*9072cb8bSMatthew G. Knepley PetscCall(DMGetBoundingBox(vdm, vmin, vmax)); 1620*9072cb8bSMatthew G. Knepley PetscCall(DMGetCoordinatesLocalSetUp(xdm)); 1621*9072cb8bSMatthew G. Knepley for (PetscInt i = 0; i < Np; ++i) rw[i] = 0.; 1622*9072cb8bSMatthew G. Knepley for (PetscInt c = 0; c < xcEnd - xcStart; ++c) { 1623*9072cb8bSMatthew G. Knepley PetscInt *pidx, Npc; 1624*9072cb8bSMatthew G. Knepley PetscInt *rpidx, rNpc; 1625*9072cb8bSMatthew G. Knepley 1626*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 1627*9072cb8bSMatthew G. Knepley for (PetscInt q = 0; q < Npc; ++q) { 1628*9072cb8bSMatthew G. Knepley const PetscInt p = pidx[q]; 1629*9072cb8bSMatthew G. Knepley const PetscReal wp = w[p]; 1630*9072cb8bSMatthew G. Knepley PetscReal Wx[3], Wv[3]; 1631*9072cb8bSMatthew G. Knepley PetscInt xs[3], vs[3]; 1632*9072cb8bSMatthew G. Knepley 1633*9072cb8bSMatthew G. Knepley // Determine the containing cell 1634*9072cb8bSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) { 1635*9072cb8bSMatthew G. Knepley const PetscReal xp = x[p * dim + d]; 1636*9072cb8bSMatthew G. Knepley const PetscReal vp = v[p * dim + d]; 1637*9072cb8bSMatthew G. Knepley 1638*9072cb8bSMatthew G. Knepley xs[d] = PetscFloorReal((xp - xmin[d]) / hx[d]); 1639*9072cb8bSMatthew G. Knepley vs[d] = PetscFloorReal((vp - vmin[d]) / hv[d]); 1640*9072cb8bSMatthew G. Knepley } 1641*9072cb8bSMatthew G. Knepley // Loop over all grid points within 2 spacings of the particle 1642*9072cb8bSMatthew G. Knepley if (debug > 2) { 1643*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "Interpolating particle %" PetscInt_FMT " wt %g (%g, %g, %g, %g) (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ")\n", p, wp, x[p * dim + 0], xcdim > 1 ? x[p * xcdim + 1] : 0., v[p * vcdim + 0], vcdim > 1 ? v[p * vcdim + 1] : 0., xs[0], xs[1], vs[0], vs[1])); 1644*9072cb8bSMatthew G. Knepley } 1645*9072cb8bSMatthew G. Knepley for (PetscInt xi = xs[0] - 1; xi < xs[0] + 3; ++xi) { 1646*9072cb8bSMatthew G. Knepley // Treat xi as periodic 1647*9072cb8bSMatthew G. Knepley const PetscInt xip = xi < 0 ? xi + xend[0] : (xi >= xend[0] ? xi - xend[0] : xi); 1648*9072cb8bSMatthew G. Knepley PetscCall(W_3_Interpolation_Private((xmin[0] + (xi + 0.5) * hx[0] - x[p * dim + 0]) / hx[0], &Wx[0])); 1649*9072cb8bSMatthew G. Knepley for (PetscInt xj = PetscMax(xs[1] - 1, 0); xj < PetscMin(xs[1] + 3, xend[1]); ++xj) { 1650*9072cb8bSMatthew G. Knepley if (xcdim > 1) PetscCall(W_3_Interpolation_Private((xmin[1] + (xj + 0.5) * hx[1] - x[p * dim + 1]) / hx[1], &Wx[1])); 1651*9072cb8bSMatthew G. Knepley else Wx[1] = 1.; 1652*9072cb8bSMatthew G. Knepley for (PetscInt vi = PetscMax(vs[0] - 1, 0); vi < PetscMin(vs[0] + 3, vend[0]); ++vi) { 1653*9072cb8bSMatthew G. Knepley PetscCall(W_3_Interpolation_Private((vmin[0] + (vi + 0.5) * hv[0] - v[p * dim + 0]) / hv[0], &Wv[0])); 1654*9072cb8bSMatthew G. Knepley for (PetscInt vj = PetscMax(vs[1] - 1, 0); vj < PetscMin(vs[1] + 3, vend[1]); ++vj) { 1655*9072cb8bSMatthew G. Knepley const PetscInt rc = xip * xend[1] + xj; 1656*9072cb8bSMatthew G. Knepley const PetscInt rv = vi * vend[1] + vj; 1657*9072cb8bSMatthew G. Knepley 1658*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortGetPointsPerCell(*rsw, rc, &rNpc, &rpidx)); 1659*9072cb8bSMatthew G. Knepley if (vcdim > 1) PetscCall(W_3_Interpolation_Private((vmin[1] + (vj + 0.5) * hv[1] - v[p * dim + 1]) / hv[1], &Wv[1])); 1660*9072cb8bSMatthew G. Knepley else Wv[1] = 1.; 1661*9072cb8bSMatthew G. Knepley if (debug > 2) 1662*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, " Depositing on particle (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ") w = %g (%g, %g, %g, %g)\n", xi, xj, vi, vj, wp * Wx[0] * Wx[1] * Wv[0] * Wv[1], Wx[0], Wx[1], Wv[0], Wv[1])); 1663*9072cb8bSMatthew G. Knepley // Add weight to new particles from original particle using interpolation function 1664*9072cb8bSMatthew G. Knepley PetscCheck(rNpc == vend[0] * vend[1], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid particle velocity binning"); 1665*9072cb8bSMatthew G. Knepley const PetscInt rp = rpidx[rv]; 1666*9072cb8bSMatthew G. Knepley PetscCheck(rp >= 0 && rp < Np, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Particle index %" PetscInt_FMT " not in [0, %" PetscInt_FMT ")", rp, Np); 1667*9072cb8bSMatthew G. Knepley rw[rp] += wp * Wx[0] * Wx[1] * Wv[0] * Wv[1]; 1668*9072cb8bSMatthew G. Knepley if (debug > 2) PetscCall(PetscPrintf(PETSC_COMM_SELF, " Adding weight %g (%g) to particle %" PetscInt_FMT "\n", wp * Wx[0] * Wx[1] * Wv[0] * Wv[1], rw[rp], rp)); 1669*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(*rsw, rc, &rNpc, &rpidx)); 1670*9072cb8bSMatthew G. Knepley } 1671*9072cb8bSMatthew G. Knepley } 1672*9072cb8bSMatthew G. Knepley } 1673*9072cb8bSMatthew G. Knepley } 1674*9072cb8bSMatthew G. Knepley } 1675*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Npc, &pidx)); 1676*9072cb8bSMatthew G. Knepley } 1677*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortRestoreAccess(sw)); 1678*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSortRestoreAccess(*rsw)); 1679*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, coordFields[0], NULL, NULL, (void **)&x)); 1680*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v)); 1681*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w)); 1682*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRestoreField(*rsw, "w_q", NULL, NULL, (void **)&rw)); 1683*9072cb8bSMatthew G. Knepley 1684*9072cb8bSMatthew G. Knepley if (debug) { 1685*9072cb8bSMatthew G. Knepley Vec w; 1686*9072cb8bSMatthew G. Knepley 1687*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCreateGlobalVectorFromField(sw, coordFields[0], &w)); 1688*9072cb8bSMatthew G. Knepley PetscCall(VecViewFromOptions(w, NULL, "-remap_view")); 1689*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, coordFields[0], &w)); 1690*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &w)); 1691*9072cb8bSMatthew G. Knepley PetscCall(VecViewFromOptions(w, NULL, "-remap_view")); 1692*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &w)); 1693*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &w)); 1694*9072cb8bSMatthew G. Knepley PetscCall(VecViewFromOptions(w, NULL, "-remap_view")); 1695*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &w)); 1696*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCreateGlobalVectorFromField(*rsw, coordFields[0], &w)); 1697*9072cb8bSMatthew G. Knepley PetscCall(VecViewFromOptions(w, NULL, "-remap_view")); 1698*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmDestroyGlobalVectorFromField(*rsw, coordFields[0], &w)); 1699*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCreateGlobalVectorFromField(*rsw, "velocity", &w)); 1700*9072cb8bSMatthew G. Knepley PetscCall(VecViewFromOptions(w, NULL, "-remap_view")); 1701*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmDestroyGlobalVectorFromField(*rsw, "velocity", &w)); 1702*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCreateGlobalVectorFromField(*rsw, "w_q", &w)); 1703*9072cb8bSMatthew G. Knepley PetscCall(VecViewFromOptions(w, NULL, "-remap_view")); 1704*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmDestroyGlobalVectorFromField(*rsw, "w_q", &w)); 1705*9072cb8bSMatthew G. Knepley } 1706*9072cb8bSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 1707*9072cb8bSMatthew G. Knepley } 1708*9072cb8bSMatthew G. Knepley 1709*9072cb8bSMatthew G. Knepley static void f0_v2(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[]) 1710*9072cb8bSMatthew G. Knepley { 1711*9072cb8bSMatthew G. Knepley PetscInt d; 1712*9072cb8bSMatthew G. Knepley 1713*9072cb8bSMatthew G. Knepley f0[0] = 0.0; 1714*9072cb8bSMatthew G. Knepley for (d = dim / 2; d < dim; ++d) f0[0] += PetscSqr(x[d]) * u[0]; 1715*9072cb8bSMatthew G. Knepley } 1716*9072cb8bSMatthew G. Knepley 1717*9072cb8bSMatthew G. Knepley static PetscErrorCode DMSwarmRemap_PFAK(DM sw, DM *rsw) 1718*9072cb8bSMatthew G. Knepley { 1719*9072cb8bSMatthew G. Knepley DM xdm, vdm, rdm; 1720*9072cb8bSMatthew G. Knepley DMSwarmCellDM rcelldm; 1721*9072cb8bSMatthew G. Knepley Mat M_p, rM_p, rPM_p; 1722*9072cb8bSMatthew G. Knepley Vec w, rw, rhs; 1723*9072cb8bSMatthew G. Knepley PetscInt Nf; 1724*9072cb8bSMatthew G. Knepley const char **fields; 1725*9072cb8bSMatthew G. Knepley AppCtx *user; 1726*9072cb8bSMatthew G. Knepley 1727*9072cb8bSMatthew G. Knepley PetscFunctionBegin; 1728*9072cb8bSMatthew G. Knepley // Create a new centroid swarm without weights 1729*9072cb8bSMatthew G. Knepley PetscCall(DMGetApplicationContext(sw, (void **)&user)); 1730*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetCellDM(sw, &xdm)); 1731*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectQuery((PetscObject)sw, "__vdm__", (PetscObject *)&vdm)); 1732*9072cb8bSMatthew G. Knepley PetscCall(CreateSwarm(xdm, user, rsw)); 1733*9072cb8bSMatthew G. Knepley // Set remap cell DM 1734*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(sw, "remap")); 1735*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetCellDMActive(sw, &rcelldm)); 1736*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCellDMGetFields(rcelldm, &Nf, &fields)); 1737*9072cb8bSMatthew G. Knepley PetscCheck(Nf == 1, PetscObjectComm((PetscObject)sw), PETSC_ERR_ARG_WRONG, "We only allow a single weight field, not %" PetscInt_FMT, Nf); 1738*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmGetCellDM(sw, &rdm)); 1739*9072cb8bSMatthew G. Knepley PetscCall(DMGetGlobalVector(rdm, &rhs)); 1740*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmMigrate(sw, PETSC_FALSE)); // Bin particles in remap mesh 1741*9072cb8bSMatthew G. Knepley // Compute rhs = M_p w_p 1742*9072cb8bSMatthew G. Knepley PetscCall(DMCreateMassMatrix(sw, rdm, &M_p)); 1743*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCreateGlobalVectorFromField(sw, fields[0], &w)); 1744*9072cb8bSMatthew G. Knepley PetscCall(VecViewFromOptions(w, NULL, "-remap_w_view")); 1745*9072cb8bSMatthew G. Knepley PetscCall(MatMultTranspose(M_p, w, rhs)); 1746*9072cb8bSMatthew G. Knepley PetscCall(VecViewFromOptions(rhs, NULL, "-remap_rhs_view")); 1747*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, fields[0], &w)); 1748*9072cb8bSMatthew G. Knepley PetscCall(MatDestroy(&M_p)); 1749*9072cb8bSMatthew G. Knepley { 1750*9072cb8bSMatthew G. Knepley KSP ksp; 1751*9072cb8bSMatthew G. Knepley Mat M_f; 1752*9072cb8bSMatthew G. Knepley Vec u_f; 1753*9072cb8bSMatthew G. Knepley PetscReal mom[4]; 1754*9072cb8bSMatthew G. Knepley PetscInt cdim; 1755*9072cb8bSMatthew G. Knepley const char *prefix; 1756*9072cb8bSMatthew G. Knepley 1757*9072cb8bSMatthew G. Knepley PetscCall(DMGetCoordinateDim(rdm, &cdim)); 1758*9072cb8bSMatthew G. Knepley PetscCall(DMCreateMassMatrix(rdm, rdm, &M_f)); 1759*9072cb8bSMatthew G. Knepley PetscCall(DMGetGlobalVector(rdm, &u_f)); 1760*9072cb8bSMatthew G. Knepley 1761*9072cb8bSMatthew G. Knepley PetscCall(KSPCreate(PetscObjectComm((PetscObject)sw), &ksp)); 1762*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectGetOptionsPrefix((PetscObject)sw, &prefix)); 1763*9072cb8bSMatthew G. Knepley PetscCall(KSPSetOptionsPrefix(ksp, prefix)); 1764*9072cb8bSMatthew G. Knepley PetscCall(KSPAppendOptionsPrefix(ksp, "ptof_")); 1765*9072cb8bSMatthew G. Knepley PetscCall(KSPSetFromOptions(ksp)); 1766*9072cb8bSMatthew G. Knepley 1767*9072cb8bSMatthew G. Knepley PetscCall(KSPSetOperators(ksp, M_f, M_f)); 1768*9072cb8bSMatthew G. Knepley PetscCall(KSPSolve(ksp, rhs, u_f)); 1769*9072cb8bSMatthew G. Knepley PetscCall(KSPDestroy(&ksp)); 1770*9072cb8bSMatthew G. Knepley PetscCall(VecViewFromOptions(u_f, NULL, "-remap_uf_view")); 1771*9072cb8bSMatthew G. Knepley 1772*9072cb8bSMatthew G. Knepley PetscCall(DMPlexComputeMoments(rdm, u_f, mom)); 1773*9072cb8bSMatthew G. Knepley // Energy is not correct since it uses (x^2 + v^2) 1774*9072cb8bSMatthew G. Knepley PetscDS rds; 1775*9072cb8bSMatthew G. Knepley PetscScalar rmom; 1776*9072cb8bSMatthew G. Knepley void *ctx; 1777*9072cb8bSMatthew G. Knepley 1778*9072cb8bSMatthew G. Knepley PetscCall(DMGetDS(rdm, &rds)); 1779*9072cb8bSMatthew G. Knepley PetscCall(DMGetApplicationContext(rdm, &ctx)); 1780*9072cb8bSMatthew G. Knepley PetscCall(PetscDSSetObjective(rds, 0, &f0_v2)); 1781*9072cb8bSMatthew G. Knepley PetscCall(DMPlexComputeIntegralFEM(rdm, u_f, &rmom, ctx)); 1782*9072cb8bSMatthew G. Knepley mom[1 + cdim] = PetscRealPart(rmom); 1783*9072cb8bSMatthew G. Knepley 1784*9072cb8bSMatthew G. Knepley PetscCall(DMRestoreGlobalVector(rdm, &u_f)); 1785*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "========== PFAK u_f ==========\n")); 1786*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "Mom 0: %g\n", mom[0])); 1787*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "Mom x: %g\n", mom[1 + 0])); 1788*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "Mom v: %g\n", mom[1 + 1])); 1789*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "Mom 2: %g\n", mom[1 + cdim])); 1790*9072cb8bSMatthew G. Knepley PetscCall(MatDestroy(&M_f)); 1791*9072cb8bSMatthew G. Knepley } 1792*9072cb8bSMatthew G. Knepley // Create Remap particle mass matrix M_p 1793*9072cb8bSMatthew G. Knepley PetscInt xcStart, xcEnd, vcStart, vcEnd, cStart, cEnd, r; 1794*9072cb8bSMatthew G. Knepley 1795*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(*rsw, "remap")); 1796*9072cb8bSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(xdm, 0, &xcStart, &xcEnd)); 1797*9072cb8bSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(vdm, 0, &vcStart, &vcEnd)); 1798*9072cb8bSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 1799*9072cb8bSMatthew G. Knepley r = (PetscInt)PetscSqrtReal(((xcEnd - xcStart) * (vcEnd - vcStart)) / (cEnd - cStart)); 1800*9072cb8bSMatthew G. Knepley PetscCall(InitializeParticles_Regular(*rsw, r)); 1801*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmMigrate(*rsw, PETSC_FALSE)); // Bin particles in remap mesh 1802*9072cb8bSMatthew G. Knepley PetscCall(DMCreateMassMatrix(*rsw, rdm, &rM_p)); 1803*9072cb8bSMatthew G. Knepley PetscCall(MatViewFromOptions(rM_p, NULL, "-rM_p_view")); 1804*9072cb8bSMatthew G. Knepley // Solve M_p 1805*9072cb8bSMatthew G. Knepley { 1806*9072cb8bSMatthew G. Knepley KSP ksp; 1807*9072cb8bSMatthew G. Knepley PC pc; 1808*9072cb8bSMatthew G. Knepley const char *prefix; 1809*9072cb8bSMatthew G. Knepley PetscBool isBjacobi; 1810*9072cb8bSMatthew G. Knepley 1811*9072cb8bSMatthew G. Knepley PetscCall(KSPCreate(PetscObjectComm((PetscObject)sw), &ksp)); 1812*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectGetOptionsPrefix((PetscObject)sw, &prefix)); 1813*9072cb8bSMatthew G. Knepley PetscCall(KSPSetOptionsPrefix(ksp, prefix)); 1814*9072cb8bSMatthew G. Knepley PetscCall(KSPAppendOptionsPrefix(ksp, "ftop_")); 1815*9072cb8bSMatthew G. Knepley PetscCall(KSPSetFromOptions(ksp)); 1816*9072cb8bSMatthew G. Knepley 1817*9072cb8bSMatthew G. Knepley PetscCall(KSPGetPC(ksp, &pc)); 1818*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCBJACOBI, &isBjacobi)); 1819*9072cb8bSMatthew G. Knepley if (isBjacobi) { 1820*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCreateMassMatrixSquare(sw, rdm, &rPM_p)); 1821*9072cb8bSMatthew G. Knepley } else { 1822*9072cb8bSMatthew G. Knepley rPM_p = rM_p; 1823*9072cb8bSMatthew G. Knepley PetscCall(PetscObjectReference((PetscObject)rPM_p)); 1824*9072cb8bSMatthew G. Knepley } 1825*9072cb8bSMatthew G. Knepley PetscCall(KSPSetOperators(ksp, rM_p, rPM_p)); 1826*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmCreateGlobalVectorFromField(*rsw, fields[0], &rw)); 1827*9072cb8bSMatthew G. Knepley PetscCall(KSPSolveTranspose(ksp, rhs, rw)); 1828*9072cb8bSMatthew G. Knepley PetscCall(VecViewFromOptions(rw, NULL, "-remap_rw_view")); 1829*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmDestroyGlobalVectorFromField(*rsw, fields[0], &rw)); 1830*9072cb8bSMatthew G. Knepley PetscCall(KSPDestroy(&ksp)); 1831*9072cb8bSMatthew G. Knepley PetscCall(MatDestroy(&rPM_p)); 1832*9072cb8bSMatthew G. Knepley PetscCall(MatDestroy(&rM_p)); 1833*9072cb8bSMatthew G. Knepley } 1834*9072cb8bSMatthew G. Knepley PetscCall(DMRestoreGlobalVector(rdm, &rhs)); 1835*9072cb8bSMatthew G. Knepley 1836*9072cb8bSMatthew G. Knepley // Restore original cell DM 1837*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(sw, "space")); 1838*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmSetCellDMActive(*rsw, "space")); 1839*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmMigrate(*rsw, PETSC_FALSE)); // Bin particles in spatial mesh 1840*9072cb8bSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 1841*9072cb8bSMatthew G. Knepley } 1842*9072cb8bSMatthew G. Knepley 1843*9072cb8bSMatthew G. Knepley static PetscErrorCode DMSwarmRemap(DM sw) 1844*9072cb8bSMatthew G. Knepley { 1845*9072cb8bSMatthew G. Knepley DM rsw; 1846*9072cb8bSMatthew G. Knepley AppCtx *user; 1847*9072cb8bSMatthew G. Knepley 1848*9072cb8bSMatthew G. Knepley PetscFunctionBegin; 1849*9072cb8bSMatthew G. Knepley PetscCall(DMGetApplicationContext(sw, (void **)&user)); 1850*9072cb8bSMatthew G. Knepley switch (user->remapType) { 1851*9072cb8bSMatthew G. Knepley case RM_COLELLA: 1852*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRemap_Colella(sw, &rsw)); 1853*9072cb8bSMatthew G. Knepley break; 1854*9072cb8bSMatthew G. Knepley case RM_PFAK: 1855*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRemap_PFAK(sw, &rsw)); 1856*9072cb8bSMatthew G. Knepley break; 1857*9072cb8bSMatthew G. Knepley default: 1858*9072cb8bSMatthew G. Knepley SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No remap algorithmic %s", RemapTypes[user->remapType]); 1859*9072cb8bSMatthew G. Knepley } 1860*9072cb8bSMatthew G. Knepley 1861*9072cb8bSMatthew G. Knepley PetscReal mom[4], rmom[4]; 1862*9072cb8bSMatthew G. Knepley PetscInt cdim; 1863*9072cb8bSMatthew G. Knepley 1864*9072cb8bSMatthew G. Knepley PetscCall(DMGetCoordinateDim(sw, &cdim)); 1865*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmComputeMoments(sw, "velocity", "w_q", mom)); 1866*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmComputeMoments(rsw, "velocity", "w_q", rmom)); 1867*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "========== Remapped ==========\n")); 1868*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "Mom 0: %g --> %g\n", mom[0], rmom[0])); 1869*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "Mom 1: %g --> %g\n", mom[1], rmom[1])); 1870*9072cb8bSMatthew G. Knepley PetscCall(PetscPrintf(PETSC_COMM_SELF, "Mom 2: %g --> %g\n", mom[1 + cdim], rmom[1 + cdim])); 1871*9072cb8bSMatthew G. Knepley if (user->weight_monitor) { 1872*9072cb8bSMatthew G. Knepley PetscCall(MonitorSwarmWeights(sw, "w_q")); 1873*9072cb8bSMatthew G. Knepley PetscCall(MonitorSwarmWeights(rsw, "w_q")); 1874*9072cb8bSMatthew G. Knepley } 1875*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmReplace(sw, &rsw)); 18763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1877b80bf5b1SJoe Pusztay } 1878b80bf5b1SJoe Pusztay 18798214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Coulomb(SNES snes, DM sw, PetscReal E[]) 1880d71ae5a4SJacob Faibussowitsch { 18818214e71cSJoe AppCtx *user; 18828214e71cSJoe PetscReal *coords; 18838214e71cSJoe PetscInt *species, dim, Np, Ns; 18848214e71cSJoe PetscMPIInt size; 18858214e71cSJoe 18868214e71cSJoe PetscFunctionBegin; 18878214e71cSJoe PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)snes), &size)); 18888214e71cSJoe PetscCheck(size == 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Coulomb code only works in serial"); 18898214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 18908214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 18918214e71cSJoe PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 18928214e71cSJoe PetscCall(DMGetApplicationContext(sw, (void *)&user)); 18938214e71cSJoe 18948214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 18958214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 18968214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 18978214e71cSJoe PetscReal *pcoord = &coords[p * dim]; 18988214e71cSJoe PetscReal pE[3] = {0., 0., 0.}; 18998214e71cSJoe 19008214e71cSJoe /* Calculate field at particle p due to particle q */ 19018214e71cSJoe for (PetscInt q = 0; q < Np; ++q) { 19028214e71cSJoe PetscReal *qcoord = &coords[q * dim]; 19038214e71cSJoe PetscReal rpq[3], r, r3, q_q; 19048214e71cSJoe 19058214e71cSJoe if (p == q) continue; 19068214e71cSJoe q_q = user->charges[species[q]] * 1.; 19078214e71cSJoe for (PetscInt d = 0; d < dim; ++d) rpq[d] = pcoord[d] - qcoord[d]; 19088214e71cSJoe r = DMPlex_NormD_Internal(dim, rpq); 19098214e71cSJoe if (r < PETSC_SQRT_MACHINE_EPSILON) continue; 19108214e71cSJoe r3 = PetscPowRealInt(r, 3); 19118214e71cSJoe for (PetscInt d = 0; d < dim; ++d) pE[d] += q_q * rpq[d] / r3; 19128214e71cSJoe } 19138214e71cSJoe for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = pE[d]; 19148214e71cSJoe } 19158214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 19168214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 19178214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 19188214e71cSJoe } 19198214e71cSJoe 19208214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Primal(SNES snes, DM sw, PetscReal E[]) 19218214e71cSJoe { 1922b80bf5b1SJoe Pusztay DM dm; 19238214e71cSJoe AppCtx *user; 19248214e71cSJoe PetscDS ds; 19258214e71cSJoe PetscFE fe; 1926f1e6e573SMatthew G. Knepley Mat M_p; 192775155f48SMatthew G. Knepley Vec rhoRhs; // Weak charge density, \int phi_i rho 192875155f48SMatthew G. Knepley Vec rho; // Charge density, M^{-1} rhoRhs 192975155f48SMatthew G. Knepley Vec phi, locPhi; // Potential 193075155f48SMatthew G. Knepley Vec f; // Particle weights 19318214e71cSJoe PetscReal *coords; 19328214e71cSJoe PetscInt dim, cStart, cEnd, Np; 19338214e71cSJoe 19348214e71cSJoe PetscFunctionBegin; 193584467f86SMatthew G. Knepley PetscCall(DMGetApplicationContext(sw, (void *)&user)); 193684467f86SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0)); 19378214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 19388214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 19398214e71cSJoe 19408214e71cSJoe KSP ksp; 194184467f86SMatthew G. Knepley const char **oldFields; 194284467f86SMatthew G. Knepley PetscInt Nf; 194384467f86SMatthew G. Knepley const char **tmp; 19448214e71cSJoe 19458214e71cSJoe PetscCall(SNESGetDM(snes, &dm)); 194684467f86SMatthew G. Knepley PetscCall(DMSwarmVectorGetField(sw, &Nf, &tmp)); 194784467f86SMatthew G. Knepley PetscCall(PetscMalloc1(Nf, &oldFields)); 194884467f86SMatthew G. Knepley for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscStrallocpy(tmp[f], (char **)&oldFields[f])); 1949f1e6e573SMatthew G. Knepley PetscCall(DMSwarmVectorDefineField(sw, "w_q")); 19508214e71cSJoe PetscCall(DMCreateMassMatrix(sw, dm, &M_p)); 1951f1e6e573SMatthew G. Knepley PetscCall(DMSwarmVectorDefineFields(sw, Nf, oldFields)); 195284467f86SMatthew G. Knepley for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscFree(oldFields[f])); 195384467f86SMatthew G. Knepley PetscCall(PetscFree(oldFields)); 19548214e71cSJoe 195575155f48SMatthew G. Knepley PetscCall(DMGetGlobalVector(dm, &rhoRhs)); 195675155f48SMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)rhoRhs, "Weak charge density")); 195775155f48SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(dm, "rho", &rho)); 19588214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f)); 19598214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)f, "particle weight")); 196075155f48SMatthew G. Knepley 19618214e71cSJoe PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view")); 1962f1e6e573SMatthew G. Knepley PetscCall(MatViewFromOptions(user->M, NULL, "-m_view")); 19638214e71cSJoe PetscCall(VecViewFromOptions(f, NULL, "-weights_view")); 196475155f48SMatthew G. Knepley 196575155f48SMatthew G. Knepley PetscCall(MatMultTranspose(M_p, f, rhoRhs)); 19668214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f)); 19678214e71cSJoe 19688214e71cSJoe PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp)); 19698214e71cSJoe PetscCall(KSPSetOptionsPrefix(ksp, "em_proj_")); 1970f1e6e573SMatthew G. Knepley PetscCall(KSPSetOperators(ksp, user->M, user->M)); 19718214e71cSJoe PetscCall(KSPSetFromOptions(ksp)); 197275155f48SMatthew G. Knepley PetscCall(KSPSolve(ksp, rhoRhs, rho)); 19738214e71cSJoe 197475155f48SMatthew G. Knepley PetscCall(VecScale(rhoRhs, -1.0)); 19758214e71cSJoe 197675155f48SMatthew G. Knepley PetscCall(VecViewFromOptions(rhoRhs, NULL, "-rho_view")); 197775155f48SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(dm, "rho", &rho)); 19788214e71cSJoe PetscCall(KSPDestroy(&ksp)); 19798214e71cSJoe PetscCall(MatDestroy(&M_p)); 19808214e71cSJoe 198175155f48SMatthew G. Knepley PetscCall(DMGetNamedGlobalVector(dm, "phi", &phi)); 19828214e71cSJoe PetscCall(VecSet(phi, 0.0)); 198375155f48SMatthew G. Knepley PetscCall(SNESSolve(snes, rhoRhs, phi)); 198475155f48SMatthew G. Knepley PetscCall(DMRestoreGlobalVector(dm, &rhoRhs)); 19858214e71cSJoe PetscCall(VecViewFromOptions(phi, NULL, "-phi_view")); 19868214e71cSJoe 19878214e71cSJoe PetscCall(DMGetLocalVector(dm, &locPhi)); 19888214e71cSJoe PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi)); 19898214e71cSJoe PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi)); 199075155f48SMatthew G. Knepley PetscCall(DMRestoreNamedGlobalVector(dm, "phi", &phi)); 199184467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0)); 19928214e71cSJoe 19938214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 19948214e71cSJoe PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe)); 19958214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 19968214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 19978214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 19988214e71cSJoe 199984467f86SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0)); 2000f1e6e573SMatthew G. Knepley PetscFEGeom *chunkgeom = NULL; 20018214e71cSJoe for (PetscInt c = cStart; c < cEnd; ++c) { 20028214e71cSJoe PetscTabulation tab; 20038214e71cSJoe PetscScalar *clPhi = NULL; 20048214e71cSJoe PetscReal *pcoord, *refcoord; 20058214e71cSJoe PetscInt *points; 20068214e71cSJoe PetscInt Ncp; 20078214e71cSJoe 20088214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points)); 20098214e71cSJoe PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord)); 20108214e71cSJoe PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord)); 20118214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) 20128214e71cSJoe for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d]; 2013f1e6e573SMatthew G. Knepley { 2014f1e6e573SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom)); 2015f1e6e573SMatthew G. Knepley for (PetscInt i = 0; i < Ncp; ++i) { 2016f1e6e573SMatthew G. Knepley const PetscReal x0[3] = {-1., -1., -1.}; 2017f1e6e573SMatthew G. Knepley CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]); 2018f1e6e573SMatthew G. Knepley } 2019f1e6e573SMatthew G. Knepley } 20208214e71cSJoe PetscCall(PetscFECreateTabulation(fe, 1, Ncp, refcoord, 1, &tab)); 20218214e71cSJoe PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 20228214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) { 20238214e71cSJoe const PetscReal *basisDer = tab->T[1]; 20248214e71cSJoe const PetscInt p = points[cp]; 20258214e71cSJoe 20268214e71cSJoe for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.; 2027f1e6e573SMatthew G. Knepley PetscCall(PetscFEFreeInterpolateGradient_Static(fe, basisDer, clPhi, dim, chunkgeom->invJ, NULL, cp, &E[p * dim])); 20288214e71cSJoe for (PetscInt d = 0; d < dim; ++d) { 20298214e71cSJoe E[p * dim + d] *= -1.0; 20308214e71cSJoe if (user->fake_1D && d > 0) E[p * dim + d] = 0; 20318214e71cSJoe } 20328214e71cSJoe } 20338214e71cSJoe PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 2034f1e6e573SMatthew G. Knepley PetscCall(PetscTabulationDestroy(&tab)); 20358214e71cSJoe PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord)); 20368214e71cSJoe PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord)); 203784467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points)); 20388214e71cSJoe } 20398214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 20408214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 20418214e71cSJoe PetscCall(DMRestoreLocalVector(dm, &locPhi)); 2042f1e6e573SMatthew G. Knepley PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom)); 204384467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0)); 20448214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 20458214e71cSJoe } 20468214e71cSJoe 20478214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Mixed(SNES snes, DM sw, PetscReal E[]) 20488214e71cSJoe { 20498214e71cSJoe AppCtx *user; 20508214e71cSJoe DM dm, potential_dm; 20518214e71cSJoe KSP ksp; 20528214e71cSJoe IS potential_IS; 20538214e71cSJoe PetscDS ds; 20548214e71cSJoe PetscFE fe; 20558214e71cSJoe Mat M_p, M; 20568214e71cSJoe Vec phi, locPhi, rho, f, temp_rho, rho0; 20578214e71cSJoe PetscQuadrature q; 205875155f48SMatthew G. Knepley PetscReal *coords; 205984467f86SMatthew G. Knepley PetscInt dim, cStart, cEnd, Np, pot_field = 1; 206084467f86SMatthew G. Knepley const char **oldFields; 206184467f86SMatthew G. Knepley PetscInt Nf; 206284467f86SMatthew G. Knepley const char **tmp; 20638214e71cSJoe 20648214e71cSJoe PetscFunctionBegin; 206584467f86SMatthew G. Knepley PetscCall(DMGetApplicationContext(sw, &user)); 206684467f86SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->ESolveEvent, snes, sw, 0, 0)); 20678214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 20688214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 20698214e71cSJoe 20708214e71cSJoe /* Create the charges rho */ 20718214e71cSJoe PetscCall(SNESGetDM(snes, &dm)); 20728214e71cSJoe PetscCall(DMGetGlobalVector(dm, &rho)); 20738214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)rho, "rho")); 20748214e71cSJoe 207584467f86SMatthew G. Knepley PetscCall(DMCreateSubDM(dm, 1, &pot_field, &potential_IS, &potential_dm)); 20768214e71cSJoe 207784467f86SMatthew G. Knepley PetscCall(DMSwarmVectorGetField(sw, &Nf, &tmp)); 207884467f86SMatthew G. Knepley PetscCall(PetscMalloc1(Nf, &oldFields)); 207984467f86SMatthew G. Knepley for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscStrallocpy(tmp[f], (char **)&oldFields[f])); 2080f1e6e573SMatthew G. Knepley PetscCall(DMSwarmVectorDefineField(sw, "w_q")); 20818214e71cSJoe PetscCall(DMCreateMassMatrix(sw, potential_dm, &M_p)); 2082f1e6e573SMatthew G. Knepley PetscCall(DMSwarmVectorDefineFields(sw, Nf, oldFields)); 208384467f86SMatthew G. Knepley for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscFree(oldFields[f])); 208484467f86SMatthew G. Knepley PetscCall(PetscFree(oldFields)); 20858214e71cSJoe 20868214e71cSJoe PetscCall(DMCreateMassMatrix(potential_dm, potential_dm, &M)); 20878214e71cSJoe PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view")); 20888214e71cSJoe PetscCall(MatViewFromOptions(M, NULL, "-m_view")); 20898214e71cSJoe PetscCall(DMGetGlobalVector(potential_dm, &temp_rho)); 20908214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)temp_rho, "Mf")); 20918214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f)); 20928214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)f, "particle weight")); 20938214e71cSJoe PetscCall(VecViewFromOptions(f, NULL, "-weights_view")); 20948214e71cSJoe PetscCall(MatMultTranspose(M_p, f, temp_rho)); 20958214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f)); 20968214e71cSJoe PetscCall(DMGetGlobalVector(potential_dm, &rho0)); 20978214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)rho0, "Charge density (rho0) from Mixed Compute")); 20988214e71cSJoe 20998214e71cSJoe PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp)); 21008214e71cSJoe PetscCall(KSPSetOptionsPrefix(ksp, "em_proj")); 21018214e71cSJoe PetscCall(KSPSetOperators(ksp, M, M)); 21028214e71cSJoe PetscCall(KSPSetFromOptions(ksp)); 21038214e71cSJoe PetscCall(KSPSolve(ksp, temp_rho, rho0)); 21048214e71cSJoe PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view")); 21058214e71cSJoe 21068214e71cSJoe PetscCall(VecISCopy(rho, potential_IS, SCATTER_FORWARD, temp_rho)); 21078214e71cSJoe PetscCall(VecScale(rho, 0.25)); 21088214e71cSJoe PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view")); 21098214e71cSJoe PetscCall(VecViewFromOptions(temp_rho, NULL, "-temprho_view")); 21108214e71cSJoe PetscCall(VecViewFromOptions(rho, NULL, "-rho_view")); 21118214e71cSJoe PetscCall(DMRestoreGlobalVector(potential_dm, &temp_rho)); 21128214e71cSJoe PetscCall(DMRestoreGlobalVector(potential_dm, &rho0)); 21138214e71cSJoe 21148214e71cSJoe PetscCall(MatDestroy(&M_p)); 21158214e71cSJoe PetscCall(MatDestroy(&M)); 21168214e71cSJoe PetscCall(KSPDestroy(&ksp)); 21178214e71cSJoe PetscCall(DMDestroy(&potential_dm)); 21188214e71cSJoe PetscCall(ISDestroy(&potential_IS)); 21198214e71cSJoe 21208214e71cSJoe PetscCall(DMGetGlobalVector(dm, &phi)); 21218214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)phi, "potential")); 21228214e71cSJoe PetscCall(VecSet(phi, 0.0)); 21238214e71cSJoe PetscCall(SNESSolve(snes, rho, phi)); 21248214e71cSJoe PetscCall(DMRestoreGlobalVector(dm, &rho)); 21258214e71cSJoe 21268214e71cSJoe PetscCall(VecViewFromOptions(phi, NULL, "-phi_view")); 21278214e71cSJoe 21288214e71cSJoe PetscCall(DMGetLocalVector(dm, &locPhi)); 21298214e71cSJoe PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi)); 21308214e71cSJoe PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi)); 21318214e71cSJoe PetscCall(DMRestoreGlobalVector(dm, &phi)); 213284467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->ESolveEvent, snes, sw, 0, 0)); 21338214e71cSJoe 213484467f86SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->ETabEvent, snes, sw, 0, 0)); 21358214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 21368214e71cSJoe PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe)); 21378214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 21388214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 21398214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 21408214e71cSJoe PetscCall(PetscFEGetQuadrature(fe, &q)); 2141f1e6e573SMatthew G. Knepley PetscFEGeom *chunkgeom = NULL; 21428214e71cSJoe for (PetscInt c = cStart; c < cEnd; ++c) { 21438214e71cSJoe PetscTabulation tab; 21448214e71cSJoe PetscScalar *clPhi = NULL; 21458214e71cSJoe PetscReal *pcoord, *refcoord; 21468214e71cSJoe PetscInt *points; 21478214e71cSJoe PetscInt Ncp; 21488214e71cSJoe 21498214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points)); 21508214e71cSJoe PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord)); 21518214e71cSJoe PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord)); 21528214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) 21538214e71cSJoe for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d]; 2154f1e6e573SMatthew G. Knepley { 2155f1e6e573SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(user->fegeom, c - cStart, c - cStart + 1, &chunkgeom)); 2156f1e6e573SMatthew G. Knepley for (PetscInt i = 0; i < Ncp; ++i) { 2157f1e6e573SMatthew G. Knepley // Apply the inverse affine transformation for each point 2158f1e6e573SMatthew G. Knepley const PetscReal x0[3] = {-1., -1., -1.}; 2159f1e6e573SMatthew G. Knepley CoordinatesRealToRef(dim, dim, x0, chunkgeom->v, chunkgeom->invJ, &pcoord[dim * i], &refcoord[dim * i]); 2160f1e6e573SMatthew G. Knepley } 2161f1e6e573SMatthew G. Knepley } 21628214e71cSJoe PetscCall(PetscFECreateTabulation(fe, 1, Ncp, refcoord, 1, &tab)); 21638214e71cSJoe PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 21648214e71cSJoe 21658214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) { 21668214e71cSJoe const PetscInt p = points[cp]; 21678214e71cSJoe 21688214e71cSJoe for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.; 2169f1e6e573SMatthew G. Knepley PetscCall(PetscFEInterpolateAtPoints_Static(fe, tab, clPhi, chunkgeom, cp, &E[p * dim])); 2170f1e6e573SMatthew G. Knepley PetscCall(PetscFEPushforward(fe, chunkgeom, 1, &E[p * dim])); 21718214e71cSJoe for (PetscInt d = 0; d < dim; ++d) { 21728214e71cSJoe E[p * dim + d] *= -2.0; 21738214e71cSJoe if (user->fake_1D && d > 0) E[p * dim + d] = 0; 21748214e71cSJoe } 21758214e71cSJoe } 21768214e71cSJoe PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 2177f1e6e573SMatthew G. Knepley PetscCall(PetscTabulationDestroy(&tab)); 21788214e71cSJoe PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord)); 21798214e71cSJoe PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord)); 218084467f86SMatthew G. Knepley PetscCall(DMSwarmSortRestorePointsPerCell(sw, c, &Ncp, &points)); 21818214e71cSJoe } 21828214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 21838214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 21848214e71cSJoe PetscCall(DMRestoreLocalVector(dm, &locPhi)); 2185f1e6e573SMatthew G. Knepley PetscCall(PetscFEGeomRestoreChunk(user->fegeom, 0, 1, &chunkgeom)); 218684467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->ETabEvent, snes, sw, 0, 0)); 21878214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 21888214e71cSJoe } 21898214e71cSJoe 21908214e71cSJoe static PetscErrorCode ComputeFieldAtParticles(SNES snes, DM sw, PetscReal E[]) 21918214e71cSJoe { 21928214e71cSJoe AppCtx *ctx; 21938214e71cSJoe PetscInt dim, Np; 21948214e71cSJoe 21958214e71cSJoe PetscFunctionBegin; 21968214e71cSJoe PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 21978214e71cSJoe PetscValidHeaderSpecific(sw, DM_CLASSID, 2); 21988214e71cSJoe PetscAssertPointer(E, 3); 21998214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 22008214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 22018214e71cSJoe PetscCall(DMGetApplicationContext(sw, &ctx)); 22028214e71cSJoe PetscCall(PetscArrayzero(E, Np * dim)); 2203*9072cb8bSMatthew G. Knepley ctx->validE = PETSC_TRUE; 22048214e71cSJoe 22058214e71cSJoe switch (ctx->em) { 22068214e71cSJoe case EM_PRIMAL: 22078214e71cSJoe PetscCall(ComputeFieldAtParticles_Primal(snes, sw, E)); 22088214e71cSJoe break; 22098214e71cSJoe case EM_COULOMB: 22108214e71cSJoe PetscCall(ComputeFieldAtParticles_Coulomb(snes, sw, E)); 22118214e71cSJoe break; 22128214e71cSJoe case EM_MIXED: 22138214e71cSJoe PetscCall(ComputeFieldAtParticles_Mixed(snes, sw, E)); 22148214e71cSJoe break; 22158214e71cSJoe case EM_NONE: 22168214e71cSJoe break; 22178214e71cSJoe default: 22188214e71cSJoe SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No solver for electrostatic model %s", EMTypes[ctx->em]); 22198214e71cSJoe } 22208214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 22218214e71cSJoe } 22228214e71cSJoe 22238214e71cSJoe static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec G, void *ctx) 22248214e71cSJoe { 22258214e71cSJoe DM sw; 22268214e71cSJoe SNES snes = ((AppCtx *)ctx)->snes; 22278214e71cSJoe const PetscReal *coords, *vel; 22288214e71cSJoe const PetscScalar *u; 22298214e71cSJoe PetscScalar *g; 22308214e71cSJoe PetscReal *E, m_p = 1., q_p = -1.; 22318214e71cSJoe PetscInt dim, d, Np, p; 2232b80bf5b1SJoe Pusztay 2233b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 22348214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 22358214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 22368214e71cSJoe PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 22378214e71cSJoe PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 22388214e71cSJoe PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 22398214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 22408214e71cSJoe PetscCall(VecGetArrayRead(U, &u)); 22418214e71cSJoe PetscCall(VecGetArray(G, &g)); 22428214e71cSJoe 22438214e71cSJoe PetscCall(ComputeFieldAtParticles(snes, sw, E)); 22448214e71cSJoe 22458214e71cSJoe Np /= 2 * dim; 22468214e71cSJoe for (p = 0; p < Np; ++p) { 22478214e71cSJoe for (d = 0; d < dim; ++d) { 22488214e71cSJoe g[(p * 2 + 0) * dim + d] = u[(p * 2 + 1) * dim + d]; 22498214e71cSJoe g[(p * 2 + 1) * dim + d] = q_p * E[p * dim + d] / m_p; 22508214e71cSJoe } 22518214e71cSJoe } 22528214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 22538214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 22548214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 22558214e71cSJoe PetscCall(VecRestoreArrayRead(U, &u)); 22568214e71cSJoe PetscCall(VecRestoreArray(G, &g)); 22578214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 22588214e71cSJoe } 22598214e71cSJoe 22608214e71cSJoe /* J_{ij} = dF_i/dx_j 22618214e71cSJoe J_p = ( 0 1) 22628214e71cSJoe (-w^2 0) 22638214e71cSJoe TODO Now there is another term with w^2 from the electric field. I think we will need to invert the operator. 22648214e71cSJoe Perhaps we can approximate the Jacobian using only the cellwise P-P gradient from Coulomb 22658214e71cSJoe */ 22668214e71cSJoe static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat P, void *ctx) 22678214e71cSJoe { 22688214e71cSJoe DM sw; 22698214e71cSJoe const PetscReal *coords, *vel; 22708214e71cSJoe PetscInt dim, d, Np, p, rStart; 22718214e71cSJoe 22728214e71cSJoe PetscFunctionBeginUser; 22738214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 22748214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 22758214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 22768214e71cSJoe PetscCall(MatGetOwnershipRange(J, &rStart, NULL)); 22778214e71cSJoe PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 22788214e71cSJoe PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 22798214e71cSJoe Np /= 2 * dim; 22808214e71cSJoe for (p = 0; p < Np; ++p) { 22818214e71cSJoe const PetscReal x0 = coords[p * dim + 0]; 22828214e71cSJoe const PetscReal vy0 = vel[p * dim + 1]; 22838214e71cSJoe const PetscReal omega = vy0 / x0; 22848214e71cSJoe PetscScalar vals[4] = {0., 1., -PetscSqr(omega), 0.}; 22858214e71cSJoe 22868214e71cSJoe for (d = 0; d < dim; ++d) { 22878214e71cSJoe const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart}; 22888214e71cSJoe PetscCall(MatSetValues(J, 2, rows, 2, rows, vals, INSERT_VALUES)); 22898214e71cSJoe } 22908214e71cSJoe } 22918214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 22928214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 22938214e71cSJoe PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 22948214e71cSJoe PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 22958214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 22968214e71cSJoe } 22978214e71cSJoe 22988214e71cSJoe static PetscErrorCode RHSFunctionX(TS ts, PetscReal t, Vec V, Vec Xres, void *ctx) 22998214e71cSJoe { 23008214e71cSJoe AppCtx *user = (AppCtx *)ctx; 23018214e71cSJoe DM sw; 23028214e71cSJoe const PetscScalar *v; 23038214e71cSJoe PetscScalar *xres; 23048214e71cSJoe PetscInt Np, p, d, dim; 23058214e71cSJoe 23068214e71cSJoe PetscFunctionBeginUser; 230784467f86SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->RhsXEvent, ts, 0, 0, 0)); 23088214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 23098214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 23108214e71cSJoe PetscCall(VecGetLocalSize(Xres, &Np)); 23119566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(V, &v)); 23128214e71cSJoe PetscCall(VecGetArray(Xres, &xres)); 2313b80bf5b1SJoe Pusztay Np /= dim; 2314b80bf5b1SJoe Pusztay for (p = 0; p < Np; ++p) { 23158214e71cSJoe for (d = 0; d < dim; ++d) { 23168214e71cSJoe xres[p * dim + d] = v[p * dim + d]; 23178214e71cSJoe if (user->fake_1D && d > 0) xres[p * dim + d] = 0; 23188214e71cSJoe } 2319b80bf5b1SJoe Pusztay } 23209566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(V, &v)); 23218214e71cSJoe PetscCall(VecRestoreArray(Xres, &xres)); 232284467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->RhsXEvent, ts, 0, 0, 0)); 23233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2324b80bf5b1SJoe Pusztay } 2325b80bf5b1SJoe Pusztay 23268214e71cSJoe static PetscErrorCode RHSFunctionV(TS ts, PetscReal t, Vec X, Vec Vres, void *ctx) 23278214e71cSJoe { 23288214e71cSJoe DM sw; 23298214e71cSJoe AppCtx *user = (AppCtx *)ctx; 23308214e71cSJoe SNES snes = ((AppCtx *)ctx)->snes; 23318214e71cSJoe const PetscScalar *x; 23328214e71cSJoe const PetscReal *coords, *vel; 23338214e71cSJoe PetscReal *E, m_p, q_p; 23348214e71cSJoe PetscScalar *vres; 23358214e71cSJoe PetscInt Np, p, dim, d; 23368214e71cSJoe Parameter *param; 23378214e71cSJoe 23388214e71cSJoe PetscFunctionBeginUser; 233984467f86SMatthew G. Knepley PetscCall(PetscLogEventBegin(user->RhsVEvent, ts, 0, 0, 0)); 23408214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 23418214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 23428214e71cSJoe PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 23438214e71cSJoe PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 23448214e71cSJoe PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 23458214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 23468214e71cSJoe m_p = user->masses[0] * param->m0; 23478214e71cSJoe q_p = user->charges[0] * param->q0; 23488214e71cSJoe PetscCall(VecGetLocalSize(Vres, &Np)); 23498214e71cSJoe PetscCall(VecGetArrayRead(X, &x)); 23508214e71cSJoe PetscCall(VecGetArray(Vres, &vres)); 23518214e71cSJoe PetscCall(ComputeFieldAtParticles(snes, sw, E)); 23528214e71cSJoe 23538214e71cSJoe Np /= dim; 23548214e71cSJoe for (p = 0; p < Np; ++p) { 23558214e71cSJoe for (d = 0; d < dim; ++d) { 23568214e71cSJoe vres[p * dim + d] = q_p * E[p * dim + d] / m_p; 23578214e71cSJoe if (user->fake_1D && d > 0) vres[p * dim + d] = 0.; 23588214e71cSJoe } 23598214e71cSJoe } 23608214e71cSJoe PetscCall(VecRestoreArrayRead(X, &x)); 23618214e71cSJoe /* 2362d7c1f440SPierre Jolivet Synchronized, ordered output for parallel/sequential test cases. 23638214e71cSJoe In the 1D (on the 2D mesh) case, every y component should be zero. 23648214e71cSJoe */ 23658214e71cSJoe if (user->checkVRes) { 23668214e71cSJoe PetscBool pr = user->checkVRes > 1 ? PETSC_TRUE : PETSC_FALSE; 23678214e71cSJoe PetscInt step; 23688214e71cSJoe 23698214e71cSJoe PetscCall(TSGetStepNumber(ts, &step)); 23708214e71cSJoe if (pr) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step: %" PetscInt_FMT "\n", step)); 23718214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 23728214e71cSJoe if (pr) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Residual: %.12g %.12g\n", (double)PetscRealPart(vres[p * dim + 0]), (double)PetscRealPart(vres[p * dim + 1]))); 23738214e71cSJoe 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])); 23748214e71cSJoe } 23758214e71cSJoe if (pr) PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT)); 23768214e71cSJoe } 23778214e71cSJoe PetscCall(VecRestoreArray(Vres, &vres)); 23788214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 23798214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 23808214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 238184467f86SMatthew G. Knepley PetscCall(PetscLogEventEnd(user->RhsVEvent, ts, 0, 0, 0)); 23828214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 23838214e71cSJoe } 23848214e71cSJoe 23858214e71cSJoe static PetscErrorCode CreateSolution(TS ts) 23868214e71cSJoe { 23878214e71cSJoe DM sw; 23888214e71cSJoe Vec u; 23898214e71cSJoe PetscInt dim, Np; 23908214e71cSJoe 23918214e71cSJoe PetscFunctionBegin; 23928214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 23938214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 23948214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 23958214e71cSJoe PetscCall(VecCreate(PETSC_COMM_WORLD, &u)); 23968214e71cSJoe PetscCall(VecSetBlockSize(u, dim)); 23978214e71cSJoe PetscCall(VecSetSizes(u, 2 * Np * dim, PETSC_DECIDE)); 23988214e71cSJoe PetscCall(VecSetUp(u)); 23998214e71cSJoe PetscCall(TSSetSolution(ts, u)); 24008214e71cSJoe PetscCall(VecDestroy(&u)); 24018214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 24028214e71cSJoe } 24038214e71cSJoe 24048214e71cSJoe static PetscErrorCode SetProblem(TS ts) 24058214e71cSJoe { 24068214e71cSJoe AppCtx *user; 24078214e71cSJoe DM sw; 24088214e71cSJoe 24098214e71cSJoe PetscFunctionBegin; 24108214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 24118214e71cSJoe PetscCall(DMGetApplicationContext(sw, (void **)&user)); 24128214e71cSJoe // Define unified system for (X, V) 24138214e71cSJoe { 24148214e71cSJoe Mat J; 24158214e71cSJoe PetscInt dim, Np; 24168214e71cSJoe 24178214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 24188214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 24198214e71cSJoe PetscCall(MatCreate(PETSC_COMM_WORLD, &J)); 24208214e71cSJoe PetscCall(MatSetSizes(J, 2 * Np * dim, 2 * Np * dim, PETSC_DECIDE, PETSC_DECIDE)); 24218214e71cSJoe PetscCall(MatSetBlockSize(J, 2 * dim)); 24228214e71cSJoe PetscCall(MatSetFromOptions(J)); 24238214e71cSJoe PetscCall(MatSetUp(J)); 24248214e71cSJoe PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, user)); 24258214e71cSJoe PetscCall(TSSetRHSJacobian(ts, J, J, RHSJacobian, user)); 24268214e71cSJoe PetscCall(MatDestroy(&J)); 24278214e71cSJoe } 24288214e71cSJoe /* Define split system for X and V */ 24298214e71cSJoe { 24308214e71cSJoe Vec u; 24318214e71cSJoe IS isx, isv, istmp; 24328214e71cSJoe const PetscInt *idx; 24338214e71cSJoe PetscInt dim, Np, rstart; 24348214e71cSJoe 24358214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 24368214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 24378214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 24388214e71cSJoe PetscCall(VecGetOwnershipRange(u, &rstart, NULL)); 24398214e71cSJoe PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 0, 2, &istmp)); 24408214e71cSJoe PetscCall(ISGetIndices(istmp, &idx)); 24418214e71cSJoe PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isx)); 24428214e71cSJoe PetscCall(ISRestoreIndices(istmp, &idx)); 24438214e71cSJoe PetscCall(ISDestroy(&istmp)); 24448214e71cSJoe PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 1, 2, &istmp)); 24458214e71cSJoe PetscCall(ISGetIndices(istmp, &idx)); 24468214e71cSJoe PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isv)); 24478214e71cSJoe PetscCall(ISRestoreIndices(istmp, &idx)); 24488214e71cSJoe PetscCall(ISDestroy(&istmp)); 24498214e71cSJoe PetscCall(TSRHSSplitSetIS(ts, "position", isx)); 24508214e71cSJoe PetscCall(TSRHSSplitSetIS(ts, "momentum", isv)); 24518214e71cSJoe PetscCall(ISDestroy(&isx)); 24528214e71cSJoe PetscCall(ISDestroy(&isv)); 24538214e71cSJoe PetscCall(TSRHSSplitSetRHSFunction(ts, "position", NULL, RHSFunctionX, user)); 24548214e71cSJoe PetscCall(TSRHSSplitSetRHSFunction(ts, "momentum", NULL, RHSFunctionV, user)); 24558214e71cSJoe } 24568214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 24578214e71cSJoe } 24588214e71cSJoe 24598214e71cSJoe static PetscErrorCode DMSwarmTSRedistribute(TS ts) 24608214e71cSJoe { 24618214e71cSJoe DM sw; 24628214e71cSJoe Vec u; 24638214e71cSJoe PetscReal t, maxt, dt; 24648214e71cSJoe PetscInt n, maxn; 24658214e71cSJoe 24668214e71cSJoe PetscFunctionBegin; 24678214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 24688214e71cSJoe PetscCall(TSGetTime(ts, &t)); 24698214e71cSJoe PetscCall(TSGetMaxTime(ts, &maxt)); 24708214e71cSJoe PetscCall(TSGetTimeStep(ts, &dt)); 24718214e71cSJoe PetscCall(TSGetStepNumber(ts, &n)); 24728214e71cSJoe PetscCall(TSGetMaxSteps(ts, &maxn)); 24738214e71cSJoe 24748214e71cSJoe PetscCall(TSReset(ts)); 24758214e71cSJoe PetscCall(TSSetDM(ts, sw)); 24768214e71cSJoe PetscCall(TSSetFromOptions(ts)); 24778214e71cSJoe PetscCall(TSSetTime(ts, t)); 24788214e71cSJoe PetscCall(TSSetMaxTime(ts, maxt)); 24798214e71cSJoe PetscCall(TSSetTimeStep(ts, dt)); 24808214e71cSJoe PetscCall(TSSetStepNumber(ts, n)); 24818214e71cSJoe PetscCall(TSSetMaxSteps(ts, maxn)); 24828214e71cSJoe 24838214e71cSJoe PetscCall(CreateSolution(ts)); 24848214e71cSJoe PetscCall(SetProblem(ts)); 24858214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 24868214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 24878214e71cSJoe } 24888214e71cSJoe 24898214e71cSJoe PetscErrorCode line(PetscInt dim, PetscReal time, const PetscReal dummy[], PetscInt p, PetscScalar x[], void *ctx) 24908214e71cSJoe { 24918214e71cSJoe DM sw, cdm; 24928214e71cSJoe PetscInt Np; 24938214e71cSJoe PetscReal low[2], high[2]; 24948214e71cSJoe AppCtx *user = (AppCtx *)ctx; 24958214e71cSJoe 24968214e71cSJoe sw = user->swarm; 24978214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &cdm)); 24988214e71cSJoe // Get the bounding box so we can equally space the particles 24998214e71cSJoe PetscCall(DMGetLocalBoundingBox(cdm, low, high)); 25008214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 25018214e71cSJoe // shift it by h/2 so nothing is initialized directly on a boundary 25028214e71cSJoe x[0] = ((high[0] - low[0]) / Np) * (p + 0.5); 25038214e71cSJoe x[1] = 0.; 25048214e71cSJoe return PETSC_SUCCESS; 25058214e71cSJoe } 25068214e71cSJoe 2507b80bf5b1SJoe Pusztay /* 25088214e71cSJoe InitializeSolveAndSwarm - Set the solution values to the swarm coordinates and velocities, and also possibly set the initial values. 25098214e71cSJoe 25108214e71cSJoe Input Parameters: 25118214e71cSJoe + ts - The TS 2512d7c1f440SPierre Jolivet - useInitial - Flag to also set the initial conditions to the current coordinates and velocities and setup the problem 25138214e71cSJoe 25148214e71cSJoe Output Parameters: 25158214e71cSJoe . u - The initialized solution vector 25168214e71cSJoe 25178214e71cSJoe Level: advanced 25188214e71cSJoe 25198214e71cSJoe .seealso: InitializeSolve() 2520b80bf5b1SJoe Pusztay */ 25218214e71cSJoe static PetscErrorCode InitializeSolveAndSwarm(TS ts, PetscBool useInitial) 2522d71ae5a4SJacob Faibussowitsch { 25238214e71cSJoe DM sw; 25248214e71cSJoe Vec u, gc, gv, gc0, gv0; 25258214e71cSJoe IS isx, isv; 25268214e71cSJoe PetscInt dim; 25278214e71cSJoe AppCtx *user; 2528b80bf5b1SJoe Pusztay 2529b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 25308214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 25318214e71cSJoe PetscCall(DMGetApplicationContext(sw, &user)); 25328214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 25338214e71cSJoe if (useInitial) { 25348214e71cSJoe PetscReal v0[2] = {1., 0.}; 25358214e71cSJoe if (user->perturbed_weights) { 25368214e71cSJoe PetscCall(InitializeParticles_PerturbedWeights(sw, user)); 25378214e71cSJoe } else { 25388214e71cSJoe PetscCall(DMSwarmComputeLocalSizeFromOptions(sw)); 25398214e71cSJoe PetscCall(DMSwarmInitializeCoordinates(sw)); 25408214e71cSJoe if (user->fake_1D) { 25418214e71cSJoe PetscCall(InitializeVelocities_Fake1D(sw, user)); 25428214e71cSJoe } else { 25438214e71cSJoe PetscCall(DMSwarmInitializeVelocitiesFromOptions(sw, v0)); 25448214e71cSJoe } 25458214e71cSJoe } 25468214e71cSJoe PetscCall(DMSwarmMigrate(sw, PETSC_TRUE)); 25478214e71cSJoe PetscCall(DMSwarmTSRedistribute(ts)); 25488214e71cSJoe } 25498214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 25508214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "position", &isx)); 25518214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv)); 25528214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 25538214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "initCoordinates", &gc0)); 25548214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv)); 25558214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "initVelocity", &gv0)); 25568214e71cSJoe if (useInitial) { 25578214e71cSJoe PetscCall(VecCopy(gc, gc0)); 25588214e71cSJoe PetscCall(VecCopy(gv, gv0)); 25598214e71cSJoe } 25608214e71cSJoe PetscCall(VecISCopy(u, isx, SCATTER_FORWARD, gc)); 25618214e71cSJoe PetscCall(VecISCopy(u, isv, SCATTER_FORWARD, gv)); 25628214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 25638214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "initCoordinates", &gc0)); 25648214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv)); 25658214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "initVelocity", &gv0)); 25668214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 25678214e71cSJoe } 25688214e71cSJoe 25698214e71cSJoe static PetscErrorCode InitializeSolve(TS ts, Vec u) 2570b80bf5b1SJoe Pusztay { 25718214e71cSJoe PetscFunctionBegin; 25728214e71cSJoe PetscCall(TSSetSolution(ts, u)); 25738214e71cSJoe PetscCall(InitializeSolveAndSwarm(ts, PETSC_TRUE)); 25748214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 2575b80bf5b1SJoe Pusztay } 2576b80bf5b1SJoe Pusztay 25778214e71cSJoe static PetscErrorCode ComputeError(TS ts, Vec U, Vec E) 25788214e71cSJoe { 25798214e71cSJoe MPI_Comm comm; 25808214e71cSJoe DM sw; 25818214e71cSJoe AppCtx *user; 25828214e71cSJoe const PetscScalar *u; 25838214e71cSJoe const PetscReal *coords, *vel; 25848214e71cSJoe PetscScalar *e; 25858214e71cSJoe PetscReal t; 25868214e71cSJoe PetscInt dim, Np, p; 2587b80bf5b1SJoe Pusztay 25888214e71cSJoe PetscFunctionBeginUser; 25898214e71cSJoe PetscCall(PetscObjectGetComm((PetscObject)ts, &comm)); 25908214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 25918214e71cSJoe PetscCall(DMGetApplicationContext(sw, &user)); 25928214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 25938214e71cSJoe PetscCall(TSGetSolveTime(ts, &t)); 25948214e71cSJoe PetscCall(VecGetArray(E, &e)); 25958214e71cSJoe PetscCall(VecGetArrayRead(U, &u)); 25968214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 25978214e71cSJoe PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 25988214e71cSJoe PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 25998214e71cSJoe Np /= 2 * dim; 26008214e71cSJoe for (p = 0; p < Np; ++p) { 26018214e71cSJoe /* TODO generalize initial conditions and project into plane instead of assuming x-y */ 26028214e71cSJoe const PetscReal r0 = DMPlex_NormD_Internal(dim, &coords[p * dim]); 26038214e71cSJoe const PetscReal th0 = PetscAtan2Real(coords[p * dim + 1], coords[p * dim + 0]); 26048214e71cSJoe const PetscReal v0 = DMPlex_NormD_Internal(dim, &vel[p * dim]); 26058214e71cSJoe const PetscReal omega = v0 / r0; 26068214e71cSJoe const PetscReal ct = PetscCosReal(omega * t + th0); 26078214e71cSJoe const PetscReal st = PetscSinReal(omega * t + th0); 26088214e71cSJoe const PetscScalar *x = &u[(p * 2 + 0) * dim]; 26098214e71cSJoe const PetscScalar *v = &u[(p * 2 + 1) * dim]; 26108214e71cSJoe const PetscReal xe[3] = {r0 * ct, r0 * st, 0.0}; 26118214e71cSJoe const PetscReal ve[3] = {-v0 * st, v0 * ct, 0.0}; 26128214e71cSJoe PetscInt d; 26138214e71cSJoe 26148214e71cSJoe for (d = 0; d < dim; ++d) { 26158214e71cSJoe e[(p * 2 + 0) * dim + d] = x[d] - xe[d]; 26168214e71cSJoe e[(p * 2 + 1) * dim + d] = v[d] - ve[d]; 2617b80bf5b1SJoe Pusztay } 26188214e71cSJoe if (user->error) { 26198214e71cSJoe const PetscReal en = 0.5 * DMPlex_DotRealD_Internal(dim, v, v); 26208214e71cSJoe const PetscReal exen = 0.5 * PetscSqr(v0); 26218214e71cSJoe PetscCall(PetscPrintf(comm, "t %.4g: p%" PetscInt_FMT " error [%.2g %.2g] sol [(%.6lf %.6lf) (%.6lf %.6lf)] exact [(%.6lf %.6lf) (%.6lf %.6lf)] energy/exact energy %g / %g (%.10lf%%)\n", (double)t, p, (double)DMPlex_NormD_Internal(dim, &e[(p * 2 + 0) * dim]), (double)DMPlex_NormD_Internal(dim, &e[(p * 2 + 1) * dim]), (double)x[0], (double)x[1], (double)v[0], (double)v[1], (double)xe[0], (double)xe[1], (double)ve[0], (double)ve[1], (double)en, (double)exen, (double)(PetscAbsReal(exen - en) * 100. / exen))); 2622b80bf5b1SJoe Pusztay } 26238214e71cSJoe } 26248214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 26258214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 26268214e71cSJoe PetscCall(VecRestoreArrayRead(U, &u)); 26278214e71cSJoe PetscCall(VecRestoreArray(E, &e)); 26288214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 26298214e71cSJoe } 26308214e71cSJoe 26318214e71cSJoe static PetscErrorCode MigrateParticles(TS ts) 26328214e71cSJoe { 26338214e71cSJoe DM sw, cdm; 26348214e71cSJoe const PetscReal *L; 2635*9072cb8bSMatthew G. Knepley AppCtx *ctx; 26368214e71cSJoe 26378214e71cSJoe PetscFunctionBeginUser; 26388214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 2639*9072cb8bSMatthew G. Knepley PetscCall(DMGetApplicationContext(sw, &ctx)); 26408214e71cSJoe PetscCall(DMViewFromOptions(sw, NULL, "-migrate_view_pre")); 26418214e71cSJoe { 26428214e71cSJoe Vec u, gc, gv, position, momentum; 26438214e71cSJoe IS isx, isv; 26448214e71cSJoe PetscReal *pos, *mom; 26458214e71cSJoe 26468214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 26478214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "position", &isx)); 26488214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv)); 26498214e71cSJoe PetscCall(VecGetSubVector(u, isx, &position)); 26508214e71cSJoe PetscCall(VecGetSubVector(u, isv, &momentum)); 26518214e71cSJoe PetscCall(VecGetArray(position, &pos)); 26528214e71cSJoe PetscCall(VecGetArray(momentum, &mom)); 26538214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 26548214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv)); 26558214e71cSJoe PetscCall(VecISCopy(u, isx, SCATTER_REVERSE, gc)); 26568214e71cSJoe PetscCall(VecISCopy(u, isv, SCATTER_REVERSE, gv)); 26578214e71cSJoe 26588214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &cdm)); 26598214e71cSJoe PetscCall(DMGetPeriodicity(cdm, NULL, NULL, &L)); 26608214e71cSJoe if ((L[0] || L[1]) >= 0.) { 26618214e71cSJoe PetscReal *x, *v, upper[3], lower[3]; 26628214e71cSJoe PetscInt Np, dim; 26638214e71cSJoe 26648214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 26658214e71cSJoe PetscCall(DMGetDimension(cdm, &dim)); 26668214e71cSJoe PetscCall(DMGetBoundingBox(cdm, lower, upper)); 26678214e71cSJoe PetscCall(VecGetArray(gc, &x)); 26688214e71cSJoe PetscCall(VecGetArray(gv, &v)); 26698214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 26708214e71cSJoe for (PetscInt d = 0; d < dim; ++d) { 26718214e71cSJoe if (pos[p * dim + d] < lower[d]) { 26728214e71cSJoe x[p * dim + d] = pos[p * dim + d] + (upper[d] - lower[d]); 26738214e71cSJoe } else if (pos[p * dim + d] > upper[d]) { 26748214e71cSJoe x[p * dim + d] = pos[p * dim + d] - (upper[d] - lower[d]); 26758214e71cSJoe } else { 26768214e71cSJoe x[p * dim + d] = pos[p * dim + d]; 26778214e71cSJoe } 26788214e71cSJoe 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]); 26798214e71cSJoe v[p * dim + d] = mom[p * dim + d]; 26808214e71cSJoe } 26818214e71cSJoe } 26828214e71cSJoe PetscCall(VecRestoreArray(gc, &x)); 26838214e71cSJoe PetscCall(VecRestoreArray(gv, &v)); 26848214e71cSJoe } 26858214e71cSJoe PetscCall(VecRestoreArray(position, &pos)); 26868214e71cSJoe PetscCall(VecRestoreArray(momentum, &mom)); 26878214e71cSJoe PetscCall(VecRestoreSubVector(u, isx, &position)); 26888214e71cSJoe PetscCall(VecRestoreSubVector(u, isv, &momentum)); 26898214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv)); 26908214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 26918214e71cSJoe } 26928214e71cSJoe PetscCall(DMSwarmMigrate(sw, PETSC_TRUE)); 2693*9072cb8bSMatthew G. Knepley PetscInt step; 2694*9072cb8bSMatthew G. Knepley 2695*9072cb8bSMatthew G. Knepley PetscCall(TSGetStepNumber(ts, &step)); 2696*9072cb8bSMatthew G. Knepley if (ctx->remap && !(step % ctx->remapFreq)) { 2697*9072cb8bSMatthew G. Knepley // Monitor electric field before we destroy it 2698*9072cb8bSMatthew G. Knepley PetscReal ptime; 2699*9072cb8bSMatthew G. Knepley PetscInt step; 2700*9072cb8bSMatthew G. Knepley 2701*9072cb8bSMatthew G. Knepley PetscCall(TSGetStepNumber(ts, &step)); 2702*9072cb8bSMatthew G. Knepley PetscCall(TSGetTime(ts, &ptime)); 2703*9072cb8bSMatthew G. Knepley if (ctx->efield_monitor) PetscCall(MonitorEField(ts, step, ptime, NULL, ctx)); 2704*9072cb8bSMatthew G. Knepley if (ctx->poisson_monitor) PetscCall(MonitorPoisson(ts, step, ptime, NULL, ctx)); 2705*9072cb8bSMatthew G. Knepley PetscCall(DMSwarmRemap(sw)); 2706*9072cb8bSMatthew G. Knepley ctx->validE = PETSC_FALSE; 2707*9072cb8bSMatthew G. Knepley } 2708*9072cb8bSMatthew G. Knepley // This MUST come last, since it recreates the subswarms and they must DMClone() the new swarm 27098214e71cSJoe PetscCall(DMSwarmTSRedistribute(ts)); 27108214e71cSJoe PetscCall(InitializeSolveAndSwarm(ts, PETSC_FALSE)); 27113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2712b80bf5b1SJoe Pusztay } 2713b80bf5b1SJoe Pusztay 2714d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv) 2715d71ae5a4SJacob Faibussowitsch { 2716b80bf5b1SJoe Pusztay DM dm, sw; 27178214e71cSJoe TS ts; 27188214e71cSJoe Vec u; 27198214e71cSJoe PetscReal dt; 27208214e71cSJoe PetscInt maxn; 2721b80bf5b1SJoe Pusztay AppCtx user; 2722b80bf5b1SJoe Pusztay 27239566063dSJacob Faibussowitsch PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 27248214e71cSJoe PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user)); 27258214e71cSJoe PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &user.bag)); 27268214e71cSJoe PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm)); 27278214e71cSJoe PetscCall(CreatePoisson(dm, &user)); 27288214e71cSJoe PetscCall(CreateSwarm(dm, &user, &sw)); 27298214e71cSJoe PetscCall(SetupParameters(PETSC_COMM_WORLD, &user)); 27308214e71cSJoe PetscCall(InitializeConstants(sw, &user)); 27318214e71cSJoe PetscCall(DMSetApplicationContext(sw, &user)); 2732b80bf5b1SJoe Pusztay 27338214e71cSJoe PetscCall(TSCreate(PETSC_COMM_WORLD, &ts)); 27348214e71cSJoe PetscCall(TSSetProblemType(ts, TS_NONLINEAR)); 27359566063dSJacob Faibussowitsch PetscCall(TSSetDM(ts, sw)); 27368214e71cSJoe PetscCall(TSSetMaxTime(ts, 0.1)); 27378214e71cSJoe PetscCall(TSSetTimeStep(ts, 0.00001)); 27388214e71cSJoe PetscCall(TSSetMaxSteps(ts, 100)); 27398214e71cSJoe PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP)); 27408214e71cSJoe 27418214e71cSJoe if (user.efield_monitor) PetscCall(TSMonitorSet(ts, MonitorEField, &user, NULL)); 2742f1e6e573SMatthew G. Knepley if (user.moment_monitor) PetscCall(TSMonitorSet(ts, MonitorMoments, &user, NULL)); 27438214e71cSJoe if (user.initial_monitor) PetscCall(TSMonitorSet(ts, MonitorInitialConditions, &user, NULL)); 2744*9072cb8bSMatthew G. Knepley if (user.positions_monitor) PetscCall(TSMonitorSet(ts, MonitorPositions_2D, &user, NULL)); 27458214e71cSJoe if (user.poisson_monitor) PetscCall(TSMonitorSet(ts, MonitorPoisson, &user, NULL)); 27468214e71cSJoe 27478214e71cSJoe PetscCall(TSSetFromOptions(ts)); 27488214e71cSJoe PetscCall(TSGetTimeStep(ts, &dt)); 27498214e71cSJoe PetscCall(TSGetMaxSteps(ts, &maxn)); 27508214e71cSJoe user.steps = maxn; 27518214e71cSJoe user.stepSize = dt; 27528214e71cSJoe PetscCall(SetupContext(dm, sw, &user)); 27538214e71cSJoe PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve)); 27548214e71cSJoe PetscCall(TSSetComputeExactError(ts, ComputeError)); 27558214e71cSJoe PetscCall(TSSetPostStep(ts, MigrateParticles)); 27568214e71cSJoe PetscCall(CreateSolution(ts)); 27578214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 27588214e71cSJoe PetscCall(TSComputeInitialCondition(ts, u)); 27598214e71cSJoe PetscCall(CheckNonNegativeWeights(sw, &user)); 27608214e71cSJoe PetscCall(TSSolve(ts, NULL)); 27618214e71cSJoe 27629566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&user.snes)); 2763f1e6e573SMatthew G. Knepley PetscCall(MatDestroy(&user.M)); 2764f1e6e573SMatthew G. Knepley PetscCall(PetscFEGeomDestroy(&user.fegeom)); 27659566063dSJacob Faibussowitsch PetscCall(TSDestroy(&ts)); 27669566063dSJacob Faibussowitsch PetscCall(DMDestroy(&sw)); 27679566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dm)); 27688214e71cSJoe PetscCall(DestroyContext(&user)); 27699566063dSJacob Faibussowitsch PetscCall(PetscFinalize()); 2770b122ec5aSJacob Faibussowitsch return 0; 2771b80bf5b1SJoe Pusztay } 2772b80bf5b1SJoe Pusztay 2773b80bf5b1SJoe Pusztay /*TEST 2774b80bf5b1SJoe Pusztay 2775b80bf5b1SJoe Pusztay build: 27768214e71cSJoe requires: !complex double 27778214e71cSJoe 27788214e71cSJoe # This tests that we can put particles in a box and compute the Coulomb force 27798214e71cSJoe # Recommend -draw_size 500,500 27808214e71cSJoe testset: 27818214e71cSJoe requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT) 27828214e71cSJoe args: -dm_plex_dim 2 -fake_1D -dm_plex_simplex 0 -dm_plex_box_faces 20,1 \ 27838214e71cSJoe -dm_plex_box_lower 0,-1 -dm_plex_box_upper 12.5664,1 \ 2784b80bf5b1SJoe Pusztay -dm_plex_box_bd periodic,none \ 2785*9072cb8bSMatthew G. Knepley -vdm_plex_simplex 0 \ 27868214e71cSJoe -dm_swarm_coordinate_density constant -dm_swarm_num_particles 100 \ 27878214e71cSJoe -sigma 1.0e-8 -timeScale 2.0e-14 \ 27888214e71cSJoe -ts_type basicsymplectic -ts_basicsymplectic_type 1 \ 27898214e71cSJoe -ts_monitor_sp_swarm -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 0 \ 27908214e71cSJoe -output_step 50 -check_vel_res 27918214e71cSJoe test: 27928214e71cSJoe suffix: none_1d 2793*9072cb8bSMatthew G. Knepley requires: 27948214e71cSJoe args: -em_type none -error 27958214e71cSJoe test: 27968214e71cSJoe suffix: coulomb_1d 27978214e71cSJoe args: -em_type coulomb 27988214e71cSJoe 27998214e71cSJoe # for viewers 28008214e71cSJoe #-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 28018214e71cSJoe testset: 28028214e71cSJoe nsize: {{1 2}} 28038214e71cSJoe requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT) 28048214e71cSJoe args: -dm_plex_dim 2 -fake_1D -dm_plex_simplex 0 -dm_plex_box_faces 36,1 \ 28058214e71cSJoe -dm_plex_box_lower 0.,-0.5 -dm_plex_box_upper 12.5664,0.5 \ 28068214e71cSJoe -dm_plex_box_bd periodic,none \ 28078214e71cSJoe -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \ 28088214e71cSJoe -vdm_plex_box_lower -3 -vdm_plex_box_upper 3 \ 280984467f86SMatthew G. Knepley -dm_swarm_num_species 1 -twostream -charges -1.,1. -sigma 1.0e-8 \ 28108214e71cSJoe -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \ 28118214e71cSJoe -ts_type basicsymplectic -ts_basicsymplectic_type 2 \ 28128214e71cSJoe -ts_dt 0.01 -ts_max_time 5 -ts_max_steps 10 \ 28138214e71cSJoe -em_snes_atol 1.e-15 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \ 281484467f86SMatthew G. Knepley -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1 28158214e71cSJoe test: 28168214e71cSJoe suffix: two_stream_c0 28178214e71cSJoe args: -em_type primal -petscfe_default_quadrature_order 2 -petscspace_degree 2 -em_pc_type svd 28188214e71cSJoe test: 28198214e71cSJoe suffix: two_stream_rt 28208214e71cSJoe requires: superlu_dist 28218214e71cSJoe args: -em_type mixed \ 28228214e71cSJoe -potential_petscspace_degree 0 \ 28238214e71cSJoe -potential_petscdualspace_lagrange_use_moments \ 28248214e71cSJoe -potential_petscdualspace_lagrange_moment_order 2 \ 28258214e71cSJoe -field_petscspace_degree 2 -field_petscfe_default_quadrature_order 1 \ 28268214e71cSJoe -field_petscspace_type sum \ 28278214e71cSJoe -field_petscspace_variables 2 \ 28288214e71cSJoe -field_petscspace_components 2 \ 28298214e71cSJoe -field_petscspace_sum_spaces 2 \ 28308214e71cSJoe -field_petscspace_sum_concatenate true \ 28318214e71cSJoe -field_sumcomp_0_petscspace_variables 2 \ 28328214e71cSJoe -field_sumcomp_0_petscspace_type tensor \ 28338214e71cSJoe -field_sumcomp_0_petscspace_tensor_spaces 2 \ 28348214e71cSJoe -field_sumcomp_0_petscspace_tensor_uniform false \ 28358214e71cSJoe -field_sumcomp_0_tensorcomp_0_petscspace_degree 1 \ 28368214e71cSJoe -field_sumcomp_0_tensorcomp_1_petscspace_degree 0 \ 28378214e71cSJoe -field_sumcomp_1_petscspace_variables 2 \ 28388214e71cSJoe -field_sumcomp_1_petscspace_type tensor \ 28398214e71cSJoe -field_sumcomp_1_petscspace_tensor_spaces 2 \ 28408214e71cSJoe -field_sumcomp_1_petscspace_tensor_uniform false \ 28418214e71cSJoe -field_sumcomp_1_tensorcomp_0_petscspace_degree 0 \ 28428214e71cSJoe -field_sumcomp_1_tensorcomp_1_petscspace_degree 1 \ 28438214e71cSJoe -field_petscdualspace_form_degree -1 \ 28448214e71cSJoe -field_petscdualspace_order 1 \ 28458214e71cSJoe -field_petscdualspace_lagrange_trimmed true \ 28468214e71cSJoe -em_snes_error_if_not_converged \ 28478214e71cSJoe -em_ksp_type preonly -em_ksp_error_if_not_converged \ 28488214e71cSJoe -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \ 28498214e71cSJoe -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \ 28508214e71cSJoe -em_fieldsplit_field_pc_type lu \ 28518214e71cSJoe -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \ 28528214e71cSJoe -em_fieldsplit_potential_pc_type svd 28538214e71cSJoe 285484467f86SMatthew G. Knepley # For an eyeball check, we use 2855*9072cb8bSMatthew G. Knepley # -ts_max_steps 1000 -dm_plex_box_faces 10,1 -vdm_plex_box_faces 2000 -efield_monitor 28568214e71cSJoe # For verification, we use 285784467f86SMatthew G. Knepley # -ts_max_steps 1000 -dm_plex_box_faces 100,1 -vdm_plex_box_faces 8000 -dm_swarm_num_particles 800000 -monitor_efield 28588214e71cSJoe # -ts_monitor_sp_swarm_multi_species 0 -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500 28598214e71cSJoe testset: 28608214e71cSJoe nsize: {{1 2}} 28618214e71cSJoe requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT) 28628214e71cSJoe args: -dm_plex_dim 2 -fake_1D -dm_plex_simplex 0 -dm_plex_box_faces 10,1 \ 28638214e71cSJoe -dm_plex_box_lower 0.,-0.5 -dm_plex_box_upper 12.5664,0.5 \ 28648214e71cSJoe -dm_plex_box_bd periodic,none \ 28658214e71cSJoe -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \ 28668214e71cSJoe -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \ 2867f1e6e573SMatthew G. Knepley -vpetscspace_degree 2 -vdm_plex_hash_location \ 286884467f86SMatthew G. Knepley -dm_swarm_num_species 1 -charges -1.,1. \ 28698214e71cSJoe -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \ 28708214e71cSJoe -ts_type basicsymplectic -ts_basicsymplectic_type 1 \ 28718214e71cSJoe -ts_dt 0.03 -ts_max_time 500 -ts_max_steps 1 \ 28728214e71cSJoe -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \ 287384467f86SMatthew G. Knepley -output_step 1 -check_vel_res -dm_swarm_print_coords 1 -dm_swarm_print_weights 1 28748214e71cSJoe 28758214e71cSJoe test: 28768214e71cSJoe suffix: uniform_equilibrium_1d 28778214e71cSJoe args: -cosine_coefficients 0.0,0.5 -em_type primal -petscspace_degree 1 -em_pc_type svd 28788214e71cSJoe test: 287975155f48SMatthew G. Knepley suffix: uniform_equilibrium_1d_real 288075155f48SMatthew G. Knepley args: -dm_plex_dim 1 -dm_plex_simplex 1 -fake_1D 0 -dm_plex_box_faces 10 \ 288175155f48SMatthew G. Knepley -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \ 288275155f48SMatthew G. Knepley -cosine_coefficients 0.0 -em_type primal -petscspace_degree 1 -em_pc_type svd 288375155f48SMatthew G. Knepley test: 28848214e71cSJoe suffix: uniform_primal_1d 28858214e71cSJoe args: -em_type primal -petscspace_degree 1 -em_pc_type svd 28868214e71cSJoe test: 288775155f48SMatthew G. Knepley suffix: uniform_primal_1d_real 288875155f48SMatthew G. Knepley args: -dm_plex_dim 1 -dm_plex_simplex 1 -fake_1D 0 -dm_plex_box_faces 10 \ 288975155f48SMatthew G. Knepley -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \ 289075155f48SMatthew G. Knepley -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd 2891*9072cb8bSMatthew G. Knepley # NOT WORKING -ftop_pc_type bjacobi -ftop_sub_pc_type lu -ftop_sub_pc_factor_shift_type nonzero 2892*9072cb8bSMatthew G. Knepley test: 2893*9072cb8bSMatthew G. Knepley suffix: uniform_primal_1d_real_pfak 2894*9072cb8bSMatthew G. Knepley nsize: 1 2895*9072cb8bSMatthew G. Knepley args: -dm_plex_dim 1 -dm_plex_simplex 1 -fake_1D 0 -dm_plex_box_faces 10 \ 2896*9072cb8bSMatthew G. Knepley -dm_plex_box_lower 0. -dm_plex_box_upper 12.5664 -dm_plex_box_bd periodic \ 2897*9072cb8bSMatthew 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 \ 2898*9072cb8bSMatthew G. Knepley -remap_dm_plex_box_lower 0.,-10. -remap_dm_plex_box_upper 12.5664,10. \ 2899*9072cb8bSMatthew G. Knepley -remap_petscspace_degree 2 -remap_dm_plex_hash_location \ 2900*9072cb8bSMatthew G. Knepley -remap -remap_freq 1 -remap_type pfak \ 2901*9072cb8bSMatthew G. Knepley -ftop_ksp_type lsqr -ftop_pc_type none -ftop_ksp_rtol 1.e-14 \ 2902*9072cb8bSMatthew G. Knepley -ptof_pc_type lu \ 2903*9072cb8bSMatthew G. Knepley -cosine_coefficients 0.01 -em_type primal -petscspace_degree 1 -em_pc_type svd -em_proj_pc_type lu 290475155f48SMatthew G. Knepley test: 29058214e71cSJoe requires: superlu_dist 29068214e71cSJoe suffix: uniform_mixed_1d 29078214e71cSJoe args: -em_type mixed \ 29088214e71cSJoe -potential_petscspace_degree 0 \ 29098214e71cSJoe -potential_petscdualspace_lagrange_use_moments \ 29108214e71cSJoe -potential_petscdualspace_lagrange_moment_order 2 \ 29118214e71cSJoe -field_petscspace_degree 2 -field_petscfe_default_quadrature_order 1 \ 29128214e71cSJoe -field_petscspace_type sum \ 29138214e71cSJoe -field_petscspace_variables 2 \ 29148214e71cSJoe -field_petscspace_components 2 \ 29158214e71cSJoe -field_petscspace_sum_spaces 2 \ 29168214e71cSJoe -field_petscspace_sum_concatenate true \ 29178214e71cSJoe -field_sumcomp_0_petscspace_variables 2 \ 29188214e71cSJoe -field_sumcomp_0_petscspace_type tensor \ 29198214e71cSJoe -field_sumcomp_0_petscspace_tensor_spaces 2 \ 29208214e71cSJoe -field_sumcomp_0_petscspace_tensor_uniform false \ 29218214e71cSJoe -field_sumcomp_0_tensorcomp_0_petscspace_degree 1 \ 29228214e71cSJoe -field_sumcomp_0_tensorcomp_1_petscspace_degree 0 \ 29238214e71cSJoe -field_sumcomp_1_petscspace_variables 2 \ 29248214e71cSJoe -field_sumcomp_1_petscspace_type tensor \ 29258214e71cSJoe -field_sumcomp_1_petscspace_tensor_spaces 2 \ 29268214e71cSJoe -field_sumcomp_1_petscspace_tensor_uniform false \ 29278214e71cSJoe -field_sumcomp_1_tensorcomp_0_petscspace_degree 0 \ 29288214e71cSJoe -field_sumcomp_1_tensorcomp_1_petscspace_degree 1 \ 29298214e71cSJoe -field_petscdualspace_form_degree -1 \ 29308214e71cSJoe -field_petscdualspace_order 1 \ 29318214e71cSJoe -field_petscdualspace_lagrange_trimmed true \ 29328214e71cSJoe -em_snes_error_if_not_converged \ 29338214e71cSJoe -em_ksp_type preonly -em_ksp_error_if_not_converged \ 29348214e71cSJoe -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \ 29358214e71cSJoe -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \ 29368214e71cSJoe -em_fieldsplit_field_pc_type lu \ 29378214e71cSJoe -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \ 29388214e71cSJoe -em_fieldsplit_potential_pc_type svd 29398214e71cSJoe 2940b80bf5b1SJoe Pusztay TEST*/ 2941