1*8214e71cSJoe static char help[] = "Landau Damping/Two Stream instability test using Vlasov-Poisson equations\n"; 2b80bf5b1SJoe Pusztay 3*8214e71cSJoe /* 4*8214e71cSJoe 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" 5*8214e71cSJoe According to Lukas, good damping results come at ~16k particles per cell 6*8214e71cSJoe 7*8214e71cSJoe To visualize the efield use 8*8214e71cSJoe 9*8214e71cSJoe -monitor_efield 10*8214e71cSJoe 11*8214e71cSJoe To visualize the swarm distribution use 12*8214e71cSJoe 13*8214e71cSJoe -ts_monitor_hg_swarm 14*8214e71cSJoe 15*8214e71cSJoe To visualize the particles, we can use 16*8214e71cSJoe 17*8214e71cSJoe -ts_monitor_sp_swarm -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500 18*8214e71cSJoe 19*8214e71cSJoe */ 20b80bf5b1SJoe Pusztay #include <petscts.h> 21*8214e71cSJoe #include <petscdmplex.h> 22*8214e71cSJoe #include <petscdmswarm.h> 23*8214e71cSJoe #include <petscfe.h> 24*8214e71cSJoe #include <petscds.h> 25*8214e71cSJoe #include <petscbag.h> 26*8214e71cSJoe #include <petscdraw.h> 27*8214e71cSJoe #include <petsc/private/dmpleximpl.h> /* For norm and dot */ 28*8214e71cSJoe #include <petsc/private/petscfeimpl.h> /* For interpolation */ 29*8214e71cSJoe #include "petscdm.h" 30*8214e71cSJoe #include "petscdmlabel.h" 31*8214e71cSJoe 32*8214e71cSJoe PETSC_EXTERN PetscErrorCode stream(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 33*8214e71cSJoe PETSC_EXTERN PetscErrorCode line(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 34*8214e71cSJoe 35*8214e71cSJoe const char *EMTypes[] = {"primal", "mixed", "coulomb", "none", "EMType", "EM_", NULL}; 36*8214e71cSJoe typedef enum { 37*8214e71cSJoe EM_PRIMAL, 38*8214e71cSJoe EM_MIXED, 39*8214e71cSJoe EM_COULOMB, 40*8214e71cSJoe EM_NONE 41*8214e71cSJoe } EMType; 42*8214e71cSJoe 43*8214e71cSJoe typedef enum { 44*8214e71cSJoe V0, 45*8214e71cSJoe X0, 46*8214e71cSJoe T0, 47*8214e71cSJoe M0, 48*8214e71cSJoe Q0, 49*8214e71cSJoe PHI0, 50*8214e71cSJoe POISSON, 51*8214e71cSJoe VLASOV, 52*8214e71cSJoe SIGMA, 53*8214e71cSJoe NUM_CONSTANTS 54*8214e71cSJoe } ConstantType; 55*8214e71cSJoe typedef struct { 56*8214e71cSJoe PetscScalar v0; /* Velocity scale, often the thermal velocity */ 57*8214e71cSJoe PetscScalar t0; /* Time scale */ 58*8214e71cSJoe PetscScalar x0; /* Space scale */ 59*8214e71cSJoe PetscScalar m0; /* Mass scale */ 60*8214e71cSJoe PetscScalar q0; /* Charge scale */ 61*8214e71cSJoe PetscScalar kb; 62*8214e71cSJoe PetscScalar epsi0; 63*8214e71cSJoe PetscScalar phi0; /* Potential scale */ 64*8214e71cSJoe PetscScalar poissonNumber; /* Non-Dimensional Poisson Number */ 65*8214e71cSJoe PetscScalar vlasovNumber; /* Non-Dimensional Vlasov Number */ 66*8214e71cSJoe PetscReal sigma; /* Nondimensional charge per length in x */ 67*8214e71cSJoe } Parameter; 68b80bf5b1SJoe Pusztay 69b80bf5b1SJoe Pusztay typedef struct { 70*8214e71cSJoe PetscBag bag; /* Problem parameters */ 71*8214e71cSJoe PetscBool error; /* Flag for printing the error */ 72*8214e71cSJoe PetscBool efield_monitor; /* Flag to show electric field monitor */ 73*8214e71cSJoe PetscBool initial_monitor; 74*8214e71cSJoe PetscBool fake_1D; /* Run simulation in 2D but zeroing second dimension */ 75*8214e71cSJoe PetscBool perturbed_weights; /* Uniformly sample x,v space with gaussian weights */ 76*8214e71cSJoe PetscBool poisson_monitor; 77*8214e71cSJoe PetscInt ostep; /* print the energy at each ostep time steps */ 78*8214e71cSJoe PetscInt numParticles; 79*8214e71cSJoe PetscReal timeScale; /* Nondimensionalizing time scale */ 80*8214e71cSJoe PetscReal charges[2]; /* The charges of each species */ 81*8214e71cSJoe PetscReal masses[2]; /* The masses of each species */ 82*8214e71cSJoe PetscReal thermal_energy[2]; /* Thermal Energy (used to get other constants)*/ 83*8214e71cSJoe PetscReal cosine_coefficients[2]; /*(alpha, k)*/ 84*8214e71cSJoe PetscReal totalWeight; 85*8214e71cSJoe PetscReal stepSize; 86*8214e71cSJoe PetscInt steps; 87*8214e71cSJoe PetscReal initVel; 88*8214e71cSJoe EMType em; /* Type of electrostatic model */ 89*8214e71cSJoe SNES snes; 90*8214e71cSJoe PetscDraw drawef; 91*8214e71cSJoe PetscDrawLG drawlg_ef; 92*8214e71cSJoe PetscDraw drawic_x; 93*8214e71cSJoe PetscDraw drawic_v; 94*8214e71cSJoe PetscDraw drawic_w; 95*8214e71cSJoe PetscDrawHG drawhgic_x; 96*8214e71cSJoe PetscDrawHG drawhgic_v; 97*8214e71cSJoe PetscDrawHG drawhgic_w; 98*8214e71cSJoe PetscDraw EDraw; 99*8214e71cSJoe PetscDraw RhoDraw; 100*8214e71cSJoe PetscDraw PotDraw; 101*8214e71cSJoe PetscDrawSP EDrawSP; 102*8214e71cSJoe PetscDrawSP RhoDrawSP; 103*8214e71cSJoe PetscDrawSP PotDrawSP; 104*8214e71cSJoe PetscBool monitor_positions; /* Flag to show particle positins at each time step */ 105*8214e71cSJoe PetscDraw positionDraw; 106*8214e71cSJoe PetscDrawSP positionDrawSP; 107*8214e71cSJoe DM swarm; 108*8214e71cSJoe PetscRandom random; 109*8214e71cSJoe PetscBool twostream; 110*8214e71cSJoe PetscBool checkweights; 111*8214e71cSJoe PetscInt checkVRes; /* Flag to check/output velocity residuals for nightly tests */ 112b80bf5b1SJoe Pusztay } AppCtx; 113b80bf5b1SJoe Pusztay 114d71ae5a4SJacob Faibussowitsch static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) 115d71ae5a4SJacob Faibussowitsch { 116b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 117*8214e71cSJoe PetscInt d = 2; 118*8214e71cSJoe PetscInt maxSpecies = 2; 119*8214e71cSJoe options->error = PETSC_FALSE; 120*8214e71cSJoe options->efield_monitor = PETSC_FALSE; 121*8214e71cSJoe options->initial_monitor = PETSC_FALSE; 122*8214e71cSJoe options->fake_1D = PETSC_FALSE; 123*8214e71cSJoe options->perturbed_weights = PETSC_FALSE; 124*8214e71cSJoe options->poisson_monitor = PETSC_FALSE; 125*8214e71cSJoe options->ostep = 100; 126*8214e71cSJoe options->timeScale = 2.0e-14; 127*8214e71cSJoe options->charges[0] = -1.0; 128*8214e71cSJoe options->charges[1] = 1.0; 129*8214e71cSJoe options->masses[0] = 1.0; 130*8214e71cSJoe options->masses[1] = 1000.0; 131*8214e71cSJoe options->thermal_energy[0] = 1.0; 132*8214e71cSJoe options->thermal_energy[1] = 1.0; 133*8214e71cSJoe options->cosine_coefficients[0] = 0.01; 134*8214e71cSJoe options->cosine_coefficients[1] = 0.5; 135*8214e71cSJoe options->initVel = 1; 136*8214e71cSJoe options->totalWeight = 1.0; 137*8214e71cSJoe options->drawef = NULL; 138*8214e71cSJoe options->drawlg_ef = NULL; 139*8214e71cSJoe options->drawic_x = NULL; 140*8214e71cSJoe options->drawic_v = NULL; 141*8214e71cSJoe options->drawic_w = NULL; 142*8214e71cSJoe options->drawhgic_x = NULL; 143*8214e71cSJoe options->drawhgic_v = NULL; 144*8214e71cSJoe options->drawhgic_w = NULL; 145*8214e71cSJoe options->EDraw = NULL; 146*8214e71cSJoe options->RhoDraw = NULL; 147*8214e71cSJoe options->PotDraw = NULL; 148*8214e71cSJoe options->EDrawSP = NULL; 149*8214e71cSJoe options->RhoDrawSP = NULL; 150*8214e71cSJoe options->PotDrawSP = NULL; 151*8214e71cSJoe options->em = EM_COULOMB; 152*8214e71cSJoe options->numParticles = 32768; 153*8214e71cSJoe options->monitor_positions = PETSC_FALSE; 154*8214e71cSJoe options->positionDraw = NULL; 155*8214e71cSJoe options->positionDrawSP = NULL; 156*8214e71cSJoe options->twostream = PETSC_FALSE; 157*8214e71cSJoe options->checkweights = PETSC_FALSE; 158*8214e71cSJoe options->checkVRes = 0; 159b80bf5b1SJoe Pusztay 160*8214e71cSJoe PetscOptionsBegin(comm, "", "Landau Damping and Two Stream options", "DMSWARM"); 161*8214e71cSJoe PetscCall(PetscOptionsBool("-error", "Flag to print the error", "ex2.c", options->error, &options->error, NULL)); 162*8214e71cSJoe PetscCall(PetscOptionsBool("-monitor_efield", "Flag to show efield plot", "ex2.c", options->efield_monitor, &options->efield_monitor, NULL)); 163*8214e71cSJoe PetscCall(PetscOptionsBool("-monitor_ics", "Flag to show initial condition histograms", "ex2.c", options->initial_monitor, &options->initial_monitor, NULL)); 164*8214e71cSJoe PetscCall(PetscOptionsBool("-monitor_positions", "The flag to show particle positions", "ex2.c", options->monitor_positions, &options->monitor_positions, NULL)); 165*8214e71cSJoe PetscCall(PetscOptionsBool("-monitor_poisson", "The flag to show charges, Efield and potential solve", "ex2.c", options->poisson_monitor, &options->poisson_monitor, NULL)); 166*8214e71cSJoe PetscCall(PetscOptionsBool("-fake_1D", "Flag to run a 1D simulation (but really in 2D)", "ex2.c", options->fake_1D, &options->fake_1D, NULL)); 167*8214e71cSJoe PetscCall(PetscOptionsBool("-twostream", "Run two stream instability", "ex2.c", options->twostream, &options->twostream, NULL)); 168*8214e71cSJoe PetscCall(PetscOptionsBool("-perturbed_weights", "Flag to run uniform sampling with perturbed weights", "ex2.c", options->perturbed_weights, &options->perturbed_weights, NULL)); 169*8214e71cSJoe PetscCall(PetscOptionsBool("-check_weights", "Ensure all particle weights are positive", "ex2.c", options->checkweights, &options->checkweights, NULL)); 170*8214e71cSJoe PetscCall(PetscOptionsInt("-check_vel_res", "Check particle velocity residuals for nightly tests", "ex2.c", options->checkVRes, &options->checkVRes, NULL)); 171*8214e71cSJoe PetscCall(PetscOptionsInt("-output_step", "Number of time steps between output", "ex2.c", options->ostep, &options->ostep, NULL)); 172*8214e71cSJoe PetscCall(PetscOptionsReal("-timeScale", "Nondimensionalizing time scale", "ex2.c", options->timeScale, &options->timeScale, NULL)); 173*8214e71cSJoe PetscCall(PetscOptionsReal("-initial_velocity", "Initial velocity of perturbed particle", "ex2.c", options->initVel, &options->initVel, NULL)); 174*8214e71cSJoe PetscCall(PetscOptionsReal("-total_weight", "Total weight of all particles", "ex2.c", options->totalWeight, &options->totalWeight, NULL)); 175*8214e71cSJoe PetscCall(PetscOptionsRealArray("-cosine_coefficients", "Amplitude and frequency of cosine equation used in initialization", "ex2.c", options->cosine_coefficients, &d, NULL)); 176*8214e71cSJoe PetscCall(PetscOptionsRealArray("-charges", "Species charges", "ex2.c", options->charges, &maxSpecies, NULL)); 177*8214e71cSJoe PetscCall(PetscOptionsEnum("-em_type", "Type of electrostatic solver", "ex2.c", EMTypes, (PetscEnum)options->em, (PetscEnum *)&options->em, NULL)); 178d0609cedSBarry Smith PetscOptionsEnd(); 1793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 180b80bf5b1SJoe Pusztay } 181b80bf5b1SJoe Pusztay 182*8214e71cSJoe static PetscErrorCode SetupContext(DM dm, DM sw, AppCtx *user) 183*8214e71cSJoe { 184*8214e71cSJoe PetscFunctionBeginUser; 185*8214e71cSJoe if (user->efield_monitor) { 186*8214e71cSJoe PetscDrawAxis axis_ef; 187*8214e71cSJoe PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_efield", 0, 300, 400, 300, &user->drawef)); 188*8214e71cSJoe PetscCall(PetscDrawSetSave(user->drawef, "ex9_Efield.png")); 189*8214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->drawef)); 190*8214e71cSJoe PetscCall(PetscDrawLGCreate(user->drawef, 1, &user->drawlg_ef)); 191*8214e71cSJoe PetscCall(PetscDrawLGGetAxis(user->drawlg_ef, &axis_ef)); 192*8214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis_ef, "Electron Electric Field", "time", "E_max")); 193*8214e71cSJoe PetscCall(PetscDrawLGSetLimits(user->drawlg_ef, 0., user->steps * user->stepSize, -10., 0.)); 194*8214e71cSJoe PetscCall(PetscDrawAxisSetLimits(axis_ef, 0., user->steps * user->stepSize, -10., 0.)); 195*8214e71cSJoe } 196*8214e71cSJoe if (user->initial_monitor) { 197*8214e71cSJoe PetscDrawAxis axis1, axis2, axis3; 198*8214e71cSJoe PetscReal dmboxlower[2], dmboxupper[2]; 199*8214e71cSJoe PetscInt dim, cStart, cEnd; 200*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 201*8214e71cSJoe PetscCall(DMGetBoundingBox(dm, dmboxlower, dmboxupper)); 202*8214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 203*8214e71cSJoe 204*8214e71cSJoe PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_x", 0, 300, 400, 300, &user->drawic_x)); 205*8214e71cSJoe PetscCall(PetscDrawSetSave(user->drawic_x, "ex9_ic_x.png")); 206*8214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->drawic_x)); 207*8214e71cSJoe PetscCall(PetscDrawHGCreate(user->drawic_x, dim, &user->drawhgic_x)); 208*8214e71cSJoe PetscCall(PetscDrawHGGetAxis(user->drawhgic_x, &axis1)); 209*8214e71cSJoe PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_x, cEnd - cStart)); 210*8214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis1, "Initial X Distribution", "X", "counts")); 211*8214e71cSJoe PetscCall(PetscDrawAxisSetLimits(axis1, dmboxlower[0], dmboxupper[0], 0, 1500)); 212*8214e71cSJoe 213*8214e71cSJoe PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_v", 400, 300, 400, 300, &user->drawic_v)); 214*8214e71cSJoe PetscCall(PetscDrawSetSave(user->drawic_v, "ex9_ic_v.png")); 215*8214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->drawic_v)); 216*8214e71cSJoe PetscCall(PetscDrawHGCreate(user->drawic_v, dim, &user->drawhgic_v)); 217*8214e71cSJoe PetscCall(PetscDrawHGGetAxis(user->drawhgic_v, &axis2)); 218*8214e71cSJoe PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_v, 1000)); 219*8214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis2, "Initial V_x Distribution", "V", "counts")); 220*8214e71cSJoe PetscCall(PetscDrawAxisSetLimits(axis2, -1, 1, 0, 1500)); 221*8214e71cSJoe 222*8214e71cSJoe PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "monitor_initial_conditions_w", 800, 300, 400, 300, &user->drawic_w)); 223*8214e71cSJoe PetscCall(PetscDrawSetSave(user->drawic_w, "ex9_ic_w.png")); 224*8214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->drawic_w)); 225*8214e71cSJoe PetscCall(PetscDrawHGCreate(user->drawic_w, dim, &user->drawhgic_w)); 226*8214e71cSJoe PetscCall(PetscDrawHGGetAxis(user->drawhgic_w, &axis3)); 227*8214e71cSJoe PetscCall(PetscDrawHGSetNumberBins(user->drawhgic_w, 10)); 228*8214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis3, "Initial W Distribution", "weight", "counts")); 229*8214e71cSJoe PetscCall(PetscDrawAxisSetLimits(axis3, 0, 0.01, 0, 5000)); 230*8214e71cSJoe } 231*8214e71cSJoe if (user->monitor_positions) { 232*8214e71cSJoe PetscDrawAxis axis; 233*8214e71cSJoe 234*8214e71cSJoe PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "position_monitor_species1", 0, 0, 400, 300, &user->positionDraw)); 235*8214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->positionDraw)); 236*8214e71cSJoe PetscCall(PetscDrawSPCreate(user->positionDraw, 10, &user->positionDrawSP)); 237*8214e71cSJoe PetscCall(PetscDrawSPSetDimension(user->positionDrawSP, 1)); 238*8214e71cSJoe PetscCall(PetscDrawSPGetAxis(user->positionDrawSP, &axis)); 239*8214e71cSJoe PetscCall(PetscDrawSPReset(user->positionDrawSP)); 240*8214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "x", "v")); 241*8214e71cSJoe PetscCall(PetscDrawSetSave(user->positionDraw, "ex9_pos.png")); 242*8214e71cSJoe } 243*8214e71cSJoe if (user->poisson_monitor) { 244*8214e71cSJoe PetscDrawAxis axis_E, axis_Rho, axis_Pot; 245*8214e71cSJoe 246*8214e71cSJoe PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "Efield_monitor", 0, 0, 400, 300, &user->EDraw)); 247*8214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->EDraw)); 248*8214e71cSJoe PetscCall(PetscDrawSPCreate(user->EDraw, 10, &user->EDrawSP)); 249*8214e71cSJoe PetscCall(PetscDrawSPSetDimension(user->EDrawSP, 1)); 250*8214e71cSJoe PetscCall(PetscDrawSPGetAxis(user->EDrawSP, &axis_E)); 251*8214e71cSJoe PetscCall(PetscDrawSPReset(user->EDrawSP)); 252*8214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis_E, "Particles", "x", "E")); 253*8214e71cSJoe PetscCall(PetscDrawSetSave(user->EDraw, "ex9_E_spatial.png")); 254*8214e71cSJoe 255*8214e71cSJoe PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "rho_monitor", 0, 0, 400, 300, &user->RhoDraw)); 256*8214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->RhoDraw)); 257*8214e71cSJoe PetscCall(PetscDrawSPCreate(user->RhoDraw, 10, &user->RhoDrawSP)); 258*8214e71cSJoe PetscCall(PetscDrawSPSetDimension(user->RhoDrawSP, 1)); 259*8214e71cSJoe PetscCall(PetscDrawSPGetAxis(user->RhoDrawSP, &axis_Rho)); 260*8214e71cSJoe PetscCall(PetscDrawSPReset(user->RhoDrawSP)); 261*8214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis_Rho, "Particles", "x", "rho")); 262*8214e71cSJoe PetscCall(PetscDrawSetSave(user->RhoDraw, "ex9_rho_spatial.png")); 263*8214e71cSJoe 264*8214e71cSJoe PetscCall(PetscDrawCreate(PETSC_COMM_WORLD, NULL, "potential_monitor", 0, 0, 400, 300, &user->PotDraw)); 265*8214e71cSJoe PetscCall(PetscDrawSetFromOptions(user->PotDraw)); 266*8214e71cSJoe PetscCall(PetscDrawSPCreate(user->PotDraw, 10, &user->PotDrawSP)); 267*8214e71cSJoe PetscCall(PetscDrawSPSetDimension(user->PotDrawSP, 1)); 268*8214e71cSJoe PetscCall(PetscDrawSPGetAxis(user->PotDrawSP, &axis_Pot)); 269*8214e71cSJoe PetscCall(PetscDrawSPReset(user->PotDrawSP)); 270*8214e71cSJoe PetscCall(PetscDrawAxisSetLabels(axis_Pot, "Particles", "x", "potential")); 271*8214e71cSJoe PetscCall(PetscDrawSetSave(user->PotDraw, "ex9_phi_spatial.png")); 272*8214e71cSJoe } 273*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 274*8214e71cSJoe } 275*8214e71cSJoe 276*8214e71cSJoe static PetscErrorCode DestroyContext(AppCtx *user) 277*8214e71cSJoe { 278*8214e71cSJoe PetscFunctionBeginUser; 279*8214e71cSJoe PetscCall(PetscDrawLGDestroy(&user->drawlg_ef)); 280*8214e71cSJoe PetscCall(PetscDrawDestroy(&user->drawef)); 281*8214e71cSJoe PetscCall(PetscDrawHGDestroy(&user->drawhgic_x)); 282*8214e71cSJoe PetscCall(PetscDrawDestroy(&user->drawic_x)); 283*8214e71cSJoe PetscCall(PetscDrawHGDestroy(&user->drawhgic_v)); 284*8214e71cSJoe PetscCall(PetscDrawDestroy(&user->drawic_v)); 285*8214e71cSJoe PetscCall(PetscDrawHGDestroy(&user->drawhgic_w)); 286*8214e71cSJoe PetscCall(PetscDrawDestroy(&user->drawic_w)); 287*8214e71cSJoe PetscCall(PetscDrawSPDestroy(&user->positionDrawSP)); 288*8214e71cSJoe PetscCall(PetscDrawDestroy(&user->positionDraw)); 289*8214e71cSJoe 290*8214e71cSJoe PetscCall(PetscDrawSPDestroy(&user->EDrawSP)); 291*8214e71cSJoe PetscCall(PetscDrawDestroy(&user->EDraw)); 292*8214e71cSJoe PetscCall(PetscDrawSPDestroy(&user->RhoDrawSP)); 293*8214e71cSJoe PetscCall(PetscDrawDestroy(&user->RhoDraw)); 294*8214e71cSJoe PetscCall(PetscDrawSPDestroy(&user->PotDrawSP)); 295*8214e71cSJoe PetscCall(PetscDrawDestroy(&user->PotDraw)); 296*8214e71cSJoe 297*8214e71cSJoe PetscCall(PetscBagDestroy(&user->bag)); 298*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 299*8214e71cSJoe } 300*8214e71cSJoe 301*8214e71cSJoe static PetscErrorCode CheckNonNegativeWeights(DM sw, AppCtx *user) 302*8214e71cSJoe { 303*8214e71cSJoe const PetscScalar *w; 304*8214e71cSJoe PetscInt Np; 305*8214e71cSJoe 306*8214e71cSJoe PetscFunctionBeginUser; 307*8214e71cSJoe if (!user->checkweights) PetscFunctionReturn(PETSC_SUCCESS); 308*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w)); 309*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 310*8214e71cSJoe 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]); 311*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w)); 312*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 313*8214e71cSJoe } 314*8214e71cSJoe 315*8214e71cSJoe static PetscErrorCode computeParticleMoments(DM sw, PetscReal moments[3], AppCtx *user) 316*8214e71cSJoe { 317*8214e71cSJoe DM dm; 318*8214e71cSJoe const PetscReal *coords; 319*8214e71cSJoe const PetscScalar *w; 320*8214e71cSJoe PetscReal mom[3] = {0.0, 0.0, 0.0}; 321*8214e71cSJoe PetscInt cell, cStart, cEnd, dim; 322*8214e71cSJoe 323*8214e71cSJoe PetscFunctionBeginUser; 324*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 325*8214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 326*8214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 327*8214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 328*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&coords)); 329*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&w)); 330*8214e71cSJoe for (cell = cStart; cell < cEnd; ++cell) { 331*8214e71cSJoe PetscInt *pidx; 332*8214e71cSJoe PetscInt Np, p, d; 333*8214e71cSJoe 334*8214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, cell, &Np, &pidx)); 335*8214e71cSJoe for (p = 0; p < Np; ++p) { 336*8214e71cSJoe const PetscInt idx = pidx[p]; 337*8214e71cSJoe const PetscReal *c = &coords[idx * dim]; 338*8214e71cSJoe 339*8214e71cSJoe mom[0] += PetscRealPart(w[idx]); 340*8214e71cSJoe mom[1] += PetscRealPart(w[idx]) * c[0]; 341*8214e71cSJoe for (d = 0; d < dim; ++d) mom[2] += PetscRealPart(w[idx]) * c[d] * c[d]; 342*8214e71cSJoe //if (w[idx] < 0. ) PetscPrintf(PETSC_COMM_WORLD, "error, negative weight %" PetscInt_FMT " \n", idx); 343*8214e71cSJoe } 344*8214e71cSJoe PetscCall(PetscFree(pidx)); 345*8214e71cSJoe } 346*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&coords)); 347*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&w)); 348*8214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 349*8214e71cSJoe PetscCallMPI(MPI_Allreduce(mom, moments, 3, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)sw))); 350*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 351*8214e71cSJoe } 352*8214e71cSJoe 353*8214e71cSJoe static void f0_1(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[]) 354*8214e71cSJoe { 355*8214e71cSJoe f0[0] = u[0]; 356*8214e71cSJoe } 357*8214e71cSJoe 358*8214e71cSJoe static void f0_x(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[]) 359*8214e71cSJoe { 360*8214e71cSJoe f0[0] = x[0] * u[0]; 361*8214e71cSJoe } 362*8214e71cSJoe 363*8214e71cSJoe static void f0_r2(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[]) 364*8214e71cSJoe { 365*8214e71cSJoe PetscInt d; 366*8214e71cSJoe 367*8214e71cSJoe f0[0] = 0.0; 368*8214e71cSJoe for (d = 0; d < dim; ++d) f0[0] += PetscSqr(x[d]) * u[0]; 369*8214e71cSJoe } 370*8214e71cSJoe 371*8214e71cSJoe static PetscErrorCode computeFEMMoments(DM dm, Vec u, PetscReal moments[3], AppCtx *user) 372*8214e71cSJoe { 373*8214e71cSJoe PetscDS prob; 374*8214e71cSJoe PetscScalar mom; 375*8214e71cSJoe PetscInt field = 0; 376*8214e71cSJoe 377*8214e71cSJoe PetscFunctionBeginUser; 378*8214e71cSJoe PetscCall(DMGetDS(dm, &prob)); 379*8214e71cSJoe PetscCall(PetscDSSetObjective(prob, field, &f0_1)); 380*8214e71cSJoe PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 381*8214e71cSJoe moments[0] = PetscRealPart(mom); 382*8214e71cSJoe PetscCall(PetscDSSetObjective(prob, field, &f0_x)); 383*8214e71cSJoe PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 384*8214e71cSJoe moments[1] = PetscRealPart(mom); 385*8214e71cSJoe PetscCall(PetscDSSetObjective(prob, field, &f0_r2)); 386*8214e71cSJoe PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 387*8214e71cSJoe moments[2] = PetscRealPart(mom); 388*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 389*8214e71cSJoe } 390*8214e71cSJoe 391*8214e71cSJoe static PetscErrorCode MonitorEField(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 392*8214e71cSJoe { 393*8214e71cSJoe AppCtx *user = (AppCtx *)ctx; 394*8214e71cSJoe DM dm, sw; 395*8214e71cSJoe PetscReal *E; 396*8214e71cSJoe PetscReal Enorm = 0., lgEnorm, lgEmax, sum = 0., Emax = 0., temp = 0., *weight, chargesum = 0.; 397*8214e71cSJoe PetscReal *x, *v; 398*8214e71cSJoe PetscInt *species, dim, p, d, Np, cStart, cEnd; 399*8214e71cSJoe PetscReal pmoments[3]; /* \int f, \int x f, \int r^2 f */ 400*8214e71cSJoe PetscReal fmoments[3]; /* \int \hat f, \int x \hat f, \int r^2 \hat f */ 401*8214e71cSJoe Vec rho; 402*8214e71cSJoe 403*8214e71cSJoe PetscFunctionBeginUser; 404*8214e71cSJoe if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); 405*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 406*8214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 407*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 408*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 409*8214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 410*8214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 411*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v)); 412*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 413*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 414*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 415*8214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 416*8214e71cSJoe 417*8214e71cSJoe for (p = 0; p < Np; ++p) { 418*8214e71cSJoe for (d = 0; d < 1; ++d) { 419*8214e71cSJoe temp = PetscAbsReal(E[p * dim + d]); 420*8214e71cSJoe if (temp > Emax) Emax = temp; 421*8214e71cSJoe } 422*8214e71cSJoe Enorm += PetscSqrtReal(E[p * dim] * E[p * dim]); 423*8214e71cSJoe sum += E[p * dim]; 424*8214e71cSJoe chargesum += user->charges[0] * weight[p]; 425*8214e71cSJoe } 426*8214e71cSJoe lgEnorm = Enorm != 0 ? PetscLog10Real(Enorm) : -16.; 427*8214e71cSJoe lgEmax = Emax != 0 ? PetscLog10Real(Emax) : -16.; 428*8214e71cSJoe 429*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 430*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v)); 431*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 432*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 433*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 434*8214e71cSJoe 435*8214e71cSJoe Parameter *param; 436*8214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 437*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "charges", &rho)); 438*8214e71cSJoe if (user->em == EM_PRIMAL) { 439*8214e71cSJoe PetscCall(computeParticleMoments(sw, pmoments, user)); 440*8214e71cSJoe PetscCall(computeFEMMoments(dm, rho, fmoments, user)); 441*8214e71cSJoe } else if (user->em == EM_MIXED) { 442*8214e71cSJoe DM potential_dm; 443*8214e71cSJoe IS potential_IS; 444*8214e71cSJoe PetscInt fields = 1; 445*8214e71cSJoe PetscCall(DMCreateSubDM(dm, 1, &fields, &potential_IS, &potential_dm)); 446*8214e71cSJoe 447*8214e71cSJoe PetscCall(computeParticleMoments(sw, pmoments, user)); 448*8214e71cSJoe PetscCall(computeFEMMoments(potential_dm, rho, fmoments, user)); 449*8214e71cSJoe PetscCall(DMDestroy(&potential_dm)); 450*8214e71cSJoe PetscCall(ISDestroy(&potential_IS)); 451*8214e71cSJoe } 452*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "charges", &rho)); 453*8214e71cSJoe 454*8214e71cSJoe PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%f\t%+e\t%e\t%f\t%f\t%f\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[2], (double)fmoments[0], (double)fmoments[1], (double)fmoments[2])); 455*8214e71cSJoe PetscCall(PetscDrawLGAddPoint(user->drawlg_ef, &t, &lgEmax)); 456*8214e71cSJoe PetscCall(PetscDrawLGDraw(user->drawlg_ef)); 457*8214e71cSJoe PetscCall(PetscDrawSave(user->drawef)); 458*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 459*8214e71cSJoe } 460*8214e71cSJoe 461*8214e71cSJoe PetscErrorCode MonitorInitialConditions(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 462*8214e71cSJoe { 463*8214e71cSJoe AppCtx *user = (AppCtx *)ctx; 464*8214e71cSJoe DM dm, sw; 465*8214e71cSJoe const PetscScalar *u; 466*8214e71cSJoe PetscReal *weight, *pos, *vel; 467*8214e71cSJoe PetscInt dim, p, Np, cStart, cEnd; 468*8214e71cSJoe 469*8214e71cSJoe PetscFunctionBegin; 470*8214e71cSJoe if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */ 471*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 472*8214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 473*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 474*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 475*8214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 476*8214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 477*8214e71cSJoe 478*8214e71cSJoe if (step == 0) { 479*8214e71cSJoe PetscCall(PetscDrawHGReset(user->drawhgic_x)); 480*8214e71cSJoe PetscCall(PetscDrawHGGetDraw(user->drawhgic_x, &user->drawic_x)); 481*8214e71cSJoe PetscCall(PetscDrawClear(user->drawic_x)); 482*8214e71cSJoe PetscCall(PetscDrawFlush(user->drawic_x)); 483*8214e71cSJoe 484*8214e71cSJoe PetscCall(PetscDrawHGReset(user->drawhgic_v)); 485*8214e71cSJoe PetscCall(PetscDrawHGGetDraw(user->drawhgic_v, &user->drawic_v)); 486*8214e71cSJoe PetscCall(PetscDrawClear(user->drawic_v)); 487*8214e71cSJoe PetscCall(PetscDrawFlush(user->drawic_v)); 488*8214e71cSJoe 489*8214e71cSJoe PetscCall(PetscDrawHGReset(user->drawhgic_w)); 490*8214e71cSJoe PetscCall(PetscDrawHGGetDraw(user->drawhgic_w, &user->drawic_w)); 491*8214e71cSJoe PetscCall(PetscDrawClear(user->drawic_w)); 492*8214e71cSJoe PetscCall(PetscDrawFlush(user->drawic_w)); 493*8214e71cSJoe 494*8214e71cSJoe PetscCall(VecGetArrayRead(U, &u)); 495*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&vel)); 496*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 497*8214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos)); 498*8214e71cSJoe 499*8214e71cSJoe PetscCall(VecGetLocalSize(U, &Np)); 500*8214e71cSJoe Np /= dim * 2; 501*8214e71cSJoe for (p = 0; p < Np; ++p) { 502*8214e71cSJoe PetscCall(PetscDrawHGAddValue(user->drawhgic_x, pos[p * dim])); 503*8214e71cSJoe PetscCall(PetscDrawHGAddValue(user->drawhgic_v, vel[p * dim])); 504*8214e71cSJoe PetscCall(PetscDrawHGAddValue(user->drawhgic_w, weight[p])); 505*8214e71cSJoe } 506*8214e71cSJoe 507*8214e71cSJoe PetscCall(VecRestoreArrayRead(U, &u)); 508*8214e71cSJoe PetscCall(PetscDrawHGDraw(user->drawhgic_x)); 509*8214e71cSJoe PetscCall(PetscDrawHGSave(user->drawhgic_x)); 510*8214e71cSJoe 511*8214e71cSJoe PetscCall(PetscDrawHGDraw(user->drawhgic_v)); 512*8214e71cSJoe PetscCall(PetscDrawHGSave(user->drawhgic_v)); 513*8214e71cSJoe 514*8214e71cSJoe PetscCall(PetscDrawHGDraw(user->drawhgic_w)); 515*8214e71cSJoe PetscCall(PetscDrawHGSave(user->drawhgic_w)); 516*8214e71cSJoe 517*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&pos)); 518*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&vel)); 519*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 520*8214e71cSJoe } 521*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 522*8214e71cSJoe } 523*8214e71cSJoe 524*8214e71cSJoe static PetscErrorCode MonitorPositions_2D(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 525*8214e71cSJoe { 526*8214e71cSJoe AppCtx *user = (AppCtx *)ctx; 527*8214e71cSJoe DM dm, sw; 528*8214e71cSJoe PetscScalar *x, *v, *weight; 529*8214e71cSJoe PetscReal lower[3], upper[3], speed; 530*8214e71cSJoe const PetscInt *s; 531*8214e71cSJoe PetscInt dim, cStart, cEnd, c; 532*8214e71cSJoe 533*8214e71cSJoe PetscFunctionBeginUser; 534*8214e71cSJoe if (step > 0 && step % user->ostep == 0) { 535*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 536*8214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 537*8214e71cSJoe PetscCall(DMGetDimension(dm, &dim)); 538*8214e71cSJoe PetscCall(DMGetBoundingBox(dm, lower, upper)); 539*8214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 540*8214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 541*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v)); 542*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 543*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&s)); 544*8214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 545*8214e71cSJoe PetscCall(PetscDrawSPReset(user->positionDrawSP)); 546*8214e71cSJoe PetscCall(PetscDrawSPSetLimits(user->positionDrawSP, lower[0], upper[0], lower[1], upper[1])); 547*8214e71cSJoe PetscCall(PetscDrawSPSetLimits(user->positionDrawSP, lower[0], upper[0], -12, 12)); 548*8214e71cSJoe for (c = 0; c < cEnd - cStart; ++c) { 549*8214e71cSJoe PetscInt *pidx, Npc, q; 550*8214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 551*8214e71cSJoe for (q = 0; q < Npc; ++q) { 552*8214e71cSJoe const PetscInt p = pidx[q]; 553*8214e71cSJoe if (s[p] == 0) { 554*8214e71cSJoe speed = PetscSqrtReal(PetscSqr(v[p * dim]) + PetscSqr(v[p * dim + 1])); 555*8214e71cSJoe if (dim == 1 || user->fake_1D) { 556*8214e71cSJoe PetscCall(PetscDrawSPAddPointColorized(user->positionDrawSP, &x[p * dim], &v[p * dim], &speed)); 557*8214e71cSJoe } else { 558*8214e71cSJoe PetscCall(PetscDrawSPAddPointColorized(user->positionDrawSP, &x[p * dim], &x[p * dim + 1], &speed)); 559*8214e71cSJoe } 560*8214e71cSJoe } else if (s[p] == 1) { 561*8214e71cSJoe PetscCall(PetscDrawSPAddPoint(user->positionDrawSP, &x[p * dim], &v[p * dim])); 562*8214e71cSJoe } 563*8214e71cSJoe } 564*8214e71cSJoe PetscCall(PetscFree(pidx)); 565*8214e71cSJoe } 566*8214e71cSJoe PetscCall(PetscDrawSPDraw(user->positionDrawSP, PETSC_TRUE)); 567*8214e71cSJoe PetscCall(PetscDrawSave(user->positionDraw)); 568*8214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 569*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 570*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 571*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v)); 572*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&s)); 573*8214e71cSJoe } 574*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 575*8214e71cSJoe } 576*8214e71cSJoe 577*8214e71cSJoe static PetscErrorCode MonitorPoisson(TS ts, PetscInt step, PetscReal t, Vec U, void *ctx) 578*8214e71cSJoe { 579*8214e71cSJoe AppCtx *user = (AppCtx *)ctx; 580*8214e71cSJoe DM dm, sw; 581*8214e71cSJoe PetscScalar *x, *E, *weight, *pot, *charges; 582*8214e71cSJoe PetscReal lower[3], upper[3], xval; 583*8214e71cSJoe PetscInt dim, cStart, cEnd, c; 584*8214e71cSJoe 585*8214e71cSJoe PetscFunctionBeginUser; 586*8214e71cSJoe if (step > 0 && step % user->ostep == 0) { 587*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 588*8214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 589*8214e71cSJoe PetscCall(DMGetDimension(dm, &dim)); 590*8214e71cSJoe PetscCall(DMGetBoundingBox(dm, lower, upper)); 591*8214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 592*8214e71cSJoe 593*8214e71cSJoe PetscCall(PetscDrawSPReset(user->RhoDrawSP)); 594*8214e71cSJoe PetscCall(PetscDrawSPReset(user->EDrawSP)); 595*8214e71cSJoe PetscCall(PetscDrawSPReset(user->PotDrawSP)); 596*8214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 597*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 598*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "potential", NULL, NULL, (void **)&pot)); 599*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "charges", NULL, NULL, (void **)&charges)); 600*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 601*8214e71cSJoe 602*8214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 603*8214e71cSJoe for (c = 0; c < cEnd - cStart; ++c) { 604*8214e71cSJoe PetscReal Esum = 0.0; 605*8214e71cSJoe PetscInt *pidx, Npc, q; 606*8214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 607*8214e71cSJoe for (q = 0; q < Npc; ++q) { 608*8214e71cSJoe const PetscInt p = pidx[q]; 609*8214e71cSJoe Esum += E[p * dim]; 610*8214e71cSJoe } 611*8214e71cSJoe xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart)); 612*8214e71cSJoe PetscCall(PetscDrawSPAddPoint(user->EDrawSP, &xval, &Esum)); 613*8214e71cSJoe PetscCall(PetscFree(pidx)); 614*8214e71cSJoe } 615*8214e71cSJoe for (c = 0; c < (cEnd - cStart); ++c) { 616*8214e71cSJoe xval = (c + 0.5) * ((upper[0] - lower[0]) / (cEnd - cStart)); 617*8214e71cSJoe PetscCall(PetscDrawSPAddPoint(user->RhoDrawSP, &xval, &charges[c])); 618*8214e71cSJoe PetscCall(PetscDrawSPAddPoint(user->PotDrawSP, &xval, &pot[c])); 619*8214e71cSJoe } 620*8214e71cSJoe PetscCall(PetscDrawSPDraw(user->RhoDrawSP, PETSC_TRUE)); 621*8214e71cSJoe PetscCall(PetscDrawSave(user->RhoDraw)); 622*8214e71cSJoe PetscCall(PetscDrawSPDraw(user->EDrawSP, PETSC_TRUE)); 623*8214e71cSJoe PetscCall(PetscDrawSave(user->EDraw)); 624*8214e71cSJoe PetscCall(PetscDrawSPDraw(user->PotDrawSP, PETSC_TRUE)); 625*8214e71cSJoe PetscCall(PetscDrawSave(user->PotDraw)); 626*8214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 627*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 628*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "potential", NULL, NULL, (void **)&pot)); 629*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "charges", NULL, NULL, (void **)&charges)); 630*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 631*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 632*8214e71cSJoe } 633*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 634*8214e71cSJoe } 635*8214e71cSJoe 636*8214e71cSJoe static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx) 637*8214e71cSJoe { 638*8214e71cSJoe PetscBag bag; 639*8214e71cSJoe Parameter *p; 640*8214e71cSJoe 641*8214e71cSJoe PetscFunctionBeginUser; 642*8214e71cSJoe /* setup PETSc parameter bag */ 643*8214e71cSJoe PetscCall(PetscBagGetData(ctx->bag, (void **)&p)); 644*8214e71cSJoe PetscCall(PetscBagSetName(ctx->bag, "par", "Vlasov-Poisson Parameters")); 645*8214e71cSJoe bag = ctx->bag; 646*8214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "v0", "Velocity scale, m/s")); 647*8214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->t0, 1.0, "t0", "Time scale, s")); 648*8214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->x0, 1.0, "x0", "Space scale, m")); 649*8214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->v0, 1.0, "phi0", "Potential scale, kg*m^2/A*s^3")); 650*8214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->q0, 1.0, "q0", "Charge Scale, A*s")); 651*8214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->m0, 1.0, "m0", "Mass Scale, kg")); 652*8214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->epsi0, 1.0, "epsi0", "Permittivity of Free Space, kg")); 653*8214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->kb, 1.0, "kb", "Boltzmann Constant, m^2 kg/s^2 K^1")); 654*8214e71cSJoe 655*8214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->sigma, 1.0, "sigma", "Charge per unit area, C/m^3")); 656*8214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->poissonNumber, 1.0, "poissonNumber", "Non-Dimensional Poisson Number")); 657*8214e71cSJoe PetscCall(PetscBagRegisterScalar(bag, &p->vlasovNumber, 1.0, "vlasovNumber", "Non-Dimensional Vlasov Number")); 658*8214e71cSJoe PetscCall(PetscBagSetFromOptions(bag)); 659*8214e71cSJoe { 660*8214e71cSJoe PetscViewer viewer; 661*8214e71cSJoe PetscViewerFormat format; 662*8214e71cSJoe PetscBool flg; 663*8214e71cSJoe 664*8214e71cSJoe PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg)); 665*8214e71cSJoe if (flg) { 666*8214e71cSJoe PetscCall(PetscViewerPushFormat(viewer, format)); 667*8214e71cSJoe PetscCall(PetscBagView(bag, viewer)); 668*8214e71cSJoe PetscCall(PetscViewerFlush(viewer)); 669*8214e71cSJoe PetscCall(PetscViewerPopFormat(viewer)); 670*8214e71cSJoe PetscCall(PetscViewerDestroy(&viewer)); 671*8214e71cSJoe } 672*8214e71cSJoe } 673*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 674*8214e71cSJoe } 675*8214e71cSJoe 676*8214e71cSJoe static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm) 677d71ae5a4SJacob Faibussowitsch { 678b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 6799566063dSJacob Faibussowitsch PetscCall(DMCreate(comm, dm)); 6809566063dSJacob Faibussowitsch PetscCall(DMSetType(*dm, DMPLEX)); 6819566063dSJacob Faibussowitsch PetscCall(DMSetFromOptions(*dm)); 6829566063dSJacob Faibussowitsch PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view")); 6833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 684b80bf5b1SJoe Pusztay } 685b80bf5b1SJoe Pusztay 686*8214e71cSJoe 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[]) 687*8214e71cSJoe { 688*8214e71cSJoe f0[0] = -constants[SIGMA]; 689*8214e71cSJoe } 690*8214e71cSJoe 691d71ae5a4SJacob 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[]) 692d71ae5a4SJacob Faibussowitsch { 693b80bf5b1SJoe Pusztay PetscInt d; 694ad540459SPierre Jolivet for (d = 0; d < dim; ++d) f1[d] = u_x[d]; 695b80bf5b1SJoe Pusztay } 696b80bf5b1SJoe Pusztay 697*8214e71cSJoe 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[]) 698d71ae5a4SJacob Faibussowitsch { 699b80bf5b1SJoe Pusztay PetscInt d; 700ad540459SPierre Jolivet for (d = 0; d < dim; ++d) g3[d * dim + d] = 1.0; 701b80bf5b1SJoe Pusztay } 702b80bf5b1SJoe Pusztay 703*8214e71cSJoe static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 704d71ae5a4SJacob Faibussowitsch { 705*8214e71cSJoe *u = 0.0; 706*8214e71cSJoe return PETSC_SUCCESS; 707b80bf5b1SJoe Pusztay } 708b80bf5b1SJoe Pusztay 709b80bf5b1SJoe Pusztay /* 710*8214e71cSJoe / I -grad\ / q \ = /0\ 711*8214e71cSJoe \-div 0 / \phi/ \f/ 712b80bf5b1SJoe Pusztay */ 713*8214e71cSJoe 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[]) 714d71ae5a4SJacob Faibussowitsch { 715*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) f0[d] += u[uOff[0] + d]; 716*8214e71cSJoe } 717*8214e71cSJoe 718*8214e71cSJoe 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[]) 719*8214e71cSJoe { 720*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) f1[d * dim + d] = u[uOff[1]]; 721*8214e71cSJoe } 722*8214e71cSJoe 723*8214e71cSJoe 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[]) 724*8214e71cSJoe { 725*8214e71cSJoe f0[0] += constants[SIGMA]; 726*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) f0[0] += u_x[uOff_x[0] + d * dim + d]; 727*8214e71cSJoe } 728*8214e71cSJoe 729*8214e71cSJoe /* Boundary residual. Dirichlet boundary for u means u_bdy=p*n */ 730*8214e71cSJoe 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[]) 731*8214e71cSJoe { 732*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) g0[d * dim + d] = 1.0; 733*8214e71cSJoe } 734*8214e71cSJoe 735*8214e71cSJoe 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[]) 736*8214e71cSJoe { 737*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) g2[d * dim + d] = 1.0; 738*8214e71cSJoe } 739*8214e71cSJoe 740*8214e71cSJoe 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[]) 741*8214e71cSJoe { 742*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) g1[d * dim + d] = 1.0; 743*8214e71cSJoe } 744*8214e71cSJoe 745*8214e71cSJoe static PetscErrorCode CreateFEM(DM dm, AppCtx *user) 746*8214e71cSJoe { 747*8214e71cSJoe PetscFE fephi, feq; 748*8214e71cSJoe PetscDS ds; 749*8214e71cSJoe PetscBool simplex; 750*8214e71cSJoe PetscInt dim; 751*8214e71cSJoe 752*8214e71cSJoe PetscFunctionBeginUser; 753*8214e71cSJoe PetscCall(DMGetDimension(dm, &dim)); 754*8214e71cSJoe PetscCall(DMPlexIsSimplex(dm, &simplex)); 755*8214e71cSJoe if (user->em == EM_MIXED) { 756*8214e71cSJoe DMLabel label; 757*8214e71cSJoe const PetscInt id = 1; 758*8214e71cSJoe 759*8214e71cSJoe PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "field_", PETSC_DETERMINE, &feq)); 760*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)feq, "field")); 761*8214e71cSJoe PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "potential_", PETSC_DETERMINE, &fephi)); 762*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)fephi, "potential")); 763*8214e71cSJoe PetscCall(PetscFECopyQuadrature(feq, fephi)); 764*8214e71cSJoe PetscCall(DMSetField(dm, 0, NULL, (PetscObject)feq)); 765*8214e71cSJoe PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fephi)); 766*8214e71cSJoe PetscCall(DMCreateDS(dm)); 767*8214e71cSJoe PetscCall(PetscFEDestroy(&fephi)); 768*8214e71cSJoe PetscCall(PetscFEDestroy(&feq)); 769*8214e71cSJoe 770*8214e71cSJoe PetscCall(DMGetLabel(dm, "marker", &label)); 771*8214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 772*8214e71cSJoe 773*8214e71cSJoe PetscCall(PetscDSSetResidual(ds, 0, f0_q, f1_q)); 774*8214e71cSJoe PetscCall(PetscDSSetResidual(ds, 1, f0_phi_backgroundCharge, NULL)); 775*8214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_qq, NULL, NULL, NULL)); 776*8214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_qphi, NULL)); 777*8214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_phiq, NULL, NULL)); 778*8214e71cSJoe 779*8214e71cSJoe PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void))zero, NULL, NULL, NULL)); 780*8214e71cSJoe 781*8214e71cSJoe } else if (user->em == EM_PRIMAL) { 782*8214e71cSJoe MatNullSpace nullsp; 783*8214e71cSJoe PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, PETSC_DETERMINE, &fephi)); 784*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)fephi, "potential")); 785*8214e71cSJoe PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fephi)); 786*8214e71cSJoe PetscCall(DMCreateDS(dm)); 787*8214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 788*8214e71cSJoe PetscCall(PetscDSSetResidual(ds, 0, ion_f0, laplacian_f1)); 789*8214e71cSJoe PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, laplacian_g3)); 790*8214e71cSJoe PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullsp)); 791*8214e71cSJoe PetscCall(PetscObjectCompose((PetscObject)fephi, "nullspace", (PetscObject)nullsp)); 792*8214e71cSJoe PetscCall(MatNullSpaceDestroy(&nullsp)); 793*8214e71cSJoe PetscCall(PetscFEDestroy(&fephi)); 794*8214e71cSJoe } 795*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 796*8214e71cSJoe } 797*8214e71cSJoe 798*8214e71cSJoe static PetscErrorCode CreatePoisson(DM dm, AppCtx *user) 799*8214e71cSJoe { 800*8214e71cSJoe SNES snes; 801*8214e71cSJoe Mat J; 802*8214e71cSJoe MatNullSpace nullSpace; 803*8214e71cSJoe 804*8214e71cSJoe PetscFunctionBeginUser; 805*8214e71cSJoe PetscCall(CreateFEM(dm, user)); 806*8214e71cSJoe PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes)); 807*8214e71cSJoe PetscCall(SNESSetOptionsPrefix(snes, "em_")); 808*8214e71cSJoe PetscCall(SNESSetDM(snes, dm)); 809*8214e71cSJoe PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, user)); 810*8214e71cSJoe PetscCall(SNESSetFromOptions(snes)); 811*8214e71cSJoe 812*8214e71cSJoe PetscCall(DMCreateMatrix(dm, &J)); 813*8214e71cSJoe PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_TRUE, 0, NULL, &nullSpace)); 814*8214e71cSJoe PetscCall(MatSetNullSpace(J, nullSpace)); 815*8214e71cSJoe PetscCall(MatNullSpaceDestroy(&nullSpace)); 816*8214e71cSJoe PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL)); 817*8214e71cSJoe PetscCall(MatDestroy(&J)); 818*8214e71cSJoe user->snes = snes; 819*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 820*8214e71cSJoe } 821*8214e71cSJoe 822*8214e71cSJoe PetscErrorCode PetscPDFPertubedConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 823*8214e71cSJoe { 824*8214e71cSJoe p[0] = (1 + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI); 825*8214e71cSJoe p[1] = (1 + 0.01 * PetscCosReal(0.5 * x[1])) / (2 * PETSC_PI); 826*8214e71cSJoe return PETSC_SUCCESS; 827*8214e71cSJoe } 828*8214e71cSJoe PetscErrorCode PetscPDFPertubedConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 829*8214e71cSJoe { 830*8214e71cSJoe p[0] = (1. + 0.01 * PetscCosReal(0.5 * x[0])) / (2 * PETSC_PI); 831*8214e71cSJoe return PETSC_SUCCESS; 832*8214e71cSJoe } 833*8214e71cSJoe 834*8214e71cSJoe PetscErrorCode PetscPDFCosine1D(const PetscReal x[], const PetscReal scale[], PetscReal p[]) 835*8214e71cSJoe { 836*8214e71cSJoe const PetscReal alpha = scale ? scale[0] : 0.0; 837*8214e71cSJoe const PetscReal k = scale ? scale[1] : 1.; 838*8214e71cSJoe p[0] = (1 + alpha * PetscCosReal(k * x[0])); 839*8214e71cSJoe return PETSC_SUCCESS; 840*8214e71cSJoe } 841*8214e71cSJoe 842*8214e71cSJoe PetscErrorCode PetscPDFCosine2D(const PetscReal x[], const PetscReal scale[], PetscReal p[]) 843*8214e71cSJoe { 844*8214e71cSJoe const PetscReal alpha = scale ? scale[0] : 0.; 845*8214e71cSJoe const PetscReal k = scale ? scale[0] : 1.; 846*8214e71cSJoe p[0] = (1 + alpha * PetscCosReal(k * (x[0] + x[1]))); 847*8214e71cSJoe return PETSC_SUCCESS; 848*8214e71cSJoe } 849*8214e71cSJoe 850*8214e71cSJoe PetscErrorCode PetscPDFCosine1D_TwoStream(const PetscReal x[], const PetscReal scale[], PetscReal p[]) 851*8214e71cSJoe { 852*8214e71cSJoe const PetscReal alpha = scale ? scale[0] : 0.0; 853*8214e71cSJoe const PetscReal k = scale ? scale[1] : 1.; 854*8214e71cSJoe p[0] = (1. + alpha * PetscCosReal(k * x[0])); 855*8214e71cSJoe return PETSC_SUCCESS; 856*8214e71cSJoe } 857*8214e71cSJoe 858*8214e71cSJoe static PetscErrorCode InitializeParticles_PerturbedWeights(DM sw, AppCtx *user) 859*8214e71cSJoe { 860*8214e71cSJoe DM vdm, dm; 861*8214e71cSJoe PetscScalar *weight; 862*8214e71cSJoe PetscReal *x, *v, vmin[3], vmax[3], gmin[3], gmax[3], xi0[3]; 863*8214e71cSJoe PetscInt *N, Ns, dim, *cellid, *species, Np, cStart, cEnd, Npc, n; 864*8214e71cSJoe PetscInt Np_global, p, q, s, c, d, cv; 865*8214e71cSJoe PetscBool flg; 866*8214e71cSJoe PetscMPIInt size, rank; 867*8214e71cSJoe Parameter *param; 868*8214e71cSJoe 869*8214e71cSJoe PetscFunctionBegin; 870*8214e71cSJoe PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)sw), &size)); 871*8214e71cSJoe PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sw), &rank)); 872*8214e71cSJoe PetscOptionsBegin(PetscObjectComm((PetscObject)sw), "", "DMSwarm Options", "DMSWARM"); 873*8214e71cSJoe PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 874*8214e71cSJoe PetscCall(PetscOptionsInt("-dm_swarm_num_species", "The number of species", "DMSwarmSetNumSpecies", Ns, &Ns, &flg)); 875*8214e71cSJoe if (flg) PetscCall(DMSwarmSetNumSpecies(sw, Ns)); 876*8214e71cSJoe PetscCall(PetscCalloc1(Ns, &N)); 877*8214e71cSJoe n = Ns; 878*8214e71cSJoe PetscCall(PetscOptionsIntArray("-dm_swarm_num_particles", "The target number of particles", "", N, &n, NULL)); 879*8214e71cSJoe PetscOptionsEnd(); 880*8214e71cSJoe 881*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 882*8214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 883*8214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 884*8214e71cSJoe 885*8214e71cSJoe PetscCall(DMCreate(PETSC_COMM_SELF, &vdm)); 886*8214e71cSJoe PetscCall(DMSetType(vdm, DMPLEX)); 887*8214e71cSJoe PetscCall(DMPlexSetOptionsPrefix(vdm, "v")); 888*8214e71cSJoe PetscCall(DMSetFromOptions(vdm)); 889*8214e71cSJoe PetscCall(DMViewFromOptions(vdm, NULL, "-vdm_view")); 890*8214e71cSJoe 891*8214e71cSJoe PetscInt vStart, vEnd; 892*8214e71cSJoe PetscCall(DMPlexGetHeightStratum(vdm, 0, &vStart, &vEnd)); 893*8214e71cSJoe PetscCall(DMGetBoundingBox(vdm, vmin, vmax)); 894*8214e71cSJoe 895*8214e71cSJoe PetscCall(DMGetBoundingBox(dm, gmin, gmax)); 896*8214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 897*8214e71cSJoe Np = (cEnd - cStart) * (vEnd - vStart); 898*8214e71cSJoe PetscCall(MPIU_Allreduce(&Np, &Np_global, 1, MPIU_INT, MPIU_SUM, PETSC_COMM_WORLD)); 899*8214e71cSJoe PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Global Np = %" PetscInt_FMT "\n", Np_global)); 900*8214e71cSJoe PetscCall(DMSwarmSetLocalSizes(sw, Np, 0)); 901*8214e71cSJoe Npc = Np / (cEnd - cStart); 902*8214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_cellid, NULL, NULL, (void **)&cellid)); 903*8214e71cSJoe for (c = 0, p = 0; c < cEnd - cStart; ++c) { 904*8214e71cSJoe for (s = 0; s < Ns; ++s) { 905*8214e71cSJoe for (q = 0; q < Npc; ++q, ++p) cellid[p] = c; 906*8214e71cSJoe } 907*8214e71cSJoe } 908*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_cellid, NULL, NULL, (void **)&cellid)); 909*8214e71cSJoe PetscCall(PetscFree(N)); 910*8214e71cSJoe 911*8214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 912*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v)); 913*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 914*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 915*8214e71cSJoe 916*8214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 917*8214e71cSJoe for (c = 0; c < cEnd - cStart; ++c) { 918*8214e71cSJoe const PetscInt cell = c + cStart; 919*8214e71cSJoe PetscInt *pidx, Npc; 920*8214e71cSJoe PetscReal centroid[3], volume; 921*8214e71cSJoe 922*8214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 923*8214e71cSJoe PetscCall(DMPlexComputeCellGeometryFVM(dm, cell, &volume, centroid, NULL)); 924*8214e71cSJoe for (q = 0; q < Npc; ++q) { 925*8214e71cSJoe const PetscInt p = pidx[q]; 926*8214e71cSJoe 927*8214e71cSJoe for (d = 0; d < dim; ++d) { 928*8214e71cSJoe x[p * dim + d] = centroid[d]; 929*8214e71cSJoe v[p * dim + d] = vmin[0] + (q + 0.5) * (vmax[0] - vmin[0]) / Npc; 930*8214e71cSJoe if (user->fake_1D && d > 0) v[p * dim + d] = 0; 931*8214e71cSJoe } 932*8214e71cSJoe } 933*8214e71cSJoe PetscCall(PetscFree(pidx)); 934*8214e71cSJoe } 935*8214e71cSJoe PetscCall(DMGetCoordinatesLocalSetUp(vdm)); 936*8214e71cSJoe 937*8214e71cSJoe /* Setup Quadrature for spatial and velocity weight calculations*/ 938*8214e71cSJoe PetscQuadrature quad_x; 939*8214e71cSJoe PetscInt Nq_x; 940*8214e71cSJoe const PetscReal *wq_x, *xq_x; 941*8214e71cSJoe PetscReal *xq_x_extended; 942*8214e71cSJoe PetscReal weightsum = 0., totalcellweight = 0., *weight_x, *weight_v; 943*8214e71cSJoe PetscReal scale[2] = {user->cosine_coefficients[0], user->cosine_coefficients[1]}; 944*8214e71cSJoe 945*8214e71cSJoe PetscCall(PetscCalloc2(cEnd - cStart, &weight_x, Np, &weight_v)); 946*8214e71cSJoe if (user->fake_1D) PetscCall(PetscDTGaussTensorQuadrature(1, 1, 5, -1.0, 1.0, &quad_x)); 947*8214e71cSJoe else PetscCall(PetscDTGaussTensorQuadrature(dim, 1, 5, -1.0, 1.0, &quad_x)); 948*8214e71cSJoe PetscCall(PetscQuadratureGetData(quad_x, NULL, NULL, &Nq_x, &xq_x, &wq_x)); 949*8214e71cSJoe if (user->fake_1D) { 950*8214e71cSJoe PetscCall(PetscCalloc1(Nq_x * dim, &xq_x_extended)); 951*8214e71cSJoe for (PetscInt i = 0; i < Nq_x; ++i) xq_x_extended[i * dim] = xq_x[i]; 952*8214e71cSJoe } 953*8214e71cSJoe /* Integrate the density function to get the weights of particles in each cell */ 954*8214e71cSJoe for (d = 0; d < dim; ++d) xi0[d] = -1.0; 955*8214e71cSJoe for (c = cStart; c < cEnd; ++c) { 956*8214e71cSJoe PetscReal v0_x[3], J_x[9], invJ_x[9], detJ_x, xr_x[3], den_x; 957*8214e71cSJoe PetscInt *pidx, Npc, q; 958*8214e71cSJoe PetscInt Ncx; 959*8214e71cSJoe const PetscScalar *array_x; 960*8214e71cSJoe PetscScalar *coords_x = NULL; 961*8214e71cSJoe PetscBool isDGx; 962*8214e71cSJoe weight_x[c] = 0.; 963*8214e71cSJoe 964*8214e71cSJoe PetscCall(DMPlexGetCellCoordinates(dm, c, &isDGx, &Ncx, &array_x, &coords_x)); 965*8214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Npc, &pidx)); 966*8214e71cSJoe PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0_x, J_x, invJ_x, &detJ_x)); 967*8214e71cSJoe for (q = 0; q < Nq_x; ++q) { 968*8214e71cSJoe /*Transform quadrature points from ref space to real space (0,12.5664)*/ 969*8214e71cSJoe if (user->fake_1D) CoordinatesRefToReal(dim, dim, xi0, v0_x, J_x, &xq_x_extended[q * dim], xr_x); 970*8214e71cSJoe else CoordinatesRefToReal(dim, dim, xi0, v0_x, J_x, &xq_x[q * dim], xr_x); 971*8214e71cSJoe 972*8214e71cSJoe /*Transform quadrature points from real space to ideal real space (0, 2PI/k)*/ 973*8214e71cSJoe if (user->fake_1D) { 974*8214e71cSJoe if (user->twostream) PetscCall(PetscPDFCosine1D_TwoStream(xr_x, scale, &den_x)); 975*8214e71cSJoe else PetscCall(PetscPDFCosine1D(xr_x, scale, &den_x)); 976*8214e71cSJoe detJ_x = J_x[0]; 977*8214e71cSJoe } else PetscCall(PetscPDFCosine2D(xr_x, scale, &den_x)); 978*8214e71cSJoe /*We have to transform the quadrature weights as well*/ 979*8214e71cSJoe weight_x[c] += den_x * (wq_x[q] * detJ_x); 980*8214e71cSJoe } 981*8214e71cSJoe // Get the cell numbering for consistent output between sequential and distributed tests 982*8214e71cSJoe IS globalOrdering; 983*8214e71cSJoe const PetscInt *ordering; 984*8214e71cSJoe PetscCall(DMPlexGetCellNumbering(dm, &globalOrdering)); 985*8214e71cSJoe PetscCall(ISGetIndices(globalOrdering, &ordering)); 986*8214e71cSJoe PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "c:%" PetscInt_FMT " [x_a,x_b] = %1.15f,%1.15f -> cell weight = %1.15f\n", ordering[c], (double)PetscRealPart(coords_x[0]), (double)PetscRealPart(coords_x[2]), (double)weight_x[c])); 987*8214e71cSJoe PetscCall(ISRestoreIndices(globalOrdering, &ordering)); 988*8214e71cSJoe totalcellweight += weight_x[c]; 989*8214e71cSJoe // Confirm the number of particles per spatial cell conforms to the size of the velocity grid 990*8214e71cSJoe PetscCheck(Npc == vEnd - vStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of particles %" PetscInt_FMT " in cell (rank %d/%d) != %" PetscInt_FMT " number of velocity vertices", Npc, rank, size, vEnd - vStart); 991*8214e71cSJoe 992*8214e71cSJoe /* Set weights to be gaussian in velocity cells (using exact solution) */ 993*8214e71cSJoe for (cv = 0; cv < vEnd - vStart; ++cv) { 994*8214e71cSJoe PetscInt Nc; 995*8214e71cSJoe const PetscScalar *array_v; 996*8214e71cSJoe PetscScalar *coords_v = NULL; 997*8214e71cSJoe PetscBool isDG; 998*8214e71cSJoe PetscCall(DMPlexGetCellCoordinates(vdm, cv, &isDG, &Nc, &array_v, &coords_v)); 999*8214e71cSJoe 1000*8214e71cSJoe const PetscInt p = pidx[cv]; 1001*8214e71cSJoe // Two stream function from 1/2pi v^2 e^(-v^2/2) 1002*8214e71cSJoe if (user->twostream) 1003*8214e71cSJoe weight_v[p] = 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.))); 1004*8214e71cSJoe else weight_v[p] = 0.5 * (PetscErfReal(coords_v[1] / PetscSqrtReal(2.)) - PetscErfReal(coords_v[0] / PetscSqrtReal(2.))); 1005*8214e71cSJoe 1006*8214e71cSJoe weight[p] = user->totalWeight * weight_v[p] * weight_x[c]; 1007*8214e71cSJoe if (weight[p] > 1.) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "weights: %g, %g, %g\n", user->totalWeight, weight_v[p], weight_x[c])); 1008*8214e71cSJoe //PetscPrintf(PETSC_COMM_WORLD, "particle %"PetscInt_FMT": %g, weight_v: %g weight_x: %g\n", p, weight[p], weight_v[p], weight_x[p]); 1009*8214e71cSJoe weightsum += weight[p]; 1010*8214e71cSJoe 1011*8214e71cSJoe PetscCall(DMPlexRestoreCellCoordinates(vdm, cv, &isDG, &Nc, &array_v, &coords_v)); 1012*8214e71cSJoe } 1013*8214e71cSJoe PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDGx, &Ncx, &array_x, &coords_x)); 1014*8214e71cSJoe PetscCall(PetscFree(pidx)); 1015*8214e71cSJoe } 1016*8214e71cSJoe PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT)); 1017*8214e71cSJoe PetscReal global_cellweight, global_weightsum; 1018*8214e71cSJoe PetscCall(MPIU_Allreduce(&totalcellweight, &global_cellweight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD)); 1019*8214e71cSJoe PetscCall(MPIU_Allreduce(&weightsum, &global_weightsum, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD)); 1020*8214e71cSJoe PetscCall(PetscPrintf(PETSC_COMM_WORLD, "particle weight sum = %1.10f cell weight sum = %1.10f\n", (double)global_cellweight, (double)global_weightsum)); 1021*8214e71cSJoe if (user->fake_1D) PetscCall(PetscFree(xq_x_extended)); 1022*8214e71cSJoe PetscCall(PetscFree2(weight_x, weight_v)); 1023*8214e71cSJoe PetscCall(PetscQuadratureDestroy(&quad_x)); 1024*8214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 1025*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&x)); 1026*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 1027*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 1028*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v)); 1029*8214e71cSJoe PetscCall(DMDestroy(&vdm)); 1030*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1031*8214e71cSJoe } 1032*8214e71cSJoe 1033*8214e71cSJoe static PetscErrorCode InitializeConstants(DM sw, AppCtx *user) 1034*8214e71cSJoe { 1035*8214e71cSJoe DM dm; 1036*8214e71cSJoe PetscInt *species; 1037*8214e71cSJoe PetscReal *weight, totalCharge = 0., totalWeight = 0., gmin[3], gmax[3], global_charge, global_weight; 1038*8214e71cSJoe PetscInt Np, dim; 1039*8214e71cSJoe 1040*8214e71cSJoe PetscFunctionBegin; 1041*8214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 1042*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1043*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1044*8214e71cSJoe PetscCall(DMGetBoundingBox(dm, gmin, gmax)); 1045*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **)&weight)); 1046*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 1047*8214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 1048*8214e71cSJoe totalWeight += weight[p]; 1049*8214e71cSJoe totalCharge += user->charges[species[p]] * weight[p]; 1050*8214e71cSJoe } 1051*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **)&weight)); 1052*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 1053*8214e71cSJoe { 1054*8214e71cSJoe Parameter *param; 1055*8214e71cSJoe PetscReal Area; 1056*8214e71cSJoe 1057*8214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 1058*8214e71cSJoe switch (dim) { 1059*8214e71cSJoe case 1: 1060*8214e71cSJoe Area = (gmax[0] - gmin[0]); 1061*8214e71cSJoe break; 1062*8214e71cSJoe case 2: 1063*8214e71cSJoe if (user->fake_1D) { 1064*8214e71cSJoe Area = (gmax[0] - gmin[0]); 1065*8214e71cSJoe } else { 1066*8214e71cSJoe Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]); 1067*8214e71cSJoe } 1068*8214e71cSJoe break; 1069*8214e71cSJoe case 3: 1070*8214e71cSJoe Area = (gmax[0] - gmin[0]) * (gmax[1] - gmin[1]) * (gmax[2] - gmin[2]); 1071*8214e71cSJoe break; 1072*8214e71cSJoe default: 1073*8214e71cSJoe SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", dim); 1074*8214e71cSJoe } 1075*8214e71cSJoe PetscCall(MPIU_Allreduce(&totalWeight, &global_weight, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD)); 1076*8214e71cSJoe PetscCall(MPIU_Allreduce(&totalCharge, &global_charge, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD)); 1077*8214e71cSJoe 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)); 1078*8214e71cSJoe param->sigma = PetscAbsReal(global_charge / (Area)); 1079*8214e71cSJoe 1080*8214e71cSJoe PetscCall(PetscPrintf(PETSC_COMM_WORLD, "sigma: %g\n", (double)param->sigma)); 1081*8214e71cSJoe 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, 1082*8214e71cSJoe (double)param->vlasovNumber)); 1083*8214e71cSJoe } 1084*8214e71cSJoe /* Setup Constants */ 1085*8214e71cSJoe { 1086*8214e71cSJoe PetscDS ds; 1087*8214e71cSJoe Parameter *param; 1088*8214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 1089*8214e71cSJoe PetscScalar constants[NUM_CONSTANTS]; 1090*8214e71cSJoe constants[SIGMA] = param->sigma; 1091*8214e71cSJoe constants[V0] = param->v0; 1092*8214e71cSJoe constants[T0] = param->t0; 1093*8214e71cSJoe constants[X0] = param->x0; 1094*8214e71cSJoe constants[M0] = param->m0; 1095*8214e71cSJoe constants[Q0] = param->q0; 1096*8214e71cSJoe constants[PHI0] = param->phi0; 1097*8214e71cSJoe constants[POISSON] = param->poissonNumber; 1098*8214e71cSJoe constants[VLASOV] = param->vlasovNumber; 1099*8214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 1100*8214e71cSJoe PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants)); 1101*8214e71cSJoe } 1102*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1103*8214e71cSJoe } 1104*8214e71cSJoe 1105*8214e71cSJoe static PetscErrorCode InitializeVelocities_Fake1D(DM sw, AppCtx *user) 1106*8214e71cSJoe { 1107*8214e71cSJoe DM dm; 1108*8214e71cSJoe PetscReal *v; 1109*8214e71cSJoe PetscInt *species, cStart, cEnd; 1110*8214e71cSJoe PetscInt dim, Np; 1111*8214e71cSJoe 1112*8214e71cSJoe PetscFunctionBegin; 1113*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1114*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1115*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **)&v)); 1116*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 1117*8214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &dm)); 1118*8214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1119*8214e71cSJoe PetscRandom rnd; 1120*8214e71cSJoe PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)sw), &rnd)); 1121*8214e71cSJoe PetscCall(PetscRandomSetInterval(rnd, 0, 1.)); 1122*8214e71cSJoe PetscCall(PetscRandomSetFromOptions(rnd)); 1123*8214e71cSJoe 1124*8214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 1125*8214e71cSJoe PetscReal a[3] = {0., 0., 0.}, vel[3] = {0., 0., 0.}; 1126*8214e71cSJoe 1127*8214e71cSJoe PetscCall(PetscRandomGetValueReal(rnd, &a[0])); 1128*8214e71cSJoe if (user->perturbed_weights) { 1129*8214e71cSJoe PetscCall(PetscPDFSampleConstant1D(a, NULL, vel)); 1130*8214e71cSJoe } else { 1131*8214e71cSJoe PetscCall(PetscPDFSampleGaussian1D(a, NULL, vel)); 1132*8214e71cSJoe } 1133*8214e71cSJoe v[p * dim] = vel[0]; 1134*8214e71cSJoe } 1135*8214e71cSJoe PetscCall(PetscRandomDestroy(&rnd)); 1136*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **)&v)); 1137*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 1138*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1139*8214e71cSJoe } 1140*8214e71cSJoe 1141*8214e71cSJoe static PetscErrorCode CreateSwarm(DM dm, AppCtx *user, DM *sw) 1142*8214e71cSJoe { 1143*8214e71cSJoe PetscReal v0[2] = {1., 0.}; 1144*8214e71cSJoe PetscInt dim; 1145b80bf5b1SJoe Pusztay 1146b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 11479566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 11489566063dSJacob Faibussowitsch PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw)); 11499566063dSJacob Faibussowitsch PetscCall(DMSetType(*sw, DMSWARM)); 11509566063dSJacob Faibussowitsch PetscCall(DMSetDimension(*sw, dim)); 11519566063dSJacob Faibussowitsch PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC)); 11529566063dSJacob Faibussowitsch PetscCall(DMSwarmSetCellDM(*sw, dm)); 11539566063dSJacob Faibussowitsch PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR)); 1154*8214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL)); 1155*8214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "species", 1, PETSC_INT)); 1156*8214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "initCoordinates", dim, PETSC_REAL)); 1157*8214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "initVelocity", dim, PETSC_REAL)); 1158*8214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "E_field", dim, PETSC_REAL)); 1159*8214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "potential", dim, PETSC_REAL)); 1160*8214e71cSJoe PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "charges", dim, PETSC_REAL)); 11619566063dSJacob Faibussowitsch PetscCall(DMSwarmFinalizeFieldRegister(*sw)); 1162*8214e71cSJoe PetscCall(DMSetApplicationContext(*sw, user)); 11639566063dSJacob Faibussowitsch PetscCall(DMSetFromOptions(*sw)); 1164*8214e71cSJoe user->swarm = *sw; 1165*8214e71cSJoe if (user->perturbed_weights) { 1166*8214e71cSJoe PetscCall(InitializeParticles_PerturbedWeights(*sw, user)); 1167b80bf5b1SJoe Pusztay } else { 1168*8214e71cSJoe PetscCall(DMSwarmComputeLocalSizeFromOptions(*sw)); 1169*8214e71cSJoe PetscCall(DMSwarmInitializeCoordinates(*sw)); 1170*8214e71cSJoe if (user->fake_1D) { 1171*8214e71cSJoe PetscCall(InitializeVelocities_Fake1D(*sw, user)); 11729371c9d4SSatish Balay } else { 1173*8214e71cSJoe PetscCall(DMSwarmInitializeVelocitiesFromOptions(*sw, v0)); 1174b80bf5b1SJoe Pusztay } 1175b80bf5b1SJoe Pusztay } 11769566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles")); 11779566063dSJacob Faibussowitsch PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view")); 1178*8214e71cSJoe { 1179*8214e71cSJoe Vec gc, gc0, gv, gv0; 1180*8214e71cSJoe 1181*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, DMSwarmPICField_coor, &gc)); 1182*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, "initCoordinates", &gc0)); 1183*8214e71cSJoe PetscCall(VecCopy(gc, gc0)); 1184*8214e71cSJoe PetscCall(VecViewFromOptions(gc, NULL, "-ic_x_view")); 1185*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, DMSwarmPICField_coor, &gc)); 1186*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, "initCoordinates", &gc0)); 1187*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, "velocity", &gv)); 1188*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(*sw, "initVelocity", &gv0)); 1189*8214e71cSJoe PetscCall(VecCopy(gv, gv0)); 1190*8214e71cSJoe PetscCall(VecViewFromOptions(gv, NULL, "-ic_v_view")); 1191*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, "velocity", &gv)); 1192*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(*sw, "initVelocity", &gv0)); 1193*8214e71cSJoe } 11943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1195b80bf5b1SJoe Pusztay } 1196b80bf5b1SJoe Pusztay 1197*8214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Coulomb(SNES snes, DM sw, PetscReal E[]) 1198d71ae5a4SJacob Faibussowitsch { 1199*8214e71cSJoe AppCtx *user; 1200*8214e71cSJoe PetscReal *coords; 1201*8214e71cSJoe PetscInt *species, dim, Np, Ns; 1202*8214e71cSJoe PetscMPIInt size; 1203*8214e71cSJoe 1204*8214e71cSJoe PetscFunctionBegin; 1205*8214e71cSJoe PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)snes), &size)); 1206*8214e71cSJoe PetscCheck(size == 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Coulomb code only works in serial"); 1207*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1208*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1209*8214e71cSJoe PetscCall(DMSwarmGetNumSpecies(sw, &Ns)); 1210*8214e71cSJoe PetscCall(DMGetApplicationContext(sw, (void *)&user)); 1211*8214e71cSJoe 1212*8214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 1213*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species)); 1214*8214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 1215*8214e71cSJoe PetscReal *pcoord = &coords[p * dim]; 1216*8214e71cSJoe PetscReal pE[3] = {0., 0., 0.}; 1217*8214e71cSJoe 1218*8214e71cSJoe /* Calculate field at particle p due to particle q */ 1219*8214e71cSJoe for (PetscInt q = 0; q < Np; ++q) { 1220*8214e71cSJoe PetscReal *qcoord = &coords[q * dim]; 1221*8214e71cSJoe PetscReal rpq[3], r, r3, q_q; 1222*8214e71cSJoe 1223*8214e71cSJoe if (p == q) continue; 1224*8214e71cSJoe q_q = user->charges[species[q]] * 1.; 1225*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) rpq[d] = pcoord[d] - qcoord[d]; 1226*8214e71cSJoe r = DMPlex_NormD_Internal(dim, rpq); 1227*8214e71cSJoe if (r < PETSC_SQRT_MACHINE_EPSILON) continue; 1228*8214e71cSJoe r3 = PetscPowRealInt(r, 3); 1229*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) pE[d] += q_q * rpq[d] / r3; 1230*8214e71cSJoe } 1231*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = pE[d]; 1232*8214e71cSJoe } 1233*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species)); 1234*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 1235*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1236*8214e71cSJoe } 1237*8214e71cSJoe 1238*8214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Primal(SNES snes, DM sw, PetscReal E[]) 1239*8214e71cSJoe { 1240b80bf5b1SJoe Pusztay DM dm; 1241*8214e71cSJoe AppCtx *user; 1242*8214e71cSJoe PetscDS ds; 1243*8214e71cSJoe PetscFE fe; 1244*8214e71cSJoe Mat M_p, M; 1245*8214e71cSJoe Vec phi, locPhi, rho, f; 1246*8214e71cSJoe PetscReal *coords; 1247*8214e71cSJoe PetscInt dim, cStart, cEnd, Np; 1248*8214e71cSJoe PetscQuadrature q; 1249*8214e71cSJoe 1250*8214e71cSJoe PetscFunctionBegin; 1251*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1252*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1253*8214e71cSJoe PetscCall(DMGetApplicationContext(sw, (void *)&user)); 1254*8214e71cSJoe 1255*8214e71cSJoe KSP ksp; 1256*8214e71cSJoe Vec rho0; 1257*8214e71cSJoe char oldField[PETSC_MAX_PATH_LEN]; 1258*8214e71cSJoe const char *tmp; 1259*8214e71cSJoe 1260*8214e71cSJoe /* Create the charges rho */ 1261*8214e71cSJoe PetscCall(SNESGetDM(snes, &dm)); 1262*8214e71cSJoe PetscCall(DMSwarmVectorGetField(sw, &tmp)); 1263*8214e71cSJoe PetscCall(PetscStrncpy(oldField, tmp, PETSC_MAX_PATH_LEN)); 1264*8214e71cSJoe PetscCall(DMSwarmVectorDefineField(sw, "w_q")); 1265*8214e71cSJoe PetscCall(DMCreateMassMatrix(sw, dm, &M_p)); 1266*8214e71cSJoe PetscCall(DMSwarmVectorDefineField(sw, oldField)); 1267*8214e71cSJoe 1268*8214e71cSJoe PetscCall(DMCreateMassMatrix(dm, dm, &M)); 1269*8214e71cSJoe PetscCall(DMGetGlobalVector(dm, &rho0)); 1270*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)rho0, "Charge density (rho0) from Primal Compute")); 1271*8214e71cSJoe PetscCall(DMGetGlobalVector(dm, &rho)); 1272*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)rho, "rho")); 1273*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f)); 1274*8214e71cSJoe 1275*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)f, "particle weight")); 1276*8214e71cSJoe PetscCall(MatMultTranspose(M_p, f, rho)); 1277*8214e71cSJoe PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view")); 1278*8214e71cSJoe PetscCall(MatViewFromOptions(M, NULL, "-m_view")); 1279*8214e71cSJoe PetscCall(VecViewFromOptions(f, NULL, "-weights_view")); 1280*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f)); 1281*8214e71cSJoe 1282*8214e71cSJoe PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp)); 1283*8214e71cSJoe PetscCall(KSPSetOptionsPrefix(ksp, "em_proj_")); 1284*8214e71cSJoe PetscCall(KSPSetOperators(ksp, M, M)); 1285*8214e71cSJoe PetscCall(KSPSetFromOptions(ksp)); 1286*8214e71cSJoe PetscCall(KSPSolve(ksp, rho, rho0)); 1287*8214e71cSJoe PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view")); 1288*8214e71cSJoe 1289*8214e71cSJoe PetscInt rhosize; 1290*8214e71cSJoe PetscReal *charges; 1291*8214e71cSJoe const PetscScalar *rho_vals; 1292*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "charges", NULL, NULL, (void **)&charges)); 1293*8214e71cSJoe PetscCall(VecGetLocalSize(rho0, &rhosize)); 1294*8214e71cSJoe PetscCall(VecGetArrayRead(rho0, &rho_vals)); 1295*8214e71cSJoe for (PetscInt c = 0; c < rhosize; ++c) charges[c] = rho_vals[c]; 1296*8214e71cSJoe PetscCall(VecRestoreArrayRead(rho0, &rho_vals)); 1297*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "charges", NULL, NULL, (void **)&charges)); 1298*8214e71cSJoe 1299*8214e71cSJoe PetscCall(VecScale(rho, -1.0)); 1300*8214e71cSJoe 1301*8214e71cSJoe PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view")); 1302*8214e71cSJoe PetscCall(VecViewFromOptions(rho, NULL, "-rho_view")); 1303*8214e71cSJoe PetscCall(DMRestoreGlobalVector(dm, &rho0)); 1304*8214e71cSJoe PetscCall(KSPDestroy(&ksp)); 1305*8214e71cSJoe PetscCall(MatDestroy(&M_p)); 1306*8214e71cSJoe PetscCall(MatDestroy(&M)); 1307*8214e71cSJoe 1308*8214e71cSJoe PetscCall(DMGetGlobalVector(dm, &phi)); 1309*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)phi, "potential")); 1310*8214e71cSJoe PetscCall(VecSet(phi, 0.0)); 1311*8214e71cSJoe PetscCall(SNESSolve(snes, rho, phi)); 1312*8214e71cSJoe PetscCall(DMRestoreGlobalVector(dm, &rho)); 1313*8214e71cSJoe PetscCall(VecViewFromOptions(phi, NULL, "-phi_view")); 1314*8214e71cSJoe 1315*8214e71cSJoe PetscInt phisize; 1316*8214e71cSJoe PetscReal *pot; 1317*8214e71cSJoe const PetscScalar *phi_vals; 1318*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "potential", NULL, NULL, (void **)&pot)); 1319*8214e71cSJoe PetscCall(VecGetLocalSize(phi, &phisize)); 1320*8214e71cSJoe PetscCall(VecGetArrayRead(phi, &phi_vals)); 1321*8214e71cSJoe for (PetscInt c = 0; c < phisize; ++c) pot[c] = phi_vals[c]; 1322*8214e71cSJoe PetscCall(VecRestoreArrayRead(phi, &phi_vals)); 1323*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "potential", NULL, NULL, (void **)&pot)); 1324*8214e71cSJoe 1325*8214e71cSJoe PetscCall(DMGetLocalVector(dm, &locPhi)); 1326*8214e71cSJoe PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi)); 1327*8214e71cSJoe PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi)); 1328*8214e71cSJoe PetscCall(DMRestoreGlobalVector(dm, &phi)); 1329*8214e71cSJoe 1330*8214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 1331*8214e71cSJoe PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe)); 1332*8214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 1333*8214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1334*8214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 1335*8214e71cSJoe 1336*8214e71cSJoe for (PetscInt c = cStart; c < cEnd; ++c) { 1337*8214e71cSJoe PetscTabulation tab; 1338*8214e71cSJoe PetscScalar *clPhi = NULL; 1339*8214e71cSJoe PetscReal *pcoord, *refcoord; 1340*8214e71cSJoe PetscReal v[3], J[9], invJ[9], detJ; 1341*8214e71cSJoe PetscInt *points; 1342*8214e71cSJoe PetscInt Ncp; 1343*8214e71cSJoe 1344*8214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points)); 1345*8214e71cSJoe PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord)); 1346*8214e71cSJoe PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord)); 1347*8214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) 1348*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d]; 1349*8214e71cSJoe PetscCall(DMPlexCoordinatesToReference(dm, c, Ncp, pcoord, refcoord)); 1350*8214e71cSJoe PetscCall(PetscFECreateTabulation(fe, 1, Ncp, refcoord, 1, &tab)); 1351*8214e71cSJoe PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v, J, invJ, &detJ)); 1352*8214e71cSJoe PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 1353*8214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) { 1354*8214e71cSJoe const PetscReal *basisDer = tab->T[1]; 1355*8214e71cSJoe const PetscInt p = points[cp]; 1356*8214e71cSJoe 1357*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.; 1358*8214e71cSJoe PetscCall(PetscFEGetQuadrature(fe, &q)); 1359*8214e71cSJoe PetscCall(PetscFEFreeInterpolateGradient_Static(fe, basisDer, clPhi, dim, invJ, NULL, cp, &E[p * dim])); 1360*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) { 1361*8214e71cSJoe E[p * dim + d] *= -1.0; 1362*8214e71cSJoe if (user->fake_1D && d > 0) E[p * dim + d] = 0; 1363*8214e71cSJoe } 1364*8214e71cSJoe } 1365*8214e71cSJoe PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 1366*8214e71cSJoe PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord)); 1367*8214e71cSJoe PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord)); 1368*8214e71cSJoe PetscCall(PetscTabulationDestroy(&tab)); 1369*8214e71cSJoe PetscCall(PetscFree(points)); 1370*8214e71cSJoe } 1371*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 1372*8214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 1373*8214e71cSJoe PetscCall(DMRestoreLocalVector(dm, &locPhi)); 1374*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1375*8214e71cSJoe } 1376*8214e71cSJoe 1377*8214e71cSJoe static PetscErrorCode ComputeFieldAtParticles_Mixed(SNES snes, DM sw, PetscReal E[]) 1378*8214e71cSJoe { 1379*8214e71cSJoe AppCtx *user; 1380*8214e71cSJoe DM dm, potential_dm; 1381*8214e71cSJoe KSP ksp; 1382*8214e71cSJoe IS potential_IS; 1383*8214e71cSJoe PetscDS ds; 1384*8214e71cSJoe PetscFE fe; 1385*8214e71cSJoe PetscFEGeom feGeometry; 1386*8214e71cSJoe Mat M_p, M; 1387*8214e71cSJoe Vec phi, locPhi, rho, f, temp_rho, rho0; 1388*8214e71cSJoe PetscQuadrature q; 1389*8214e71cSJoe PetscReal *coords, *pot; 1390*8214e71cSJoe PetscInt dim, cStart, cEnd, Np, fields = 1; 1391*8214e71cSJoe char oldField[PETSC_MAX_PATH_LEN]; 1392*8214e71cSJoe const char *tmp; 1393*8214e71cSJoe 1394*8214e71cSJoe PetscFunctionBegin; 1395*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1396*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1397*8214e71cSJoe PetscCall(DMGetApplicationContext(sw, &user)); 1398*8214e71cSJoe 1399*8214e71cSJoe /* Create the charges rho */ 1400*8214e71cSJoe PetscCall(SNESGetDM(snes, &dm)); 1401*8214e71cSJoe PetscCall(DMGetGlobalVector(dm, &rho)); 1402*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)rho, "rho")); 1403*8214e71cSJoe 1404*8214e71cSJoe PetscCall(DMCreateSubDM(dm, 1, &fields, &potential_IS, &potential_dm)); 1405*8214e71cSJoe 1406*8214e71cSJoe PetscCall(DMSwarmVectorGetField(sw, &tmp)); 1407*8214e71cSJoe PetscCall(PetscStrncpy(oldField, tmp, PETSC_MAX_PATH_LEN)); 1408*8214e71cSJoe PetscCall(DMSwarmVectorDefineField(sw, "w_q")); 1409*8214e71cSJoe PetscCall(DMCreateMassMatrix(sw, potential_dm, &M_p)); 1410*8214e71cSJoe PetscCall(DMSwarmVectorDefineField(sw, oldField)); 1411*8214e71cSJoe 1412*8214e71cSJoe PetscCall(DMCreateMassMatrix(potential_dm, potential_dm, &M)); 1413*8214e71cSJoe PetscCall(MatViewFromOptions(M_p, NULL, "-mp_view")); 1414*8214e71cSJoe PetscCall(MatViewFromOptions(M, NULL, "-m_view")); 1415*8214e71cSJoe PetscCall(DMGetGlobalVector(potential_dm, &temp_rho)); 1416*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)temp_rho, "Mf")); 1417*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "w_q", &f)); 1418*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)f, "particle weight")); 1419*8214e71cSJoe PetscCall(VecViewFromOptions(f, NULL, "-weights_view")); 1420*8214e71cSJoe PetscCall(MatMultTranspose(M_p, f, temp_rho)); 1421*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "w_q", &f)); 1422*8214e71cSJoe PetscCall(DMGetGlobalVector(potential_dm, &rho0)); 1423*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)rho0, "Charge density (rho0) from Mixed Compute")); 1424*8214e71cSJoe 1425*8214e71cSJoe PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp)); 1426*8214e71cSJoe PetscCall(KSPSetOptionsPrefix(ksp, "em_proj")); 1427*8214e71cSJoe PetscCall(KSPSetOperators(ksp, M, M)); 1428*8214e71cSJoe PetscCall(KSPSetFromOptions(ksp)); 1429*8214e71cSJoe PetscCall(KSPSolve(ksp, temp_rho, rho0)); 1430*8214e71cSJoe PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view")); 1431*8214e71cSJoe 1432*8214e71cSJoe PetscInt rhosize; 1433*8214e71cSJoe PetscReal *charges; 1434*8214e71cSJoe const PetscScalar *rho_vals; 1435*8214e71cSJoe Parameter *param; 1436*8214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 1437*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "charges", NULL, NULL, (void **)&charges)); 1438*8214e71cSJoe PetscCall(VecGetLocalSize(rho0, &rhosize)); 1439*8214e71cSJoe 1440*8214e71cSJoe /* Integral over reference element is size 1. Reference element area is 4. Scale rho0 by 1/4 because the basis function is 1/4 */ 1441*8214e71cSJoe PetscCall(VecScale(rho0, 0.25)); 1442*8214e71cSJoe PetscCall(VecGetArrayRead(rho0, &rho_vals)); 1443*8214e71cSJoe for (PetscInt c = 0; c < rhosize; ++c) charges[c] = rho_vals[c]; 1444*8214e71cSJoe PetscCall(VecRestoreArrayRead(rho0, &rho_vals)); 1445*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "charges", NULL, NULL, (void **)&charges)); 1446*8214e71cSJoe 1447*8214e71cSJoe PetscCall(VecISCopy(rho, potential_IS, SCATTER_FORWARD, temp_rho)); 1448*8214e71cSJoe PetscCall(VecScale(rho, 0.25)); 1449*8214e71cSJoe PetscCall(VecViewFromOptions(rho0, NULL, "-rho0_view")); 1450*8214e71cSJoe PetscCall(VecViewFromOptions(temp_rho, NULL, "-temprho_view")); 1451*8214e71cSJoe PetscCall(VecViewFromOptions(rho, NULL, "-rho_view")); 1452*8214e71cSJoe PetscCall(DMRestoreGlobalVector(potential_dm, &temp_rho)); 1453*8214e71cSJoe PetscCall(DMRestoreGlobalVector(potential_dm, &rho0)); 1454*8214e71cSJoe 1455*8214e71cSJoe PetscCall(MatDestroy(&M_p)); 1456*8214e71cSJoe PetscCall(MatDestroy(&M)); 1457*8214e71cSJoe PetscCall(KSPDestroy(&ksp)); 1458*8214e71cSJoe PetscCall(DMDestroy(&potential_dm)); 1459*8214e71cSJoe PetscCall(ISDestroy(&potential_IS)); 1460*8214e71cSJoe 1461*8214e71cSJoe PetscCall(DMGetGlobalVector(dm, &phi)); 1462*8214e71cSJoe PetscCall(PetscObjectSetName((PetscObject)phi, "potential")); 1463*8214e71cSJoe PetscCall(VecSet(phi, 0.0)); 1464*8214e71cSJoe PetscCall(SNESSolve(snes, rho, phi)); 1465*8214e71cSJoe PetscCall(DMRestoreGlobalVector(dm, &rho)); 1466*8214e71cSJoe 1467*8214e71cSJoe PetscInt phisize; 1468*8214e71cSJoe const PetscScalar *phi_vals; 1469*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "potential", NULL, NULL, (void **)&pot)); 1470*8214e71cSJoe PetscCall(VecGetLocalSize(phi, &phisize)); 1471*8214e71cSJoe PetscCall(VecViewFromOptions(phi, NULL, "-phi_view")); 1472*8214e71cSJoe PetscCall(VecGetArrayRead(phi, &phi_vals)); 1473*8214e71cSJoe for (PetscInt c = 0; c < phisize; ++c) pot[c] = phi_vals[c]; 1474*8214e71cSJoe PetscCall(VecRestoreArrayRead(phi, &phi_vals)); 1475*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "potential", NULL, NULL, (void **)&pot)); 1476*8214e71cSJoe 1477*8214e71cSJoe PetscCall(DMGetLocalVector(dm, &locPhi)); 1478*8214e71cSJoe PetscCall(DMGlobalToLocalBegin(dm, phi, INSERT_VALUES, locPhi)); 1479*8214e71cSJoe PetscCall(DMGlobalToLocalEnd(dm, phi, INSERT_VALUES, locPhi)); 1480*8214e71cSJoe PetscCall(DMRestoreGlobalVector(dm, &phi)); 1481*8214e71cSJoe 1482*8214e71cSJoe PetscCall(DMGetDS(dm, &ds)); 1483*8214e71cSJoe PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe)); 1484*8214e71cSJoe PetscCall(DMSwarmSortGetAccess(sw)); 1485*8214e71cSJoe PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1486*8214e71cSJoe PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 1487*8214e71cSJoe PetscCall(PetscFEGetQuadrature(fe, &q)); 1488*8214e71cSJoe PetscCall(PetscFECreateCellGeometry(fe, q, &feGeometry)); 1489*8214e71cSJoe for (PetscInt c = cStart; c < cEnd; ++c) { 1490*8214e71cSJoe PetscTabulation tab; 1491*8214e71cSJoe PetscScalar *clPhi = NULL; 1492*8214e71cSJoe PetscReal *pcoord, *refcoord; 1493*8214e71cSJoe PetscInt *points; 1494*8214e71cSJoe PetscInt Ncp; 1495*8214e71cSJoe 1496*8214e71cSJoe PetscCall(DMSwarmSortGetPointsPerCell(sw, c, &Ncp, &points)); 1497*8214e71cSJoe PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord)); 1498*8214e71cSJoe PetscCall(DMGetWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord)); 1499*8214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) 1500*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) pcoord[cp * dim + d] = coords[points[cp] * dim + d]; 1501*8214e71cSJoe PetscCall(DMPlexCoordinatesToReference(dm, c, Ncp, pcoord, refcoord)); 1502*8214e71cSJoe PetscCall(PetscFECreateTabulation(fe, 1, Ncp, refcoord, 1, &tab)); 1503*8214e71cSJoe PetscCall(DMPlexComputeCellGeometryFEM(dm, c, q, feGeometry.v, feGeometry.J, feGeometry.invJ, feGeometry.detJ)); 1504*8214e71cSJoe PetscCall(DMPlexVecGetClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 1505*8214e71cSJoe 1506*8214e71cSJoe for (PetscInt cp = 0; cp < Ncp; ++cp) { 1507*8214e71cSJoe const PetscInt p = points[cp]; 1508*8214e71cSJoe 1509*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) E[p * dim + d] = 0.; 1510*8214e71cSJoe PetscCall(PetscFEInterpolateAtPoints_Static(fe, tab, clPhi, &feGeometry, cp, &E[p * dim])); 1511*8214e71cSJoe PetscCall(PetscFEPushforward(fe, &feGeometry, 1, &E[p * dim])); 1512*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) { 1513*8214e71cSJoe E[p * dim + d] *= -2.0; 1514*8214e71cSJoe if (user->fake_1D && d > 0) E[p * dim + d] = 0; 1515*8214e71cSJoe } 1516*8214e71cSJoe } 1517*8214e71cSJoe PetscCall(DMPlexVecRestoreClosure(dm, NULL, locPhi, c, NULL, &clPhi)); 1518*8214e71cSJoe PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &pcoord)); 1519*8214e71cSJoe PetscCall(DMRestoreWorkArray(dm, Ncp * dim, MPIU_REAL, &refcoord)); 1520*8214e71cSJoe PetscCall(PetscTabulationDestroy(&tab)); 1521*8214e71cSJoe PetscCall(PetscFree(points)); 1522*8214e71cSJoe } 1523*8214e71cSJoe PetscCall(PetscFEDestroyCellGeometry(fe, &feGeometry)); 1524*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 1525*8214e71cSJoe PetscCall(DMSwarmSortRestoreAccess(sw)); 1526*8214e71cSJoe PetscCall(DMRestoreLocalVector(dm, &locPhi)); 1527*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1528*8214e71cSJoe } 1529*8214e71cSJoe 1530*8214e71cSJoe static PetscErrorCode ComputeFieldAtParticles(SNES snes, DM sw, PetscReal E[]) 1531*8214e71cSJoe { 1532*8214e71cSJoe AppCtx *ctx; 1533*8214e71cSJoe PetscInt dim, Np; 1534*8214e71cSJoe 1535*8214e71cSJoe PetscFunctionBegin; 1536*8214e71cSJoe PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1537*8214e71cSJoe PetscValidHeaderSpecific(sw, DM_CLASSID, 2); 1538*8214e71cSJoe PetscAssertPointer(E, 3); 1539*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1540*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1541*8214e71cSJoe PetscCall(DMGetApplicationContext(sw, &ctx)); 1542*8214e71cSJoe PetscCall(PetscArrayzero(E, Np * dim)); 1543*8214e71cSJoe 1544*8214e71cSJoe switch (ctx->em) { 1545*8214e71cSJoe case EM_PRIMAL: 1546*8214e71cSJoe PetscCall(ComputeFieldAtParticles_Primal(snes, sw, E)); 1547*8214e71cSJoe break; 1548*8214e71cSJoe case EM_COULOMB: 1549*8214e71cSJoe PetscCall(ComputeFieldAtParticles_Coulomb(snes, sw, E)); 1550*8214e71cSJoe break; 1551*8214e71cSJoe case EM_MIXED: 1552*8214e71cSJoe PetscCall(ComputeFieldAtParticles_Mixed(snes, sw, E)); 1553*8214e71cSJoe break; 1554*8214e71cSJoe case EM_NONE: 1555*8214e71cSJoe break; 1556*8214e71cSJoe default: 1557*8214e71cSJoe SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No solver for electrostatic model %s", EMTypes[ctx->em]); 1558*8214e71cSJoe } 1559*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1560*8214e71cSJoe } 1561*8214e71cSJoe 1562*8214e71cSJoe static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec G, void *ctx) 1563*8214e71cSJoe { 1564*8214e71cSJoe DM sw; 1565*8214e71cSJoe SNES snes = ((AppCtx *)ctx)->snes; 1566*8214e71cSJoe const PetscReal *coords, *vel; 1567*8214e71cSJoe const PetscScalar *u; 1568*8214e71cSJoe PetscScalar *g; 1569*8214e71cSJoe PetscReal *E, m_p = 1., q_p = -1.; 1570*8214e71cSJoe PetscInt dim, d, Np, p; 1571b80bf5b1SJoe Pusztay 1572b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 1573*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 1574*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1575*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 1576*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 1577*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 1578*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1579*8214e71cSJoe PetscCall(VecGetArrayRead(U, &u)); 1580*8214e71cSJoe PetscCall(VecGetArray(G, &g)); 1581*8214e71cSJoe 1582*8214e71cSJoe PetscCall(ComputeFieldAtParticles(snes, sw, E)); 1583*8214e71cSJoe 1584*8214e71cSJoe Np /= 2 * dim; 1585*8214e71cSJoe for (p = 0; p < Np; ++p) { 1586*8214e71cSJoe for (d = 0; d < dim; ++d) { 1587*8214e71cSJoe g[(p * 2 + 0) * dim + d] = u[(p * 2 + 1) * dim + d]; 1588*8214e71cSJoe g[(p * 2 + 1) * dim + d] = q_p * E[p * dim + d] / m_p; 1589*8214e71cSJoe } 1590*8214e71cSJoe } 1591*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 1592*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 1593*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 1594*8214e71cSJoe PetscCall(VecRestoreArrayRead(U, &u)); 1595*8214e71cSJoe PetscCall(VecRestoreArray(G, &g)); 1596*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1597*8214e71cSJoe } 1598*8214e71cSJoe 1599*8214e71cSJoe /* J_{ij} = dF_i/dx_j 1600*8214e71cSJoe J_p = ( 0 1) 1601*8214e71cSJoe (-w^2 0) 1602*8214e71cSJoe TODO Now there is another term with w^2 from the electric field. I think we will need to invert the operator. 1603*8214e71cSJoe Perhaps we can approximate the Jacobian using only the cellwise P-P gradient from Coulomb 1604*8214e71cSJoe */ 1605*8214e71cSJoe static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat P, void *ctx) 1606*8214e71cSJoe { 1607*8214e71cSJoe DM sw; 1608*8214e71cSJoe const PetscReal *coords, *vel; 1609*8214e71cSJoe PetscInt dim, d, Np, p, rStart; 1610*8214e71cSJoe 1611*8214e71cSJoe PetscFunctionBeginUser; 1612*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 1613*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1614*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1615*8214e71cSJoe PetscCall(MatGetOwnershipRange(J, &rStart, NULL)); 1616*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 1617*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 1618*8214e71cSJoe Np /= 2 * dim; 1619*8214e71cSJoe for (p = 0; p < Np; ++p) { 1620*8214e71cSJoe const PetscReal x0 = coords[p * dim + 0]; 1621*8214e71cSJoe const PetscReal vy0 = vel[p * dim + 1]; 1622*8214e71cSJoe const PetscReal omega = vy0 / x0; 1623*8214e71cSJoe PetscScalar vals[4] = {0., 1., -PetscSqr(omega), 0.}; 1624*8214e71cSJoe 1625*8214e71cSJoe for (d = 0; d < dim; ++d) { 1626*8214e71cSJoe const PetscInt rows[2] = {(p * 2 + 0) * dim + d + rStart, (p * 2 + 1) * dim + d + rStart}; 1627*8214e71cSJoe PetscCall(MatSetValues(J, 2, rows, 2, rows, vals, INSERT_VALUES)); 1628*8214e71cSJoe } 1629*8214e71cSJoe } 1630*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 1631*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 1632*8214e71cSJoe PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 1633*8214e71cSJoe PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 1634*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1635*8214e71cSJoe } 1636*8214e71cSJoe 1637*8214e71cSJoe static PetscErrorCode RHSFunctionX(TS ts, PetscReal t, Vec V, Vec Xres, void *ctx) 1638*8214e71cSJoe { 1639*8214e71cSJoe AppCtx *user = (AppCtx *)ctx; 1640*8214e71cSJoe DM sw; 1641*8214e71cSJoe const PetscScalar *v; 1642*8214e71cSJoe PetscScalar *xres; 1643*8214e71cSJoe PetscInt Np, p, d, dim; 1644*8214e71cSJoe 1645*8214e71cSJoe PetscFunctionBeginUser; 1646*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 1647*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1648*8214e71cSJoe PetscCall(VecGetLocalSize(Xres, &Np)); 16499566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(V, &v)); 1650*8214e71cSJoe PetscCall(VecGetArray(Xres, &xres)); 1651b80bf5b1SJoe Pusztay Np /= dim; 1652b80bf5b1SJoe Pusztay for (p = 0; p < Np; ++p) { 1653*8214e71cSJoe for (d = 0; d < dim; ++d) { 1654*8214e71cSJoe xres[p * dim + d] = v[p * dim + d]; 1655*8214e71cSJoe if (user->fake_1D && d > 0) xres[p * dim + d] = 0; 1656*8214e71cSJoe } 1657b80bf5b1SJoe Pusztay } 16589566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(V, &v)); 1659*8214e71cSJoe PetscCall(VecRestoreArray(Xres, &xres)); 16603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1661b80bf5b1SJoe Pusztay } 1662b80bf5b1SJoe Pusztay 1663*8214e71cSJoe static PetscErrorCode RHSFunctionV(TS ts, PetscReal t, Vec X, Vec Vres, void *ctx) 1664*8214e71cSJoe { 1665*8214e71cSJoe DM sw; 1666*8214e71cSJoe AppCtx *user = (AppCtx *)ctx; 1667*8214e71cSJoe SNES snes = ((AppCtx *)ctx)->snes; 1668*8214e71cSJoe const PetscScalar *x; 1669*8214e71cSJoe const PetscReal *coords, *vel; 1670*8214e71cSJoe PetscReal *E, m_p, q_p; 1671*8214e71cSJoe PetscScalar *vres; 1672*8214e71cSJoe PetscInt Np, p, dim, d; 1673*8214e71cSJoe Parameter *param; 1674*8214e71cSJoe 1675*8214e71cSJoe PetscFunctionBeginUser; 1676*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 1677*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1678*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 1679*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 1680*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "E_field", NULL, NULL, (void **)&E)); 1681*8214e71cSJoe PetscCall(PetscBagGetData(user->bag, (void **)¶m)); 1682*8214e71cSJoe m_p = user->masses[0] * param->m0; 1683*8214e71cSJoe q_p = user->charges[0] * param->q0; 1684*8214e71cSJoe PetscCall(VecGetLocalSize(Vres, &Np)); 1685*8214e71cSJoe PetscCall(VecGetArrayRead(X, &x)); 1686*8214e71cSJoe PetscCall(VecGetArray(Vres, &vres)); 1687*8214e71cSJoe PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension must be 2"); 1688*8214e71cSJoe PetscCall(ComputeFieldAtParticles(snes, sw, E)); 1689*8214e71cSJoe 1690*8214e71cSJoe Np /= dim; 1691*8214e71cSJoe for (p = 0; p < Np; ++p) { 1692*8214e71cSJoe for (d = 0; d < dim; ++d) { 1693*8214e71cSJoe vres[p * dim + d] = q_p * E[p * dim + d] / m_p; 1694*8214e71cSJoe if (user->fake_1D && d > 0) vres[p * dim + d] = 0.; 1695*8214e71cSJoe } 1696*8214e71cSJoe } 1697*8214e71cSJoe PetscCall(VecRestoreArrayRead(X, &x)); 1698*8214e71cSJoe /* 1699*8214e71cSJoe Syncrhonized, ordered output for parallel/sequential test cases. 1700*8214e71cSJoe In the 1D (on the 2D mesh) case, every y component should be zero. 1701*8214e71cSJoe */ 1702*8214e71cSJoe if (user->checkVRes) { 1703*8214e71cSJoe PetscBool pr = user->checkVRes > 1 ? PETSC_TRUE : PETSC_FALSE; 1704*8214e71cSJoe PetscInt step; 1705*8214e71cSJoe 1706*8214e71cSJoe PetscCall(TSGetStepNumber(ts, &step)); 1707*8214e71cSJoe if (pr) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "step: %" PetscInt_FMT "\n", step)); 1708*8214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 1709*8214e71cSJoe if (pr) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Residual: %.12g %.12g\n", (double)PetscRealPart(vres[p * dim + 0]), (double)PetscRealPart(vres[p * dim + 1]))); 1710*8214e71cSJoe 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])); 1711*8214e71cSJoe } 1712*8214e71cSJoe if (pr) PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT)); 1713*8214e71cSJoe } 1714*8214e71cSJoe PetscCall(VecRestoreArray(Vres, &vres)); 1715*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 1716*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 1717*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "E_field", NULL, NULL, (void **)&E)); 1718*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1719*8214e71cSJoe } 1720*8214e71cSJoe 1721*8214e71cSJoe static PetscErrorCode CreateSolution(TS ts) 1722*8214e71cSJoe { 1723*8214e71cSJoe DM sw; 1724*8214e71cSJoe Vec u; 1725*8214e71cSJoe PetscInt dim, Np; 1726*8214e71cSJoe 1727*8214e71cSJoe PetscFunctionBegin; 1728*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 1729*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1730*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1731*8214e71cSJoe PetscCall(VecCreate(PETSC_COMM_WORLD, &u)); 1732*8214e71cSJoe PetscCall(VecSetBlockSize(u, dim)); 1733*8214e71cSJoe PetscCall(VecSetSizes(u, 2 * Np * dim, PETSC_DECIDE)); 1734*8214e71cSJoe PetscCall(VecSetUp(u)); 1735*8214e71cSJoe PetscCall(TSSetSolution(ts, u)); 1736*8214e71cSJoe PetscCall(VecDestroy(&u)); 1737*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1738*8214e71cSJoe } 1739*8214e71cSJoe 1740*8214e71cSJoe static PetscErrorCode SetProblem(TS ts) 1741*8214e71cSJoe { 1742*8214e71cSJoe AppCtx *user; 1743*8214e71cSJoe DM sw; 1744*8214e71cSJoe 1745*8214e71cSJoe PetscFunctionBegin; 1746*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 1747*8214e71cSJoe PetscCall(DMGetApplicationContext(sw, (void **)&user)); 1748*8214e71cSJoe // Define unified system for (X, V) 1749*8214e71cSJoe { 1750*8214e71cSJoe Mat J; 1751*8214e71cSJoe PetscInt dim, Np; 1752*8214e71cSJoe 1753*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1754*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1755*8214e71cSJoe PetscCall(MatCreate(PETSC_COMM_WORLD, &J)); 1756*8214e71cSJoe PetscCall(MatSetSizes(J, 2 * Np * dim, 2 * Np * dim, PETSC_DECIDE, PETSC_DECIDE)); 1757*8214e71cSJoe PetscCall(MatSetBlockSize(J, 2 * dim)); 1758*8214e71cSJoe PetscCall(MatSetFromOptions(J)); 1759*8214e71cSJoe PetscCall(MatSetUp(J)); 1760*8214e71cSJoe PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, user)); 1761*8214e71cSJoe PetscCall(TSSetRHSJacobian(ts, J, J, RHSJacobian, user)); 1762*8214e71cSJoe PetscCall(MatDestroy(&J)); 1763*8214e71cSJoe } 1764*8214e71cSJoe /* Define split system for X and V */ 1765*8214e71cSJoe { 1766*8214e71cSJoe Vec u; 1767*8214e71cSJoe IS isx, isv, istmp; 1768*8214e71cSJoe const PetscInt *idx; 1769*8214e71cSJoe PetscInt dim, Np, rstart; 1770*8214e71cSJoe 1771*8214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 1772*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1773*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1774*8214e71cSJoe PetscCall(VecGetOwnershipRange(u, &rstart, NULL)); 1775*8214e71cSJoe PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 0, 2, &istmp)); 1776*8214e71cSJoe PetscCall(ISGetIndices(istmp, &idx)); 1777*8214e71cSJoe PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isx)); 1778*8214e71cSJoe PetscCall(ISRestoreIndices(istmp, &idx)); 1779*8214e71cSJoe PetscCall(ISDestroy(&istmp)); 1780*8214e71cSJoe PetscCall(ISCreateStride(PETSC_COMM_WORLD, Np, (rstart / dim) + 1, 2, &istmp)); 1781*8214e71cSJoe PetscCall(ISGetIndices(istmp, &idx)); 1782*8214e71cSJoe PetscCall(ISCreateBlock(PETSC_COMM_WORLD, dim, Np, idx, PETSC_COPY_VALUES, &isv)); 1783*8214e71cSJoe PetscCall(ISRestoreIndices(istmp, &idx)); 1784*8214e71cSJoe PetscCall(ISDestroy(&istmp)); 1785*8214e71cSJoe PetscCall(TSRHSSplitSetIS(ts, "position", isx)); 1786*8214e71cSJoe PetscCall(TSRHSSplitSetIS(ts, "momentum", isv)); 1787*8214e71cSJoe PetscCall(ISDestroy(&isx)); 1788*8214e71cSJoe PetscCall(ISDestroy(&isv)); 1789*8214e71cSJoe PetscCall(TSRHSSplitSetRHSFunction(ts, "position", NULL, RHSFunctionX, user)); 1790*8214e71cSJoe PetscCall(TSRHSSplitSetRHSFunction(ts, "momentum", NULL, RHSFunctionV, user)); 1791*8214e71cSJoe } 1792*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1793*8214e71cSJoe } 1794*8214e71cSJoe 1795*8214e71cSJoe static PetscErrorCode DMSwarmTSRedistribute(TS ts) 1796*8214e71cSJoe { 1797*8214e71cSJoe DM sw; 1798*8214e71cSJoe Vec u; 1799*8214e71cSJoe PetscReal t, maxt, dt; 1800*8214e71cSJoe PetscInt n, maxn; 1801*8214e71cSJoe 1802*8214e71cSJoe PetscFunctionBegin; 1803*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 1804*8214e71cSJoe PetscCall(TSGetTime(ts, &t)); 1805*8214e71cSJoe PetscCall(TSGetMaxTime(ts, &maxt)); 1806*8214e71cSJoe PetscCall(TSGetTimeStep(ts, &dt)); 1807*8214e71cSJoe PetscCall(TSGetStepNumber(ts, &n)); 1808*8214e71cSJoe PetscCall(TSGetMaxSteps(ts, &maxn)); 1809*8214e71cSJoe 1810*8214e71cSJoe PetscCall(TSReset(ts)); 1811*8214e71cSJoe PetscCall(TSSetDM(ts, sw)); 1812*8214e71cSJoe PetscCall(TSSetFromOptions(ts)); 1813*8214e71cSJoe PetscCall(TSSetTime(ts, t)); 1814*8214e71cSJoe PetscCall(TSSetMaxTime(ts, maxt)); 1815*8214e71cSJoe PetscCall(TSSetTimeStep(ts, dt)); 1816*8214e71cSJoe PetscCall(TSSetStepNumber(ts, n)); 1817*8214e71cSJoe PetscCall(TSSetMaxSteps(ts, maxn)); 1818*8214e71cSJoe 1819*8214e71cSJoe PetscCall(CreateSolution(ts)); 1820*8214e71cSJoe PetscCall(SetProblem(ts)); 1821*8214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 1822*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1823*8214e71cSJoe } 1824*8214e71cSJoe 1825*8214e71cSJoe PetscErrorCode line(PetscInt dim, PetscReal time, const PetscReal dummy[], PetscInt p, PetscScalar x[], void *ctx) 1826*8214e71cSJoe { 1827*8214e71cSJoe DM sw, cdm; 1828*8214e71cSJoe PetscInt Np; 1829*8214e71cSJoe PetscReal low[2], high[2]; 1830*8214e71cSJoe AppCtx *user = (AppCtx *)ctx; 1831*8214e71cSJoe 1832*8214e71cSJoe sw = user->swarm; 1833*8214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &cdm)); 1834*8214e71cSJoe // Get the bounding box so we can equally space the particles 1835*8214e71cSJoe PetscCall(DMGetLocalBoundingBox(cdm, low, high)); 1836*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1837*8214e71cSJoe // shift it by h/2 so nothing is initialized directly on a boundary 1838*8214e71cSJoe x[0] = ((high[0] - low[0]) / Np) * (p + 0.5); 1839*8214e71cSJoe x[1] = 0.; 1840*8214e71cSJoe return PETSC_SUCCESS; 1841*8214e71cSJoe } 1842*8214e71cSJoe 1843b80bf5b1SJoe Pusztay /* 1844*8214e71cSJoe InitializeSolveAndSwarm - Set the solution values to the swarm coordinates and velocities, and also possibly set the initial values. 1845*8214e71cSJoe 1846*8214e71cSJoe Input Parameters: 1847*8214e71cSJoe + ts - The TS 1848*8214e71cSJoe - useInitial - Flag to also set the initial conditions to the current coodinates and velocities and setup the problem 1849*8214e71cSJoe 1850*8214e71cSJoe Output Parameters: 1851*8214e71cSJoe . u - The initialized solution vector 1852*8214e71cSJoe 1853*8214e71cSJoe Level: advanced 1854*8214e71cSJoe 1855*8214e71cSJoe .seealso: InitializeSolve() 1856b80bf5b1SJoe Pusztay */ 1857*8214e71cSJoe static PetscErrorCode InitializeSolveAndSwarm(TS ts, PetscBool useInitial) 1858d71ae5a4SJacob Faibussowitsch { 1859*8214e71cSJoe DM sw; 1860*8214e71cSJoe Vec u, gc, gv, gc0, gv0; 1861*8214e71cSJoe IS isx, isv; 1862*8214e71cSJoe PetscInt dim; 1863*8214e71cSJoe AppCtx *user; 1864b80bf5b1SJoe Pusztay 1865b80bf5b1SJoe Pusztay PetscFunctionBeginUser; 1866*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 1867*8214e71cSJoe PetscCall(DMGetApplicationContext(sw, &user)); 1868*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1869*8214e71cSJoe if (useInitial) { 1870*8214e71cSJoe PetscReal v0[2] = {1., 0.}; 1871*8214e71cSJoe if (user->perturbed_weights) { 1872*8214e71cSJoe PetscCall(InitializeParticles_PerturbedWeights(sw, user)); 1873*8214e71cSJoe } else { 1874*8214e71cSJoe PetscCall(DMSwarmComputeLocalSizeFromOptions(sw)); 1875*8214e71cSJoe PetscCall(DMSwarmInitializeCoordinates(sw)); 1876*8214e71cSJoe if (user->fake_1D) { 1877*8214e71cSJoe PetscCall(InitializeVelocities_Fake1D(sw, user)); 1878*8214e71cSJoe } else { 1879*8214e71cSJoe PetscCall(DMSwarmInitializeVelocitiesFromOptions(sw, v0)); 1880*8214e71cSJoe } 1881*8214e71cSJoe } 1882*8214e71cSJoe PetscCall(DMSwarmMigrate(sw, PETSC_TRUE)); 1883*8214e71cSJoe PetscCall(DMSwarmTSRedistribute(ts)); 1884*8214e71cSJoe } 1885*8214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 1886*8214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "position", &isx)); 1887*8214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv)); 1888*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 1889*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "initCoordinates", &gc0)); 1890*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv)); 1891*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "initVelocity", &gv0)); 1892*8214e71cSJoe if (useInitial) { 1893*8214e71cSJoe PetscCall(VecCopy(gc, gc0)); 1894*8214e71cSJoe PetscCall(VecCopy(gv, gv0)); 1895*8214e71cSJoe } 1896*8214e71cSJoe PetscCall(VecISCopy(u, isx, SCATTER_FORWARD, gc)); 1897*8214e71cSJoe PetscCall(VecISCopy(u, isv, SCATTER_FORWARD, gv)); 1898*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 1899*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "initCoordinates", &gc0)); 1900*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv)); 1901*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "initVelocity", &gv0)); 1902*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1903*8214e71cSJoe } 1904*8214e71cSJoe 1905*8214e71cSJoe static PetscErrorCode InitializeSolve(TS ts, Vec u) 1906b80bf5b1SJoe Pusztay { 1907*8214e71cSJoe PetscFunctionBegin; 1908*8214e71cSJoe PetscCall(TSSetSolution(ts, u)); 1909*8214e71cSJoe PetscCall(InitializeSolveAndSwarm(ts, PETSC_TRUE)); 1910*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1911b80bf5b1SJoe Pusztay } 1912b80bf5b1SJoe Pusztay 1913*8214e71cSJoe static PetscErrorCode ComputeError(TS ts, Vec U, Vec E) 1914*8214e71cSJoe { 1915*8214e71cSJoe MPI_Comm comm; 1916*8214e71cSJoe DM sw; 1917*8214e71cSJoe AppCtx *user; 1918*8214e71cSJoe const PetscScalar *u; 1919*8214e71cSJoe const PetscReal *coords, *vel; 1920*8214e71cSJoe PetscScalar *e; 1921*8214e71cSJoe PetscReal t; 1922*8214e71cSJoe PetscInt dim, Np, p; 1923b80bf5b1SJoe Pusztay 1924*8214e71cSJoe PetscFunctionBeginUser; 1925*8214e71cSJoe PetscCall(PetscObjectGetComm((PetscObject)ts, &comm)); 1926*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 1927*8214e71cSJoe PetscCall(DMGetApplicationContext(sw, &user)); 1928*8214e71cSJoe PetscCall(DMGetDimension(sw, &dim)); 1929*8214e71cSJoe PetscCall(TSGetSolveTime(ts, &t)); 1930*8214e71cSJoe PetscCall(VecGetArray(E, &e)); 1931*8214e71cSJoe PetscCall(VecGetArrayRead(U, &u)); 1932*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1933*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 1934*8214e71cSJoe PetscCall(DMSwarmGetField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 1935*8214e71cSJoe Np /= 2 * dim; 1936*8214e71cSJoe for (p = 0; p < Np; ++p) { 1937*8214e71cSJoe /* TODO generalize initial conditions and project into plane instead of assuming x-y */ 1938*8214e71cSJoe const PetscReal r0 = DMPlex_NormD_Internal(dim, &coords[p * dim]); 1939*8214e71cSJoe const PetscReal th0 = PetscAtan2Real(coords[p * dim + 1], coords[p * dim + 0]); 1940*8214e71cSJoe const PetscReal v0 = DMPlex_NormD_Internal(dim, &vel[p * dim]); 1941*8214e71cSJoe const PetscReal omega = v0 / r0; 1942*8214e71cSJoe const PetscReal ct = PetscCosReal(omega * t + th0); 1943*8214e71cSJoe const PetscReal st = PetscSinReal(omega * t + th0); 1944*8214e71cSJoe const PetscScalar *x = &u[(p * 2 + 0) * dim]; 1945*8214e71cSJoe const PetscScalar *v = &u[(p * 2 + 1) * dim]; 1946*8214e71cSJoe const PetscReal xe[3] = {r0 * ct, r0 * st, 0.0}; 1947*8214e71cSJoe const PetscReal ve[3] = {-v0 * st, v0 * ct, 0.0}; 1948*8214e71cSJoe PetscInt d; 1949*8214e71cSJoe 1950*8214e71cSJoe for (d = 0; d < dim; ++d) { 1951*8214e71cSJoe e[(p * 2 + 0) * dim + d] = x[d] - xe[d]; 1952*8214e71cSJoe e[(p * 2 + 1) * dim + d] = v[d] - ve[d]; 1953b80bf5b1SJoe Pusztay } 1954*8214e71cSJoe if (user->error) { 1955*8214e71cSJoe const PetscReal en = 0.5 * DMPlex_DotRealD_Internal(dim, v, v); 1956*8214e71cSJoe const PetscReal exen = 0.5 * PetscSqr(v0); 1957*8214e71cSJoe 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))); 1958b80bf5b1SJoe Pusztay } 1959*8214e71cSJoe } 1960*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initCoordinates", NULL, NULL, (void **)&coords)); 1961*8214e71cSJoe PetscCall(DMSwarmRestoreField(sw, "initVelocity", NULL, NULL, (void **)&vel)); 1962*8214e71cSJoe PetscCall(VecRestoreArrayRead(U, &u)); 1963*8214e71cSJoe PetscCall(VecRestoreArray(E, &e)); 1964*8214e71cSJoe PetscFunctionReturn(PETSC_SUCCESS); 1965*8214e71cSJoe } 1966*8214e71cSJoe 1967*8214e71cSJoe static PetscErrorCode MigrateParticles(TS ts) 1968*8214e71cSJoe { 1969*8214e71cSJoe DM sw, cdm; 1970*8214e71cSJoe const PetscReal *L; 1971*8214e71cSJoe 1972*8214e71cSJoe PetscFunctionBeginUser; 1973*8214e71cSJoe PetscCall(TSGetDM(ts, &sw)); 1974*8214e71cSJoe PetscCall(DMViewFromOptions(sw, NULL, "-migrate_view_pre")); 1975*8214e71cSJoe { 1976*8214e71cSJoe Vec u, gc, gv, position, momentum; 1977*8214e71cSJoe IS isx, isv; 1978*8214e71cSJoe PetscReal *pos, *mom; 1979*8214e71cSJoe 1980*8214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 1981*8214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "position", &isx)); 1982*8214e71cSJoe PetscCall(TSRHSSplitGetIS(ts, "momentum", &isv)); 1983*8214e71cSJoe PetscCall(VecGetSubVector(u, isx, &position)); 1984*8214e71cSJoe PetscCall(VecGetSubVector(u, isv, &momentum)); 1985*8214e71cSJoe PetscCall(VecGetArray(position, &pos)); 1986*8214e71cSJoe PetscCall(VecGetArray(momentum, &mom)); 1987*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 1988*8214e71cSJoe PetscCall(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &gv)); 1989*8214e71cSJoe PetscCall(VecISCopy(u, isx, SCATTER_REVERSE, gc)); 1990*8214e71cSJoe PetscCall(VecISCopy(u, isv, SCATTER_REVERSE, gv)); 1991*8214e71cSJoe 1992*8214e71cSJoe PetscCall(DMSwarmGetCellDM(sw, &cdm)); 1993*8214e71cSJoe PetscCall(DMGetPeriodicity(cdm, NULL, NULL, &L)); 1994*8214e71cSJoe if ((L[0] || L[1]) >= 0.) { 1995*8214e71cSJoe PetscReal *x, *v, upper[3], lower[3]; 1996*8214e71cSJoe PetscInt Np, dim; 1997*8214e71cSJoe 1998*8214e71cSJoe PetscCall(DMSwarmGetLocalSize(sw, &Np)); 1999*8214e71cSJoe PetscCall(DMGetDimension(cdm, &dim)); 2000*8214e71cSJoe PetscCall(DMGetBoundingBox(cdm, lower, upper)); 2001*8214e71cSJoe PetscCall(VecGetArray(gc, &x)); 2002*8214e71cSJoe PetscCall(VecGetArray(gv, &v)); 2003*8214e71cSJoe for (PetscInt p = 0; p < Np; ++p) { 2004*8214e71cSJoe for (PetscInt d = 0; d < dim; ++d) { 2005*8214e71cSJoe if (pos[p * dim + d] < lower[d]) { 2006*8214e71cSJoe x[p * dim + d] = pos[p * dim + d] + (upper[d] - lower[d]); 2007*8214e71cSJoe } else if (pos[p * dim + d] > upper[d]) { 2008*8214e71cSJoe x[p * dim + d] = pos[p * dim + d] - (upper[d] - lower[d]); 2009*8214e71cSJoe } else { 2010*8214e71cSJoe x[p * dim + d] = pos[p * dim + d]; 2011*8214e71cSJoe } 2012*8214e71cSJoe 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]); 2013*8214e71cSJoe v[p * dim + d] = mom[p * dim + d]; 2014*8214e71cSJoe } 2015*8214e71cSJoe } 2016*8214e71cSJoe PetscCall(VecRestoreArray(gc, &x)); 2017*8214e71cSJoe PetscCall(VecRestoreArray(gv, &v)); 2018*8214e71cSJoe } 2019*8214e71cSJoe PetscCall(VecRestoreArray(position, &pos)); 2020*8214e71cSJoe PetscCall(VecRestoreArray(momentum, &mom)); 2021*8214e71cSJoe PetscCall(VecRestoreSubVector(u, isx, &position)); 2022*8214e71cSJoe PetscCall(VecRestoreSubVector(u, isv, &momentum)); 2023*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &gv)); 2024*8214e71cSJoe PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, DMSwarmPICField_coor, &gc)); 2025*8214e71cSJoe } 2026*8214e71cSJoe PetscCall(DMSwarmMigrate(sw, PETSC_TRUE)); 2027*8214e71cSJoe PetscCall(DMSwarmTSRedistribute(ts)); 2028*8214e71cSJoe PetscCall(InitializeSolveAndSwarm(ts, PETSC_FALSE)); 20293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2030b80bf5b1SJoe Pusztay } 2031b80bf5b1SJoe Pusztay 2032d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv) 2033d71ae5a4SJacob Faibussowitsch { 2034b80bf5b1SJoe Pusztay DM dm, sw; 2035*8214e71cSJoe TS ts; 2036*8214e71cSJoe Vec u; 2037*8214e71cSJoe PetscReal dt; 2038*8214e71cSJoe PetscInt maxn; 2039b80bf5b1SJoe Pusztay AppCtx user; 2040b80bf5b1SJoe Pusztay 20419566063dSJacob Faibussowitsch PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 2042*8214e71cSJoe PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user)); 2043*8214e71cSJoe PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &user.bag)); 2044*8214e71cSJoe PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm)); 2045*8214e71cSJoe PetscCall(CreatePoisson(dm, &user)); 2046*8214e71cSJoe PetscCall(CreateSwarm(dm, &user, &sw)); 2047*8214e71cSJoe PetscCall(SetupParameters(PETSC_COMM_WORLD, &user)); 2048*8214e71cSJoe PetscCall(InitializeConstants(sw, &user)); 2049*8214e71cSJoe PetscCall(DMSetApplicationContext(sw, &user)); 2050b80bf5b1SJoe Pusztay 2051*8214e71cSJoe PetscCall(TSCreate(PETSC_COMM_WORLD, &ts)); 2052*8214e71cSJoe PetscCall(TSSetProblemType(ts, TS_NONLINEAR)); 20539566063dSJacob Faibussowitsch PetscCall(TSSetDM(ts, sw)); 2054*8214e71cSJoe PetscCall(TSSetMaxTime(ts, 0.1)); 2055*8214e71cSJoe PetscCall(TSSetTimeStep(ts, 0.00001)); 2056*8214e71cSJoe PetscCall(TSSetMaxSteps(ts, 100)); 2057*8214e71cSJoe PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP)); 2058*8214e71cSJoe 2059*8214e71cSJoe if (user.efield_monitor) PetscCall(TSMonitorSet(ts, MonitorEField, &user, NULL)); 2060*8214e71cSJoe if (user.initial_monitor) PetscCall(TSMonitorSet(ts, MonitorInitialConditions, &user, NULL)); 2061*8214e71cSJoe if (user.monitor_positions) PetscCall(TSMonitorSet(ts, MonitorPositions_2D, &user, NULL)); 2062*8214e71cSJoe if (user.poisson_monitor) PetscCall(TSMonitorSet(ts, MonitorPoisson, &user, NULL)); 2063*8214e71cSJoe 2064*8214e71cSJoe PetscCall(TSSetFromOptions(ts)); 2065*8214e71cSJoe PetscCall(TSGetTimeStep(ts, &dt)); 2066*8214e71cSJoe PetscCall(TSGetMaxSteps(ts, &maxn)); 2067*8214e71cSJoe user.steps = maxn; 2068*8214e71cSJoe user.stepSize = dt; 2069*8214e71cSJoe PetscCall(SetupContext(dm, sw, &user)); 2070*8214e71cSJoe PetscCall(DMSwarmVectorDefineField(sw, "velocity")); 2071*8214e71cSJoe PetscCall(TSSetComputeInitialCondition(ts, InitializeSolve)); 2072*8214e71cSJoe PetscCall(TSSetComputeExactError(ts, ComputeError)); 2073*8214e71cSJoe PetscCall(TSSetPostStep(ts, MigrateParticles)); 2074*8214e71cSJoe PetscCall(CreateSolution(ts)); 2075*8214e71cSJoe PetscCall(TSGetSolution(ts, &u)); 2076*8214e71cSJoe PetscCall(TSComputeInitialCondition(ts, u)); 2077*8214e71cSJoe PetscCall(CheckNonNegativeWeights(sw, &user)); 2078*8214e71cSJoe PetscCall(TSSolve(ts, NULL)); 2079*8214e71cSJoe 20809566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&user.snes)); 20819566063dSJacob Faibussowitsch PetscCall(TSDestroy(&ts)); 20829566063dSJacob Faibussowitsch PetscCall(DMDestroy(&sw)); 20839566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dm)); 2084*8214e71cSJoe PetscCall(DestroyContext(&user)); 20859566063dSJacob Faibussowitsch PetscCall(PetscFinalize()); 2086b122ec5aSJacob Faibussowitsch return 0; 2087b80bf5b1SJoe Pusztay } 2088b80bf5b1SJoe Pusztay 2089b80bf5b1SJoe Pusztay /*TEST 2090b80bf5b1SJoe Pusztay 2091b80bf5b1SJoe Pusztay build: 2092*8214e71cSJoe requires: !complex double 2093*8214e71cSJoe 2094*8214e71cSJoe # This tests that we can put particles in a box and compute the Coulomb force 2095*8214e71cSJoe # Recommend -draw_size 500,500 2096*8214e71cSJoe testset: 2097*8214e71cSJoe requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT) 2098*8214e71cSJoe args: -dm_plex_dim 2 -fake_1D -dm_plex_simplex 0 -dm_plex_box_faces 20,1 \ 2099*8214e71cSJoe -dm_plex_box_lower 0,-1 -dm_plex_box_upper 12.5664,1 \ 2100b80bf5b1SJoe Pusztay -dm_plex_box_bd periodic,none \ 2101*8214e71cSJoe -dm_swarm_coordinate_density constant -dm_swarm_num_particles 100 \ 2102*8214e71cSJoe -sigma 1.0e-8 -timeScale 2.0e-14 \ 2103*8214e71cSJoe -ts_type basicsymplectic -ts_basicsymplectic_type 1 \ 2104*8214e71cSJoe -ts_monitor_sp_swarm -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 0 \ 2105*8214e71cSJoe -output_step 50 -check_vel_res 2106*8214e71cSJoe test: 2107*8214e71cSJoe suffix: none_1d 2108*8214e71cSJoe args: -em_type none -error 2109*8214e71cSJoe test: 2110*8214e71cSJoe suffix: coulomb_1d 2111*8214e71cSJoe args: -em_type coulomb 2112*8214e71cSJoe 2113*8214e71cSJoe # for viewers 2114*8214e71cSJoe #-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 2115*8214e71cSJoe testset: 2116*8214e71cSJoe nsize: {{1 2}} 2117*8214e71cSJoe requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT) 2118*8214e71cSJoe args: -dm_plex_dim 2 -fake_1D -dm_plex_simplex 0 -dm_plex_box_faces 36,1 \ 2119*8214e71cSJoe -dm_plex_box_lower 0.,-0.5 -dm_plex_box_upper 12.5664,0.5 \ 2120*8214e71cSJoe -dm_plex_box_bd periodic,none \ 2121*8214e71cSJoe -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \ 2122*8214e71cSJoe -vdm_plex_box_lower -3 -vdm_plex_box_upper 3 \ 2123*8214e71cSJoe -dm_swarm_num_species 1 -dm_swarm_num_particles 360 \ 2124*8214e71cSJoe -twostream -charges -1.,1. -sigma 1.0e-8 \ 2125*8214e71cSJoe -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \ 2126*8214e71cSJoe -ts_type basicsymplectic -ts_basicsymplectic_type 2 \ 2127*8214e71cSJoe -ts_dt 0.01 -ts_max_time 5 -ts_max_steps 10 \ 2128*8214e71cSJoe -em_snes_atol 1.e-15 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \ 2129*8214e71cSJoe -output_step 1 -check_vel_res 2130*8214e71cSJoe test: 2131*8214e71cSJoe suffix: two_stream_c0 2132*8214e71cSJoe args: -em_type primal -petscfe_default_quadrature_order 2 -petscspace_degree 2 -em_pc_type svd 2133*8214e71cSJoe test: 2134*8214e71cSJoe suffix: two_stream_rt 2135*8214e71cSJoe requires: superlu_dist 2136*8214e71cSJoe args: -em_type mixed \ 2137*8214e71cSJoe -potential_petscspace_degree 0 \ 2138*8214e71cSJoe -potential_petscdualspace_lagrange_use_moments \ 2139*8214e71cSJoe -potential_petscdualspace_lagrange_moment_order 2 \ 2140*8214e71cSJoe -field_petscspace_degree 2 -field_petscfe_default_quadrature_order 1 \ 2141*8214e71cSJoe -field_petscspace_type sum \ 2142*8214e71cSJoe -field_petscspace_variables 2 \ 2143*8214e71cSJoe -field_petscspace_components 2 \ 2144*8214e71cSJoe -field_petscspace_sum_spaces 2 \ 2145*8214e71cSJoe -field_petscspace_sum_concatenate true \ 2146*8214e71cSJoe -field_sumcomp_0_petscspace_variables 2 \ 2147*8214e71cSJoe -field_sumcomp_0_petscspace_type tensor \ 2148*8214e71cSJoe -field_sumcomp_0_petscspace_tensor_spaces 2 \ 2149*8214e71cSJoe -field_sumcomp_0_petscspace_tensor_uniform false \ 2150*8214e71cSJoe -field_sumcomp_0_tensorcomp_0_petscspace_degree 1 \ 2151*8214e71cSJoe -field_sumcomp_0_tensorcomp_1_petscspace_degree 0 \ 2152*8214e71cSJoe -field_sumcomp_1_petscspace_variables 2 \ 2153*8214e71cSJoe -field_sumcomp_1_petscspace_type tensor \ 2154*8214e71cSJoe -field_sumcomp_1_petscspace_tensor_spaces 2 \ 2155*8214e71cSJoe -field_sumcomp_1_petscspace_tensor_uniform false \ 2156*8214e71cSJoe -field_sumcomp_1_tensorcomp_0_petscspace_degree 0 \ 2157*8214e71cSJoe -field_sumcomp_1_tensorcomp_1_petscspace_degree 1 \ 2158*8214e71cSJoe -field_petscdualspace_form_degree -1 \ 2159*8214e71cSJoe -field_petscdualspace_order 1 \ 2160*8214e71cSJoe -field_petscdualspace_lagrange_trimmed true \ 2161*8214e71cSJoe -em_snes_error_if_not_converged \ 2162*8214e71cSJoe -em_ksp_type preonly -em_ksp_error_if_not_converged \ 2163*8214e71cSJoe -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \ 2164*8214e71cSJoe -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \ 2165*8214e71cSJoe -em_fieldsplit_field_pc_type lu \ 2166*8214e71cSJoe -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \ 2167*8214e71cSJoe -em_fieldsplit_potential_pc_type svd 2168*8214e71cSJoe 2169*8214e71cSJoe # For verification, we use 2170*8214e71cSJoe # -dm_plex_box_faces 100,1 -vdm_plex_box_faces 8000 -dm_swarm_num_particles 800000 2171*8214e71cSJoe # -ts_monitor_sp_swarm_multi_species 0 -ts_monitor_sp_swarm_retain 0 -ts_monitor_sp_swarm_phase 1 -draw_size 500,500 2172*8214e71cSJoe testset: 2173*8214e71cSJoe nsize: {{1 2}} 2174*8214e71cSJoe requires: defined(PETSC_HAVE_EXECUTABLE_EXPORT) 2175*8214e71cSJoe args: -dm_plex_dim 2 -fake_1D -dm_plex_simplex 0 -dm_plex_box_faces 10,1 \ 2176*8214e71cSJoe -dm_plex_box_lower 0.,-0.5 -dm_plex_box_upper 12.5664,0.5 \ 2177*8214e71cSJoe -dm_plex_box_bd periodic,none \ 2178*8214e71cSJoe -vdm_plex_dim 1 -vdm_plex_simplex 0 -vdm_plex_box_faces 10 \ 2179*8214e71cSJoe -vdm_plex_box_lower -10 -vdm_plex_box_upper 10 \ 2180*8214e71cSJoe -dm_swarm_num_species 1 -dm_swarm_num_particles 100 \ 2181*8214e71cSJoe -charges -1.,1. \ 2182*8214e71cSJoe -cosine_coefficients 0.01,0.5 -perturbed_weights -total_weight 1. \ 2183*8214e71cSJoe -ts_type basicsymplectic -ts_basicsymplectic_type 1 \ 2184*8214e71cSJoe -ts_dt 0.03 -ts_max_time 500 -ts_max_steps 1 \ 2185*8214e71cSJoe -em_snes_atol 1.e-12 -em_snes_error_if_not_converged -em_ksp_error_if_not_converged \ 2186*8214e71cSJoe -output_step 1 -check_vel_res 2187*8214e71cSJoe 2188*8214e71cSJoe test: 2189*8214e71cSJoe suffix: uniform_equilibrium_1d 2190*8214e71cSJoe args: -cosine_coefficients 0.0,0.5 -em_type primal -petscspace_degree 1 -em_pc_type svd 2191*8214e71cSJoe test: 2192*8214e71cSJoe suffix: uniform_primal_1d 2193*8214e71cSJoe args: -em_type primal -petscspace_degree 1 -em_pc_type svd 2194*8214e71cSJoe test: 2195*8214e71cSJoe requires: superlu_dist 2196*8214e71cSJoe suffix: uniform_mixed_1d 2197*8214e71cSJoe args: -em_type mixed \ 2198*8214e71cSJoe -potential_petscspace_degree 0 \ 2199*8214e71cSJoe -potential_petscdualspace_lagrange_use_moments \ 2200*8214e71cSJoe -potential_petscdualspace_lagrange_moment_order 2 \ 2201*8214e71cSJoe -field_petscspace_degree 2 -field_petscfe_default_quadrature_order 1 \ 2202*8214e71cSJoe -field_petscspace_type sum \ 2203*8214e71cSJoe -field_petscspace_variables 2 \ 2204*8214e71cSJoe -field_petscspace_components 2 \ 2205*8214e71cSJoe -field_petscspace_sum_spaces 2 \ 2206*8214e71cSJoe -field_petscspace_sum_concatenate true \ 2207*8214e71cSJoe -field_sumcomp_0_petscspace_variables 2 \ 2208*8214e71cSJoe -field_sumcomp_0_petscspace_type tensor \ 2209*8214e71cSJoe -field_sumcomp_0_petscspace_tensor_spaces 2 \ 2210*8214e71cSJoe -field_sumcomp_0_petscspace_tensor_uniform false \ 2211*8214e71cSJoe -field_sumcomp_0_tensorcomp_0_petscspace_degree 1 \ 2212*8214e71cSJoe -field_sumcomp_0_tensorcomp_1_petscspace_degree 0 \ 2213*8214e71cSJoe -field_sumcomp_1_petscspace_variables 2 \ 2214*8214e71cSJoe -field_sumcomp_1_petscspace_type tensor \ 2215*8214e71cSJoe -field_sumcomp_1_petscspace_tensor_spaces 2 \ 2216*8214e71cSJoe -field_sumcomp_1_petscspace_tensor_uniform false \ 2217*8214e71cSJoe -field_sumcomp_1_tensorcomp_0_petscspace_degree 0 \ 2218*8214e71cSJoe -field_sumcomp_1_tensorcomp_1_petscspace_degree 1 \ 2219*8214e71cSJoe -field_petscdualspace_form_degree -1 \ 2220*8214e71cSJoe -field_petscdualspace_order 1 \ 2221*8214e71cSJoe -field_petscdualspace_lagrange_trimmed true \ 2222*8214e71cSJoe -em_snes_error_if_not_converged \ 2223*8214e71cSJoe -em_ksp_type preonly -em_ksp_error_if_not_converged \ 2224*8214e71cSJoe -em_pc_type fieldsplit -em_pc_fieldsplit_type schur \ 2225*8214e71cSJoe -em_pc_fieldsplit_schur_fact_type full -em_pc_fieldsplit_schur_precondition full \ 2226*8214e71cSJoe -em_fieldsplit_field_pc_type lu \ 2227*8214e71cSJoe -em_fieldsplit_field_pc_factor_mat_solver_type superlu_dist \ 2228*8214e71cSJoe -em_fieldsplit_potential_pc_type svd 2229*8214e71cSJoe 2230b80bf5b1SJoe Pusztay TEST*/ 2231