xref: /petsc/src/dm/impls/swarm/tests/ex11.c (revision d8b4a0667a1b407f3333490918f86a8a6bfb26b1)
10ee167adSMatthew G. Knepley static char help[] = "Tests multifield and multicomponent L2 projection.\n";
20ee167adSMatthew G. Knepley 
30ee167adSMatthew G. Knepley #include <petscdmswarm.h>
40ee167adSMatthew G. Knepley #include <petscksp.h>
50ee167adSMatthew G. Knepley #include <petscdmplex.h>
60ee167adSMatthew G. Knepley #include <petscds.h>
70ee167adSMatthew G. Knepley 
80ee167adSMatthew G. Knepley typedef struct {
90ee167adSMatthew G. Knepley   PetscBool           pass;  // Don't fail when moments are wrong
100ee167adSMatthew G. Knepley   PetscBool           fv;    // Use an FV discretization, instead of FE
110ee167adSMatthew G. Knepley   PetscInt            Npc;   // The number of partices per cell
120ee167adSMatthew G. Knepley   PetscInt            field; // The field to project
130ee167adSMatthew G. Knepley   PetscInt            Nm;    // The number of moments to match
140ee167adSMatthew G. Knepley   PetscReal           mtol;  // Tolerance for checking moment conservation
150ee167adSMatthew G. Knepley   PetscSimplePointFn *func;  // Function used to set particle weights
160ee167adSMatthew G. Knepley } AppCtx;
170ee167adSMatthew G. Knepley 
180ee167adSMatthew G. Knepley typedef enum {
190ee167adSMatthew G. Knepley   FUNCTION_CONSTANT,
200ee167adSMatthew G. Knepley   FUNCTION_LINEAR,
210ee167adSMatthew G. Knepley   FUNCTION_SIN,
220ee167adSMatthew G. Knepley   FUNCTION_X2_X4,
230ee167adSMatthew G. Knepley   FUNCTION_UNKNOWN,
240ee167adSMatthew G. Knepley   NUM_FUNCTIONS
250ee167adSMatthew G. Knepley } FunctionType;
260ee167adSMatthew G. Knepley const char *const FunctionTypes[] = {"constant", "linear", "sin", "x2_x4", "unknown", "FunctionType", "FUNCTION_", NULL};
270ee167adSMatthew G. Knepley 
280ee167adSMatthew G. Knepley static PetscErrorCode constant(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
290ee167adSMatthew G. Knepley {
300ee167adSMatthew G. Knepley   u[0] = 1.0;
310ee167adSMatthew G. Knepley   return PETSC_SUCCESS;
320ee167adSMatthew G. Knepley }
330ee167adSMatthew G. Knepley 
340ee167adSMatthew G. Knepley static PetscErrorCode linear(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
350ee167adSMatthew G. Knepley {
360ee167adSMatthew G. Knepley   u[0] = 0.0;
370ee167adSMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) u[0] += x[d];
380ee167adSMatthew G. Knepley   return PETSC_SUCCESS;
390ee167adSMatthew G. Knepley }
400ee167adSMatthew G. Knepley 
410ee167adSMatthew G. Knepley static PetscErrorCode sinx(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
420ee167adSMatthew G. Knepley {
430ee167adSMatthew G. Knepley   u[0] = 1;
440ee167adSMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) u[0] *= PetscSinReal(2. * PETSC_PI * x[d]);
450ee167adSMatthew G. Knepley   return PETSC_SUCCESS;
460ee167adSMatthew G. Knepley }
470ee167adSMatthew G. Knepley 
480ee167adSMatthew G. Knepley static PetscErrorCode x2_x4(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
490ee167adSMatthew G. Knepley {
500ee167adSMatthew G. Knepley   u[0] = 1;
510ee167adSMatthew G. Knepley   for (PetscInt d = 0; d < dim; ++d) u[0] *= PetscSqr(x[d]) - PetscSqr(PetscSqr(x[d]));
520ee167adSMatthew G. Knepley   return PETSC_SUCCESS;
530ee167adSMatthew G. Knepley }
540ee167adSMatthew G. Knepley 
550ee167adSMatthew G. Knepley static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
560ee167adSMatthew G. Knepley {
570ee167adSMatthew G. Knepley   FunctionType func = FUNCTION_LINEAR;
580ee167adSMatthew G. Knepley   PetscBool    flg;
590ee167adSMatthew G. Knepley 
600ee167adSMatthew G. Knepley   PetscFunctionBeginUser;
610ee167adSMatthew G. Knepley   options->pass  = PETSC_FALSE;
620ee167adSMatthew G. Knepley   options->fv    = PETSC_FALSE;
630ee167adSMatthew G. Knepley   options->Npc   = 1;
640ee167adSMatthew G. Knepley   options->field = 0;
650ee167adSMatthew G. Knepley   options->Nm    = 1;
660ee167adSMatthew G. Knepley   options->mtol  = 100. * PETSC_MACHINE_EPSILON;
670ee167adSMatthew G. Knepley 
680ee167adSMatthew G. Knepley   PetscOptionsBegin(comm, "", "L2 Projection Options", "DMPLEX");
690ee167adSMatthew G. Knepley   PetscCall(PetscOptionsBool("-pass", "Don't fail when moments are wrong", __FILE__, options->pass, &options->pass, NULL));
700ee167adSMatthew G. Knepley   PetscCall(PetscOptionsBool("-fv", "Use FV instead of FE", __FILE__, options->fv, &options->fv, NULL));
710ee167adSMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-npc", "Number of particles per cell", __FILE__, options->Npc, &options->Npc, NULL, 1));
720ee167adSMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-field", "The field to project", __FILE__, options->field, &options->field, NULL, 0));
730ee167adSMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-moments", "Number of moments to match", __FILE__, options->Nm, &options->Nm, NULL, 0));
740ee167adSMatthew G. Knepley   PetscCheck(options->Nm < 4, comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot match %" PetscInt_FMT " > 3 moments", options->Nm);
750ee167adSMatthew G. Knepley   PetscCall(PetscOptionsReal("-mtol", "Tolerance for moment checks", "ex2.c", options->mtol, &options->mtol, NULL));
760ee167adSMatthew G. Knepley   PetscCall(PetscOptionsEnum("-func", "Type of particle weight function", __FILE__, FunctionTypes, (PetscEnum)func, (PetscEnum *)&func, &flg));
770ee167adSMatthew G. Knepley   switch (func) {
780ee167adSMatthew G. Knepley   case FUNCTION_CONSTANT:
790ee167adSMatthew G. Knepley     options->func = constant;
800ee167adSMatthew G. Knepley     break;
810ee167adSMatthew G. Knepley   case FUNCTION_LINEAR:
820ee167adSMatthew G. Knepley     options->func = linear;
830ee167adSMatthew G. Knepley     break;
840ee167adSMatthew G. Knepley   case FUNCTION_SIN:
850ee167adSMatthew G. Knepley     options->func = sinx;
860ee167adSMatthew G. Knepley     break;
870ee167adSMatthew G. Knepley   case FUNCTION_X2_X4:
880ee167adSMatthew G. Knepley     options->func = x2_x4;
890ee167adSMatthew G. Knepley     break;
900ee167adSMatthew G. Knepley   default:
91*d8b4a066SPierre Jolivet     PetscCheck(flg, comm, PETSC_ERR_ARG_WRONG, "Cannot handle function \"%s\"", FunctionTypes[func]);
920ee167adSMatthew G. Knepley   }
930ee167adSMatthew G. Knepley   PetscOptionsEnd();
940ee167adSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
950ee167adSMatthew G. Knepley }
960ee167adSMatthew G. Knepley 
970ee167adSMatthew G. Knepley static PetscErrorCode CreateMesh(MPI_Comm comm, DM *dm, AppCtx *user)
980ee167adSMatthew G. Knepley {
990ee167adSMatthew G. Knepley   PetscFunctionBeginUser;
1000ee167adSMatthew G. Knepley   PetscCall(DMCreate(comm, dm));
1010ee167adSMatthew G. Knepley   PetscCall(DMSetType(*dm, DMPLEX));
1020ee167adSMatthew G. Knepley   PetscCall(DMSetFromOptions(*dm));
1030ee167adSMatthew G. Knepley   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
1040ee167adSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1050ee167adSMatthew G. Knepley }
1060ee167adSMatthew G. Knepley 
1070ee167adSMatthew G. Knepley static PetscErrorCode CreateDiscretization(DM dm, AppCtx *user)
1080ee167adSMatthew G. Knepley {
1090ee167adSMatthew G. Knepley   PetscFE        fe;
1100ee167adSMatthew G. Knepley   PetscFV        fv;
1110ee167adSMatthew G. Knepley   DMPolytopeType ct;
1120ee167adSMatthew G. Knepley   PetscInt       dim, cStart;
1130ee167adSMatthew G. Knepley 
1140ee167adSMatthew G. Knepley   PetscFunctionBeginUser;
1150ee167adSMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
1160ee167adSMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
1170ee167adSMatthew G. Knepley   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
1180ee167adSMatthew G. Knepley   if (user->fv) {
1190ee167adSMatthew G. Knepley     PetscCall(PetscFVCreate(PETSC_COMM_SELF, &fv));
1200ee167adSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)fv, "fv"));
1210ee167adSMatthew G. Knepley     PetscCall(PetscFVSetNumComponents(fv, 1));
1220ee167adSMatthew G. Knepley     PetscCall(PetscFVSetSpatialDimension(fv, dim));
1230ee167adSMatthew G. Knepley     PetscCall(PetscFVCreateDualSpace(fv, ct));
1240ee167adSMatthew G. Knepley     PetscCall(PetscFVSetFromOptions(fv));
1250ee167adSMatthew G. Knepley     PetscCall(DMAddField(dm, NULL, (PetscObject)fv));
1260ee167adSMatthew G. Knepley     PetscCall(PetscFVDestroy(&fv));
1270ee167adSMatthew G. Knepley     PetscCall(PetscFVCreate(PETSC_COMM_SELF, &fv));
1280ee167adSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)fv, "fv2"));
1290ee167adSMatthew G. Knepley     PetscCall(PetscFVSetNumComponents(fv, 2));
1300ee167adSMatthew G. Knepley     PetscCall(PetscFVSetSpatialDimension(fv, dim));
1310ee167adSMatthew G. Knepley     PetscCall(PetscFVCreateDualSpace(fv, ct));
1320ee167adSMatthew G. Knepley     PetscCall(PetscFVSetFromOptions(fv));
1330ee167adSMatthew G. Knepley     PetscCall(DMAddField(dm, NULL, (PetscObject)fv));
1340ee167adSMatthew G. Knepley     PetscCall(PetscFVDestroy(&fv));
1350ee167adSMatthew G. Knepley   } else {
1360ee167adSMatthew G. Knepley     PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, NULL, -1, &fe));
1370ee167adSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)fe, "fe"));
1380ee167adSMatthew G. Knepley     PetscCall(DMAddField(dm, NULL, (PetscObject)fe));
1390ee167adSMatthew G. Knepley     PetscCall(PetscFEDestroy(&fe));
1400ee167adSMatthew G. Knepley     PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 2, ct, NULL, -1, &fe));
1410ee167adSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)fe, "fe2"));
1420ee167adSMatthew G. Knepley     PetscCall(DMAddField(dm, NULL, (PetscObject)fe));
1430ee167adSMatthew G. Knepley     PetscCall(PetscFEDestroy(&fe));
1440ee167adSMatthew G. Knepley   }
1450ee167adSMatthew G. Knepley   PetscCall(DMCreateDS(dm));
1460ee167adSMatthew G. Knepley   if (user->fv) {
1470ee167adSMatthew G. Knepley     DMLabel  label;
1480ee167adSMatthew G. Knepley     PetscInt values[1] = {1};
1490ee167adSMatthew G. Knepley 
1500ee167adSMatthew G. Knepley     PetscCall(DMCreateLabel(dm, "ghost"));
1510ee167adSMatthew G. Knepley     PetscCall(DMGetLabel(dm, "marker", &label));
1520ee167adSMatthew G. Knepley     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "dummy", label, 1, values, 0, 0, NULL, NULL, NULL, NULL, NULL));
1530ee167adSMatthew G. Knepley     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "dummy", label, 1, values, 1, 0, NULL, NULL, NULL, NULL, NULL));
1540ee167adSMatthew G. Knepley   }
1550ee167adSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1560ee167adSMatthew G. Knepley }
1570ee167adSMatthew G. Knepley 
1580ee167adSMatthew G. Knepley static PetscErrorCode CreateSwarm(DM dm, DM *sw, AppCtx *user)
1590ee167adSMatthew G. Knepley {
1600ee167adSMatthew G. Knepley   PetscScalar *coords, *wvals, *xvals;
1610ee167adSMatthew G. Knepley   PetscInt     Npc = user->Npc, dim, Np;
1620ee167adSMatthew G. Knepley 
1630ee167adSMatthew G. Knepley   PetscFunctionBeginUser;
1640ee167adSMatthew G. Knepley   PetscCall(DMGetDimension(dm, &dim));
1650ee167adSMatthew G. Knepley 
1660ee167adSMatthew G. Knepley   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), sw));
1670ee167adSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)*sw, "Particles"));
1680ee167adSMatthew G. Knepley   PetscCall(DMSetType(*sw, DMSWARM));
1690ee167adSMatthew G. Knepley   PetscCall(DMSetDimension(*sw, dim));
1700ee167adSMatthew G. Knepley   PetscCall(DMSwarmSetType(*sw, DMSWARM_PIC));
1710ee167adSMatthew G. Knepley   PetscCall(DMSwarmSetCellDM(*sw, dm));
1720ee167adSMatthew G. Knepley   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR));
1730ee167adSMatthew G. Knepley   PetscCall(DMSwarmRegisterPetscDatatypeField(*sw, "x_q", 2, PETSC_SCALAR));
1740ee167adSMatthew G. Knepley   PetscCall(DMSwarmFinalizeFieldRegister(*sw));
1750ee167adSMatthew G. Knepley   PetscCall(DMSwarmInsertPointsUsingCellDM(*sw, DMSWARMPIC_LAYOUT_GAUSS, Npc));
1760ee167adSMatthew G. Knepley   PetscCall(DMSetFromOptions(*sw));
1770ee167adSMatthew G. Knepley 
1780ee167adSMatthew G. Knepley   PetscCall(DMSwarmGetLocalSize(*sw, &Np));
1790ee167adSMatthew G. Knepley   PetscCall(DMSwarmGetField(*sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1800ee167adSMatthew G. Knepley   PetscCall(DMSwarmGetField(*sw, "w_q", NULL, NULL, (void **)&wvals));
1810ee167adSMatthew G. Knepley   PetscCall(DMSwarmGetField(*sw, "x_q", NULL, NULL, (void **)&xvals));
1820ee167adSMatthew G. Knepley   for (PetscInt p = 0; p < Np; ++p) {
1830ee167adSMatthew G. Knepley     PetscCall(user->func(dim, 0., &coords[p * dim], 1, &wvals[p], user));
1840ee167adSMatthew G. Knepley     for (PetscInt c = 0; c < 2; ++c) PetscCall(user->func(dim, 0., &coords[p * dim], 1, &xvals[p * 2 + c], user));
1850ee167adSMatthew G. Knepley   }
1860ee167adSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(*sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
1870ee167adSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(*sw, "w_q", NULL, NULL, (void **)&wvals));
1880ee167adSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(*sw, "x_q", NULL, NULL, (void **)&xvals));
1890ee167adSMatthew G. Knepley 
1900ee167adSMatthew G. Knepley   PetscCall(DMViewFromOptions(*sw, NULL, "-sw_view"));
1910ee167adSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
1920ee167adSMatthew G. Knepley }
1930ee167adSMatthew G. Knepley 
1940ee167adSMatthew G. Knepley static PetscErrorCode computeParticleMoments(DM sw, Vec u, PetscReal moments[3], AppCtx *user)
1950ee167adSMatthew G. Knepley {
1960ee167adSMatthew G. Knepley   DM                 dm;
1970ee167adSMatthew G. Knepley   const PetscReal   *coords;
1980ee167adSMatthew G. Knepley   const PetscScalar *w;
1990ee167adSMatthew G. Knepley   PetscReal          mom[3] = {0.0, 0.0, 0.0};
2000ee167adSMatthew G. Knepley   PetscInt           dim, cStart, cEnd, Nc;
2010ee167adSMatthew G. Knepley 
2020ee167adSMatthew G. Knepley   PetscFunctionBeginUser;
2030ee167adSMatthew G. Knepley   PetscCall(DMGetDimension(sw, &dim));
2040ee167adSMatthew G. Knepley   PetscCall(DMSwarmGetCellDM(sw, &dm));
2050ee167adSMatthew G. Knepley   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2060ee167adSMatthew G. Knepley   PetscCall(DMSwarmSortGetAccess(sw));
2070ee167adSMatthew G. Knepley   PetscCall(DMSwarmGetFieldInfo(sw, user->field ? "x_q" : "w_q", &Nc, NULL));
2080ee167adSMatthew G. Knepley   PetscCall(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2090ee167adSMatthew G. Knepley   PetscCall(VecGetArrayRead(u, &w));
2100ee167adSMatthew G. Knepley   for (PetscInt cell = cStart; cell < cEnd; ++cell) {
2110ee167adSMatthew G. Knepley     PetscInt *pidx;
2120ee167adSMatthew G. Knepley     PetscInt  Np;
2130ee167adSMatthew G. Knepley 
2140ee167adSMatthew G. Knepley     PetscCall(DMSwarmSortGetPointsPerCell(sw, cell, &Np, &pidx));
2150ee167adSMatthew G. Knepley     for (PetscInt p = 0; p < Np; ++p) {
2160ee167adSMatthew G. Knepley       const PetscInt   idx = pidx[p];
2170ee167adSMatthew G. Knepley       const PetscReal *x   = &coords[idx * dim];
2180ee167adSMatthew G. Knepley 
2190ee167adSMatthew G. Knepley       for (PetscInt c = 0; c < Nc; ++c) {
2200ee167adSMatthew G. Knepley         mom[0] += PetscRealPart(w[idx * Nc + c]);
2210ee167adSMatthew G. Knepley         mom[1] += PetscRealPart(w[idx * Nc + c]) * x[0];
2220ee167adSMatthew G. Knepley         for (PetscInt d = 0; d < dim; ++d) mom[2] += PetscRealPart(w[idx * Nc + c]) * PetscSqr(x[d]);
2230ee167adSMatthew G. Knepley       }
2240ee167adSMatthew G. Knepley     }
2250ee167adSMatthew G. Knepley     PetscCall(PetscFree(pidx));
2260ee167adSMatthew G. Knepley   }
2270ee167adSMatthew G. Knepley   PetscCall(VecRestoreArrayRead(u, &w));
2280ee167adSMatthew G. Knepley   PetscCall(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **)&coords));
2290ee167adSMatthew G. Knepley   PetscCall(DMSwarmSortRestoreAccess(sw));
2300ee167adSMatthew G. Knepley   PetscCall(MPIU_Allreduce(mom, moments, 3, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)sw)));
2310ee167adSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2320ee167adSMatthew G. Knepley }
2330ee167adSMatthew G. Knepley 
2340ee167adSMatthew 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[])
2350ee167adSMatthew G. Knepley {
2360ee167adSMatthew G. Knepley   const PetscInt Nc = uOff[1] - uOff[0];
2370ee167adSMatthew G. Knepley 
2380ee167adSMatthew G. Knepley   for (PetscInt c = 0; c < Nc; ++c) f0[0] += u[c];
2390ee167adSMatthew G. Knepley }
2400ee167adSMatthew G. Knepley 
2410ee167adSMatthew 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[])
2420ee167adSMatthew G. Knepley {
2430ee167adSMatthew G. Knepley   const PetscInt Nc = uOff[1] - uOff[0];
2440ee167adSMatthew G. Knepley 
2450ee167adSMatthew G. Knepley   for (PetscInt c = 0; c < Nc; ++c) f0[0] += x[0] * u[c];
2460ee167adSMatthew G. Knepley }
2470ee167adSMatthew G. Knepley 
2480ee167adSMatthew 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[])
2490ee167adSMatthew G. Knepley {
2500ee167adSMatthew G. Knepley   const PetscInt Nc = uOff[1] - uOff[0];
2510ee167adSMatthew G. Knepley 
2520ee167adSMatthew G. Knepley   for (PetscInt c = 0; c < Nc; ++c)
2530ee167adSMatthew G. Knepley     for (PetscInt d = 0; d < dim; ++d) f0[0] += PetscSqr(x[d]) * u[c];
2540ee167adSMatthew G. Knepley }
2550ee167adSMatthew G. Knepley 
2560ee167adSMatthew G. Knepley static PetscErrorCode computeFieldMoments(DM dm, Vec u, PetscReal moments[3], AppCtx *user)
2570ee167adSMatthew G. Knepley {
2580ee167adSMatthew G. Knepley   PetscDS     ds;
2590ee167adSMatthew G. Knepley   PetscScalar mom;
2600ee167adSMatthew G. Knepley 
2610ee167adSMatthew G. Knepley   PetscFunctionBeginUser;
2620ee167adSMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
2630ee167adSMatthew G. Knepley   PetscCall(PetscDSSetObjective(ds, 0, &f0_1));
2640ee167adSMatthew G. Knepley   mom = 0.;
2650ee167adSMatthew G. Knepley   PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user));
2660ee167adSMatthew G. Knepley   moments[0] = PetscRealPart(mom);
2670ee167adSMatthew G. Knepley   PetscCall(PetscDSSetObjective(ds, 0, &f0_x));
2680ee167adSMatthew G. Knepley   mom = 0.;
2690ee167adSMatthew G. Knepley   PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user));
2700ee167adSMatthew G. Knepley   moments[1] = PetscRealPart(mom);
2710ee167adSMatthew G. Knepley   PetscCall(PetscDSSetObjective(ds, 0, &f0_r2));
2720ee167adSMatthew G. Knepley   mom = 0.;
2730ee167adSMatthew G. Knepley   PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, user));
2740ee167adSMatthew G. Knepley   moments[2] = PetscRealPart(mom);
2750ee167adSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
2760ee167adSMatthew G. Knepley }
2770ee167adSMatthew G. Knepley 
2780ee167adSMatthew G. Knepley static PetscErrorCode TestParticlesToField(DM sw, DM dm, Vec fhat, AppCtx *user)
2790ee167adSMatthew G. Knepley {
2800ee167adSMatthew G. Knepley   const char *fieldnames[1] = {user->field ? "x_q" : "w_q"};
2810ee167adSMatthew G. Knepley   Vec         fields[1]     = {fhat}, f;
2820ee167adSMatthew G. Knepley   PetscReal   pmoments[3]; // \int f, \int x f, \int r^2 f
2830ee167adSMatthew G. Knepley   PetscReal   fmoments[3]; // \int \hat f, \int x \hat f, \int r^2 \hat f
2840ee167adSMatthew G. Knepley 
2850ee167adSMatthew G. Knepley   PetscFunctionBeginUser;
2860ee167adSMatthew G. Knepley   PetscCall(DMSwarmProjectFields(sw, dm, 1, fieldnames, fields, SCATTER_FORWARD));
2870ee167adSMatthew G. Knepley 
2880ee167adSMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, fieldnames[0], &f));
2890ee167adSMatthew G. Knepley   PetscCall(computeParticleMoments(sw, f, pmoments, user));
2900ee167adSMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, fieldnames[0], &f));
2910ee167adSMatthew G. Knepley   PetscCall(computeFieldMoments(dm, fhat, fmoments, user));
2920ee167adSMatthew G. Knepley   PetscCall(VecViewFromOptions(fhat, NULL, "-fhat_view"));
2930ee167adSMatthew 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]));
2940ee167adSMatthew G. Knepley   for (PetscInt m = 0; m < user->Nm; ++m) {
2950ee167adSMatthew G. Knepley     if (user->pass) {
2960ee167adSMatthew G. Knepley       if (PetscAbsReal((fmoments[m] - pmoments[m]) / fmoments[m]) > user->mtol) {
2970ee167adSMatthew 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]));
2980ee167adSMatthew G. Knepley       }
2990ee167adSMatthew G. Knepley     } else {
3000ee167adSMatthew 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]),
3010ee167adSMatthew G. Knepley                  user->mtol);
3020ee167adSMatthew G. Knepley     }
3030ee167adSMatthew G. Knepley   }
3040ee167adSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
3050ee167adSMatthew G. Knepley }
3060ee167adSMatthew G. Knepley 
3070ee167adSMatthew G. Knepley static PetscErrorCode TestFieldToParticles(DM sw, DM dm, Vec fhat, AppCtx *user)
3080ee167adSMatthew G. Knepley {
3090ee167adSMatthew G. Knepley   const char *fieldnames[1] = {user->field ? "x_q" : "w_q"};
3100ee167adSMatthew G. Knepley   Vec         fields[1]     = {fhat}, f;
3110ee167adSMatthew G. Knepley   PetscReal   pmoments[3]; // \int f, \int x f, \int r^2 f
3120ee167adSMatthew G. Knepley   PetscReal   fmoments[3]; // \int \hat f, \int x \hat f, \int r^2 \hat f
3130ee167adSMatthew G. Knepley 
3140ee167adSMatthew G. Knepley   PetscFunctionBeginUser;
3150ee167adSMatthew G. Knepley   PetscCall(DMSwarmProjectFields(sw, dm, 1, fieldnames, fields, SCATTER_REVERSE));
3160ee167adSMatthew G. Knepley 
3170ee167adSMatthew G. Knepley   PetscCall(DMSwarmCreateGlobalVectorFromField(sw, fieldnames[0], &f));
3180ee167adSMatthew G. Knepley   PetscCall(computeParticleMoments(sw, f, pmoments, user));
3190ee167adSMatthew G. Knepley   PetscCall(DMSwarmDestroyGlobalVectorFromField(sw, fieldnames[0], &f));
3200ee167adSMatthew G. Knepley   PetscCall(computeFieldMoments(dm, fhat, fmoments, user));
3210ee167adSMatthew 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]));
3220ee167adSMatthew G. Knepley   for (PetscInt m = 0; m < user->Nm; ++m) {
3230ee167adSMatthew G. Knepley     if (user->pass) {
3240ee167adSMatthew G. Knepley       if (PetscAbsReal((fmoments[m] - pmoments[m]) / fmoments[m]) > user->mtol) {
3250ee167adSMatthew 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]));
3260ee167adSMatthew G. Knepley       }
3270ee167adSMatthew G. Knepley     } else {
3280ee167adSMatthew 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]),
3290ee167adSMatthew G. Knepley                  user->mtol);
3300ee167adSMatthew G. Knepley     }
3310ee167adSMatthew G. Knepley   }
3320ee167adSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
3330ee167adSMatthew G. Knepley }
3340ee167adSMatthew G. Knepley 
3350ee167adSMatthew G. Knepley int main(int argc, char *argv[])
3360ee167adSMatthew G. Knepley {
3370ee167adSMatthew G. Knepley   DM     dm, subdm, sw;
3380ee167adSMatthew G. Knepley   Vec    fhat;
3390ee167adSMatthew G. Knepley   IS     subis;
3400ee167adSMatthew G. Knepley   AppCtx user;
3410ee167adSMatthew G. Knepley 
3420ee167adSMatthew G. Knepley   PetscFunctionBeginUser;
3430ee167adSMatthew G. Knepley   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
3440ee167adSMatthew G. Knepley   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
3450ee167adSMatthew G. Knepley   PetscCall(CreateMesh(PETSC_COMM_WORLD, &dm, &user));
3460ee167adSMatthew G. Knepley   PetscCall(CreateDiscretization(dm, &user));
3470ee167adSMatthew G. Knepley   PetscCall(CreateSwarm(dm, &sw, &user));
3480ee167adSMatthew G. Knepley 
3490ee167adSMatthew G. Knepley   PetscCall(DMCreateSubDM(dm, 1, &user.field, &subis, &subdm));
3500ee167adSMatthew G. Knepley 
3510ee167adSMatthew G. Knepley   PetscCall(DMGetGlobalVector(subdm, &fhat));
3520ee167adSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)fhat, "FEM f"));
3530ee167adSMatthew G. Knepley   PetscCall(TestParticlesToField(sw, subdm, fhat, &user));
3540ee167adSMatthew G. Knepley   PetscCall(TestFieldToParticles(sw, subdm, fhat, &user));
3550ee167adSMatthew G. Knepley   PetscCall(DMRestoreGlobalVector(subdm, &fhat));
3560ee167adSMatthew G. Knepley 
3570ee167adSMatthew G. Knepley   PetscCall(ISDestroy(&subis));
3580ee167adSMatthew G. Knepley   PetscCall(DMDestroy(&subdm));
3590ee167adSMatthew G. Knepley   PetscCall(DMDestroy(&dm));
3600ee167adSMatthew G. Knepley   PetscCall(DMDestroy(&sw));
3610ee167adSMatthew G. Knepley   PetscCall(PetscFinalize());
3620ee167adSMatthew G. Knepley   return 0;
3630ee167adSMatthew G. Knepley }
3640ee167adSMatthew G. Knepley 
3650ee167adSMatthew G. Knepley /*TEST
3660ee167adSMatthew G. Knepley 
3670ee167adSMatthew G. Knepley   # Swarm does not handle complex or quad
3680ee167adSMatthew G. Knepley   build:
3690ee167adSMatthew G. Knepley     requires: !complex double
3700ee167adSMatthew G. Knepley 
3710ee167adSMatthew G. Knepley   testset:
3720ee167adSMatthew G. Knepley     requires: triangle
3730ee167adSMatthew G. Knepley     args: -dm_refine 1 -petscspace_degree 2 -moments 3 \
3740ee167adSMatthew G. Knepley           -ptof_pc_type lu  \
3750ee167adSMatthew G. Knepley           -ftop_ksp_rtol 1e-15 -ftop_ksp_type lsqr -ftop_pc_type none
3760ee167adSMatthew G. Knepley 
3770ee167adSMatthew G. Knepley     test:
3780ee167adSMatthew G. Knepley       suffix: tri_fe_f0
3790ee167adSMatthew G. Knepley       args: -field 0
3800ee167adSMatthew G. Knepley 
3810ee167adSMatthew G. Knepley     test:
3820ee167adSMatthew G. Knepley       suffix: tri_fe_f1
3830ee167adSMatthew G. Knepley       args: -field 1
3840ee167adSMatthew G. Knepley 
3850ee167adSMatthew G. Knepley     test:
3860ee167adSMatthew G. Knepley       suffix: quad_fe_f0
3870ee167adSMatthew G. Knepley       args: -dm_plex_simplex 0 -field 0
3880ee167adSMatthew G. Knepley 
3890ee167adSMatthew G. Knepley     test:
3900ee167adSMatthew G. Knepley       suffix: quad_fe_f1
3910ee167adSMatthew G. Knepley       args: -dm_plex_simplex 0 -field 1
3920ee167adSMatthew G. Knepley 
3930ee167adSMatthew G. Knepley   testset:
3940ee167adSMatthew G. Knepley     requires: triangle
3950ee167adSMatthew G. Knepley     args: -dm_refine 1 -moments 1 -fv \
3960ee167adSMatthew G. Knepley           -ptof_pc_type lu \
3970ee167adSMatthew G. Knepley           -ftop_ksp_rtol 1e-15 -ftop_ksp_type lsqr -ftop_pc_type none
3980ee167adSMatthew G. Knepley 
3990ee167adSMatthew G. Knepley     test:
4000ee167adSMatthew G. Knepley       suffix: tri_fv_f0
4010ee167adSMatthew G. Knepley       args: -field 0
4020ee167adSMatthew G. Knepley 
4030ee167adSMatthew G. Knepley     test:
4040ee167adSMatthew G. Knepley       suffix: tri_fv_f1
4050ee167adSMatthew G. Knepley       args: -field 1
4060ee167adSMatthew G. Knepley 
4070ee167adSMatthew G. Knepley     test:
4080ee167adSMatthew G. Knepley       suffix: quad_fv_f0
4090ee167adSMatthew G. Knepley       args: -dm_plex_simplex 0 -field 0
4100ee167adSMatthew G. Knepley 
4110ee167adSMatthew G. Knepley     test:
4120ee167adSMatthew G. Knepley       suffix: quad_fv_f1
4130ee167adSMatthew G. Knepley       args: -dm_plex_simplex 0 -field 1
4140ee167adSMatthew G. Knepley 
4150ee167adSMatthew G. Knepley TEST*/
416