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