xref: /petsc/src/dm/impls/swarm/tests/ex11.c (revision 0ee167adfe72d9a35211b7fb52bb3ed13989589f)
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