1*0ee167adSMatthew G. Knepley static char help[] = "Tests multifield and multicomponent L2 projection.\n"; 2*0ee167adSMatthew G. Knepley 3*0ee167adSMatthew G. Knepley #include <petscdmswarm.h> 4*0ee167adSMatthew G. Knepley #include <petscksp.h> 5*0ee167adSMatthew G. Knepley #include <petscdmplex.h> 6*0ee167adSMatthew G. Knepley #include <petscds.h> 7*0ee167adSMatthew G. Knepley 8*0ee167adSMatthew G. Knepley typedef struct { 9*0ee167adSMatthew G. Knepley PetscBool pass; // Don't fail when moments are wrong 10*0ee167adSMatthew G. Knepley PetscBool fv; // Use an FV discretization, instead of FE 11*0ee167adSMatthew G. Knepley PetscInt Npc; // The number of partices per cell 12*0ee167adSMatthew G. Knepley PetscInt field; // The field to project 13*0ee167adSMatthew G. Knepley PetscInt Nm; // The number of moments to match 14*0ee167adSMatthew G. Knepley PetscReal mtol; // Tolerance for checking moment conservation 15*0ee167adSMatthew G. Knepley PetscSimplePointFn *func; // Function used to set particle weights 16*0ee167adSMatthew G. Knepley } AppCtx; 17*0ee167adSMatthew G. Knepley 18*0ee167adSMatthew G. Knepley typedef enum { 19*0ee167adSMatthew G. Knepley FUNCTION_CONSTANT, 20*0ee167adSMatthew G. Knepley FUNCTION_LINEAR, 21*0ee167adSMatthew G. Knepley FUNCTION_SIN, 22*0ee167adSMatthew G. Knepley FUNCTION_X2_X4, 23*0ee167adSMatthew G. Knepley FUNCTION_UNKNOWN, 24*0ee167adSMatthew G. Knepley NUM_FUNCTIONS 25*0ee167adSMatthew G. Knepley } FunctionType; 26*0ee167adSMatthew G. Knepley const char *const FunctionTypes[] = {"constant", "linear", "sin", "x2_x4", "unknown", "FunctionType", "FUNCTION_", NULL}; 27*0ee167adSMatthew G. Knepley 28*0ee167adSMatthew G. Knepley static PetscErrorCode constant(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 29*0ee167adSMatthew G. Knepley { 30*0ee167adSMatthew G. Knepley u[0] = 1.0; 31*0ee167adSMatthew G. Knepley return PETSC_SUCCESS; 32*0ee167adSMatthew G. Knepley } 33*0ee167adSMatthew G. Knepley 34*0ee167adSMatthew G. Knepley static PetscErrorCode linear(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 35*0ee167adSMatthew G. Knepley { 36*0ee167adSMatthew G. Knepley u[0] = 0.0; 37*0ee167adSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) u[0] += x[d]; 38*0ee167adSMatthew G. Knepley return PETSC_SUCCESS; 39*0ee167adSMatthew G. Knepley } 40*0ee167adSMatthew G. Knepley 41*0ee167adSMatthew G. Knepley static PetscErrorCode sinx(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 42*0ee167adSMatthew G. Knepley { 43*0ee167adSMatthew G. Knepley u[0] = 1; 44*0ee167adSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) u[0] *= PetscSinReal(2. * PETSC_PI * x[d]); 45*0ee167adSMatthew G. Knepley return PETSC_SUCCESS; 46*0ee167adSMatthew G. Knepley } 47*0ee167adSMatthew G. Knepley 48*0ee167adSMatthew G. Knepley static PetscErrorCode x2_x4(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 49*0ee167adSMatthew G. Knepley { 50*0ee167adSMatthew G. Knepley u[0] = 1; 51*0ee167adSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) u[0] *= PetscSqr(x[d]) - PetscSqr(PetscSqr(x[d])); 52*0ee167adSMatthew G. Knepley return PETSC_SUCCESS; 53*0ee167adSMatthew G. Knepley } 54*0ee167adSMatthew G. Knepley 55*0ee167adSMatthew G. Knepley static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) 56*0ee167adSMatthew G. Knepley { 57*0ee167adSMatthew G. Knepley FunctionType func = FUNCTION_LINEAR; 58*0ee167adSMatthew G. Knepley PetscBool flg; 59*0ee167adSMatthew G. Knepley 60*0ee167adSMatthew G. Knepley PetscFunctionBeginUser; 61*0ee167adSMatthew G. Knepley options->pass = PETSC_FALSE; 62*0ee167adSMatthew G. Knepley options->fv = PETSC_FALSE; 63*0ee167adSMatthew G. Knepley options->Npc = 1; 64*0ee167adSMatthew G. Knepley options->field = 0; 65*0ee167adSMatthew G. Knepley options->Nm = 1; 66*0ee167adSMatthew G. Knepley options->mtol = 100. * PETSC_MACHINE_EPSILON; 67*0ee167adSMatthew G. Knepley 68*0ee167adSMatthew G. Knepley PetscOptionsBegin(comm, "", "L2 Projection Options", "DMPLEX"); 69*0ee167adSMatthew G. Knepley PetscCall(PetscOptionsBool("-pass", "Don't fail when moments are wrong", __FILE__, options->pass, &options->pass, NULL)); 70*0ee167adSMatthew G. Knepley PetscCall(PetscOptionsBool("-fv", "Use FV instead of FE", __FILE__, options->fv, &options->fv, NULL)); 71*0ee167adSMatthew G. Knepley PetscCall(PetscOptionsBoundedInt("-npc", "Number of particles per cell", __FILE__, options->Npc, &options->Npc, NULL, 1)); 72*0ee167adSMatthew G. Knepley PetscCall(PetscOptionsBoundedInt("-field", "The field to project", __FILE__, options->field, &options->field, NULL, 0)); 73*0ee167adSMatthew G. Knepley PetscCall(PetscOptionsBoundedInt("-moments", "Number of moments to match", __FILE__, options->Nm, &options->Nm, NULL, 0)); 74*0ee167adSMatthew G. Knepley PetscCheck(options->Nm < 4, comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot match %" PetscInt_FMT " > 3 moments", options->Nm); 75*0ee167adSMatthew G. Knepley PetscCall(PetscOptionsReal("-mtol", "Tolerance for moment checks", "ex2.c", options->mtol, &options->mtol, NULL)); 76*0ee167adSMatthew G. Knepley PetscCall(PetscOptionsEnum("-func", "Type of particle weight function", __FILE__, FunctionTypes, (PetscEnum)func, (PetscEnum *)&func, &flg)); 77*0ee167adSMatthew G. Knepley switch (func) { 78*0ee167adSMatthew G. Knepley case FUNCTION_CONSTANT: 79*0ee167adSMatthew G. Knepley options->func = constant; 80*0ee167adSMatthew G. Knepley break; 81*0ee167adSMatthew G. Knepley case FUNCTION_LINEAR: 82*0ee167adSMatthew G. Knepley options->func = linear; 83*0ee167adSMatthew G. Knepley break; 84*0ee167adSMatthew G. Knepley case FUNCTION_SIN: 85*0ee167adSMatthew G. Knepley options->func = sinx; 86*0ee167adSMatthew G. Knepley break; 87*0ee167adSMatthew G. Knepley case FUNCTION_X2_X4: 88*0ee167adSMatthew G. Knepley options->func = x2_x4; 89*0ee167adSMatthew G. Knepley break; 90*0ee167adSMatthew G. Knepley default: 91*0ee167adSMatthew G. Knepley PetscCheck(flg, comm, PETSC_ERR_ARG_WRONG, "Cannnot handle function \"%s\"", FunctionTypes[func]); 92*0ee167adSMatthew G. Knepley } 93*0ee167adSMatthew G. Knepley PetscOptionsEnd(); 94*0ee167adSMatthew G. Knepley 95*0ee167adSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 96*0ee167adSMatthew G. Knepley } 97*0ee167adSMatthew G. Knepley 98*0ee167adSMatthew G. Knepley static PetscErrorCode CreateMesh(MPI_Comm comm, DM *dm, AppCtx *user) 99*0ee167adSMatthew G. Knepley { 100*0ee167adSMatthew G. Knepley PetscFunctionBeginUser; 101*0ee167adSMatthew G. Knepley PetscCall(DMCreate(comm, dm)); 102*0ee167adSMatthew G. Knepley PetscCall(DMSetType(*dm, DMPLEX)); 103*0ee167adSMatthew G. Knepley PetscCall(DMSetFromOptions(*dm)); 104*0ee167adSMatthew G. Knepley PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view")); 105*0ee167adSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 106*0ee167adSMatthew G. Knepley } 107*0ee167adSMatthew G. Knepley 108*0ee167adSMatthew G. Knepley static PetscErrorCode CreateDiscretization(DM dm, AppCtx *user) 109*0ee167adSMatthew G. Knepley { 110*0ee167adSMatthew G. Knepley PetscFE fe; 111*0ee167adSMatthew G. Knepley PetscFV fv; 112*0ee167adSMatthew G. Knepley DMPolytopeType ct; 113*0ee167adSMatthew G. Knepley PetscInt dim, cStart; 114*0ee167adSMatthew G. Knepley 115*0ee167adSMatthew G. Knepley PetscFunctionBeginUser; 116*0ee167adSMatthew G. Knepley PetscCall(DMGetDimension(dm, &dim)); 117*0ee167adSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 118*0ee167adSMatthew G. Knepley PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 119*0ee167adSMatthew G. Knepley if (user->fv) { 120*0ee167adSMatthew G. Knepley PetscCall(PetscFVCreate(PETSC_COMM_SELF, &fv)); 121*0ee167adSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)fv, "fv")); 122*0ee167adSMatthew G. Knepley PetscCall(PetscFVSetNumComponents(fv, 1)); 123*0ee167adSMatthew G. Knepley PetscCall(PetscFVSetSpatialDimension(fv, dim)); 124*0ee167adSMatthew G. Knepley PetscCall(PetscFVCreateDualSpace(fv, ct)); 125*0ee167adSMatthew G. Knepley PetscCall(PetscFVSetFromOptions(fv)); 126*0ee167adSMatthew G. Knepley PetscCall(DMAddField(dm, NULL, (PetscObject)fv)); 127*0ee167adSMatthew G. Knepley PetscCall(PetscFVDestroy(&fv)); 128*0ee167adSMatthew G. Knepley PetscCall(PetscFVCreate(PETSC_COMM_SELF, &fv)); 129*0ee167adSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)fv, "fv2")); 130*0ee167adSMatthew G. Knepley PetscCall(PetscFVSetNumComponents(fv, 2)); 131*0ee167adSMatthew G. Knepley PetscCall(PetscFVSetSpatialDimension(fv, dim)); 132*0ee167adSMatthew G. Knepley PetscCall(PetscFVCreateDualSpace(fv, ct)); 133*0ee167adSMatthew G. Knepley PetscCall(PetscFVSetFromOptions(fv)); 134*0ee167adSMatthew G. Knepley PetscCall(DMAddField(dm, NULL, (PetscObject)fv)); 135*0ee167adSMatthew G. Knepley PetscCall(PetscFVDestroy(&fv)); 136*0ee167adSMatthew G. Knepley } else { 137*0ee167adSMatthew G. Knepley PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, NULL, -1, &fe)); 138*0ee167adSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)fe, "fe")); 139*0ee167adSMatthew G. Knepley PetscCall(DMAddField(dm, NULL, (PetscObject)fe)); 140*0ee167adSMatthew G. Knepley PetscCall(PetscFEDestroy(&fe)); 141*0ee167adSMatthew G. Knepley PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 2, ct, NULL, -1, &fe)); 142*0ee167adSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)fe, "fe2")); 143*0ee167adSMatthew G. Knepley PetscCall(DMAddField(dm, NULL, (PetscObject)fe)); 144*0ee167adSMatthew G. Knepley PetscCall(PetscFEDestroy(&fe)); 145*0ee167adSMatthew G. Knepley } 146*0ee167adSMatthew G. Knepley PetscCall(DMCreateDS(dm)); 147*0ee167adSMatthew G. Knepley if (user->fv) { 148*0ee167adSMatthew G. Knepley DMLabel label; 149*0ee167adSMatthew G. Knepley PetscInt values[1] = {1}; 150*0ee167adSMatthew G. Knepley 151*0ee167adSMatthew G. Knepley PetscCall(DMCreateLabel(dm, "ghost")); 152*0ee167adSMatthew G. Knepley PetscCall(DMGetLabel(dm, "marker", &label)); 153*0ee167adSMatthew G. Knepley PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "dummy", label, 1, values, 0, 0, NULL, NULL, NULL, NULL, NULL)); 154*0ee167adSMatthew G. Knepley PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "dummy", label, 1, values, 1, 0, NULL, NULL, NULL, NULL, NULL)); 155*0ee167adSMatthew G. Knepley } 156*0ee167adSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 157*0ee167adSMatthew G. Knepley } 158*0ee167adSMatthew G. Knepley 159*0ee167adSMatthew G. Knepley static PetscErrorCode CreateSwarm(DM dm, DM *sw, AppCtx *user) 160*0ee167adSMatthew G. Knepley { 161*0ee167adSMatthew G. Knepley PetscScalar *coords, *wvals, *xvals; 162*0ee167adSMatthew G. Knepley PetscInt Npc = user->Npc, dim, Np; 163*0ee167adSMatthew G. Knepley 164*0ee167adSMatthew G. Knepley PetscFunctionBeginUser; 165*0ee167adSMatthew G. Knepley PetscCall(DMGetDimension(dm, &dim)); 166*0ee167adSMatthew G. Knepley 167*0ee167adSMatthew G. Knepley PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw)); 168*0ee167adSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles")); 169*0ee167adSMatthew G. Knepley PetscCall(DMSetType(*sw, DMSWARM)); 170*0ee167adSMatthew G. Knepley PetscCall(DMSetDimension(*sw, dim)); 171*0ee167adSMatthew G. Knepley PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC)); 172*0ee167adSMatthew G. Knepley PetscCall(DMSwarmSetCellDM(*sw, dm)); 173*0ee167adSMatthew G. Knepley PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR)); 174*0ee167adSMatthew G. Knepley PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "x_q", 2, PETSC_SCALAR)); 175*0ee167adSMatthew G. Knepley PetscCall(DMSwarmFinalizeFieldRegister(*sw)); 176*0ee167adSMatthew G. Knepley PetscCall(DMSwarmInsertPointsUsingCellDM(*sw, DMSWARMPIC_LAYOUT_GAUSS, Npc)); 177*0ee167adSMatthew G. Knepley PetscCall(DMSetFromOptions(*sw)); 178*0ee167adSMatthew G. Knepley 179*0ee167adSMatthew G. Knepley PetscCall(DMSwarmGetLocalSize(*sw, &Np)); 180*0ee167adSMatthew G. Knepley PetscCall(DMSwarmGetField(*sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 181*0ee167adSMatthew G. Knepley PetscCall(DMSwarmGetField(*sw, "w_q", NULL, NULL, (void **)&wvals)); 182*0ee167adSMatthew G. Knepley PetscCall(DMSwarmGetField(*sw, "x_q", NULL, NULL, (void **)&xvals)); 183*0ee167adSMatthew G. Knepley for (PetscInt p = 0; p < Np; ++p) { 184*0ee167adSMatthew G. Knepley PetscCall(user->func(dim, 0., &coords[p * dim], 1, &wvals[p], user)); 185*0ee167adSMatthew G. Knepley for (PetscInt c = 0; c < 2; ++c) PetscCall(user->func(dim, 0., &coords[p * dim], 1, &xvals[p * 2 + c], user)); 186*0ee167adSMatthew G. Knepley } 187*0ee167adSMatthew G. Knepley PetscCall(DMSwarmRestoreField(*sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 188*0ee167adSMatthew G. Knepley PetscCall(DMSwarmRestoreField(*sw, "w_q", NULL, NULL, (void **)&wvals)); 189*0ee167adSMatthew G. Knepley PetscCall(DMSwarmRestoreField(*sw, "x_q", NULL, NULL, (void **)&xvals)); 190*0ee167adSMatthew G. Knepley 191*0ee167adSMatthew G. Knepley PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view")); 192*0ee167adSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 193*0ee167adSMatthew G. Knepley } 194*0ee167adSMatthew G. Knepley 195*0ee167adSMatthew G. Knepley static PetscErrorCode computeParticleMoments(DM sw, Vec u, PetscReal moments[3], AppCtx *user) 196*0ee167adSMatthew G. Knepley { 197*0ee167adSMatthew G. Knepley DM dm; 198*0ee167adSMatthew G. Knepley const PetscReal *coords; 199*0ee167adSMatthew G. Knepley const PetscScalar *w; 200*0ee167adSMatthew G. Knepley PetscReal mom[3] = {0.0, 0.0, 0.0}; 201*0ee167adSMatthew G. Knepley PetscInt dim, cStart, cEnd, Nc; 202*0ee167adSMatthew G. Knepley 203*0ee167adSMatthew G. Knepley PetscFunctionBeginUser; 204*0ee167adSMatthew G. Knepley PetscCall(DMGetDimension(sw, &dim)); 205*0ee167adSMatthew G. Knepley PetscCall(DMSwarmGetCellDM(sw, &dm)); 206*0ee167adSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 207*0ee167adSMatthew G. Knepley PetscCall(DMSwarmSortGetAccess(sw)); 208*0ee167adSMatthew G. Knepley PetscCall(DMSwarmGetFieldInfo(sw, user->field ? "x_q" : "w_q", &Nc, NULL)); 209*0ee167adSMatthew G. Knepley PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 210*0ee167adSMatthew G. Knepley PetscCall(VecGetArrayRead(u, &w)); 211*0ee167adSMatthew G. Knepley for (PetscInt cell = cStart; cell < cEnd; ++cell) { 212*0ee167adSMatthew G. Knepley PetscInt *pidx; 213*0ee167adSMatthew G. Knepley PetscInt Np; 214*0ee167adSMatthew G. Knepley 215*0ee167adSMatthew G. Knepley PetscCall(DMSwarmSortGetPointsPerCell(sw, cell, &Np, &pidx)); 216*0ee167adSMatthew G. Knepley for (PetscInt p = 0; p < Np; ++p) { 217*0ee167adSMatthew G. Knepley const PetscInt idx = pidx[p]; 218*0ee167adSMatthew G. Knepley const PetscReal *x = &coords[idx * dim]; 219*0ee167adSMatthew G. Knepley 220*0ee167adSMatthew G. Knepley for (PetscInt c = 0; c < Nc; ++c) { 221*0ee167adSMatthew G. Knepley mom[0] += PetscRealPart(w[idx * Nc + c]); 222*0ee167adSMatthew G. Knepley mom[1] += PetscRealPart(w[idx * Nc + c]) * x[0]; 223*0ee167adSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) mom[2] += PetscRealPart(w[idx * Nc + c]) * PetscSqr(x[d]); 224*0ee167adSMatthew G. Knepley } 225*0ee167adSMatthew G. Knepley } 226*0ee167adSMatthew G. Knepley PetscCall(PetscFree(pidx)); 227*0ee167adSMatthew G. Knepley } 228*0ee167adSMatthew G. Knepley PetscCall(VecRestoreArrayRead(u, &w)); 229*0ee167adSMatthew G. Knepley PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords)); 230*0ee167adSMatthew G. Knepley PetscCall(DMSwarmSortRestoreAccess(sw)); 231*0ee167adSMatthew G. Knepley PetscCall(MPIU_Allreduce(mom, moments, 3, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)sw))); 232*0ee167adSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 233*0ee167adSMatthew G. Knepley } 234*0ee167adSMatthew G. Knepley 235*0ee167adSMatthew G. Knepley 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[]) 236*0ee167adSMatthew G. Knepley { 237*0ee167adSMatthew G. Knepley const PetscInt Nc = uOff[1] - uOff[0]; 238*0ee167adSMatthew G. Knepley 239*0ee167adSMatthew G. Knepley for (PetscInt c = 0; c < Nc; ++c) f0[0] += u[c]; 240*0ee167adSMatthew G. Knepley } 241*0ee167adSMatthew G. Knepley 242*0ee167adSMatthew G. Knepley 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[]) 243*0ee167adSMatthew G. Knepley { 244*0ee167adSMatthew G. Knepley const PetscInt Nc = uOff[1] - uOff[0]; 245*0ee167adSMatthew G. Knepley 246*0ee167adSMatthew G. Knepley for (PetscInt c = 0; c < Nc; ++c) f0[0] += x[0] * u[c]; 247*0ee167adSMatthew G. Knepley } 248*0ee167adSMatthew G. Knepley 249*0ee167adSMatthew G. Knepley 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[]) 250*0ee167adSMatthew G. Knepley { 251*0ee167adSMatthew G. Knepley const PetscInt Nc = uOff[1] - uOff[0]; 252*0ee167adSMatthew G. Knepley 253*0ee167adSMatthew G. Knepley for (PetscInt c = 0; c < Nc; ++c) 254*0ee167adSMatthew G. Knepley for (PetscInt d = 0; d < dim; ++d) f0[0] += PetscSqr(x[d]) * u[c]; 255*0ee167adSMatthew G. Knepley } 256*0ee167adSMatthew G. Knepley 257*0ee167adSMatthew G. Knepley static PetscErrorCode computeFieldMoments(DM dm, Vec u, PetscReal moments[3], AppCtx *user) 258*0ee167adSMatthew G. Knepley { 259*0ee167adSMatthew G. Knepley PetscDS ds; 260*0ee167adSMatthew G. Knepley PetscScalar mom; 261*0ee167adSMatthew G. Knepley 262*0ee167adSMatthew G. Knepley PetscFunctionBeginUser; 263*0ee167adSMatthew G. Knepley PetscCall(DMGetDS(dm, &ds)); 264*0ee167adSMatthew G. Knepley PetscCall(PetscDSSetObjective(ds, 0, &f0_1)); 265*0ee167adSMatthew G. Knepley mom = 0.; 266*0ee167adSMatthew G. Knepley PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 267*0ee167adSMatthew G. Knepley moments[0] = PetscRealPart(mom); 268*0ee167adSMatthew G. Knepley PetscCall(PetscDSSetObjective(ds, 0, &f0_x)); 269*0ee167adSMatthew G. Knepley mom = 0.; 270*0ee167adSMatthew G. Knepley PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 271*0ee167adSMatthew G. Knepley moments[1] = PetscRealPart(mom); 272*0ee167adSMatthew G. Knepley PetscCall(PetscDSSetObjective(ds, 0, &f0_r2)); 273*0ee167adSMatthew G. Knepley mom = 0.; 274*0ee167adSMatthew G. Knepley PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user)); 275*0ee167adSMatthew G. Knepley moments[2] = PetscRealPart(mom); 276*0ee167adSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 277*0ee167adSMatthew G. Knepley } 278*0ee167adSMatthew G. Knepley 279*0ee167adSMatthew G. Knepley static PetscErrorCode TestParticlesToField(DM sw, DM dm, Vec fhat, AppCtx *user) 280*0ee167adSMatthew G. Knepley { 281*0ee167adSMatthew G. Knepley const char *fieldnames[1] = {user->field ? "x_q" : "w_q"}; 282*0ee167adSMatthew G. Knepley Vec fields[1] = {fhat}, f; 283*0ee167adSMatthew G. Knepley PetscReal pmoments[3]; // \int f, \int x f, \int r^2 f 284*0ee167adSMatthew G. Knepley PetscReal fmoments[3]; // \int \hat f, \int x \hat f, \int r^2 \hat f 285*0ee167adSMatthew G. Knepley 286*0ee167adSMatthew G. Knepley PetscFunctionBeginUser; 287*0ee167adSMatthew G. Knepley PetscCall(DMSwarmProjectFields(sw, dm, 1, fieldnames, fields, SCATTER_FORWARD)); 288*0ee167adSMatthew G. Knepley 289*0ee167adSMatthew G. Knepley PetscCall(DMSwarmCreateGlobalVectorFromField(sw, fieldnames[0], &f)); 290*0ee167adSMatthew G. Knepley PetscCall(computeParticleMoments(sw, f, pmoments, user)); 291*0ee167adSMatthew G. Knepley PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, fieldnames[0], &f)); 292*0ee167adSMatthew G. Knepley PetscCall(computeFieldMoments(dm, fhat, fmoments, user)); 293*0ee167adSMatthew G. Knepley PetscCall(VecViewFromOptions(fhat, NULL, "-fhat_view")); 294*0ee167adSMatthew G. Knepley PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "L2 projection mass: %20.10e, x-momentum: %20.10e, energy: %20.10e.\n", fmoments[0], fmoments[1], fmoments[2])); 295*0ee167adSMatthew G. Knepley for (PetscInt m = 0; m < user->Nm; ++m) { 296*0ee167adSMatthew G. Knepley if (user->pass) { 297*0ee167adSMatthew G. Knepley if (PetscAbsReal((fmoments[m] - pmoments[m]) / fmoments[m]) > user->mtol) { 298*0ee167adSMatthew G. Knepley PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "p projection mass: %20.10e, x-momentum: %20.10e, energy: %20.10e.\n", pmoments[0], pmoments[1], pmoments[2])); 299*0ee167adSMatthew G. Knepley } 300*0ee167adSMatthew G. Knepley } else { 301*0ee167adSMatthew G. Knepley PetscCheck(PetscAbsReal((fmoments[m] - pmoments[m]) / fmoments[m]) <= user->mtol, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Moment %" PetscInt_FMT " error too large %g > %g", m, PetscAbsReal((fmoments[m] - pmoments[m]) / fmoments[m]), 302*0ee167adSMatthew G. Knepley user->mtol); 303*0ee167adSMatthew G. Knepley } 304*0ee167adSMatthew G. Knepley } 305*0ee167adSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 306*0ee167adSMatthew G. Knepley } 307*0ee167adSMatthew G. Knepley 308*0ee167adSMatthew G. Knepley static PetscErrorCode TestFieldToParticles(DM sw, DM dm, Vec fhat, AppCtx *user) 309*0ee167adSMatthew G. Knepley { 310*0ee167adSMatthew G. Knepley const char *fieldnames[1] = {user->field ? "x_q" : "w_q"}; 311*0ee167adSMatthew G. Knepley Vec fields[1] = {fhat}, f; 312*0ee167adSMatthew G. Knepley PetscReal pmoments[3]; // \int f, \int x f, \int r^2 f 313*0ee167adSMatthew G. Knepley PetscReal fmoments[3]; // \int \hat f, \int x \hat f, \int r^2 \hat f 314*0ee167adSMatthew G. Knepley 315*0ee167adSMatthew G. Knepley PetscFunctionBeginUser; 316*0ee167adSMatthew G. Knepley PetscCall(DMSwarmProjectFields(sw, dm, 1, fieldnames, fields, SCATTER_REVERSE)); 317*0ee167adSMatthew G. Knepley 318*0ee167adSMatthew G. Knepley PetscCall(DMSwarmCreateGlobalVectorFromField(sw, fieldnames[0], &f)); 319*0ee167adSMatthew G. Knepley PetscCall(computeParticleMoments(sw, f, pmoments, user)); 320*0ee167adSMatthew G. Knepley PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, fieldnames[0], &f)); 321*0ee167adSMatthew G. Knepley PetscCall(computeFieldMoments(dm, fhat, fmoments, user)); 322*0ee167adSMatthew G. Knepley PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "L2 projection mass: %20.10e, x-momentum: %20.10e, energy: %20.10e.\n", fmoments[0], fmoments[1], fmoments[2])); 323*0ee167adSMatthew G. Knepley for (PetscInt m = 0; m < user->Nm; ++m) { 324*0ee167adSMatthew G. Knepley if (user->pass) { 325*0ee167adSMatthew G. Knepley if (PetscAbsReal((fmoments[m] - pmoments[m]) / fmoments[m]) > user->mtol) { 326*0ee167adSMatthew G. Knepley PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "p projection mass: %20.10e, x-momentum: %20.10e, energy: %20.10e.\n", pmoments[0], pmoments[1], pmoments[2])); 327*0ee167adSMatthew G. Knepley } 328*0ee167adSMatthew G. Knepley } else { 329*0ee167adSMatthew G. Knepley PetscCheck(PetscAbsReal((fmoments[m] - pmoments[m]) / fmoments[m]) <= user->mtol, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Moment %" PetscInt_FMT " error too large %g > %g", m, PetscAbsReal((fmoments[m] - pmoments[m]) / fmoments[m]), 330*0ee167adSMatthew G. Knepley user->mtol); 331*0ee167adSMatthew G. Knepley } 332*0ee167adSMatthew G. Knepley } 333*0ee167adSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 334*0ee167adSMatthew G. Knepley } 335*0ee167adSMatthew G. Knepley 336*0ee167adSMatthew G. Knepley int main(int argc, char *argv[]) 337*0ee167adSMatthew G. Knepley { 338*0ee167adSMatthew G. Knepley DM dm, subdm, sw; 339*0ee167adSMatthew G. Knepley Vec fhat; 340*0ee167adSMatthew G. Knepley IS subis; 341*0ee167adSMatthew G. Knepley AppCtx user; 342*0ee167adSMatthew G. Knepley 343*0ee167adSMatthew G. Knepley PetscFunctionBeginUser; 344*0ee167adSMatthew G. Knepley PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 345*0ee167adSMatthew G. Knepley PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user)); 346*0ee167adSMatthew G. Knepley PetscCall(CreateMesh(PETSC_COMM_WORLD, &dm, &user)); 347*0ee167adSMatthew G. Knepley PetscCall(CreateDiscretization(dm, &user)); 348*0ee167adSMatthew G. Knepley PetscCall(CreateSwarm(dm, &sw, &user)); 349*0ee167adSMatthew G. Knepley 350*0ee167adSMatthew G. Knepley PetscCall(DMCreateSubDM(dm, 1, &user.field, &subis, &subdm)); 351*0ee167adSMatthew G. Knepley 352*0ee167adSMatthew G. Knepley PetscCall(DMGetGlobalVector(subdm, &fhat)); 353*0ee167adSMatthew G. Knepley PetscCall(PetscObjectSetName((PetscObject)fhat, "FEM f")); 354*0ee167adSMatthew G. Knepley PetscCall(TestParticlesToField(sw, subdm, fhat, &user)); 355*0ee167adSMatthew G. Knepley PetscCall(TestFieldToParticles(sw, subdm, fhat, &user)); 356*0ee167adSMatthew G. Knepley PetscCall(DMRestoreGlobalVector(subdm, &fhat)); 357*0ee167adSMatthew G. Knepley 358*0ee167adSMatthew G. Knepley PetscCall(ISDestroy(&subis)); 359*0ee167adSMatthew G. Knepley PetscCall(DMDestroy(&subdm)); 360*0ee167adSMatthew G. Knepley PetscCall(DMDestroy(&dm)); 361*0ee167adSMatthew G. Knepley PetscCall(DMDestroy(&sw)); 362*0ee167adSMatthew G. Knepley PetscCall(PetscFinalize()); 363*0ee167adSMatthew G. Knepley return 0; 364*0ee167adSMatthew G. Knepley } 365*0ee167adSMatthew G. Knepley 366*0ee167adSMatthew G. Knepley /*TEST 367*0ee167adSMatthew G. Knepley 368*0ee167adSMatthew G. Knepley # Swarm does not handle complex or quad 369*0ee167adSMatthew G. Knepley build: 370*0ee167adSMatthew G. Knepley requires: !complex double 371*0ee167adSMatthew G. Knepley 372*0ee167adSMatthew G. Knepley testset: 373*0ee167adSMatthew G. Knepley requires: triangle 374*0ee167adSMatthew G. Knepley args: -dm_refine 1 -petscspace_degree 2 -moments 3 \ 375*0ee167adSMatthew G. Knepley -ptof_pc_type lu \ 376*0ee167adSMatthew G. Knepley -ftop_ksp_rtol 1e-15 -ftop_ksp_type lsqr -ftop_pc_type none 377*0ee167adSMatthew G. Knepley 378*0ee167adSMatthew G. Knepley test: 379*0ee167adSMatthew G. Knepley suffix: tri_fe_f0 380*0ee167adSMatthew G. Knepley args: -field 0 381*0ee167adSMatthew G. Knepley 382*0ee167adSMatthew G. Knepley test: 383*0ee167adSMatthew G. Knepley suffix: tri_fe_f1 384*0ee167adSMatthew G. Knepley args: -field 1 385*0ee167adSMatthew G. Knepley 386*0ee167adSMatthew G. Knepley test: 387*0ee167adSMatthew G. Knepley suffix: quad_fe_f0 388*0ee167adSMatthew G. Knepley args: -dm_plex_simplex 0 -field 0 389*0ee167adSMatthew G. Knepley 390*0ee167adSMatthew G. Knepley test: 391*0ee167adSMatthew G. Knepley suffix: quad_fe_f1 392*0ee167adSMatthew G. Knepley args: -dm_plex_simplex 0 -field 1 393*0ee167adSMatthew G. Knepley 394*0ee167adSMatthew G. Knepley testset: 395*0ee167adSMatthew G. Knepley requires: triangle 396*0ee167adSMatthew G. Knepley args: -dm_refine 1 -moments 1 -fv \ 397*0ee167adSMatthew G. Knepley -ptof_pc_type lu \ 398*0ee167adSMatthew G. Knepley -ftop_ksp_rtol 1e-15 -ftop_ksp_type lsqr -ftop_pc_type none 399*0ee167adSMatthew G. Knepley 400*0ee167adSMatthew G. Knepley test: 401*0ee167adSMatthew G. Knepley suffix: tri_fv_f0 402*0ee167adSMatthew G. Knepley args: -field 0 403*0ee167adSMatthew G. Knepley 404*0ee167adSMatthew G. Knepley test: 405*0ee167adSMatthew G. Knepley suffix: tri_fv_f1 406*0ee167adSMatthew G. Knepley args: -field 1 407*0ee167adSMatthew G. Knepley 408*0ee167adSMatthew G. Knepley test: 409*0ee167adSMatthew G. Knepley suffix: quad_fv_f0 410*0ee167adSMatthew G. Knepley args: -dm_plex_simplex 0 -field 0 411*0ee167adSMatthew G. Knepley 412*0ee167adSMatthew G. Knepley test: 413*0ee167adSMatthew G. Knepley suffix: quad_fv_f1 414*0ee167adSMatthew G. Knepley args: -dm_plex_simplex 0 -field 1 415*0ee167adSMatthew G. Knepley 416*0ee167adSMatthew G. Knepley TEST*/ 417