xref: /petsc/src/dm/impls/plex/tests/ex3.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
1c4762a1bSJed Brown static char help[] = "Check that a DM can accurately represent and interpolate functions of a given polynomial order\n\n";
2c4762a1bSJed Brown 
3c4762a1bSJed Brown #include <petscdmplex.h>
4c4762a1bSJed Brown #include <petscdm.h>
5c4762a1bSJed Brown #include <petscdmda.h>
6c4762a1bSJed Brown #include <petscfe.h>
7c4762a1bSJed Brown #include <petscds.h>
8c4762a1bSJed Brown #include <petscksp.h>
9c4762a1bSJed Brown #include <petscsnes.h>
10c4762a1bSJed Brown 
11c4762a1bSJed Brown typedef struct {
12c4762a1bSJed Brown   /* Domain and mesh definition */
13c4762a1bSJed Brown   PetscBool useDA;           /* Flag DMDA tensor product mesh */
14c4762a1bSJed Brown   PetscBool shearCoords;     /* Flag for shear transform */
15c4762a1bSJed Brown   PetscBool nonaffineCoords; /* Flag for non-affine transform */
16c4762a1bSJed Brown   /* Element definition */
17c4762a1bSJed Brown   PetscInt  qorder;        /* Order of the quadrature */
18c4762a1bSJed Brown   PetscInt  numComponents; /* Number of field components */
19c4762a1bSJed Brown   PetscFE   fe;            /* The finite element */
20c4762a1bSJed Brown   /* Testing space */
21c4762a1bSJed Brown   PetscInt  porder;         /* Order of polynomials to test */
22c4762a1bSJed Brown   PetscBool convergence;    /* Test for order of convergence */
23c4762a1bSJed Brown   PetscBool convRefine;     /* Test for convergence using refinement, otherwise use coarsening */
24c4762a1bSJed Brown   PetscBool constraints;    /* Test local constraints */
25c4762a1bSJed Brown   PetscBool tree;           /* Test tree routines */
26c4762a1bSJed Brown   PetscBool testFEjacobian; /* Test finite element Jacobian assembly */
27c4762a1bSJed Brown   PetscBool testFVgrad;     /* Test finite difference gradient routine */
28c4762a1bSJed Brown   PetscBool testInjector;   /* Test finite element injection routines */
29c4762a1bSJed Brown   PetscInt  treeCell;       /* Cell to refine in tree test */
30c4762a1bSJed Brown   PetscReal constants[3];   /* Constant values for each dimension */
31c4762a1bSJed Brown } AppCtx;
32c4762a1bSJed Brown 
33c4762a1bSJed Brown /* u = 1 */
349371c9d4SSatish Balay PetscErrorCode constant(PetscInt dim, PetscReal time, const PetscReal coords[], PetscInt Nf, PetscScalar *u, void *ctx) {
35c4762a1bSJed Brown   AppCtx  *user = (AppCtx *)ctx;
36c4762a1bSJed Brown   PetscInt d;
3730602db0SMatthew G. Knepley   for (d = 0; d < dim; ++d) u[d] = user->constants[d];
38c4762a1bSJed Brown   return 0;
39c4762a1bSJed Brown }
409371c9d4SSatish Balay PetscErrorCode constantDer(PetscInt dim, PetscReal time, const PetscReal coords[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx) {
41c4762a1bSJed Brown   PetscInt d;
4230602db0SMatthew G. Knepley   for (d = 0; d < dim; ++d) u[d] = 0.0;
43c4762a1bSJed Brown   return 0;
44c4762a1bSJed Brown }
45c4762a1bSJed Brown 
46c4762a1bSJed Brown /* u = x */
479371c9d4SSatish Balay PetscErrorCode linear(PetscInt dim, PetscReal time, const PetscReal coords[], PetscInt Nf, PetscScalar *u, void *ctx) {
48c4762a1bSJed Brown   PetscInt d;
49c4762a1bSJed Brown   for (d = 0; d < dim; ++d) u[d] = coords[d];
50c4762a1bSJed Brown   return 0;
51c4762a1bSJed Brown }
529371c9d4SSatish Balay PetscErrorCode linearDer(PetscInt dim, PetscReal time, const PetscReal coords[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx) {
53c4762a1bSJed Brown   PetscInt d, e;
54c4762a1bSJed Brown   for (d = 0; d < dim; ++d) {
55c4762a1bSJed Brown     u[d] = 0.0;
56c4762a1bSJed Brown     for (e = 0; e < dim; ++e) u[d] += (d == e ? 1.0 : 0.0) * n[e];
57c4762a1bSJed Brown   }
58c4762a1bSJed Brown   return 0;
59c4762a1bSJed Brown }
60c4762a1bSJed Brown 
61c4762a1bSJed Brown /* u = x^2 or u = (x^2, xy) or u = (xy, yz, zx) */
629371c9d4SSatish Balay PetscErrorCode quadratic(PetscInt dim, PetscReal time, const PetscReal coords[], PetscInt Nf, PetscScalar *u, void *ctx) {
639371c9d4SSatish Balay   if (dim > 2) {
649371c9d4SSatish Balay     u[0] = coords[0] * coords[1];
659371c9d4SSatish Balay     u[1] = coords[1] * coords[2];
669371c9d4SSatish Balay     u[2] = coords[2] * coords[0];
679371c9d4SSatish Balay   } else if (dim > 1) {
689371c9d4SSatish Balay     u[0] = coords[0] * coords[0];
699371c9d4SSatish Balay     u[1] = coords[0] * coords[1];
709371c9d4SSatish Balay   } else if (dim > 0) {
719371c9d4SSatish Balay     u[0] = coords[0] * coords[0];
729371c9d4SSatish Balay   }
73c4762a1bSJed Brown   return 0;
74c4762a1bSJed Brown }
759371c9d4SSatish Balay PetscErrorCode quadraticDer(PetscInt dim, PetscReal time, const PetscReal coords[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx) {
769371c9d4SSatish Balay   if (dim > 2) {
779371c9d4SSatish Balay     u[0] = coords[1] * n[0] + coords[0] * n[1];
789371c9d4SSatish Balay     u[1] = coords[2] * n[1] + coords[1] * n[2];
799371c9d4SSatish Balay     u[2] = coords[2] * n[0] + coords[0] * n[2];
809371c9d4SSatish Balay   } else if (dim > 1) {
819371c9d4SSatish Balay     u[0] = 2.0 * coords[0] * n[0];
829371c9d4SSatish Balay     u[1] = coords[1] * n[0] + coords[0] * n[1];
839371c9d4SSatish Balay   } else if (dim > 0) {
849371c9d4SSatish Balay     u[0] = 2.0 * coords[0] * n[0];
859371c9d4SSatish Balay   }
86c4762a1bSJed Brown   return 0;
87c4762a1bSJed Brown }
88c4762a1bSJed Brown 
89c4762a1bSJed Brown /* u = x^3 or u = (x^3, x^2y) or u = (x^2y, y^2z, z^2x) */
909371c9d4SSatish Balay PetscErrorCode cubic(PetscInt dim, PetscReal time, const PetscReal coords[], PetscInt Nf, PetscScalar *u, void *ctx) {
919371c9d4SSatish Balay   if (dim > 2) {
929371c9d4SSatish Balay     u[0] = coords[0] * coords[0] * coords[1];
939371c9d4SSatish Balay     u[1] = coords[1] * coords[1] * coords[2];
949371c9d4SSatish Balay     u[2] = coords[2] * coords[2] * coords[0];
959371c9d4SSatish Balay   } else if (dim > 1) {
969371c9d4SSatish Balay     u[0] = coords[0] * coords[0] * coords[0];
979371c9d4SSatish Balay     u[1] = coords[0] * coords[0] * coords[1];
989371c9d4SSatish Balay   } else if (dim > 0) {
999371c9d4SSatish Balay     u[0] = coords[0] * coords[0] * coords[0];
1009371c9d4SSatish Balay   }
101c4762a1bSJed Brown   return 0;
102c4762a1bSJed Brown }
1039371c9d4SSatish Balay PetscErrorCode cubicDer(PetscInt dim, PetscReal time, const PetscReal coords[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx) {
1049371c9d4SSatish Balay   if (dim > 2) {
1059371c9d4SSatish Balay     u[0] = 2.0 * coords[0] * coords[1] * n[0] + coords[0] * coords[0] * n[1];
1069371c9d4SSatish Balay     u[1] = 2.0 * coords[1] * coords[2] * n[1] + coords[1] * coords[1] * n[2];
1079371c9d4SSatish Balay     u[2] = 2.0 * coords[2] * coords[0] * n[2] + coords[2] * coords[2] * n[0];
1089371c9d4SSatish Balay   } else if (dim > 1) {
1099371c9d4SSatish Balay     u[0] = 3.0 * coords[0] * coords[0] * n[0];
1109371c9d4SSatish Balay     u[1] = 2.0 * coords[0] * coords[1] * n[0] + coords[0] * coords[0] * n[1];
1119371c9d4SSatish Balay   } else if (dim > 0) {
1129371c9d4SSatish Balay     u[0] = 3.0 * coords[0] * coords[0] * n[0];
1139371c9d4SSatish Balay   }
114c4762a1bSJed Brown   return 0;
115c4762a1bSJed Brown }
116c4762a1bSJed Brown 
117c4762a1bSJed Brown /* u = tanh(x) */
1189371c9d4SSatish Balay PetscErrorCode trig(PetscInt dim, PetscReal time, const PetscReal coords[], PetscInt Nf, PetscScalar *u, void *ctx) {
119c4762a1bSJed Brown   PetscInt d;
12030602db0SMatthew G. Knepley   for (d = 0; d < dim; ++d) u[d] = PetscTanhReal(coords[d] - 0.5);
121c4762a1bSJed Brown   return 0;
122c4762a1bSJed Brown }
1239371c9d4SSatish Balay PetscErrorCode trigDer(PetscInt dim, PetscReal time, const PetscReal coords[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx) {
124c4762a1bSJed Brown   PetscInt d;
12530602db0SMatthew G. Knepley   for (d = 0; d < dim; ++d) u[d] = 1.0 / PetscSqr(PetscCoshReal(coords[d] - 0.5)) * n[d];
126c4762a1bSJed Brown   return 0;
127c4762a1bSJed Brown }
128c4762a1bSJed Brown 
1299371c9d4SSatish Balay static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) {
130c4762a1bSJed Brown   PetscInt n = 3;
131c4762a1bSJed Brown 
132c4762a1bSJed Brown   PetscFunctionBeginUser;
13330602db0SMatthew G. Knepley   options->useDA           = PETSC_FALSE;
134c4762a1bSJed Brown   options->shearCoords     = PETSC_FALSE;
135c4762a1bSJed Brown   options->nonaffineCoords = PETSC_FALSE;
136c4762a1bSJed Brown   options->qorder          = 0;
137c4762a1bSJed Brown   options->numComponents   = PETSC_DEFAULT;
138c4762a1bSJed Brown   options->porder          = 0;
139c4762a1bSJed Brown   options->convergence     = PETSC_FALSE;
140c4762a1bSJed Brown   options->convRefine      = PETSC_TRUE;
141c4762a1bSJed Brown   options->constraints     = PETSC_FALSE;
142c4762a1bSJed Brown   options->tree            = PETSC_FALSE;
143c4762a1bSJed Brown   options->treeCell        = 0;
144c4762a1bSJed Brown   options->testFEjacobian  = PETSC_FALSE;
145c4762a1bSJed Brown   options->testFVgrad      = PETSC_FALSE;
146c4762a1bSJed Brown   options->testInjector    = PETSC_FALSE;
147c4762a1bSJed Brown   options->constants[0]    = 1.0;
148c4762a1bSJed Brown   options->constants[1]    = 2.0;
149c4762a1bSJed Brown   options->constants[2]    = 3.0;
150c4762a1bSJed Brown 
151d0609cedSBarry Smith   PetscOptionsBegin(comm, "", "Projection Test Options", "DMPlex");
1529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-use_da", "Flag for DMDA mesh", "ex3.c", options->useDA, &options->useDA, NULL));
1539566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-shear_coords", "Transform coordinates with a shear", "ex3.c", options->shearCoords, &options->shearCoords, NULL));
1549566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-non_affine_coords", "Transform coordinates with a non-affine transform", "ex3.c", options->nonaffineCoords, &options->nonaffineCoords, NULL));
1559566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-qorder", "The quadrature order", "ex3.c", options->qorder, &options->qorder, NULL, 0));
1569566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-num_comp", "The number of field components", "ex3.c", options->numComponents, &options->numComponents, NULL, PETSC_DEFAULT));
1579566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-porder", "The order of polynomials to test", "ex3.c", options->porder, &options->porder, NULL, 0));
1589566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-convergence", "Check the convergence rate", "ex3.c", options->convergence, &options->convergence, NULL));
1599566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-conv_refine", "Use refinement for the convergence rate", "ex3.c", options->convRefine, &options->convRefine, NULL));
1609566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-constraints", "Test local constraints (serial only)", "ex3.c", options->constraints, &options->constraints, NULL));
1619566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-tree", "Test tree routines", "ex3.c", options->tree, &options->tree, NULL));
1629566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-tree_cell", "cell to refine in tree test", "ex3.c", options->treeCell, &options->treeCell, NULL, 0));
1639566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-test_fe_jacobian", "Test finite element Jacobian assembly", "ex3.c", options->testFEjacobian, &options->testFEjacobian, NULL));
1649566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-test_fv_grad", "Test finite volume gradient reconstruction", "ex3.c", options->testFVgrad, &options->testFVgrad, NULL));
1659566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-test_injector", "Test finite element injection", "ex3.c", options->testInjector, &options->testInjector, NULL));
1669566063dSJacob Faibussowitsch   PetscCall(PetscOptionsRealArray("-constants", "Set the constant values", "ex3.c", options->constants, &n, NULL));
167d0609cedSBarry Smith   PetscOptionsEnd();
168c4762a1bSJed Brown 
169c4762a1bSJed Brown   PetscFunctionReturn(0);
170c4762a1bSJed Brown }
171c4762a1bSJed Brown 
1729371c9d4SSatish Balay static PetscErrorCode TransformCoordinates(DM dm, AppCtx *user) {
173c4762a1bSJed Brown   PetscSection coordSection;
174c4762a1bSJed Brown   Vec          coordinates;
175c4762a1bSJed Brown   PetscScalar *coords;
176c4762a1bSJed Brown   PetscInt     vStart, vEnd, v;
177c4762a1bSJed Brown 
178c4762a1bSJed Brown   PetscFunctionBeginUser;
179c4762a1bSJed Brown   if (user->nonaffineCoords) {
180c4762a1bSJed Brown     /* x' = r^(1/p) (x/r), y' = r^(1/p) (y/r), z' = z */
1819566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &coordSection));
1829566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
1839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1849566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
185c4762a1bSJed Brown     for (v = vStart; v < vEnd; ++v) {
186c4762a1bSJed Brown       PetscInt  dof, off;
187c4762a1bSJed Brown       PetscReal p = 4.0, r;
188c4762a1bSJed Brown 
1899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
1909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
191c4762a1bSJed Brown       switch (dof) {
192c4762a1bSJed Brown       case 2:
193c4762a1bSJed Brown         r               = PetscSqr(PetscRealPart(coords[off + 0])) + PetscSqr(PetscRealPart(coords[off + 1]));
194c4762a1bSJed Brown         coords[off + 0] = r == 0.0 ? 0.0 : PetscPowReal(r, (1 - p) / (2 * p)) * coords[off + 0];
195c4762a1bSJed Brown         coords[off + 1] = r == 0.0 ? 0.0 : PetscPowReal(r, (1 - p) / (2 * p)) * coords[off + 1];
196c4762a1bSJed Brown         break;
197c4762a1bSJed Brown       case 3:
198c4762a1bSJed Brown         r               = PetscSqr(PetscRealPart(coords[off + 0])) + PetscSqr(PetscRealPart(coords[off + 1]));
199c4762a1bSJed Brown         coords[off + 0] = r == 0.0 ? 0.0 : PetscPowReal(r, (1 - p) / (2 * p)) * coords[off + 0];
200c4762a1bSJed Brown         coords[off + 1] = r == 0.0 ? 0.0 : PetscPowReal(r, (1 - p) / (2 * p)) * coords[off + 1];
201c4762a1bSJed Brown         coords[off + 2] = coords[off + 2];
202c4762a1bSJed Brown         break;
203c4762a1bSJed Brown       }
204c4762a1bSJed Brown     }
2059566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
206c4762a1bSJed Brown   }
207c4762a1bSJed Brown   if (user->shearCoords) {
208c4762a1bSJed Brown     /* x' = x + m y + m z, y' = y + m z,  z' = z */
2099566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &coordSection));
2109566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
2119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2129566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
213c4762a1bSJed Brown     for (v = vStart; v < vEnd; ++v) {
214c4762a1bSJed Brown       PetscInt  dof, off;
215c4762a1bSJed Brown       PetscReal m = 1.0;
216c4762a1bSJed Brown 
2179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
2189566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
219c4762a1bSJed Brown       switch (dof) {
220c4762a1bSJed Brown       case 2:
221c4762a1bSJed Brown         coords[off + 0] = coords[off + 0] + m * coords[off + 1];
222c4762a1bSJed Brown         coords[off + 1] = coords[off + 1];
223c4762a1bSJed Brown         break;
224c4762a1bSJed Brown       case 3:
225c4762a1bSJed Brown         coords[off + 0] = coords[off + 0] + m * coords[off + 1] + m * coords[off + 2];
226c4762a1bSJed Brown         coords[off + 1] = coords[off + 1] + m * coords[off + 2];
227c4762a1bSJed Brown         coords[off + 2] = coords[off + 2];
228c4762a1bSJed Brown         break;
229c4762a1bSJed Brown       }
230c4762a1bSJed Brown     }
2319566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
232c4762a1bSJed Brown   }
233c4762a1bSJed Brown   PetscFunctionReturn(0);
234c4762a1bSJed Brown }
235c4762a1bSJed Brown 
2369371c9d4SSatish Balay static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm) {
23730602db0SMatthew G. Knepley   PetscInt  dim = 2;
23830602db0SMatthew G. Knepley   PetscBool simplex;
239c4762a1bSJed Brown 
240c4762a1bSJed Brown   PetscFunctionBeginUser;
24130602db0SMatthew G. Knepley   if (user->useDA) {
24230602db0SMatthew G. Knepley     switch (dim) {
243c4762a1bSJed Brown     case 2:
2449566063dSJacob Faibussowitsch       PetscCall(DMDACreate2d(comm, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_BOX, 2, 2, PETSC_DETERMINE, PETSC_DETERMINE, 1, 1, NULL, NULL, dm));
2459566063dSJacob Faibussowitsch       PetscCall(DMSetFromOptions(*dm));
2469566063dSJacob Faibussowitsch       PetscCall(DMSetUp(*dm));
2479566063dSJacob Faibussowitsch       PetscCall(DMDASetVertexCoordinates(*dm, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0));
248c4762a1bSJed Brown       break;
2499371c9d4SSatish Balay     default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot create structured mesh of dimension %" PetscInt_FMT, dim);
250c4762a1bSJed Brown     }
2519566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)*dm, "Hexahedral Mesh"));
25230602db0SMatthew G. Knepley   } else {
2539566063dSJacob Faibussowitsch     PetscCall(DMCreate(comm, dm));
2549566063dSJacob Faibussowitsch     PetscCall(DMSetType(*dm, DMPLEX));
2559566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
2569566063dSJacob Faibussowitsch     PetscCall(DMSetFromOptions(*dm));
257c4762a1bSJed Brown 
2589566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(*dm, &dim));
2599566063dSJacob Faibussowitsch     PetscCall(DMPlexIsSimplex(*dm, &simplex));
2609566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(&simplex, 1, MPIU_BOOL, 0, comm));
261c4762a1bSJed Brown     if (user->tree) {
26230602db0SMatthew G. Knepley       DM refTree, ncdm = NULL;
263c4762a1bSJed Brown 
2649566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateDefaultReferenceTree(comm, dim, simplex, &refTree));
2659566063dSJacob Faibussowitsch       PetscCall(DMViewFromOptions(refTree, NULL, "-reftree_dm_view"));
2669566063dSJacob Faibussowitsch       PetscCall(DMPlexSetReferenceTree(*dm, refTree));
2679566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&refTree));
2689566063dSJacob Faibussowitsch       PetscCall(DMPlexTreeRefineCell(*dm, user->treeCell, &ncdm));
269c4762a1bSJed Brown       if (ncdm) {
2709566063dSJacob Faibussowitsch         PetscCall(DMDestroy(dm));
271c4762a1bSJed Brown         *dm = ncdm;
2729566063dSJacob Faibussowitsch         PetscCall(DMPlexSetRefinementUniform(*dm, PETSC_FALSE));
273c4762a1bSJed Brown       }
2749566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, "tree_"));
2759566063dSJacob Faibussowitsch       PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
2769566063dSJacob Faibussowitsch       PetscCall(DMSetFromOptions(*dm));
2779566063dSJacob Faibussowitsch       PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
278c4762a1bSJed Brown     } else {
2799566063dSJacob Faibussowitsch       PetscCall(DMPlexSetRefinementUniform(*dm, PETSC_TRUE));
280c4762a1bSJed Brown     }
2819566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, "dist_"));
2829566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
2839566063dSJacob Faibussowitsch     PetscCall(DMSetFromOptions(*dm));
2849566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, NULL));
2859566063dSJacob Faibussowitsch     if (simplex) PetscCall(PetscObjectSetName((PetscObject)*dm, "Simplicial Mesh"));
2869566063dSJacob Faibussowitsch     else PetscCall(PetscObjectSetName((PetscObject)*dm, "Hexahedral Mesh"));
287c4762a1bSJed Brown   }
2889566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*dm));
2899566063dSJacob Faibussowitsch   PetscCall(TransformCoordinates(*dm, user));
2909566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
291c4762a1bSJed Brown   PetscFunctionReturn(0);
292c4762a1bSJed Brown }
293c4762a1bSJed Brown 
2949371c9d4SSatish Balay static void simple_mass(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[]) {
295c4762a1bSJed Brown   PetscInt d, e;
2969371c9d4SSatish Balay   for (d = 0, e = 0; d < dim; d++, e += dim + 1) { g0[e] = 1.; }
297c4762a1bSJed Brown }
298c4762a1bSJed Brown 
299c4762a1bSJed Brown /* < \nabla v, 1/2(\nabla u + {\nabla u}^T) > */
3009371c9d4SSatish Balay static void symmetric_gradient_inner_product(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 C[]) {
301c4762a1bSJed Brown   PetscInt compI, compJ, d, e;
302c4762a1bSJed Brown 
303c4762a1bSJed Brown   for (compI = 0; compI < dim; ++compI) {
304c4762a1bSJed Brown     for (compJ = 0; compJ < dim; ++compJ) {
305c4762a1bSJed Brown       for (d = 0; d < dim; ++d) {
306c4762a1bSJed Brown         for (e = 0; e < dim; e++) {
307c4762a1bSJed Brown           if (d == e && d == compI && d == compJ) {
308c4762a1bSJed Brown             C[((compI * dim + compJ) * dim + d) * dim + e] = 1.0;
309c4762a1bSJed Brown           } else if ((d == compJ && e == compI) || (d == e && compI == compJ)) {
310c4762a1bSJed Brown             C[((compI * dim + compJ) * dim + d) * dim + e] = 0.5;
311c4762a1bSJed Brown           } else {
312c4762a1bSJed Brown             C[((compI * dim + compJ) * dim + d) * dim + e] = 0.0;
313c4762a1bSJed Brown           }
314c4762a1bSJed Brown         }
315c4762a1bSJed Brown       }
316c4762a1bSJed Brown     }
317c4762a1bSJed Brown   }
318c4762a1bSJed Brown }
319c4762a1bSJed Brown 
3209371c9d4SSatish Balay static PetscErrorCode SetupSection(DM dm, AppCtx *user) {
321c4762a1bSJed Brown   PetscFunctionBeginUser;
32230602db0SMatthew G. Knepley   if (user->constraints) {
323c4762a1bSJed Brown     /* test local constraints */
324c4762a1bSJed Brown     DM           coordDM;
325c4762a1bSJed Brown     PetscInt     fStart, fEnd, f, vStart, vEnd, v;
326c4762a1bSJed Brown     PetscInt     edgesx = 2, vertsx;
327c4762a1bSJed Brown     PetscInt     edgesy = 2, vertsy;
328c4762a1bSJed Brown     PetscMPIInt  size;
329c4762a1bSJed Brown     PetscInt     numConst;
330c4762a1bSJed Brown     PetscSection aSec;
331c4762a1bSJed Brown     PetscInt    *anchors;
332c4762a1bSJed Brown     PetscInt     offset;
333c4762a1bSJed Brown     IS           aIS;
334c4762a1bSJed Brown     MPI_Comm     comm = PetscObjectComm((PetscObject)dm);
335c4762a1bSJed Brown 
3369566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
33708401ef6SPierre Jolivet     PetscCheck(size <= 1, comm, PETSC_ERR_SUP, "Local constraint test can only be performed in serial");
338c4762a1bSJed Brown 
339c4762a1bSJed Brown     /* we are going to test constraints by using them to enforce periodicity
340c4762a1bSJed Brown      * in one direction, and comparing to the existing method of enforcing
341c4762a1bSJed Brown      * periodicity */
342c4762a1bSJed Brown 
343c4762a1bSJed Brown     /* first create the coordinate section so that it does not clone the
344c4762a1bSJed Brown      * constraints */
3459566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(dm, &coordDM));
346c4762a1bSJed Brown 
347c4762a1bSJed Brown     /* create the constrained-to-anchor section */
3489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
3499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 1, &fStart, &fEnd));
3509566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &aSec));
3519566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(aSec, PetscMin(fStart, vStart), PetscMax(fEnd, vEnd)));
352c4762a1bSJed Brown 
353c4762a1bSJed Brown     /* define the constraints */
3549566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetInt(NULL, NULL, "-da_grid_x", &edgesx, NULL));
3559566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetInt(NULL, NULL, "-da_grid_y", &edgesy, NULL));
356c4762a1bSJed Brown     vertsx   = edgesx + 1;
357c4762a1bSJed Brown     vertsy   = edgesy + 1;
358c4762a1bSJed Brown     numConst = vertsy + edgesy;
3599566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numConst, &anchors));
360c4762a1bSJed Brown     offset = 0;
361c4762a1bSJed Brown     for (v = vStart + edgesx; v < vEnd; v += vertsx) {
3629566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(aSec, v, 1));
363c4762a1bSJed Brown       anchors[offset++] = v - edgesx;
364c4762a1bSJed Brown     }
365c4762a1bSJed Brown     for (f = fStart + edgesx * vertsy + edgesx * edgesy; f < fEnd; f++) {
3669566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(aSec, f, 1));
367c4762a1bSJed Brown       anchors[offset++] = f - edgesx * edgesy;
368c4762a1bSJed Brown     }
3699566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(aSec));
3709566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numConst, anchors, PETSC_OWN_POINTER, &aIS));
371c4762a1bSJed Brown 
3729566063dSJacob Faibussowitsch     PetscCall(DMPlexSetAnchors(dm, aSec, aIS));
3739566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&aSec));
3749566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&aIS));
375c4762a1bSJed Brown   }
3769566063dSJacob Faibussowitsch   PetscCall(DMSetNumFields(dm, 1));
3779566063dSJacob Faibussowitsch   PetscCall(DMSetField(dm, 0, NULL, (PetscObject)user->fe));
3789566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(dm));
37930602db0SMatthew G. Knepley   if (user->constraints) {
380c4762a1bSJed Brown     /* test getting local constraint matrix that matches section */
381c4762a1bSJed Brown     PetscSection aSec;
382c4762a1bSJed Brown     IS           aIS;
383c4762a1bSJed Brown 
3849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
385c4762a1bSJed Brown     if (aSec) {
386c4762a1bSJed Brown       PetscDS         ds;
387c4762a1bSJed Brown       PetscSection    cSec, section;
388c4762a1bSJed Brown       PetscInt        cStart, cEnd, c, numComp;
389c4762a1bSJed Brown       Mat             cMat, mass;
390c4762a1bSJed Brown       Vec             local;
391c4762a1bSJed Brown       const PetscInt *anchors;
392c4762a1bSJed Brown 
3939566063dSJacob Faibussowitsch       PetscCall(DMGetLocalSection(dm, &section));
394c4762a1bSJed Brown       /* this creates the matrix and preallocates the matrix structure: we
395c4762a1bSJed Brown        * just have to fill in the values */
3969566063dSJacob Faibussowitsch       PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
3979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
3989566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(aIS, &anchors));
3999566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(user->fe, &numComp));
400c4762a1bSJed Brown       for (c = cStart; c < cEnd; c++) {
401c4762a1bSJed Brown         PetscInt cDof;
402c4762a1bSJed Brown 
403c4762a1bSJed Brown         /* is this point constrained? (does it have an anchor?) */
4049566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, c, &cDof));
405c4762a1bSJed Brown         if (cDof) {
406c4762a1bSJed Brown           PetscInt cOff, a, aDof, aOff, j;
40763a3b9bcSJacob Faibussowitsch           PetscCheck(cDof == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Found %" PetscInt_FMT " anchor points: should be just one", cDof);
408c4762a1bSJed Brown 
409c4762a1bSJed Brown           /* find the anchor point */
4109566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(aSec, c, &cOff));
411c4762a1bSJed Brown           a = anchors[cOff];
412c4762a1bSJed Brown 
413c4762a1bSJed Brown           /* find the constrained dofs (row in constraint matrix) */
4149566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, c, &cDof));
4159566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(cSec, c, &cOff));
416c4762a1bSJed Brown 
417c4762a1bSJed Brown           /* find the anchor dofs (column in constraint matrix) */
4189566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, a, &aDof));
4199566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, a, &aOff));
420c4762a1bSJed Brown 
42163a3b9bcSJacob Faibussowitsch           PetscCheck(cDof == aDof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point and anchor have different number of dofs: %" PetscInt_FMT ", %" PetscInt_FMT, cDof, aDof);
42263a3b9bcSJacob Faibussowitsch           PetscCheck(cDof % numComp == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point dofs not divisible by field components: %" PetscInt_FMT ", %" PetscInt_FMT, cDof, numComp);
423c4762a1bSJed Brown 
424c4762a1bSJed Brown           /* put in a simple equality constraint */
425*48a46eb9SPierre Jolivet           for (j = 0; j < cDof; j++) PetscCall(MatSetValue(cMat, cOff + j, aOff + j, 1., INSERT_VALUES));
426c4762a1bSJed Brown         }
427c4762a1bSJed Brown       }
4289566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
4299566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
4309566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(aIS, &anchors));
431c4762a1bSJed Brown 
432c4762a1bSJed Brown       /* Now that we have constructed the constraint matrix, any FE matrix
433c4762a1bSJed Brown        * that we construct will apply the constraints during construction */
434c4762a1bSJed Brown 
4359566063dSJacob Faibussowitsch       PetscCall(DMCreateMatrix(dm, &mass));
436c4762a1bSJed Brown       /* get a dummy local variable to serve as the solution */
4379566063dSJacob Faibussowitsch       PetscCall(DMGetLocalVector(dm, &local));
4389566063dSJacob Faibussowitsch       PetscCall(DMGetDS(dm, &ds));
439c4762a1bSJed Brown       /* set the jacobian to be the mass matrix */
4409566063dSJacob Faibussowitsch       PetscCall(PetscDSSetJacobian(ds, 0, 0, simple_mass, NULL, NULL, NULL));
441c4762a1bSJed Brown       /* build the mass matrix */
4429566063dSJacob Faibussowitsch       PetscCall(DMPlexSNESComputeJacobianFEM(dm, local, mass, mass, NULL));
4439566063dSJacob Faibussowitsch       PetscCall(MatView(mass, PETSC_VIEWER_STDOUT_WORLD));
4449566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mass));
4459566063dSJacob Faibussowitsch       PetscCall(DMRestoreLocalVector(dm, &local));
446c4762a1bSJed Brown     }
447c4762a1bSJed Brown   }
448c4762a1bSJed Brown   PetscFunctionReturn(0);
449c4762a1bSJed Brown }
450c4762a1bSJed Brown 
4519371c9d4SSatish Balay static PetscErrorCode TestFEJacobian(DM dm, AppCtx *user) {
452c4762a1bSJed Brown   PetscFunctionBeginUser;
45330602db0SMatthew G. Knepley   if (!user->useDA) {
454c4762a1bSJed Brown     Vec          local;
455c4762a1bSJed Brown     const Vec   *vecs;
456c4762a1bSJed Brown     Mat          E;
457c4762a1bSJed Brown     MatNullSpace sp;
458c4762a1bSJed Brown     PetscBool    isNullSpace, hasConst;
45930602db0SMatthew G. Knepley     PetscInt     dim, n, i;
460c4762a1bSJed Brown     Vec          res = NULL, localX, localRes;
461c4762a1bSJed Brown     PetscDS      ds;
462c4762a1bSJed Brown 
4639566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
46463a3b9bcSJacob Faibussowitsch     PetscCheck(user->numComponents == dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "The number of components %" PetscInt_FMT " must be equal to the dimension %" PetscInt_FMT " for this test", user->numComponents, dim);
4659566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dm, &ds));
4669566063dSJacob Faibussowitsch     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, symmetric_gradient_inner_product));
4679566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dm, &E));
4689566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dm, &local));
4699566063dSJacob Faibussowitsch     PetscCall(DMPlexSNESComputeJacobianFEM(dm, local, E, E, NULL));
4709566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateRigidBody(dm, 0, &sp));
4719566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceGetVecs(sp, &hasConst, &n, &vecs));
4729566063dSJacob Faibussowitsch     if (n) PetscCall(VecDuplicate(vecs[0], &res));
4739566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(dm, &localX));
4749566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(dm, &localRes));
475c4762a1bSJed Brown     for (i = 0; i < n; i++) { /* also test via matrix-free Jacobian application */
476c4762a1bSJed Brown       PetscReal resNorm;
477c4762a1bSJed Brown 
4789566063dSJacob Faibussowitsch       PetscCall(VecSet(localRes, 0.));
4799566063dSJacob Faibussowitsch       PetscCall(VecSet(localX, 0.));
4809566063dSJacob Faibussowitsch       PetscCall(VecSet(local, 0.));
4819566063dSJacob Faibussowitsch       PetscCall(VecSet(res, 0.));
4829566063dSJacob Faibussowitsch       PetscCall(DMGlobalToLocalBegin(dm, vecs[i], INSERT_VALUES, localX));
4839566063dSJacob Faibussowitsch       PetscCall(DMGlobalToLocalEnd(dm, vecs[i], INSERT_VALUES, localX));
4849566063dSJacob Faibussowitsch       PetscCall(DMSNESComputeJacobianAction(dm, local, localX, localRes, NULL));
4859566063dSJacob Faibussowitsch       PetscCall(DMLocalToGlobalBegin(dm, localRes, ADD_VALUES, res));
4869566063dSJacob Faibussowitsch       PetscCall(DMLocalToGlobalEnd(dm, localRes, ADD_VALUES, res));
4879566063dSJacob Faibussowitsch       PetscCall(VecNorm(res, NORM_2, &resNorm));
488*48a46eb9SPierre Jolivet       if (resNorm > PETSC_SMALL) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Symmetric gradient action null space vector %" PetscInt_FMT " residual: %E\n", i, (double)resNorm));
489c4762a1bSJed Brown     }
4909566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&localRes));
4919566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&localX));
4929566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&res));
4939566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceTest(sp, E, &isNullSpace));
494c4762a1bSJed Brown     if (isNullSpace) {
4959566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Symmetric gradient null space: PASS\n"));
496c4762a1bSJed Brown     } else {
4979566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Symmetric gradient null space: FAIL\n"));
498c4762a1bSJed Brown     }
4999566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceDestroy(&sp));
5009566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&E));
5019566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dm, &local));
502c4762a1bSJed Brown   }
503c4762a1bSJed Brown   PetscFunctionReturn(0);
504c4762a1bSJed Brown }
505c4762a1bSJed Brown 
5069371c9d4SSatish Balay static PetscErrorCode TestInjector(DM dm, AppCtx *user) {
507c4762a1bSJed Brown   DM          refTree;
508c4762a1bSJed Brown   PetscMPIInt rank;
509c4762a1bSJed Brown 
510c4762a1bSJed Brown   PetscFunctionBegin;
5119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
512c4762a1bSJed Brown   if (refTree) {
513c4762a1bSJed Brown     Mat inj;
514c4762a1bSJed Brown 
5159566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorReferenceTree(refTree, &inj));
5169566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)inj, "Reference Tree Injector"));
5179566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
518*48a46eb9SPierre Jolivet     if (rank == 0) PetscCall(MatView(inj, PETSC_VIEWER_STDOUT_SELF));
5199566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&inj));
520c4762a1bSJed Brown   }
521c4762a1bSJed Brown   PetscFunctionReturn(0);
522c4762a1bSJed Brown }
523c4762a1bSJed Brown 
5249371c9d4SSatish Balay static PetscErrorCode TestFVGrad(DM dm, AppCtx *user) {
525c4762a1bSJed Brown   MPI_Comm           comm;
526c4762a1bSJed Brown   DM                 dmRedist, dmfv, dmgrad, dmCell, refTree;
527c4762a1bSJed Brown   PetscFV            fv;
52830602db0SMatthew G. Knepley   PetscInt           dim, nvecs, v, cStart, cEnd, cEndInterior;
529c4762a1bSJed Brown   PetscMPIInt        size;
530c4762a1bSJed Brown   Vec                cellgeom, grad, locGrad;
531c4762a1bSJed Brown   const PetscScalar *cgeom;
532c4762a1bSJed Brown   PetscReal          allVecMaxDiff = 0., fvTol = 100. * PETSC_MACHINE_EPSILON;
533c4762a1bSJed Brown 
534c4762a1bSJed Brown   PetscFunctionBeginUser;
535c4762a1bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
5369566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
537c4762a1bSJed Brown   /* duplicate DM, give dup. a FV discretization */
5389566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
5399566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
540c4762a1bSJed Brown   dmRedist = NULL;
541*48a46eb9SPierre Jolivet   if (size > 1) PetscCall(DMPlexDistributeOverlap(dm, 1, NULL, &dmRedist));
542c4762a1bSJed Brown   if (!dmRedist) {
543c4762a1bSJed Brown     dmRedist = dm;
5449566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmRedist));
545c4762a1bSJed Brown   }
5469566063dSJacob Faibussowitsch   PetscCall(PetscFVCreate(comm, &fv));
5479566063dSJacob Faibussowitsch   PetscCall(PetscFVSetType(fv, PETSCFVLEASTSQUARES));
5489566063dSJacob Faibussowitsch   PetscCall(PetscFVSetNumComponents(fv, user->numComponents));
5499566063dSJacob Faibussowitsch   PetscCall(PetscFVSetSpatialDimension(fv, dim));
5509566063dSJacob Faibussowitsch   PetscCall(PetscFVSetFromOptions(fv));
5519566063dSJacob Faibussowitsch   PetscCall(PetscFVSetUp(fv));
5529566063dSJacob Faibussowitsch   PetscCall(DMPlexConstructGhostCells(dmRedist, NULL, NULL, &dmfv));
5539566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRedist));
5549566063dSJacob Faibussowitsch   PetscCall(DMSetNumFields(dmfv, 1));
5559566063dSJacob Faibussowitsch   PetscCall(DMSetField(dmfv, 0, NULL, (PetscObject)fv));
5569566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(dmfv));
5579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
5589566063dSJacob Faibussowitsch   if (refTree) PetscCall(DMCopyDisc(dmfv, refTree));
5599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGradientDM(dmfv, fv, &dmgrad));
5609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmfv, 0, &cStart, &cEnd));
56130602db0SMatthew G. Knepley   nvecs = dim * (dim + 1) / 2;
5629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGeometryFVM(dmfv, NULL, &cellgeom, NULL));
5639566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellgeom, &dmCell));
5649566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellgeom, &cgeom));
5659566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dmgrad, &grad));
5669566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmgrad, &locGrad));
5679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dmgrad, &cEndInterior, NULL));
568c4762a1bSJed Brown   cEndInterior = (cEndInterior < 0) ? cEnd : cEndInterior;
569c4762a1bSJed Brown   for (v = 0; v < nvecs; v++) {
570c4762a1bSJed Brown     Vec                locX;
571c4762a1bSJed Brown     PetscInt           c;
572c4762a1bSJed Brown     PetscScalar        trueGrad[3][3] = {{0.}};
573c4762a1bSJed Brown     const PetscScalar *gradArray;
574c4762a1bSJed Brown     PetscReal          maxDiff, maxDiffGlob;
575c4762a1bSJed Brown 
5769566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmfv, &locX));
577c4762a1bSJed Brown     /* get the local projection of the rigid body mode */
578c4762a1bSJed Brown     for (c = cStart; c < cEnd; c++) {
579c4762a1bSJed Brown       PetscFVCellGeom *cg;
580c4762a1bSJed Brown       PetscScalar      cx[3] = {0., 0., 0.};
581c4762a1bSJed Brown 
5829566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, c, cgeom, &cg));
58330602db0SMatthew G. Knepley       if (v < dim) {
584c4762a1bSJed Brown         cx[v] = 1.;
585c4762a1bSJed Brown       } else {
58630602db0SMatthew G. Knepley         PetscInt w = v - dim;
587c4762a1bSJed Brown 
58830602db0SMatthew G. Knepley         cx[(w + 1) % dim] = cg->centroid[(w + 2) % dim];
58930602db0SMatthew G. Knepley         cx[(w + 2) % dim] = -cg->centroid[(w + 1) % dim];
590c4762a1bSJed Brown       }
5919566063dSJacob Faibussowitsch       PetscCall(DMPlexVecSetClosure(dmfv, NULL, locX, c, cx, INSERT_ALL_VALUES));
592c4762a1bSJed Brown     }
593c4762a1bSJed Brown     /* TODO: this isn't in any header */
5949566063dSJacob Faibussowitsch     PetscCall(DMPlexReconstructGradientsFVM(dmfv, locX, grad));
5959566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmgrad, grad, INSERT_VALUES, locGrad));
5969566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmgrad, grad, INSERT_VALUES, locGrad));
5979566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(locGrad, &gradArray));
598c4762a1bSJed Brown     /* compare computed gradient to exact gradient */
59930602db0SMatthew G. Knepley     if (v >= dim) {
60030602db0SMatthew G. Knepley       PetscInt w = v - dim;
601c4762a1bSJed Brown 
60230602db0SMatthew G. Knepley       trueGrad[(w + 1) % dim][(w + 2) % dim] = 1.;
60330602db0SMatthew G. Knepley       trueGrad[(w + 2) % dim][(w + 1) % dim] = -1.;
604c4762a1bSJed Brown     }
605c4762a1bSJed Brown     maxDiff = 0.;
606c4762a1bSJed Brown     for (c = cStart; c < cEndInterior; c++) {
607c4762a1bSJed Brown       PetscScalar *compGrad;
608c4762a1bSJed Brown       PetscInt     i, j, k;
609c4762a1bSJed Brown       PetscReal    FrobDiff = 0.;
610c4762a1bSJed Brown 
6119566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmgrad, c, gradArray, &compGrad));
612c4762a1bSJed Brown 
61330602db0SMatthew G. Knepley       for (i = 0, k = 0; i < dim; i++) {
61430602db0SMatthew G. Knepley         for (j = 0; j < dim; j++, k++) {
615c4762a1bSJed Brown           PetscScalar diff = compGrad[k] - trueGrad[i][j];
616c4762a1bSJed Brown           FrobDiff += PetscRealPart(diff * PetscConj(diff));
617c4762a1bSJed Brown         }
618c4762a1bSJed Brown       }
619c4762a1bSJed Brown       FrobDiff = PetscSqrtReal(FrobDiff);
620c4762a1bSJed Brown       maxDiff  = PetscMax(maxDiff, FrobDiff);
621c4762a1bSJed Brown     }
6229566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allreduce(&maxDiff, &maxDiffGlob, 1, MPIU_REAL, MPIU_MAX, comm));
623c4762a1bSJed Brown     allVecMaxDiff = PetscMax(allVecMaxDiff, maxDiffGlob);
6249566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(locGrad, &gradArray));
6259566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmfv, &locX));
626c4762a1bSJed Brown   }
627c4762a1bSJed Brown   if (allVecMaxDiff < fvTol) {
6289566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Finite volume gradient reconstruction: PASS\n"));
629c4762a1bSJed Brown   } else {
63063a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Finite volume gradient reconstruction: FAIL at tolerance %g with max difference %g\n", (double)fvTol, (double)allVecMaxDiff));
631c4762a1bSJed Brown   }
6329566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dmgrad, &locGrad));
6339566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dmgrad, &grad));
6349566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellgeom, &cgeom));
6359566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmfv));
6369566063dSJacob Faibussowitsch   PetscCall(PetscFVDestroy(&fv));
637c4762a1bSJed Brown   PetscFunctionReturn(0);
638c4762a1bSJed Brown }
639c4762a1bSJed Brown 
6409371c9d4SSatish Balay static PetscErrorCode ComputeError(DM dm, PetscErrorCode (**exactFuncs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), PetscErrorCode (**exactFuncDers)(PetscInt, PetscReal, const PetscReal[], const PetscReal[], PetscInt, PetscScalar *, void *), void **exactCtxs, PetscReal *error, PetscReal *errorDer, AppCtx *user) {
641c4762a1bSJed Brown   Vec       u;
642c4762a1bSJed Brown   PetscReal n[3] = {1.0, 1.0, 1.0};
643c4762a1bSJed Brown 
644c4762a1bSJed Brown   PetscFunctionBeginUser;
6459566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dm, &u));
646c4762a1bSJed Brown   /* Project function into FE function space */
6479566063dSJacob Faibussowitsch   PetscCall(DMProjectFunction(dm, 0.0, exactFuncs, exactCtxs, INSERT_ALL_VALUES, u));
6489566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(u, NULL, "-projection_view"));
649c4762a1bSJed Brown   /* Compare approximation to exact in L_2 */
6509566063dSJacob Faibussowitsch   PetscCall(DMComputeL2Diff(dm, 0.0, exactFuncs, exactCtxs, u, error));
6519566063dSJacob Faibussowitsch   PetscCall(DMComputeL2GradientDiff(dm, 0.0, exactFuncDers, exactCtxs, u, n, errorDer));
6529566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dm, &u));
653c4762a1bSJed Brown   PetscFunctionReturn(0);
654c4762a1bSJed Brown }
655c4762a1bSJed Brown 
6569371c9d4SSatish Balay static PetscErrorCode CheckFunctions(DM dm, PetscInt order, AppCtx *user) {
657c4762a1bSJed Brown   PetscErrorCode (*exactFuncs[1])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx);
658c4762a1bSJed Brown   PetscErrorCode (*exactFuncDers[1])(PetscInt dim, PetscReal time, const PetscReal x[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx);
659c4762a1bSJed Brown   void     *exactCtxs[3];
660c4762a1bSJed Brown   MPI_Comm  comm;
661c4762a1bSJed Brown   PetscReal error, errorDer, tol = PETSC_SMALL;
662c4762a1bSJed Brown 
663c4762a1bSJed Brown   PetscFunctionBeginUser;
664c4762a1bSJed Brown   exactCtxs[0] = user;
665c4762a1bSJed Brown   exactCtxs[1] = user;
666c4762a1bSJed Brown   exactCtxs[2] = user;
6679566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
668c4762a1bSJed Brown   /* Setup functions to approximate */
669c4762a1bSJed Brown   switch (order) {
670c4762a1bSJed Brown   case 0:
671c4762a1bSJed Brown     exactFuncs[0]    = constant;
672c4762a1bSJed Brown     exactFuncDers[0] = constantDer;
673c4762a1bSJed Brown     break;
674c4762a1bSJed Brown   case 1:
675c4762a1bSJed Brown     exactFuncs[0]    = linear;
676c4762a1bSJed Brown     exactFuncDers[0] = linearDer;
677c4762a1bSJed Brown     break;
678c4762a1bSJed Brown   case 2:
679c4762a1bSJed Brown     exactFuncs[0]    = quadratic;
680c4762a1bSJed Brown     exactFuncDers[0] = quadraticDer;
681c4762a1bSJed Brown     break;
682c4762a1bSJed Brown   case 3:
683c4762a1bSJed Brown     exactFuncs[0]    = cubic;
684c4762a1bSJed Brown     exactFuncDers[0] = cubicDer;
685c4762a1bSJed Brown     break;
6869371c9d4SSatish Balay   default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Could not determine functions to test for order %" PetscInt_FMT, order);
687c4762a1bSJed Brown   }
6889566063dSJacob Faibussowitsch   PetscCall(ComputeError(dm, exactFuncs, exactFuncDers, exactCtxs, &error, &errorDer, user));
689c4762a1bSJed Brown   /* Report result */
69063a3b9bcSJacob Faibussowitsch   if (error > tol) PetscCall(PetscPrintf(comm, "Function tests FAIL for order %" PetscInt_FMT " at tolerance %g error %g\n", order, (double)tol, (double)error));
69163a3b9bcSJacob Faibussowitsch   else PetscCall(PetscPrintf(comm, "Function tests pass for order %" PetscInt_FMT " at tolerance %g\n", order, (double)tol));
69263a3b9bcSJacob Faibussowitsch   if (errorDer > tol) PetscCall(PetscPrintf(comm, "Function tests FAIL for order %" PetscInt_FMT " derivatives at tolerance %g error %g\n", order, (double)tol, (double)errorDer));
69363a3b9bcSJacob Faibussowitsch   else PetscCall(PetscPrintf(comm, "Function tests pass for order %" PetscInt_FMT " derivatives at tolerance %g\n", order, (double)tol));
694c4762a1bSJed Brown   PetscFunctionReturn(0);
695c4762a1bSJed Brown }
696c4762a1bSJed Brown 
6979371c9d4SSatish Balay static PetscErrorCode CheckInterpolation(DM dm, PetscBool checkRestrict, PetscInt order, AppCtx *user) {
698c4762a1bSJed Brown   PetscErrorCode (*exactFuncs[1])(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
699c4762a1bSJed Brown   PetscErrorCode (*exactFuncDers[1])(PetscInt, PetscReal, const PetscReal x[], const PetscReal n[], PetscInt, PetscScalar *u, void *ctx);
700c4762a1bSJed Brown   PetscReal n[3] = {1.0, 1.0, 1.0};
701c4762a1bSJed Brown   void     *exactCtxs[3];
702c4762a1bSJed Brown   DM        rdm, idm, fdm;
703c4762a1bSJed Brown   Mat       Interp;
704c4762a1bSJed Brown   Vec       iu, fu, scaling;
705c4762a1bSJed Brown   MPI_Comm  comm;
70630602db0SMatthew G. Knepley   PetscInt  dim;
707c4762a1bSJed Brown   PetscReal error, errorDer, tol = PETSC_SMALL;
708c4762a1bSJed Brown 
709c4762a1bSJed Brown   PetscFunctionBeginUser;
710c4762a1bSJed Brown   exactCtxs[0] = user;
711c4762a1bSJed Brown   exactCtxs[1] = user;
712c4762a1bSJed Brown   exactCtxs[2] = user;
7139566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
7149566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
7159566063dSJacob Faibussowitsch   PetscCall(DMRefine(dm, comm, &rdm));
7169566063dSJacob Faibussowitsch   PetscCall(DMSetCoarseDM(rdm, dm));
7179566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRegularRefinement(rdm, user->convRefine));
71830602db0SMatthew G. Knepley   if (user->tree) {
719c4762a1bSJed Brown     DM refTree;
7209566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(dm, &refTree));
7219566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(rdm, refTree));
722c4762a1bSJed Brown   }
7239566063dSJacob Faibussowitsch   if (user->useDA) PetscCall(DMDASetVertexCoordinates(rdm, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0));
7249566063dSJacob Faibussowitsch   PetscCall(SetupSection(rdm, user));
725c4762a1bSJed Brown   /* Setup functions to approximate */
726c4762a1bSJed Brown   switch (order) {
727c4762a1bSJed Brown   case 0:
728c4762a1bSJed Brown     exactFuncs[0]    = constant;
729c4762a1bSJed Brown     exactFuncDers[0] = constantDer;
730c4762a1bSJed Brown     break;
731c4762a1bSJed Brown   case 1:
732c4762a1bSJed Brown     exactFuncs[0]    = linear;
733c4762a1bSJed Brown     exactFuncDers[0] = linearDer;
734c4762a1bSJed Brown     break;
735c4762a1bSJed Brown   case 2:
736c4762a1bSJed Brown     exactFuncs[0]    = quadratic;
737c4762a1bSJed Brown     exactFuncDers[0] = quadraticDer;
738c4762a1bSJed Brown     break;
739c4762a1bSJed Brown   case 3:
740c4762a1bSJed Brown     exactFuncs[0]    = cubic;
741c4762a1bSJed Brown     exactFuncDers[0] = cubicDer;
742c4762a1bSJed Brown     break;
7439371c9d4SSatish Balay   default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Could not determine functions to test for dimension %" PetscInt_FMT " order %" PetscInt_FMT, dim, order);
744c4762a1bSJed Brown   }
745c4762a1bSJed Brown   idm = checkRestrict ? rdm : dm;
746c4762a1bSJed Brown   fdm = checkRestrict ? dm : rdm;
7479566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(idm, &iu));
7489566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(fdm, &fu));
7499566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(dm, user));
7509566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(rdm, user));
7519566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolation(dm, rdm, &Interp, &scaling));
752c4762a1bSJed Brown   /* Project function into initial FE function space */
7539566063dSJacob Faibussowitsch   PetscCall(DMProjectFunction(idm, 0.0, exactFuncs, exactCtxs, INSERT_ALL_VALUES, iu));
754c4762a1bSJed Brown   /* Interpolate function into final FE function space */
7559371c9d4SSatish Balay   if (checkRestrict) {
7569371c9d4SSatish Balay     PetscCall(MatRestrict(Interp, iu, fu));
7579371c9d4SSatish Balay     PetscCall(VecPointwiseMult(fu, scaling, fu));
7589371c9d4SSatish Balay   } else PetscCall(MatInterpolate(Interp, iu, fu));
759c4762a1bSJed Brown   /* Compare approximation to exact in L_2 */
7609566063dSJacob Faibussowitsch   PetscCall(DMComputeL2Diff(fdm, 0.0, exactFuncs, exactCtxs, fu, &error));
7619566063dSJacob Faibussowitsch   PetscCall(DMComputeL2GradientDiff(fdm, 0.0, exactFuncDers, exactCtxs, fu, n, &errorDer));
762c4762a1bSJed Brown   /* Report result */
76363a3b9bcSJacob Faibussowitsch   if (error > tol) PetscCall(PetscPrintf(comm, "Interpolation tests FAIL for order %" PetscInt_FMT " at tolerance %g error %g\n", order, (double)tol, (double)error));
76463a3b9bcSJacob Faibussowitsch   else PetscCall(PetscPrintf(comm, "Interpolation tests pass for order %" PetscInt_FMT " at tolerance %g\n", order, (double)tol));
76563a3b9bcSJacob Faibussowitsch   if (errorDer > tol) PetscCall(PetscPrintf(comm, "Interpolation tests FAIL for order %" PetscInt_FMT " derivatives at tolerance %g error %g\n", order, (double)tol, (double)errorDer));
76663a3b9bcSJacob Faibussowitsch   else PetscCall(PetscPrintf(comm, "Interpolation tests pass for order %" PetscInt_FMT " derivatives at tolerance %g\n", order, (double)tol));
7679566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(idm, &iu));
7689566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(fdm, &fu));
7699566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Interp));
7709566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&scaling));
7719566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&rdm));
772c4762a1bSJed Brown   PetscFunctionReturn(0);
773c4762a1bSJed Brown }
774c4762a1bSJed Brown 
7759371c9d4SSatish Balay static PetscErrorCode CheckConvergence(DM dm, PetscInt Nr, AppCtx *user) {
776c4762a1bSJed Brown   DM odm = dm, rdm = NULL, cdm = NULL;
777c4762a1bSJed Brown   PetscErrorCode (*exactFuncs[1])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)                         = {trig};
778c4762a1bSJed Brown   PetscErrorCode (*exactFuncDers[1])(PetscInt dim, PetscReal time, const PetscReal x[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx) = {trigDer};
779c4762a1bSJed Brown   void     *exactCtxs[3];
780c4762a1bSJed Brown   PetscInt  r, c, cStart, cEnd;
781c4762a1bSJed Brown   PetscReal errorOld, errorDerOld, error, errorDer, rel, len, lenOld;
782c4762a1bSJed Brown   double    p;
783c4762a1bSJed Brown 
784c4762a1bSJed Brown   PetscFunctionBeginUser;
785c4762a1bSJed Brown   if (!user->convergence) PetscFunctionReturn(0);
786c4762a1bSJed Brown   exactCtxs[0] = user;
787c4762a1bSJed Brown   exactCtxs[1] = user;
788c4762a1bSJed Brown   exactCtxs[2] = user;
7899566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)odm));
790c4762a1bSJed Brown   if (!user->convRefine) {
791c4762a1bSJed Brown     for (r = 0; r < Nr; ++r) {
7929566063dSJacob Faibussowitsch       PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)dm), &rdm));
7939566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&odm));
794c4762a1bSJed Brown       odm = rdm;
795c4762a1bSJed Brown     }
7969566063dSJacob Faibussowitsch     PetscCall(SetupSection(odm, user));
797c4762a1bSJed Brown   }
7989566063dSJacob Faibussowitsch   PetscCall(ComputeError(odm, exactFuncs, exactFuncDers, exactCtxs, &errorOld, &errorDerOld, user));
799c4762a1bSJed Brown   if (user->convRefine) {
800c4762a1bSJed Brown     for (r = 0; r < Nr; ++r) {
8019566063dSJacob Faibussowitsch       PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)dm), &rdm));
8029566063dSJacob Faibussowitsch       if (user->useDA) PetscCall(DMDASetVertexCoordinates(rdm, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0));
8039566063dSJacob Faibussowitsch       PetscCall(SetupSection(rdm, user));
8049566063dSJacob Faibussowitsch       PetscCall(ComputeError(rdm, exactFuncs, exactFuncDers, exactCtxs, &error, &errorDer, user));
805c4762a1bSJed Brown       p = PetscLog2Real(errorOld / error);
80663a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Function   convergence rate at refinement %" PetscInt_FMT ": %.2f\n", r, (double)p));
807c4762a1bSJed Brown       p = PetscLog2Real(errorDerOld / errorDer);
80863a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Derivative convergence rate at refinement %" PetscInt_FMT ": %.2f\n", r, (double)p));
8099566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&odm));
810c4762a1bSJed Brown       odm         = rdm;
811c4762a1bSJed Brown       errorOld    = error;
812c4762a1bSJed Brown       errorDerOld = errorDer;
813c4762a1bSJed Brown     }
814c4762a1bSJed Brown   } else {
8159566063dSJacob Faibussowitsch     /* PetscCall(ComputeLongestEdge(dm, &lenOld)); */
8169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(odm, 0, &cStart, &cEnd));
817c4762a1bSJed Brown     lenOld = cEnd - cStart;
818c4762a1bSJed Brown     for (c = 0; c < Nr; ++c) {
8199566063dSJacob Faibussowitsch       PetscCall(DMCoarsen(odm, PetscObjectComm((PetscObject)dm), &cdm));
8209566063dSJacob Faibussowitsch       if (user->useDA) PetscCall(DMDASetVertexCoordinates(cdm, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0));
8219566063dSJacob Faibussowitsch       PetscCall(SetupSection(cdm, user));
8229566063dSJacob Faibussowitsch       PetscCall(ComputeError(cdm, exactFuncs, exactFuncDers, exactCtxs, &error, &errorDer, user));
8239566063dSJacob Faibussowitsch       /* PetscCall(ComputeLongestEdge(cdm, &len)); */
8249566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd));
825c4762a1bSJed Brown       len = cEnd - cStart;
826c4762a1bSJed Brown       rel = error / errorOld;
827c4762a1bSJed Brown       p   = PetscLogReal(rel) / PetscLogReal(lenOld / len);
82863a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Function   convergence rate at coarsening %" PetscInt_FMT ": %.2f\n", c, (double)p));
829c4762a1bSJed Brown       rel = errorDer / errorDerOld;
830c4762a1bSJed Brown       p   = PetscLogReal(rel) / PetscLogReal(lenOld / len);
83163a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Derivative convergence rate at coarsening %" PetscInt_FMT ": %.2f\n", c, (double)p));
8329566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&odm));
833c4762a1bSJed Brown       odm         = cdm;
834c4762a1bSJed Brown       errorOld    = error;
835c4762a1bSJed Brown       errorDerOld = errorDer;
836c4762a1bSJed Brown       lenOld      = len;
837c4762a1bSJed Brown     }
838c4762a1bSJed Brown   }
8399566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&odm));
840c4762a1bSJed Brown   PetscFunctionReturn(0);
841c4762a1bSJed Brown }
842c4762a1bSJed Brown 
8439371c9d4SSatish Balay int main(int argc, char **argv) {
844c4762a1bSJed Brown   DM        dm;
845c4762a1bSJed Brown   AppCtx    user; /* user-defined work context */
84630602db0SMatthew G. Knepley   PetscInt  dim     = 2;
84730602db0SMatthew G. Knepley   PetscBool simplex = PETSC_FALSE;
848c4762a1bSJed Brown 
849327415f7SBarry Smith   PetscFunctionBeginUser;
8509566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
8519566063dSJacob Faibussowitsch   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
8529566063dSJacob Faibussowitsch   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
85330602db0SMatthew G. Knepley   if (!user.useDA) {
8549566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
8559566063dSJacob Faibussowitsch     PetscCall(DMPlexIsSimplex(dm, &simplex));
85630602db0SMatthew G. Knepley   }
8579566063dSJacob Faibussowitsch   PetscCall(DMPlexMetricSetFromOptions(dm));
85830602db0SMatthew G. Knepley   user.numComponents = user.numComponents < 0 ? dim : user.numComponents;
8599566063dSJacob Faibussowitsch   PetscCall(PetscFECreateDefault(PETSC_COMM_WORLD, dim, user.numComponents, simplex, NULL, user.qorder, &user.fe));
8609566063dSJacob Faibussowitsch   PetscCall(SetupSection(dm, &user));
8619566063dSJacob Faibussowitsch   if (user.testFEjacobian) PetscCall(TestFEJacobian(dm, &user));
8629566063dSJacob Faibussowitsch   if (user.testFVgrad) PetscCall(TestFVGrad(dm, &user));
8639566063dSJacob Faibussowitsch   if (user.testInjector) PetscCall(TestInjector(dm, &user));
8649566063dSJacob Faibussowitsch   PetscCall(CheckFunctions(dm, user.porder, &user));
865c4762a1bSJed Brown   {
866c4762a1bSJed Brown     PetscDualSpace dsp;
867c4762a1bSJed Brown     PetscInt       k;
868c4762a1bSJed Brown 
8699566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDualSpace(user.fe, &dsp));
8709566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
87130602db0SMatthew G. Knepley     if (dim == 2 && simplex == PETSC_TRUE && user.tree == PETSC_FALSE && k == 0) {
8729566063dSJacob Faibussowitsch       PetscCall(CheckInterpolation(dm, PETSC_FALSE, user.porder, &user));
8739566063dSJacob Faibussowitsch       PetscCall(CheckInterpolation(dm, PETSC_TRUE, user.porder, &user));
874c4762a1bSJed Brown     }
875c4762a1bSJed Brown   }
8769566063dSJacob Faibussowitsch   PetscCall(CheckConvergence(dm, 3, &user));
8779566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&user.fe));
8789566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
8799566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
880b122ec5aSJacob Faibussowitsch   return 0;
881c4762a1bSJed Brown }
882c4762a1bSJed Brown 
883c4762a1bSJed Brown /*TEST
884c4762a1bSJed Brown 
885c4762a1bSJed Brown   test:
886c4762a1bSJed Brown     suffix: 1
887c4762a1bSJed Brown     requires: triangle
888c4762a1bSJed Brown 
889c4762a1bSJed Brown   # 2D P_1 on a triangle
890c4762a1bSJed Brown   test:
891c4762a1bSJed Brown     suffix: p1_2d_0
892c4762a1bSJed Brown     requires: triangle
893c4762a1bSJed Brown     args: -petscspace_degree 1 -qorder 1 -convergence
894c4762a1bSJed Brown   test:
895c4762a1bSJed Brown     suffix: p1_2d_1
896c4762a1bSJed Brown     requires: triangle
897c4762a1bSJed Brown     args: -petscspace_degree 1 -qorder 1 -porder 1
898c4762a1bSJed Brown   test:
899c4762a1bSJed Brown     suffix: p1_2d_2
900c4762a1bSJed Brown     requires: triangle
901c4762a1bSJed Brown     args: -petscspace_degree 1 -qorder 1 -porder 2
902c4762a1bSJed Brown   test:
903c4762a1bSJed Brown     suffix: p1_2d_3
904e788613bSJoe Wallwork     requires: triangle mmg
905c4762a1bSJed Brown     args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -convergence -conv_refine 0
906c4762a1bSJed Brown   test:
907c4762a1bSJed Brown     suffix: p1_2d_4
908e788613bSJoe Wallwork     requires: triangle mmg
909c4762a1bSJed Brown     args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 1 -conv_refine 0
910c4762a1bSJed Brown   test:
911c4762a1bSJed Brown     suffix: p1_2d_5
912e788613bSJoe Wallwork     requires: triangle mmg
913c4762a1bSJed Brown     args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 2 -conv_refine 0
914c4762a1bSJed Brown 
915c4762a1bSJed Brown   # 3D P_1 on a tetrahedron
916c4762a1bSJed Brown   test:
917c4762a1bSJed Brown     suffix: p1_3d_0
918c4762a1bSJed Brown     requires: ctetgen
91930602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 1 -qorder 1 -convergence
920c4762a1bSJed Brown   test:
921c4762a1bSJed Brown     suffix: p1_3d_1
922c4762a1bSJed Brown     requires: ctetgen
92330602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 1 -qorder 1 -porder 1
924c4762a1bSJed Brown   test:
925c4762a1bSJed Brown     suffix: p1_3d_2
926c4762a1bSJed Brown     requires: ctetgen
92730602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 1 -qorder 1 -porder 2
928c4762a1bSJed Brown   test:
929c4762a1bSJed Brown     suffix: p1_3d_3
930e788613bSJoe Wallwork     requires: ctetgen mmg
93130602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -convergence -conv_refine 0
932c4762a1bSJed Brown   test:
933c4762a1bSJed Brown     suffix: p1_3d_4
934e788613bSJoe Wallwork     requires: ctetgen mmg
93530602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 1 -conv_refine 0
936c4762a1bSJed Brown   test:
937c4762a1bSJed Brown     suffix: p1_3d_5
938e788613bSJoe Wallwork     requires: ctetgen mmg
93930602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 2 -conv_refine 0
940c4762a1bSJed Brown 
941c4762a1bSJed Brown   # 2D P_2 on a triangle
942c4762a1bSJed Brown   test:
943c4762a1bSJed Brown     suffix: p2_2d_0
944c4762a1bSJed Brown     requires: triangle
945c4762a1bSJed Brown     args: -petscspace_degree 2 -qorder 2 -convergence
946c4762a1bSJed Brown   test:
947c4762a1bSJed Brown     suffix: p2_2d_1
948c4762a1bSJed Brown     requires: triangle
949c4762a1bSJed Brown     args: -petscspace_degree 2 -qorder 2 -porder 1
950c4762a1bSJed Brown   test:
951c4762a1bSJed Brown     suffix: p2_2d_2
952c4762a1bSJed Brown     requires: triangle
953c4762a1bSJed Brown     args: -petscspace_degree 2 -qorder 2 -porder 2
954c4762a1bSJed Brown   test:
955c4762a1bSJed Brown     suffix: p2_2d_3
956e788613bSJoe Wallwork     requires: triangle mmg
957c4762a1bSJed Brown     args: -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -convergence -conv_refine 0
958c4762a1bSJed Brown   test:
959c4762a1bSJed Brown     suffix: p2_2d_4
960e788613bSJoe Wallwork     requires: triangle mmg
961c4762a1bSJed Brown     args: -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -porder 1 -conv_refine 0
962c4762a1bSJed Brown   test:
963c4762a1bSJed Brown     suffix: p2_2d_5
964e788613bSJoe Wallwork     requires: triangle mmg
965c4762a1bSJed Brown     args: -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -porder 2 -conv_refine 0
966c4762a1bSJed Brown 
967c4762a1bSJed Brown   # 3D P_2 on a tetrahedron
968c4762a1bSJed Brown   test:
969c4762a1bSJed Brown     suffix: p2_3d_0
970c4762a1bSJed Brown     requires: ctetgen
97130602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 2 -qorder 2 -convergence
972c4762a1bSJed Brown   test:
973c4762a1bSJed Brown     suffix: p2_3d_1
974c4762a1bSJed Brown     requires: ctetgen
97530602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 2 -qorder 2 -porder 1
976c4762a1bSJed Brown   test:
977c4762a1bSJed Brown     suffix: p2_3d_2
978c4762a1bSJed Brown     requires: ctetgen
97930602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 2 -qorder 2 -porder 2
980c4762a1bSJed Brown   test:
981c4762a1bSJed Brown     suffix: p2_3d_3
982e788613bSJoe Wallwork     requires: ctetgen mmg
98330602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -convergence -conv_refine 0
984c4762a1bSJed Brown   test:
985c4762a1bSJed Brown     suffix: p2_3d_4
986e788613bSJoe Wallwork     requires: ctetgen mmg
98730602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -porder 1 -conv_refine 0
988c4762a1bSJed Brown   test:
989c4762a1bSJed Brown     suffix: p2_3d_5
990e788613bSJoe Wallwork     requires: ctetgen mmg
99130602db0SMatthew G. Knepley     args: -dm_plex_dim 3 -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -porder 2 -conv_refine 0
992c4762a1bSJed Brown 
993c4762a1bSJed Brown   # 2D Q_1 on a quadrilaterial DA
994c4762a1bSJed Brown   test:
995c4762a1bSJed Brown     suffix: q1_2d_da_0
99699a192c5SJunchao Zhang     requires: broken
99730602db0SMatthew G. Knepley     args: -use_da 1 -petscspace_degree 1 -qorder 1 -convergence
998c4762a1bSJed Brown   test:
999c4762a1bSJed Brown     suffix: q1_2d_da_1
100099a192c5SJunchao Zhang     requires: broken
100130602db0SMatthew G. Knepley     args: -use_da 1 -petscspace_degree 1 -qorder 1 -porder 1
1002c4762a1bSJed Brown   test:
1003c4762a1bSJed Brown     suffix: q1_2d_da_2
100499a192c5SJunchao Zhang     requires: broken
100530602db0SMatthew G. Knepley     args: -use_da 1 -petscspace_degree 1 -qorder 1 -porder 2
1006c4762a1bSJed Brown 
1007c4762a1bSJed Brown   # 2D Q_1 on a quadrilaterial Plex
1008c4762a1bSJed Brown   test:
1009c4762a1bSJed Brown     suffix: q1_2d_plex_0
101030602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -qorder 1 -convergence
1011c4762a1bSJed Brown   test:
1012c4762a1bSJed Brown     suffix: q1_2d_plex_1
101330602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -qorder 1 -porder 1
1014c4762a1bSJed Brown   test:
1015c4762a1bSJed Brown     suffix: q1_2d_plex_2
101630602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -qorder 1 -porder 2
1017c4762a1bSJed Brown   test:
1018c4762a1bSJed Brown     suffix: q1_2d_plex_3
101930602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -qorder 1 -porder 1 -shear_coords
1020c4762a1bSJed Brown   test:
1021c4762a1bSJed Brown     suffix: q1_2d_plex_4
102230602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -qorder 1 -porder 2 -shear_coords
1023c4762a1bSJed Brown   test:
1024c4762a1bSJed Brown     suffix: q1_2d_plex_5
102530602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -petscspace_type tensor -qorder 1 -porder 0 -non_affine_coords -convergence
1026c4762a1bSJed Brown   test:
1027c4762a1bSJed Brown     suffix: q1_2d_plex_6
102830602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -petscspace_type tensor -qorder 1 -porder 1 -non_affine_coords -convergence
1029c4762a1bSJed Brown   test:
1030c4762a1bSJed Brown     suffix: q1_2d_plex_7
103130602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -petscspace_type tensor -qorder 1 -porder 2 -non_affine_coords -convergence
1032c4762a1bSJed Brown 
1033c4762a1bSJed Brown   # 2D Q_2 on a quadrilaterial
1034c4762a1bSJed Brown   test:
1035c4762a1bSJed Brown     suffix: q2_2d_plex_0
103630602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 2 -convergence
1037c4762a1bSJed Brown   test:
1038c4762a1bSJed Brown     suffix: q2_2d_plex_1
103930602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 2 -porder 1
1040c4762a1bSJed Brown   test:
1041c4762a1bSJed Brown     suffix: q2_2d_plex_2
104230602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 2 -porder 2
1043c4762a1bSJed Brown   test:
1044c4762a1bSJed Brown     suffix: q2_2d_plex_3
104530602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 2 -porder 1 -shear_coords
1046c4762a1bSJed Brown   test:
1047c4762a1bSJed Brown     suffix: q2_2d_plex_4
104830602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 2 -porder 2 -shear_coords
1049c4762a1bSJed Brown   test:
1050c4762a1bSJed Brown     suffix: q2_2d_plex_5
105130602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -petscspace_type tensor -qorder 2 -porder 0 -non_affine_coords -convergence
1052c4762a1bSJed Brown   test:
1053c4762a1bSJed Brown     suffix: q2_2d_plex_6
105430602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -petscspace_type tensor -qorder 2 -porder 1 -non_affine_coords -convergence
1055c4762a1bSJed Brown   test:
1056c4762a1bSJed Brown     suffix: q2_2d_plex_7
105730602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -petscspace_type tensor -qorder 2 -porder 2 -non_affine_coords -convergence
1058c4762a1bSJed Brown 
1059c4762a1bSJed Brown   # 2D P_3 on a triangle
1060c4762a1bSJed Brown   test:
1061c4762a1bSJed Brown     suffix: p3_2d_0
1062c4762a1bSJed Brown     requires: triangle !single
1063c4762a1bSJed Brown     args: -petscspace_degree 3 -qorder 3 -convergence
1064c4762a1bSJed Brown   test:
1065c4762a1bSJed Brown     suffix: p3_2d_1
1066c4762a1bSJed Brown     requires: triangle !single
1067c4762a1bSJed Brown     args: -petscspace_degree 3 -qorder 3 -porder 1
1068c4762a1bSJed Brown   test:
1069c4762a1bSJed Brown     suffix: p3_2d_2
1070c4762a1bSJed Brown     requires: triangle !single
1071c4762a1bSJed Brown     args: -petscspace_degree 3 -qorder 3 -porder 2
1072c4762a1bSJed Brown   test:
1073c4762a1bSJed Brown     suffix: p3_2d_3
1074c4762a1bSJed Brown     requires: triangle !single
1075c4762a1bSJed Brown     args: -petscspace_degree 3 -qorder 3 -porder 3
1076c4762a1bSJed Brown   test:
1077c4762a1bSJed Brown     suffix: p3_2d_4
1078e788613bSJoe Wallwork     requires: triangle mmg
1079c4762a1bSJed Brown     args: -petscspace_degree 3 -qorder 3 -dm_plex_hash_location -convergence -conv_refine 0
1080c4762a1bSJed Brown   test:
1081c4762a1bSJed Brown     suffix: p3_2d_5
1082e788613bSJoe Wallwork     requires: triangle mmg
1083c4762a1bSJed Brown     args: -petscspace_degree 3 -qorder 3 -dm_plex_hash_location -porder 1 -conv_refine 0
1084c4762a1bSJed Brown   test:
1085c4762a1bSJed Brown     suffix: p3_2d_6
1086e788613bSJoe Wallwork     requires: triangle mmg
1087c4762a1bSJed Brown     args: -petscspace_degree 3 -qorder 3 -dm_plex_hash_location -porder 3 -conv_refine 0
1088c4762a1bSJed Brown 
1089c4762a1bSJed Brown   # 2D Q_3 on a quadrilaterial
1090c4762a1bSJed Brown   test:
1091c4762a1bSJed Brown     suffix: q3_2d_0
109299a192c5SJunchao Zhang     requires: !single
109330602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 3 -qorder 3 -convergence
1094c4762a1bSJed Brown   test:
1095c4762a1bSJed Brown     suffix: q3_2d_1
109699a192c5SJunchao Zhang     requires: !single
109730602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 3 -qorder 3 -porder 1
1098c4762a1bSJed Brown   test:
1099c4762a1bSJed Brown     suffix: q3_2d_2
110099a192c5SJunchao Zhang     requires: !single
110130602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 3 -qorder 3 -porder 2
1102c4762a1bSJed Brown   test:
1103c4762a1bSJed Brown     suffix: q3_2d_3
110499a192c5SJunchao Zhang     requires: !single
110530602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 3 -qorder 3 -porder 3
1106c4762a1bSJed Brown 
1107c4762a1bSJed Brown   # 2D P_1disc on a triangle/quadrilateral
1108c4762a1bSJed Brown   test:
1109c4762a1bSJed Brown     suffix: p1d_2d_0
1110c4762a1bSJed Brown     requires: triangle
1111c4762a1bSJed Brown     args: -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -convergence
1112c4762a1bSJed Brown   test:
1113c4762a1bSJed Brown     suffix: p1d_2d_1
1114c4762a1bSJed Brown     requires: triangle
1115c4762a1bSJed Brown     args: -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -porder 1
1116c4762a1bSJed Brown   test:
1117c4762a1bSJed Brown     suffix: p1d_2d_2
1118c4762a1bSJed Brown     requires: triangle
1119c4762a1bSJed Brown     args: -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -porder 2
1120c4762a1bSJed Brown   test:
1121c4762a1bSJed Brown     suffix: p1d_2d_3
1122c4762a1bSJed Brown     requires: triangle
112330602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -convergence
1124c4762a1bSJed Brown     filter: sed  -e "s/convergence rate at refinement 0: 2/convergence rate at refinement 0: 1.9/g"
1125c4762a1bSJed Brown   test:
1126c4762a1bSJed Brown     suffix: p1d_2d_4
1127c4762a1bSJed Brown     requires: triangle
112830602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -porder 1
1129c4762a1bSJed Brown   test:
1130c4762a1bSJed Brown     suffix: p1d_2d_5
1131c4762a1bSJed Brown     requires: triangle
113230602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -porder 2
1133c4762a1bSJed Brown 
1134c4762a1bSJed Brown   # 2D BDM_1 on a triangle
1135c4762a1bSJed Brown   test:
1136c4762a1bSJed Brown     suffix: bdm1_2d_0
1137c4762a1bSJed Brown     requires: triangle
1138c4762a1bSJed Brown     args: -petscspace_degree 1 -petscdualspace_type bdm \
1139c4762a1bSJed Brown           -num_comp 2 -qorder 1 -convergence
1140c4762a1bSJed Brown   test:
1141c4762a1bSJed Brown     suffix: bdm1_2d_1
1142c4762a1bSJed Brown     requires: triangle
1143c4762a1bSJed Brown     args: -petscspace_degree 1 -petscdualspace_type bdm \
1144c4762a1bSJed Brown           -num_comp 2 -qorder 1 -porder 1
1145c4762a1bSJed Brown   test:
1146c4762a1bSJed Brown     suffix: bdm1_2d_2
1147c4762a1bSJed Brown     requires: triangle
1148c4762a1bSJed Brown     args: -petscspace_degree 1 -petscdualspace_type bdm \
1149c4762a1bSJed Brown           -num_comp 2 -qorder 1 -porder 2
1150c4762a1bSJed Brown 
1151c4762a1bSJed Brown   # 2D BDM_1 on a quadrilateral
1152c4762a1bSJed Brown   test:
1153c4762a1bSJed Brown     suffix: bdm1q_2d_0
1154c4762a1bSJed Brown     requires: triangle
1155c4762a1bSJed Brown     args: -petscspace_degree 1 -petscdualspace_type bdm \
11563f27d899SToby Isaac           -petscdualspace_lagrange_tensor 1 \
115730602db0SMatthew G. Knepley           -dm_plex_simplex 0 -num_comp 2 -qorder 1 -convergence
1158c4762a1bSJed Brown   test:
1159c4762a1bSJed Brown     suffix: bdm1q_2d_1
1160c4762a1bSJed Brown     requires: triangle
1161c4762a1bSJed Brown     args: -petscspace_degree 1 -petscdualspace_type bdm \
11623f27d899SToby Isaac           -petscdualspace_lagrange_tensor 1 \
116330602db0SMatthew G. Knepley           -dm_plex_simplex 0 -num_comp 2 -qorder 1 -porder 1
1164c4762a1bSJed Brown   test:
1165c4762a1bSJed Brown     suffix: bdm1q_2d_2
1166c4762a1bSJed Brown     requires: triangle
1167c4762a1bSJed Brown     args: -petscspace_degree 1 -petscdualspace_type bdm \
11683f27d899SToby Isaac           -petscdualspace_lagrange_tensor 1 \
116930602db0SMatthew G. Knepley           -dm_plex_simplex 0 -num_comp 2 -qorder 1 -porder 2
1170c4762a1bSJed Brown 
1171c4762a1bSJed Brown   # Test high order quadrature
1172c4762a1bSJed Brown   test:
1173c4762a1bSJed Brown     suffix: p1_quad_2
1174c4762a1bSJed Brown     requires: triangle
1175c4762a1bSJed Brown     args: -petscspace_degree 1 -qorder 2 -porder 1
1176c4762a1bSJed Brown   test:
1177c4762a1bSJed Brown     suffix: p1_quad_5
1178c4762a1bSJed Brown     requires: triangle
1179c4762a1bSJed Brown     args: -petscspace_degree 1 -qorder 5 -porder 1
1180c4762a1bSJed Brown   test:
1181c4762a1bSJed Brown     suffix: p2_quad_3
1182c4762a1bSJed Brown     requires: triangle
1183c4762a1bSJed Brown     args: -petscspace_degree 2 -qorder 3 -porder 2
1184c4762a1bSJed Brown   test:
1185c4762a1bSJed Brown     suffix: p2_quad_5
1186c4762a1bSJed Brown     requires: triangle
1187c4762a1bSJed Brown     args: -petscspace_degree 2 -qorder 5 -porder 2
1188c4762a1bSJed Brown   test:
1189c4762a1bSJed Brown     suffix: q1_quad_2
119030602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -qorder 2 -porder 1
1191c4762a1bSJed Brown   test:
1192c4762a1bSJed Brown     suffix: q1_quad_5
119330602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 1 -qorder 5 -porder 1
1194c4762a1bSJed Brown   test:
1195c4762a1bSJed Brown     suffix: q2_quad_3
119630602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 3 -porder 1
1197c4762a1bSJed Brown   test:
1198c4762a1bSJed Brown     suffix: q2_quad_5
119930602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 5 -porder 1
1200c4762a1bSJed Brown 
1201c4762a1bSJed Brown   # Nonconforming tests
1202c4762a1bSJed Brown   test:
1203c4762a1bSJed Brown     suffix: constraints
120430602db0SMatthew G. Knepley     args: -dm_coord_space 0 -dm_plex_simplex 0 -petscspace_type tensor -petscspace_degree 1 -qorder 0 -constraints
1205c4762a1bSJed Brown   test:
1206c4762a1bSJed Brown     suffix: nonconforming_tensor_2
1207c4762a1bSJed Brown     nsize: 4
120830602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fe_jacobian -test_injector -petscpartitioner_type simple -tree -dm_plex_simplex 0 -dm_plex_max_projection_height 1 -petscspace_type tensor -petscspace_degree 2 -qorder 2 -dm_view ascii::ASCII_INFO_DETAIL
1209c4762a1bSJed Brown   test:
1210c4762a1bSJed Brown     suffix: nonconforming_tensor_3
1211c4762a1bSJed Brown     nsize: 4
121230602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fe_jacobian -petscpartitioner_type simple -tree -dm_plex_simplex 0 -dm_plex_dim 3 -dm_plex_box_faces 2,2,2 -dm_plex_max_projection_height 2 -petscspace_type tensor -petscspace_degree 1 -qorder 1 -dm_view ascii::ASCII_INFO_DETAIL
1213c4762a1bSJed Brown   test:
1214c4762a1bSJed Brown     suffix: nonconforming_tensor_2_fv
1215c4762a1bSJed Brown     nsize: 4
121630602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fv_grad -test_injector -petsclimiter_type none -petscpartitioner_type simple -tree -dm_plex_simplex 0 -num_comp 2
1217c4762a1bSJed Brown   test:
1218c4762a1bSJed Brown     suffix: nonconforming_tensor_3_fv
1219c4762a1bSJed Brown     nsize: 4
122030602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fv_grad -test_injector -petsclimiter_type none -petscpartitioner_type simple -tree -dm_plex_simplex 0 -dm_plex_dim 3 -dm_plex_box_faces 2,2,2 -num_comp 3
1221c4762a1bSJed Brown   test:
1222c4762a1bSJed Brown     suffix: nonconforming_tensor_2_hi
1223c4762a1bSJed Brown     requires: !single
1224c4762a1bSJed Brown     nsize: 4
122530602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fe_jacobian -petscpartitioner_type simple -tree -dm_plex_simplex 0 -dm_plex_max_projection_height 1 -petscspace_type tensor -petscspace_degree 4 -qorder 4
1226c4762a1bSJed Brown   test:
1227c4762a1bSJed Brown     suffix: nonconforming_tensor_3_hi
1228c4762a1bSJed Brown     requires: !single skip
1229c4762a1bSJed Brown     nsize: 4
123030602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fe_jacobian -petscpartitioner_type simple -tree -dm_plex_simplex 0 -dm_plex_dim 3 -dm_plex_box_faces 2,2,2 -dm_plex_max_projection_height 2 -petscspace_type tensor -petscspace_degree 4 -qorder 4
1231c4762a1bSJed Brown   test:
1232c4762a1bSJed Brown     suffix: nonconforming_simplex_2
1233c4762a1bSJed Brown     requires: triangle
1234c4762a1bSJed Brown     nsize: 4
123530602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fe_jacobian -test_injector -petscpartitioner_type simple -tree -dm_plex_max_projection_height 1 -petscspace_degree 2 -qorder 2 -dm_view ascii::ASCII_INFO_DETAIL
1236c4762a1bSJed Brown   test:
1237c4762a1bSJed Brown     suffix: nonconforming_simplex_2_hi
1238c4762a1bSJed Brown     requires: triangle !single
1239c4762a1bSJed Brown     nsize: 4
124030602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fe_jacobian -petscpartitioner_type simple -tree -dm_plex_max_projection_height 1 -petscspace_degree 4 -qorder 4
1241c4762a1bSJed Brown   test:
1242c4762a1bSJed Brown     suffix: nonconforming_simplex_2_fv
1243c4762a1bSJed Brown     requires: triangle
1244c4762a1bSJed Brown     nsize: 4
124530602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fv_grad -test_injector -petsclimiter_type none -petscpartitioner_type simple -tree -num_comp 2
1246c4762a1bSJed Brown   test:
1247c4762a1bSJed Brown     suffix: nonconforming_simplex_3
1248c4762a1bSJed Brown     requires: ctetgen
1249c4762a1bSJed Brown     nsize: 4
125030602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fe_jacobian -test_injector -petscpartitioner_type simple -tree -dm_plex_dim 3 -dm_plex_max_projection_height 2 -petscspace_degree 2 -qorder 2 -dm_view ascii::ASCII_INFO_DETAIL
1251c4762a1bSJed Brown   test:
1252c4762a1bSJed Brown     suffix: nonconforming_simplex_3_hi
1253c4762a1bSJed Brown     requires: ctetgen skip
1254c4762a1bSJed Brown     nsize: 4
125530602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fe_jacobian -petscpartitioner_type simple -tree -dm_plex_dim 3 -dm_plex_max_projection_height 2 -petscspace_degree 4 -qorder 4
1256c4762a1bSJed Brown   test:
1257c4762a1bSJed Brown     suffix: nonconforming_simplex_3_fv
1258c4762a1bSJed Brown     requires: ctetgen
1259c4762a1bSJed Brown     nsize: 4
126030602db0SMatthew G. Knepley     args: -dist_dm_distribute -test_fv_grad -test_injector -petsclimiter_type none -petscpartitioner_type simple -tree -dm_plex_dim 3 -num_comp 3
1261c4762a1bSJed Brown 
1262d21efd2eSMatthew G. Knepley   # 3D WXY on a triangular prism
1263d21efd2eSMatthew G. Knepley   test:
1264d21efd2eSMatthew G. Knepley     suffix: wxy_0
1265d21efd2eSMatthew G. Knepley     args: -dm_plex_reference_cell_domain -dm_plex_cell triangular_prism -qorder 2 -porder 0 \
1266e239af90SMatthew G. Knepley           -petscspace_type sum \
1267e239af90SMatthew G. Knepley           -petscspace_variables 3 \
1268e239af90SMatthew G. Knepley           -petscspace_components 3 \
1269e239af90SMatthew G. Knepley           -petscspace_sum_spaces 2 \
1270e239af90SMatthew G. Knepley           -petscspace_sum_concatenate false \
1271e239af90SMatthew G. Knepley           -sumcomp_0_petscspace_variables 3 \
1272e239af90SMatthew G. Knepley           -sumcomp_0_petscspace_components 3 \
1273e239af90SMatthew G. Knepley           -sumcomp_0_petscspace_degree 1 \
1274e239af90SMatthew G. Knepley           -sumcomp_1_petscspace_variables 3 \
1275e239af90SMatthew G. Knepley           -sumcomp_1_petscspace_components 3 \
1276e239af90SMatthew G. Knepley           -sumcomp_1_petscspace_type wxy \
1277e239af90SMatthew G. Knepley           -petscdualspace_refcell triangular_prism \
1278e239af90SMatthew G. Knepley           -petscdualspace_form_degree 0 \
1279e239af90SMatthew G. Knepley           -petscdualspace_order 1 \
1280e239af90SMatthew G. Knepley           -petscdualspace_components 3
1281d21efd2eSMatthew G. Knepley 
1282c4762a1bSJed Brown TEST*/
1283c4762a1bSJed Brown 
1284c4762a1bSJed Brown /*
1285c4762a1bSJed Brown    # 2D Q_2 on a quadrilaterial Plex
1286c4762a1bSJed Brown   test:
1287c4762a1bSJed Brown     suffix: q2_2d_plex_0
128830602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 2 -convergence
1289c4762a1bSJed Brown   test:
1290c4762a1bSJed Brown     suffix: q2_2d_plex_1
129130602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 2 -porder 1
1292c4762a1bSJed Brown   test:
1293c4762a1bSJed Brown     suffix: q2_2d_plex_2
129430602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 2 -porder 2
1295c4762a1bSJed Brown   test:
1296c4762a1bSJed Brown     suffix: q2_2d_plex_3
129730602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 2 -porder 1 -shear_coords
1298c4762a1bSJed Brown   test:
1299c4762a1bSJed Brown     suffix: q2_2d_plex_4
130030602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -qorder 2 -porder 2 -shear_coords
1301c4762a1bSJed Brown   test:
1302c4762a1bSJed Brown     suffix: q2_2d_plex_5
130330602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -petscspace_poly_tensor 1 -qorder 2 -porder 0 -non_affine_coords
1304c4762a1bSJed Brown   test:
1305c4762a1bSJed Brown     suffix: q2_2d_plex_6
130630602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -petscspace_poly_tensor 1 -qorder 2 -porder 1 -non_affine_coords
1307c4762a1bSJed Brown   test:
1308c4762a1bSJed Brown     suffix: q2_2d_plex_7
130930602db0SMatthew G. Knepley     args: -dm_plex_simplex 0 -petscspace_degree 2 -petscspace_poly_tensor 1 -qorder 2 -porder 2 -non_affine_coords
1310c4762a1bSJed Brown 
1311c4762a1bSJed Brown   test:
1312c4762a1bSJed Brown     suffix: p1d_2d_6
1313e788613bSJoe Wallwork     requires: mmg
1314c4762a1bSJed Brown     args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -convergence -conv_refine 0
1315c4762a1bSJed Brown   test:
1316c4762a1bSJed Brown     suffix: p1d_2d_7
1317e788613bSJoe Wallwork     requires: mmg
1318c4762a1bSJed Brown     args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 1 -conv_refine 0
1319c4762a1bSJed Brown   test:
1320c4762a1bSJed Brown     suffix: p1d_2d_8
1321e788613bSJoe Wallwork     requires: mmg
1322c4762a1bSJed Brown     args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 2 -conv_refine 0
1323c4762a1bSJed Brown */
1324