Actual source code: ex3.c
petsc-3.14.6 2021-03-30
1: static char help[] = "Check that a DM can accurately represent and interpolate functions of a given polynomial order\n\n";
3: #include <petscdmplex.h>
4: #include <petscdm.h>
5: #include <petscdmda.h>
6: #include <petscfe.h>
7: #include <petscds.h>
8: #include <petscksp.h>
9: #include <petscsnes.h>
11: typedef struct {
12: PetscInt debug; /* The debugging level */
13: /* Domain and mesh definition */
14: PetscInt dim; /* The topological mesh dimension */
15: PetscBool simplex; /* Flag for simplex or tensor product mesh */
16: PetscBool refcell; /* Make the mesh only a reference cell */
17: PetscBool useDA; /* Flag DMDA tensor product mesh */
18: PetscBool interpolate; /* Generate intermediate mesh elements */
19: PetscReal refinementLimit; /* The largest allowable cell volume */
20: PetscBool shearCoords; /* Flag for shear transform */
21: PetscBool nonaffineCoords; /* Flag for non-affine transform */
22: /* Element definition */
23: PetscInt qorder; /* Order of the quadrature */
24: PetscInt numComponents; /* Number of field components */
25: PetscFE fe; /* The finite element */
26: /* Testing space */
27: PetscInt porder; /* Order of polynomials to test */
28: PetscBool convergence; /* Test for order of convergence */
29: PetscBool convRefine; /* Test for convergence using refinement, otherwise use coarsening */
30: PetscBool constraints; /* Test local constraints */
31: PetscBool tree; /* Test tree routines */
32: PetscBool testFEjacobian; /* Test finite element Jacobian assembly */
33: PetscBool testFVgrad; /* Test finite difference gradient routine */
34: PetscBool testInjector; /* Test finite element injection routines */
35: PetscInt treeCell; /* Cell to refine in tree test */
36: PetscReal constants[3]; /* Constant values for each dimension */
37: } AppCtx;
39: /* u = 1 */
40: PetscErrorCode constant(PetscInt dim, PetscReal time, const PetscReal coords[], PetscInt Nf, PetscScalar *u, void *ctx)
41: {
42: AppCtx *user = (AppCtx *) ctx;
43: PetscInt d;
44: for (d = 0; d < user->dim; ++d) u[d] = user->constants[d];
45: return 0;
46: }
47: PetscErrorCode constantDer(PetscInt dim, PetscReal time, const PetscReal coords[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx)
48: {
49: AppCtx *user = (AppCtx *) ctx;
50: PetscInt d;
51: for (d = 0; d < user->dim; ++d) u[d] = 0.0;
52: return 0;
53: }
55: /* u = x */
56: PetscErrorCode linear(PetscInt dim, PetscReal time, const PetscReal coords[], PetscInt Nf, PetscScalar *u, void *ctx)
57: {
58: PetscInt d;
59: for (d = 0; d < dim; ++d) u[d] = coords[d];
60: return 0;
61: }
62: PetscErrorCode linearDer(PetscInt dim, PetscReal time, const PetscReal coords[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx)
63: {
64: PetscInt d, e;
65: for (d = 0; d < dim; ++d) {
66: u[d] = 0.0;
67: for (e = 0; e < dim; ++e) u[d] += (d == e ? 1.0 : 0.0) * n[e];
68: }
69: return 0;
70: }
72: /* u = x^2 or u = (x^2, xy) or u = (xy, yz, zx) */
73: PetscErrorCode quadratic(PetscInt dim, PetscReal time, const PetscReal coords[], PetscInt Nf, PetscScalar *u, void *ctx)
74: {
75: AppCtx *user = (AppCtx *) ctx;
76: if (user->dim > 2) {u[0] = coords[0]*coords[1]; u[1] = coords[1]*coords[2]; u[2] = coords[2]*coords[0];}
77: else if (user->dim > 1) {u[0] = coords[0]*coords[0]; u[1] = coords[0]*coords[1];}
78: else if (user->dim > 0) {u[0] = coords[0]*coords[0];}
79: return 0;
80: }
81: PetscErrorCode quadraticDer(PetscInt dim, PetscReal time, const PetscReal coords[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx)
82: {
83: AppCtx *user = (AppCtx *) ctx;
84: if (user->dim > 2) {u[0] = coords[1]*n[0] + coords[0]*n[1]; u[1] = coords[2]*n[1] + coords[1]*n[2]; u[2] = coords[2]*n[0] + coords[0]*n[2];}
85: else if (user->dim > 1) {u[0] = 2.0*coords[0]*n[0]; u[1] = coords[1]*n[0] + coords[0]*n[1];}
86: else if (user->dim > 0) {u[0] = 2.0*coords[0]*n[0];}
87: return 0;
88: }
90: /* u = x^3 or u = (x^3, x^2y) or u = (x^2y, y^2z, z^2x) */
91: PetscErrorCode cubic(PetscInt dim, PetscReal time, const PetscReal coords[], PetscInt Nf, PetscScalar *u, void *ctx)
92: {
93: AppCtx *user = (AppCtx *) ctx;
94: if (user->dim > 2) {u[0] = coords[0]*coords[0]*coords[1]; u[1] = coords[1]*coords[1]*coords[2]; u[2] = coords[2]*coords[2]*coords[0];}
95: else if (user->dim > 1) {u[0] = coords[0]*coords[0]*coords[0]; u[1] = coords[0]*coords[0]*coords[1];}
96: else if (user->dim > 0) {u[0] = coords[0]*coords[0]*coords[0];}
97: return 0;
98: }
99: PetscErrorCode cubicDer(PetscInt dim, PetscReal time, const PetscReal coords[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx)
100: {
101: AppCtx *user = (AppCtx *) ctx;
102: if (user->dim > 2) {u[0] = 2.0*coords[0]*coords[1]*n[0] + coords[0]*coords[0]*n[1]; u[1] = 2.0*coords[1]*coords[2]*n[1] + coords[1]*coords[1]*n[2]; u[2] = 2.0*coords[2]*coords[0]*n[2] + coords[2]*coords[2]*n[0];}
103: else if (user->dim > 1) {u[0] = 3.0*coords[0]*coords[0]*n[0]; u[1] = 2.0*coords[0]*coords[1]*n[0] + coords[0]*coords[0]*n[1];}
104: else if (user->dim > 0) {u[0] = 3.0*coords[0]*coords[0]*n[0];}
105: return 0;
106: }
108: /* u = tanh(x) */
109: PetscErrorCode trig(PetscInt dim, PetscReal time, const PetscReal coords[], PetscInt Nf, PetscScalar *u, void *ctx)
110: {
111: AppCtx *user = (AppCtx *) ctx;
112: PetscInt d;
113: for (d = 0; d < user->dim; ++d) u[d] = PetscTanhReal(coords[d] - 0.5);
114: return 0;
115: }
116: PetscErrorCode trigDer(PetscInt dim, PetscReal time, const PetscReal coords[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx)
117: {
118: AppCtx *user = (AppCtx *) ctx;
119: PetscInt d;
120: for (d = 0; d < user->dim; ++d) u[d] = 1.0/PetscSqr(PetscCoshReal(coords[d] - 0.5)) * n[d];
121: return 0;
122: }
124: static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
125: {
126: PetscInt n = 3;
130: options->debug = 0;
131: options->dim = 2;
132: options->simplex = PETSC_TRUE;
133: options->refcell = PETSC_FALSE;
134: options->useDA = PETSC_TRUE;
135: options->interpolate = PETSC_TRUE;
136: options->refinementLimit = 0.0;
137: options->shearCoords = PETSC_FALSE;
138: options->nonaffineCoords = PETSC_FALSE;
139: options->qorder = 0;
140: options->numComponents = PETSC_DEFAULT;
141: options->porder = 0;
142: options->convergence = PETSC_FALSE;
143: options->convRefine = PETSC_TRUE;
144: options->constraints = PETSC_FALSE;
145: options->tree = PETSC_FALSE;
146: options->treeCell = 0;
147: options->testFEjacobian = PETSC_FALSE;
148: options->testFVgrad = PETSC_FALSE;
149: options->testInjector = PETSC_FALSE;
150: options->constants[0] = 1.0;
151: options->constants[1] = 2.0;
152: options->constants[2] = 3.0;
154: PetscOptionsBegin(comm, "", "Projection Test Options", "DMPlex");
155: PetscOptionsBoundedInt("-debug", "The debugging level", "ex3.c", options->debug, &options->debug, NULL,0);
156: PetscOptionsRangeInt("-dim", "The topological mesh dimension", "ex3.c", options->dim, &options->dim, NULL,1,3);
157: PetscOptionsBool("-simplex", "Flag for simplices or hexhedra", "ex3.c", options->simplex, &options->simplex, NULL);
158: PetscOptionsBool("-refcell", "Make the mesh only the reference cell", "ex3.c", options->refcell, &options->refcell, NULL);
159: PetscOptionsBool("-use_da", "Flag for DMDA mesh", "ex3.c", options->useDA, &options->useDA, NULL);
160: PetscOptionsBool("-interpolate", "Generate intermediate mesh elements", "ex3.c", options->interpolate, &options->interpolate, NULL);
161: PetscOptionsReal("-refinement_limit", "The largest allowable cell volume", "ex3.c", options->refinementLimit, &options->refinementLimit, NULL);
162: PetscOptionsBool("-shear_coords", "Transform coordinates with a shear", "ex3.c", options->shearCoords, &options->shearCoords, NULL);
163: PetscOptionsBool("-non_affine_coords", "Transform coordinates with a non-affine transform", "ex3.c", options->nonaffineCoords, &options->nonaffineCoords, NULL);
164: PetscOptionsBoundedInt("-qorder", "The quadrature order", "ex3.c", options->qorder, &options->qorder, NULL,0);
165: PetscOptionsBoundedInt("-num_comp", "The number of field components", "ex3.c", options->numComponents, &options->numComponents, NULL,PETSC_DEFAULT);
166: PetscOptionsBoundedInt("-porder", "The order of polynomials to test", "ex3.c", options->porder, &options->porder, NULL,0);
167: PetscOptionsBool("-convergence", "Check the convergence rate", "ex3.c", options->convergence, &options->convergence, NULL);
168: PetscOptionsBool("-conv_refine", "Use refinement for the convergence rate", "ex3.c", options->convRefine, &options->convRefine, NULL);
169: PetscOptionsBool("-constraints", "Test local constraints (serial only)", "ex3.c", options->constraints, &options->constraints, NULL);
170: PetscOptionsBool("-tree", "Test tree routines", "ex3.c", options->tree, &options->tree, NULL);
171: PetscOptionsBoundedInt("-tree_cell", "cell to refine in tree test", "ex3.c", options->treeCell, &options->treeCell, NULL,0);
172: PetscOptionsBool("-test_fe_jacobian", "Test finite element Jacobian assembly", "ex3.c", options->testFEjacobian, &options->testFEjacobian, NULL);
173: PetscOptionsBool("-test_fv_grad", "Test finite volume gradient reconstruction", "ex3.c", options->testFVgrad, &options->testFVgrad, NULL);
174: PetscOptionsBool("-test_injector","Test finite element injection", "ex3.c", options->testInjector, &options->testInjector,NULL);
175: PetscOptionsRealArray("-constants","Set the constant values", "ex3.c", options->constants, &n,NULL);
176: PetscOptionsEnd();
178: options->numComponents = options->numComponents < 0 ? options->dim : options->numComponents;
180: return(0);
181: }
183: static PetscErrorCode TransformCoordinates(DM dm, AppCtx *user)
184: {
185: PetscSection coordSection;
186: Vec coordinates;
187: PetscScalar *coords;
188: PetscInt vStart, vEnd, v;
192: if (user->nonaffineCoords) {
193: /* x' = r^(1/p) (x/r), y' = r^(1/p) (y/r), z' = z */
194: DMGetCoordinateSection(dm, &coordSection);
195: DMGetCoordinatesLocal(dm, &coordinates);
196: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
197: VecGetArray(coordinates, &coords);
198: for (v = vStart; v < vEnd; ++v) {
199: PetscInt dof, off;
200: PetscReal p = 4.0, r;
202: PetscSectionGetDof(coordSection, v, &dof);
203: PetscSectionGetOffset(coordSection, v, &off);
204: switch (dof) {
205: case 2:
206: r = PetscSqr(PetscRealPart(coords[off+0])) + PetscSqr(PetscRealPart(coords[off+1]));
207: coords[off+0] = r == 0.0 ? 0.0 : PetscPowReal(r, (1 - p)/(2*p))*coords[off+0];
208: coords[off+1] = r == 0.0 ? 0.0 : PetscPowReal(r, (1 - p)/(2*p))*coords[off+1];
209: break;
210: case 3:
211: r = PetscSqr(PetscRealPart(coords[off+0])) + PetscSqr(PetscRealPart(coords[off+1]));
212: coords[off+0] = r == 0.0 ? 0.0 : PetscPowReal(r, (1 - p)/(2*p))*coords[off+0];
213: coords[off+1] = r == 0.0 ? 0.0 : PetscPowReal(r, (1 - p)/(2*p))*coords[off+1];
214: coords[off+2] = coords[off+2];
215: break;
216: }
217: }
218: VecRestoreArray(coordinates, &coords);
219: }
220: if (user->shearCoords) {
221: /* x' = x + m y + m z, y' = y + m z, z' = z */
222: DMGetCoordinateSection(dm, &coordSection);
223: DMGetCoordinatesLocal(dm, &coordinates);
224: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
225: VecGetArray(coordinates, &coords);
226: for (v = vStart; v < vEnd; ++v) {
227: PetscInt dof, off;
228: PetscReal m = 1.0;
230: PetscSectionGetDof(coordSection, v, &dof);
231: PetscSectionGetOffset(coordSection, v, &off);
232: switch (dof) {
233: case 2:
234: coords[off+0] = coords[off+0] + m*coords[off+1];
235: coords[off+1] = coords[off+1];
236: break;
237: case 3:
238: coords[off+0] = coords[off+0] + m*coords[off+1] + m*coords[off+2];
239: coords[off+1] = coords[off+1] + m*coords[off+2];
240: coords[off+2] = coords[off+2];
241: break;
242: }
243: }
244: VecRestoreArray(coordinates, &coords);
245: }
246: return(0);
247: }
249: static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
250: {
251: PetscInt dim = user->dim;
252: PetscBool interpolate = user->interpolate;
253: PetscReal refinementLimit = user->refinementLimit;
254: PetscBool isPlex;
258: if (user->refcell) {
259: DMPlexCreateReferenceCell(comm, dim, user->simplex, dm);
260: } else if (user->simplex || !user->useDA) {
261: DM refinedMesh = NULL;
263: DMPlexCreateBoxMesh(comm, dim, user->simplex, NULL, NULL, NULL, NULL, interpolate, dm);
264: /* Refine mesh using a volume constraint */
265: DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
266: DMPlexSetRefinementLimit(*dm, refinementLimit);
267: DMRefine(*dm, comm, &refinedMesh);
268: if (refinedMesh) {
269: DMDestroy(dm);
270: *dm = refinedMesh;
271: }
272: DMPlexSetRefinementUniform(*dm, PETSC_TRUE);
273: } else {
274: if (user->constraints || user->tree || !user->useDA) {
275: PetscInt cells[3] = {2, 2, 2};
277: PetscOptionsGetInt(NULL,NULL,"-da_grid_x",&cells[0],NULL);
278: PetscOptionsGetInt(NULL,NULL,"-da_grid_y",&cells[1],NULL);
279: PetscOptionsGetInt(NULL,NULL,"-da_grid_z",&cells[2],NULL);
280: DMPlexCreateBoxMesh(comm, dim, PETSC_FALSE, cells, NULL, NULL, NULL, PETSC_TRUE, dm);
281: } else {
282: switch (user->dim) {
283: case 2:
284: DMDACreate2d(comm, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_BOX, 2, 2, PETSC_DETERMINE, PETSC_DETERMINE, 1, 1, NULL, NULL, dm);
285: DMSetFromOptions(*dm);
286: DMSetUp(*dm);
287: DMDASetVertexCoordinates(*dm, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
288: break;
289: default:
290: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot create structured mesh of dimension %d", dim);
291: }
292: PetscObjectSetName((PetscObject) *dm, "Hexahedral Mesh");
293: }
294: }
295: PetscObjectTypeCompare((PetscObject)*dm,DMPLEX,&isPlex);
296: if (isPlex) {
297: PetscPartitioner part;
298: DM distributedMesh = NULL;
300: if (user->tree) {
301: DM refTree;
302: DM ncdm = NULL;
304: DMPlexCreateDefaultReferenceTree(comm,user->dim,user->simplex,&refTree);
305: DMPlexSetReferenceTree(*dm,refTree);
306: DMDestroy(&refTree);
307: DMPlexTreeRefineCell(*dm,user->treeCell,&ncdm);
308: if (ncdm) {
309: DMDestroy(dm);
310: *dm = ncdm;
311: DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
312: }
313: } else {
314: DMPlexSetRefinementUniform(*dm, PETSC_TRUE);
315: }
316: /* Distribute mesh over processes */
317: DMPlexGetPartitioner(*dm,&part);
318: PetscPartitionerSetFromOptions(part);
319: DMPlexDistribute(*dm, 0, NULL, &distributedMesh);
320: if (distributedMesh) {
321: DMDestroy(dm);
322: *dm = distributedMesh;
323: }
324: if (user->simplex) {
325: PetscObjectSetName((PetscObject) *dm, "Simplicial Mesh");
326: } else {
327: PetscObjectSetName((PetscObject) *dm, "Hexahedral Mesh");
328: }
329: }
330: DMSetFromOptions(*dm);
331: TransformCoordinates(*dm, user);
332: DMViewFromOptions(*dm,NULL,"-dm_view");
333: return(0);
334: }
336: static void simple_mass(PetscInt dim, PetscInt Nf, PetscInt NfAux,
337: const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
338: const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
339: PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
340: {
341: PetscInt d, e;
342: for (d = 0, e = 0; d < dim; d++, e+=dim+1) {
343: g0[e] = 1.;
344: }
345: }
347: /* < \nabla v, 1/2(\nabla u + {\nabla u}^T) > */
348: static void symmetric_gradient_inner_product(PetscInt dim, PetscInt Nf, PetscInt NfAux,
349: const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
350: const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
351: PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar C[])
352: {
353: PetscInt compI, compJ, d, e;
355: for (compI = 0; compI < dim; ++compI) {
356: for (compJ = 0; compJ < dim; ++compJ) {
357: for (d = 0; d < dim; ++d) {
358: for (e = 0; e < dim; e++) {
359: if (d == e && d == compI && d == compJ) {
360: C[((compI*dim+compJ)*dim+d)*dim+e] = 1.0;
361: } else if ((d == compJ && e == compI) || (d == e && compI == compJ)) {
362: C[((compI*dim+compJ)*dim+d)*dim+e] = 0.5;
363: } else {
364: C[((compI*dim+compJ)*dim+d)*dim+e] = 0.0;
365: }
366: }
367: }
368: }
369: }
370: }
372: static PetscErrorCode SetupSection(DM dm, AppCtx *user)
373: {
377: if (!user->simplex && user->constraints) {
378: /* test local constraints */
379: DM coordDM;
380: PetscInt fStart, fEnd, f, vStart, vEnd, v;
381: PetscInt edgesx = 2, vertsx;
382: PetscInt edgesy = 2, vertsy;
383: PetscMPIInt size;
384: PetscInt numConst;
385: PetscSection aSec;
386: PetscInt *anchors;
387: PetscInt offset;
388: IS aIS;
389: MPI_Comm comm = PetscObjectComm((PetscObject)dm);
391: MPI_Comm_size(comm,&size);
392: if (size > 1) SETERRQ(comm,PETSC_ERR_SUP,"Local constraint test can only be performed in serial");
394: /* we are going to test constraints by using them to enforce periodicity
395: * in one direction, and comparing to the existing method of enforcing
396: * periodicity */
398: /* first create the coordinate section so that it does not clone the
399: * constraints */
400: DMGetCoordinateDM(dm,&coordDM);
402: /* create the constrained-to-anchor section */
403: DMPlexGetDepthStratum(dm,0,&vStart,&vEnd);
404: DMPlexGetDepthStratum(dm,1,&fStart,&fEnd);
405: PetscSectionCreate(PETSC_COMM_SELF,&aSec);
406: PetscSectionSetChart(aSec,PetscMin(fStart,vStart),PetscMax(fEnd,vEnd));
408: /* define the constraints */
409: PetscOptionsGetInt(NULL,NULL,"-da_grid_x",&edgesx,NULL);
410: PetscOptionsGetInt(NULL,NULL,"-da_grid_y",&edgesy,NULL);
411: vertsx = edgesx + 1;
412: vertsy = edgesy + 1;
413: numConst = vertsy + edgesy;
414: PetscMalloc1(numConst,&anchors);
415: offset = 0;
416: for (v = vStart + edgesx; v < vEnd; v+= vertsx) {
417: PetscSectionSetDof(aSec,v,1);
418: anchors[offset++] = v - edgesx;
419: }
420: for (f = fStart + edgesx * vertsy + edgesx * edgesy; f < fEnd; f++) {
421: PetscSectionSetDof(aSec,f,1);
422: anchors[offset++] = f - edgesx * edgesy;
423: }
424: PetscSectionSetUp(aSec);
425: ISCreateGeneral(PETSC_COMM_SELF,numConst,anchors,PETSC_OWN_POINTER,&aIS);
427: DMPlexSetAnchors(dm,aSec,aIS);
428: PetscSectionDestroy(&aSec);
429: ISDestroy(&aIS);
430: }
431: DMSetNumFields(dm, 1);
432: DMSetField(dm, 0, NULL, (PetscObject) user->fe);
433: DMCreateDS(dm);
434: if (!user->simplex && user->constraints) {
435: /* test getting local constraint matrix that matches section */
436: PetscSection aSec;
437: IS aIS;
439: DMPlexGetAnchors(dm,&aSec,&aIS);
440: if (aSec) {
441: PetscDS ds;
442: PetscSection cSec, section;
443: PetscInt cStart, cEnd, c, numComp;
444: Mat cMat, mass;
445: Vec local;
446: const PetscInt *anchors;
448: DMGetLocalSection(dm,§ion);
449: /* this creates the matrix and preallocates the matrix structure: we
450: * just have to fill in the values */
451: DMGetDefaultConstraints(dm,&cSec,&cMat);
452: PetscSectionGetChart(cSec,&cStart,&cEnd);
453: ISGetIndices(aIS,&anchors);
454: PetscFEGetNumComponents(user->fe, &numComp);
455: for (c = cStart; c < cEnd; c++) {
456: PetscInt cDof;
458: /* is this point constrained? (does it have an anchor?) */
459: PetscSectionGetDof(aSec,c,&cDof);
460: if (cDof) {
461: PetscInt cOff, a, aDof, aOff, j;
462: if (cDof != 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Found %d anchor points: should be just one",cDof);
464: /* find the anchor point */
465: PetscSectionGetOffset(aSec,c,&cOff);
466: a = anchors[cOff];
468: /* find the constrained dofs (row in constraint matrix) */
469: PetscSectionGetDof(cSec,c,&cDof);
470: PetscSectionGetOffset(cSec,c,&cOff);
472: /* find the anchor dofs (column in constraint matrix) */
473: PetscSectionGetDof(section,a,&aDof);
474: PetscSectionGetOffset(section,a,&aOff);
476: if (cDof != aDof) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point and anchor have different number of dofs: %d, %d\n",cDof,aDof);
477: if (cDof % numComp) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point dofs not divisible by field components: %d, %d\n",cDof,numComp);
479: /* put in a simple equality constraint */
480: for (j = 0; j < cDof; j++) {
481: MatSetValue(cMat,cOff+j,aOff+j,1.,INSERT_VALUES);
482: }
483: }
484: }
485: MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);
486: MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);
487: ISRestoreIndices(aIS,&anchors);
489: /* Now that we have constructed the constraint matrix, any FE matrix
490: * that we construct will apply the constraints during construction */
492: DMCreateMatrix(dm,&mass);
493: /* get a dummy local variable to serve as the solution */
494: DMGetLocalVector(dm,&local);
495: DMGetDS(dm,&ds);
496: /* set the jacobian to be the mass matrix */
497: PetscDSSetJacobian(ds, 0, 0, simple_mass, NULL, NULL, NULL);
498: /* build the mass matrix */
499: DMPlexSNESComputeJacobianFEM(dm,local,mass,mass,NULL);
500: MatView(mass,PETSC_VIEWER_STDOUT_WORLD);
501: MatDestroy(&mass);
502: DMRestoreLocalVector(dm,&local);
503: }
504: }
505: return(0);
506: }
508: static PetscErrorCode TestFEJacobian(DM dm, AppCtx *user)
509: {
510: PetscBool isPlex;
514: PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isPlex);
515: if (isPlex) {
516: Vec local;
517: const Vec *vecs;
518: Mat E;
519: MatNullSpace sp;
520: PetscBool isNullSpace, hasConst;
521: PetscInt n, i;
522: Vec res = NULL, localX, localRes;
523: PetscDS ds;
525: if (user->numComponents != user->dim) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "The number of components %d must be equal to the dimension %d for this test", user->numComponents, user->dim);
526: DMGetDS(dm,&ds);
527: PetscDSSetJacobian(ds,0,0,NULL,NULL,NULL,symmetric_gradient_inner_product);
528: DMCreateMatrix(dm,&E);
529: DMGetLocalVector(dm,&local);
530: DMPlexSNESComputeJacobianFEM(dm,local,E,E,NULL);
531: DMPlexCreateRigidBody(dm,0,&sp);
532: MatNullSpaceGetVecs(sp,&hasConst,&n,&vecs);
533: if (n) {VecDuplicate(vecs[0],&res);}
534: DMCreateLocalVector(dm,&localX);
535: DMCreateLocalVector(dm,&localRes);
536: for (i = 0; i < n; i++) { /* also test via matrix-free Jacobian application */
537: PetscReal resNorm;
539: VecSet(localRes,0.);
540: VecSet(localX,0.);
541: VecSet(local,0.);
542: VecSet(res,0.);
543: DMGlobalToLocalBegin(dm,vecs[i],INSERT_VALUES,localX);
544: DMGlobalToLocalEnd(dm,vecs[i],INSERT_VALUES,localX);
545: DMPlexComputeJacobianAction(dm,NULL,0,0,local,NULL,localX,localRes,NULL);
546: DMLocalToGlobalBegin(dm,localRes,ADD_VALUES,res);
547: DMLocalToGlobalEnd(dm,localRes,ADD_VALUES,res);
548: VecNorm(res,NORM_2,&resNorm);
549: if (resNorm > PETSC_SMALL) {
550: PetscPrintf(PetscObjectComm((PetscObject)dm),"Symmetric gradient action null space vector %D residual: %E\n",i,resNorm);
551: }
552: }
553: VecDestroy(&localRes);
554: VecDestroy(&localX);
555: VecDestroy(&res);
556: MatNullSpaceTest(sp,E,&isNullSpace);
557: if (isNullSpace) {
558: PetscPrintf(PetscObjectComm((PetscObject)dm),"Symmetric gradient null space: PASS\n");
559: } else {
560: PetscPrintf(PetscObjectComm((PetscObject)dm),"Symmetric gradient null space: FAIL\n");
561: }
562: MatNullSpaceDestroy(&sp);
563: MatDestroy(&E);
564: DMRestoreLocalVector(dm,&local);
565: }
566: return(0);
567: }
569: static PetscErrorCode TestInjector(DM dm, AppCtx *user)
570: {
571: DM refTree;
572: PetscMPIInt rank;
576: DMPlexGetReferenceTree(dm,&refTree);
577: if (refTree) {
578: Mat inj;
580: DMPlexComputeInjectorReferenceTree(refTree,&inj);
581: PetscObjectSetName((PetscObject)inj,"Reference Tree Injector");
582: MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
583: if (!rank) {
584: MatView(inj,PETSC_VIEWER_STDOUT_SELF);
585: }
586: MatDestroy(&inj);
587: }
588: return(0);
589: }
591: static PetscErrorCode TestFVGrad(DM dm, AppCtx *user)
592: {
593: MPI_Comm comm;
594: DM dmRedist, dmfv, dmgrad, dmCell, refTree;
595: PetscFV fv;
596: PetscInt nvecs, v, cStart, cEnd, cEndInterior;
597: PetscMPIInt size;
598: Vec cellgeom, grad, locGrad;
599: const PetscScalar *cgeom;
600: PetscReal allVecMaxDiff = 0., fvTol = 100. * PETSC_MACHINE_EPSILON;
601: PetscErrorCode ierr;
604: comm = PetscObjectComm((PetscObject)dm);
605: /* duplicate DM, give dup. a FV discretization */
606: DMSetBasicAdjacency(dm,PETSC_TRUE,PETSC_FALSE);
607: MPI_Comm_size(comm,&size);
608: dmRedist = NULL;
609: if (size > 1) {
610: DMPlexDistributeOverlap(dm,1,NULL,&dmRedist);
611: }
612: if (!dmRedist) {
613: dmRedist = dm;
614: PetscObjectReference((PetscObject)dmRedist);
615: }
616: PetscFVCreate(comm,&fv);
617: PetscFVSetType(fv,PETSCFVLEASTSQUARES);
618: PetscFVSetNumComponents(fv,user->numComponents);
619: PetscFVSetSpatialDimension(fv,user->dim);
620: PetscFVSetFromOptions(fv);
621: PetscFVSetUp(fv);
622: DMPlexConstructGhostCells(dmRedist,NULL,NULL,&dmfv);
623: DMDestroy(&dmRedist);
624: DMSetNumFields(dmfv,1);
625: DMSetField(dmfv, 0, NULL, (PetscObject) fv);
626: DMCreateDS(dmfv);
627: DMPlexGetReferenceTree(dm,&refTree);
628: if (refTree) {DMCopyDisc(dmfv,refTree);}
629: DMPlexGetGradientDM(dmfv, fv, &dmgrad);
630: DMPlexGetHeightStratum(dmfv,0,&cStart,&cEnd);
631: nvecs = user->dim * (user->dim+1) / 2;
632: DMPlexGetGeometryFVM(dmfv,NULL,&cellgeom,NULL);
633: VecGetDM(cellgeom,&dmCell);
634: VecGetArrayRead(cellgeom,&cgeom);
635: DMGetGlobalVector(dmgrad,&grad);
636: DMGetLocalVector(dmgrad,&locGrad);
637: DMPlexGetGhostCellStratum(dmgrad,&cEndInterior,NULL);
638: cEndInterior = (cEndInterior < 0) ? cEnd: cEndInterior;
639: for (v = 0; v < nvecs; v++) {
640: Vec locX;
641: PetscInt c;
642: PetscScalar trueGrad[3][3] = {{0.}};
643: const PetscScalar *gradArray;
644: PetscReal maxDiff, maxDiffGlob;
646: DMGetLocalVector(dmfv,&locX);
647: /* get the local projection of the rigid body mode */
648: for (c = cStart; c < cEnd; c++) {
649: PetscFVCellGeom *cg;
650: PetscScalar cx[3] = {0.,0.,0.};
652: DMPlexPointLocalRead(dmCell, c, cgeom, &cg);
653: if (v < user->dim) {
654: cx[v] = 1.;
655: } else {
656: PetscInt w = v - user->dim;
658: cx[(w + 1) % user->dim] = cg->centroid[(w + 2) % user->dim];
659: cx[(w + 2) % user->dim] = -cg->centroid[(w + 1) % user->dim];
660: }
661: DMPlexVecSetClosure(dmfv,NULL,locX,c,cx,INSERT_ALL_VALUES);
662: }
663: /* TODO: this isn't in any header */
664: DMPlexReconstructGradientsFVM(dmfv,locX,grad);
665: DMGlobalToLocalBegin(dmgrad,grad,INSERT_VALUES,locGrad);
666: DMGlobalToLocalEnd(dmgrad,grad,INSERT_VALUES,locGrad);
667: VecGetArrayRead(locGrad,&gradArray);
668: /* compare computed gradient to exact gradient */
669: if (v >= user->dim) {
670: PetscInt w = v - user->dim;
672: trueGrad[(w + 1) % user->dim][(w + 2) % user->dim] = 1.;
673: trueGrad[(w + 2) % user->dim][(w + 1) % user->dim] = -1.;
674: }
675: maxDiff = 0.;
676: for (c = cStart; c < cEndInterior; c++) {
677: PetscScalar *compGrad;
678: PetscInt i, j, k;
679: PetscReal FrobDiff = 0.;
681: DMPlexPointLocalRead(dmgrad, c, gradArray, &compGrad);
683: for (i = 0, k = 0; i < user->dim; i++) {
684: for (j = 0; j < user->dim; j++, k++) {
685: PetscScalar diff = compGrad[k] - trueGrad[i][j];
686: FrobDiff += PetscRealPart(diff * PetscConj(diff));
687: }
688: }
689: FrobDiff = PetscSqrtReal(FrobDiff);
690: maxDiff = PetscMax(maxDiff,FrobDiff);
691: }
692: MPI_Allreduce(&maxDiff,&maxDiffGlob,1,MPIU_REAL,MPIU_MAX,comm);
693: allVecMaxDiff = PetscMax(allVecMaxDiff,maxDiffGlob);
694: VecRestoreArrayRead(locGrad,&gradArray);
695: DMRestoreLocalVector(dmfv,&locX);
696: }
697: if (allVecMaxDiff < fvTol) {
698: PetscPrintf(PetscObjectComm((PetscObject)dm),"Finite volume gradient reconstruction: PASS\n");
699: } else {
700: PetscPrintf(PetscObjectComm((PetscObject)dm),"Finite volume gradient reconstruction: FAIL at tolerance %g with max difference %g\n",fvTol,allVecMaxDiff);
701: }
702: DMRestoreLocalVector(dmgrad,&locGrad);
703: DMRestoreGlobalVector(dmgrad,&grad);
704: VecRestoreArrayRead(cellgeom,&cgeom);
705: DMDestroy(&dmfv);
706: PetscFVDestroy(&fv);
707: return(0);
708: }
710: static PetscErrorCode ComputeError(DM dm, PetscErrorCode (**exactFuncs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *),
711: PetscErrorCode (**exactFuncDers)(PetscInt, PetscReal, const PetscReal[], const PetscReal[], PetscInt, PetscScalar *, void *),
712: void **exactCtxs, PetscReal *error, PetscReal *errorDer, AppCtx *user)
713: {
714: Vec u;
715: PetscReal n[3] = {1.0, 1.0, 1.0};
719: DMGetGlobalVector(dm, &u);
720: /* Project function into FE function space */
721: DMProjectFunction(dm, 0.0, exactFuncs, exactCtxs, INSERT_ALL_VALUES, u);
722: VecViewFromOptions(u, NULL, "-projection_view");
723: /* Compare approximation to exact in L_2 */
724: DMComputeL2Diff(dm, 0.0, exactFuncs, exactCtxs, u, error);
725: DMComputeL2GradientDiff(dm, 0.0, exactFuncDers, exactCtxs, u, n, errorDer);
726: DMRestoreGlobalVector(dm, &u);
727: return(0);
728: }
730: static PetscErrorCode CheckFunctions(DM dm, PetscInt order, AppCtx *user)
731: {
732: PetscErrorCode (*exactFuncs[1]) (PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx);
733: PetscErrorCode (*exactFuncDers[1]) (PetscInt dim, PetscReal time, const PetscReal x[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx);
734: void *exactCtxs[3];
735: MPI_Comm comm;
736: PetscReal error, errorDer, tol = PETSC_SMALL;
737: PetscErrorCode ierr;
740: exactCtxs[0] = user;
741: exactCtxs[1] = user;
742: exactCtxs[2] = user;
743: PetscObjectGetComm((PetscObject)dm, &comm);
744: /* Setup functions to approximate */
745: switch (order) {
746: case 0:
747: exactFuncs[0] = constant;
748: exactFuncDers[0] = constantDer;
749: break;
750: case 1:
751: exactFuncs[0] = linear;
752: exactFuncDers[0] = linearDer;
753: break;
754: case 2:
755: exactFuncs[0] = quadratic;
756: exactFuncDers[0] = quadraticDer;
757: break;
758: case 3:
759: exactFuncs[0] = cubic;
760: exactFuncDers[0] = cubicDer;
761: break;
762: default:
763: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Could not determine functions to test for dimension %d order %d", user->dim, order);
764: }
765: ComputeError(dm, exactFuncs, exactFuncDers, exactCtxs, &error, &errorDer, user);
766: /* Report result */
767: if (error > tol) {PetscPrintf(comm, "Function tests FAIL for order %D at tolerance %g error %g\n", order, (double)tol,(double) error);}
768: else {PetscPrintf(comm, "Function tests pass for order %D at tolerance %g\n", order, (double)tol);}
769: if (errorDer > tol) {PetscPrintf(comm, "Function tests FAIL for order %D derivatives at tolerance %g error %g\n", order, (double)tol, (double)errorDer);}
770: else {PetscPrintf(comm, "Function tests pass for order %D derivatives at tolerance %g\n", order, (double)tol);}
771: return(0);
772: }
774: static PetscErrorCode CheckInterpolation(DM dm, PetscBool checkRestrict, PetscInt order, AppCtx *user)
775: {
776: PetscErrorCode (*exactFuncs[1]) (PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
777: PetscErrorCode (*exactFuncDers[1]) (PetscInt, PetscReal, const PetscReal x[], const PetscReal n[], PetscInt, PetscScalar *u, void *ctx);
778: PetscReal n[3] = {1.0, 1.0, 1.0};
779: void *exactCtxs[3];
780: DM rdm, idm, fdm;
781: Mat Interp;
782: Vec iu, fu, scaling;
783: MPI_Comm comm;
784: PetscInt dim = user->dim;
785: PetscReal error, errorDer, tol = PETSC_SMALL;
786: PetscBool isPlex;
787: PetscErrorCode ierr;
790: exactCtxs[0] = user;
791: exactCtxs[1] = user;
792: exactCtxs[2] = user;
793: PetscObjectGetComm((PetscObject)dm,&comm);
794: PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);
795: DMRefine(dm, comm, &rdm);
796: DMSetCoarseDM(rdm, dm);
797: DMPlexSetRegularRefinement(rdm, user->convRefine);
798: if (user->tree && isPlex) {
799: DM refTree;
800: DMPlexGetReferenceTree(dm,&refTree);
801: DMPlexSetReferenceTree(rdm,refTree);
802: }
803: if (!user->simplex && !user->constraints) {DMDASetVertexCoordinates(rdm, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);}
804: SetupSection(rdm, user);
805: /* Setup functions to approximate */
806: switch (order) {
807: case 0:
808: exactFuncs[0] = constant;
809: exactFuncDers[0] = constantDer;
810: break;
811: case 1:
812: exactFuncs[0] = linear;
813: exactFuncDers[0] = linearDer;
814: break;
815: case 2:
816: exactFuncs[0] = quadratic;
817: exactFuncDers[0] = quadraticDer;
818: break;
819: case 3:
820: exactFuncs[0] = cubic;
821: exactFuncDers[0] = cubicDer;
822: break;
823: default:
824: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Could not determine functions to test for dimension %D order %D", dim, order);
825: }
826: idm = checkRestrict ? rdm : dm;
827: fdm = checkRestrict ? dm : rdm;
828: DMGetGlobalVector(idm, &iu);
829: DMGetGlobalVector(fdm, &fu);
830: DMSetApplicationContext(dm, user);
831: DMSetApplicationContext(rdm, user);
832: DMCreateInterpolation(dm, rdm, &Interp, &scaling);
833: /* Project function into initial FE function space */
834: DMProjectFunction(idm, 0.0, exactFuncs, exactCtxs, INSERT_ALL_VALUES, iu);
835: /* Interpolate function into final FE function space */
836: if (checkRestrict) {MatRestrict(Interp, iu, fu);VecPointwiseMult(fu, scaling, fu);}
837: else {MatInterpolate(Interp, iu, fu);}
838: /* Compare approximation to exact in L_2 */
839: DMComputeL2Diff(fdm, 0.0, exactFuncs, exactCtxs, fu, &error);
840: DMComputeL2GradientDiff(fdm, 0.0, exactFuncDers, exactCtxs, fu, n, &errorDer);
841: /* Report result */
842: if (error > tol) {PetscPrintf(comm, "Interpolation tests FAIL for order %D at tolerance %g error %g\n", order, (double)tol, (double)error);}
843: else {PetscPrintf(comm, "Interpolation tests pass for order %D at tolerance %g\n", order, (double)tol);}
844: if (errorDer > tol) {PetscPrintf(comm, "Interpolation tests FAIL for order %D derivatives at tolerance %g error %g\n", order, (double)tol, (double)errorDer);}
845: else {PetscPrintf(comm, "Interpolation tests pass for order %D derivatives at tolerance %g\n", order, (double)tol);}
846: DMRestoreGlobalVector(idm, &iu);
847: DMRestoreGlobalVector(fdm, &fu);
848: MatDestroy(&Interp);
849: VecDestroy(&scaling);
850: DMDestroy(&rdm);
851: return(0);
852: }
854: static PetscErrorCode CheckConvergence(DM dm, PetscInt Nr, AppCtx *user)
855: {
856: DM odm = dm, rdm = NULL, cdm = NULL;
857: PetscErrorCode (*exactFuncs[1]) (PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx) = {trig};
858: PetscErrorCode (*exactFuncDers[1]) (PetscInt dim, PetscReal time, const PetscReal x[], const PetscReal n[], PetscInt Nf, PetscScalar *u, void *ctx) = {trigDer};
859: void *exactCtxs[3];
860: PetscInt r, c, cStart, cEnd;
861: PetscReal errorOld, errorDerOld, error, errorDer, rel, len, lenOld;
862: double p;
863: PetscErrorCode ierr;
866: if (!user->convergence) return(0);
867: exactCtxs[0] = user;
868: exactCtxs[1] = user;
869: exactCtxs[2] = user;
870: PetscObjectReference((PetscObject) odm);
871: if (!user->convRefine) {
872: for (r = 0; r < Nr; ++r) {
873: DMRefine(odm, PetscObjectComm((PetscObject) dm), &rdm);
874: DMDestroy(&odm);
875: odm = rdm;
876: }
877: SetupSection(odm, user);
878: }
879: ComputeError(odm, exactFuncs, exactFuncDers, exactCtxs, &errorOld, &errorDerOld, user);
880: if (user->convRefine) {
881: for (r = 0; r < Nr; ++r) {
882: DMRefine(odm, PetscObjectComm((PetscObject) dm), &rdm);
883: if (!user->simplex && user->useDA) {DMDASetVertexCoordinates(rdm, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);}
884: SetupSection(rdm, user);
885: ComputeError(rdm, exactFuncs, exactFuncDers, exactCtxs, &error, &errorDer, user);
886: p = PetscLog2Real(errorOld/error);
887: PetscPrintf(PetscObjectComm((PetscObject) dm), "Function convergence rate at refinement %D: %.2f\n", r, (double)p);
888: p = PetscLog2Real(errorDerOld/errorDer);
889: PetscPrintf(PetscObjectComm((PetscObject) dm), "Derivative convergence rate at refinement %D: %.2f\n", r, (double)p);
890: DMDestroy(&odm);
891: odm = rdm;
892: errorOld = error;
893: errorDerOld = errorDer;
894: }
895: } else {
896: /* ComputeLongestEdge(dm, &lenOld); */
897: DMPlexGetHeightStratum(odm, 0, &cStart, &cEnd);
898: lenOld = cEnd - cStart;
899: for (c = 0; c < Nr; ++c) {
900: DMCoarsen(odm, PetscObjectComm((PetscObject) dm), &cdm);
901: if (!user->simplex && user->useDA) {DMDASetVertexCoordinates(cdm, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);}
902: SetupSection(cdm, user);
903: ComputeError(cdm, exactFuncs, exactFuncDers, exactCtxs, &error, &errorDer, user);
904: /* ComputeLongestEdge(cdm, &len); */
905: DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
906: len = cEnd - cStart;
907: rel = error/errorOld;
908: p = PetscLogReal(rel) / PetscLogReal(lenOld / len);
909: PetscPrintf(PetscObjectComm((PetscObject) dm), "Function convergence rate at coarsening %D: %.2f\n", c, (double)p);
910: rel = errorDer/errorDerOld;
911: p = PetscLogReal(rel) / PetscLogReal(lenOld / len);
912: PetscPrintf(PetscObjectComm((PetscObject) dm), "Derivative convergence rate at coarsening %D: %.2f\n", c, (double)p);
913: DMDestroy(&odm);
914: odm = cdm;
915: errorOld = error;
916: errorDerOld = errorDer;
917: lenOld = len;
918: }
919: }
920: DMDestroy(&odm);
921: return(0);
922: }
924: int main(int argc, char **argv)
925: {
926: DM dm;
927: AppCtx user; /* user-defined work context */
930: PetscInitialize(&argc, &argv, NULL, help);if (ierr) return ierr;
931: ProcessOptions(PETSC_COMM_WORLD, &user);
932: CreateMesh(PETSC_COMM_WORLD, &user, &dm);
933: PetscFECreateDefault(PETSC_COMM_WORLD, user.dim, user.numComponents, user.simplex, NULL, user.qorder, &user.fe);
934: SetupSection(dm, &user);
935: if (user.testFEjacobian) {TestFEJacobian(dm, &user);}
936: if (user.testFVgrad) {TestFVGrad(dm, &user);}
937: if (user.testInjector) {TestInjector(dm, &user);}
938: CheckFunctions(dm, user.porder, &user);
939: {
940: PetscDualSpace dsp;
941: PetscInt k;
943: PetscFEGetDualSpace(user.fe, &dsp);
944: PetscDualSpaceGetDeRahm(dsp, &k);
945: if (user.dim == 2 && user.simplex == PETSC_TRUE && user.tree == PETSC_FALSE && k == 0) {
946: CheckInterpolation(dm, PETSC_FALSE, user.porder, &user);
947: CheckInterpolation(dm, PETSC_TRUE, user.porder, &user);
948: }
949: }
950: CheckConvergence(dm, 3, &user);
951: PetscFEDestroy(&user.fe);
952: DMDestroy(&dm);
953: PetscFinalize();
954: return ierr;
955: }
957: /*TEST
959: test:
960: suffix: 1
961: requires: triangle
963: # 2D P_1 on a triangle
964: test:
965: suffix: p1_2d_0
966: requires: triangle
967: args: -petscspace_degree 1 -qorder 1 -convergence
968: test:
969: suffix: p1_2d_1
970: requires: triangle
971: args: -petscspace_degree 1 -qorder 1 -porder 1
972: test:
973: suffix: p1_2d_2
974: requires: triangle
975: args: -petscspace_degree 1 -qorder 1 -porder 2
976: test:
977: suffix: p1_2d_3
978: requires: triangle pragmatic
979: args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -convergence -conv_refine 0
980: filter: grep -v DEBUG
981: test:
982: suffix: p1_2d_4
983: requires: triangle pragmatic
984: args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 1 -conv_refine 0
985: test:
986: suffix: p1_2d_5
987: requires: triangle pragmatic
988: args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 2 -conv_refine 0
990: # 3D P_1 on a tetrahedron
991: test:
992: suffix: p1_3d_0
993: requires: ctetgen
994: args: -dim 3 -petscspace_degree 1 -qorder 1 -convergence
995: test:
996: suffix: p1_3d_1
997: requires: ctetgen
998: args: -dim 3 -petscspace_degree 1 -qorder 1 -porder 1
999: test:
1000: suffix: p1_3d_2
1001: requires: ctetgen
1002: args: -dim 3 -petscspace_degree 1 -qorder 1 -porder 2
1003: test:
1004: suffix: p1_3d_3
1005: requires: ctetgen pragmatic
1006: args: -dim 3 -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -convergence -conv_refine 0
1007: filter: grep -v DEBUG
1008: test:
1009: suffix: p1_3d_4
1010: requires: ctetgen pragmatic
1011: args: -dim 3 -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 1 -conv_refine 0
1012: test:
1013: suffix: p1_3d_5
1014: requires: ctetgen pragmatic
1015: args: -dim 3 -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 2 -conv_refine 0
1017: # 2D P_2 on a triangle
1018: test:
1019: suffix: p2_2d_0
1020: requires: triangle
1021: args: -petscspace_degree 2 -qorder 2 -convergence
1022: test:
1023: suffix: p2_2d_1
1024: requires: triangle
1025: args: -petscspace_degree 2 -qorder 2 -porder 1
1026: test:
1027: suffix: p2_2d_2
1028: requires: triangle
1029: args: -petscspace_degree 2 -qorder 2 -porder 2
1030: test:
1031: suffix: p2_2d_3
1032: requires: triangle pragmatic
1033: args: -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -convergence -conv_refine 0
1034: filter: grep -v DEBUG
1035: test:
1036: suffix: p2_2d_4
1037: requires: triangle pragmatic
1038: args: -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -porder 1 -conv_refine 0
1039: test:
1040: suffix: p2_2d_5
1041: requires: triangle pragmatic
1042: args: -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -porder 2 -conv_refine 0
1044: # 3D P_2 on a tetrahedron
1045: test:
1046: suffix: p2_3d_0
1047: requires: ctetgen
1048: args: -dim 3 -petscspace_degree 2 -qorder 2 -convergence
1049: test:
1050: suffix: p2_3d_1
1051: requires: ctetgen
1052: args: -dim 3 -petscspace_degree 2 -qorder 2 -porder 1
1053: test:
1054: suffix: p2_3d_2
1055: requires: ctetgen
1056: args: -dim 3 -petscspace_degree 2 -qorder 2 -porder 2
1057: test:
1058: suffix: p2_3d_3
1059: requires: ctetgen pragmatic
1060: args: -dim 3 -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -convergence -conv_refine 0
1061: filter: grep -v DEBUG
1062: test:
1063: suffix: p2_3d_4
1064: requires: ctetgen pragmatic
1065: args: -dim 3 -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -porder 1 -conv_refine 0
1066: test:
1067: suffix: p2_3d_5
1068: requires: ctetgen pragmatic
1069: args: -dim 3 -petscspace_degree 2 -qorder 2 -dm_plex_hash_location -porder 2 -conv_refine 0
1071: # 2D Q_1 on a quadrilaterial DA
1072: test:
1073: suffix: q1_2d_da_0
1074: requires: mpi_type_get_envelope broken
1075: args: -simplex 0 -petscspace_degree 1 -qorder 1 -convergence
1076: test:
1077: suffix: q1_2d_da_1
1078: requires: mpi_type_get_envelope broken
1079: args: -simplex 0 -petscspace_degree 1 -qorder 1 -porder 1
1080: test:
1081: suffix: q1_2d_da_2
1082: requires: mpi_type_get_envelope broken
1083: args: -simplex 0 -petscspace_degree 1 -qorder 1 -porder 2
1085: # 2D Q_1 on a quadrilaterial Plex
1086: test:
1087: suffix: q1_2d_plex_0
1088: args: -use_da 0 -simplex 0 -petscspace_degree 1 -qorder 1 -convergence
1089: test:
1090: suffix: q1_2d_plex_1
1091: args: -use_da 0 -simplex 0 -petscspace_degree 1 -qorder 1 -porder 1
1092: test:
1093: suffix: q1_2d_plex_2
1094: args: -use_da 0 -simplex 0 -petscspace_degree 1 -qorder 1 -porder 2
1095: test:
1096: suffix: q1_2d_plex_3
1097: args: -use_da 0 -simplex 0 -petscspace_degree 1 -qorder 1 -porder 1 -shear_coords
1098: test:
1099: suffix: q1_2d_plex_4
1100: args: -use_da 0 -simplex 0 -petscspace_degree 1 -qorder 1 -porder 2 -shear_coords
1101: test:
1102: suffix: q1_2d_plex_5
1103: args: -use_da 0 -simplex 0 -petscspace_degree 1 -petscspace_type tensor -qorder 1 -porder 0 -non_affine_coords -convergence
1104: test:
1105: suffix: q1_2d_plex_6
1106: args: -use_da 0 -simplex 0 -petscspace_degree 1 -petscspace_type tensor -qorder 1 -porder 1 -non_affine_coords -convergence
1107: test:
1108: suffix: q1_2d_plex_7
1109: args: -use_da 0 -simplex 0 -petscspace_degree 1 -petscspace_type tensor -qorder 1 -porder 2 -non_affine_coords -convergence
1111: # 2D Q_2 on a quadrilaterial
1112: test:
1113: suffix: q2_2d_plex_0
1114: requires: mpi_type_get_envelope
1115: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 2 -convergence
1116: test:
1117: suffix: q2_2d_plex_1
1118: requires: mpi_type_get_envelope
1119: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 2 -porder 1
1120: test:
1121: suffix: q2_2d_plex_2
1122: requires: mpi_type_get_envelope
1123: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 2 -porder 2
1124: test:
1125: suffix: q2_2d_plex_3
1126: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 2 -porder 1 -shear_coords
1127: test:
1128: suffix: q2_2d_plex_4
1129: requires: mpi_type_get_envelope
1130: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 2 -porder 2 -shear_coords
1131: test:
1132: suffix: q2_2d_plex_5
1133: requires: mpi_type_get_envelope
1134: args: -use_da 0 -simplex 0 -petscspace_degree 2 -petscspace_type tensor -qorder 2 -porder 0 -non_affine_coords -convergence
1135: test:
1136: suffix: q2_2d_plex_6
1137: requires: mpi_type_get_envelope
1138: args: -use_da 0 -simplex 0 -petscspace_degree 2 -petscspace_type tensor -qorder 2 -porder 1 -non_affine_coords -convergence
1139: test:
1140: suffix: q2_2d_plex_7
1141: requires: mpi_type_get_envelope
1142: args: -use_da 0 -simplex 0 -petscspace_degree 2 -petscspace_type tensor -qorder 2 -porder 2 -non_affine_coords -convergence
1145: # 2D P_3 on a triangle
1146: test:
1147: suffix: p3_2d_0
1148: requires: triangle !single
1149: args: -petscspace_degree 3 -qorder 3 -convergence
1150: test:
1151: suffix: p3_2d_1
1152: requires: triangle !single
1153: args: -petscspace_degree 3 -qorder 3 -porder 1
1154: test:
1155: suffix: p3_2d_2
1156: requires: triangle !single
1157: args: -petscspace_degree 3 -qorder 3 -porder 2
1158: test:
1159: suffix: p3_2d_3
1160: requires: triangle !single
1161: args: -petscspace_degree 3 -qorder 3 -porder 3
1162: test:
1163: suffix: p3_2d_4
1164: requires: triangle pragmatic
1165: args: -petscspace_degree 3 -qorder 3 -dm_plex_hash_location -convergence -conv_refine 0
1166: filter: grep -v DEBUG
1167: test:
1168: suffix: p3_2d_5
1169: requires: triangle pragmatic
1170: args: -petscspace_degree 3 -qorder 3 -dm_plex_hash_location -porder 1 -conv_refine 0
1171: test:
1172: suffix: p3_2d_6
1173: requires: triangle pragmatic
1174: args: -petscspace_degree 3 -qorder 3 -dm_plex_hash_location -porder 3 -conv_refine 0
1176: # 2D Q_3 on a quadrilaterial
1177: test:
1178: suffix: q3_2d_0
1179: requires: mpi_type_get_envelope !single
1180: args: -use_da 0 -simplex 0 -petscspace_degree 3 -qorder 3 -convergence
1181: test:
1182: suffix: q3_2d_1
1183: requires: mpi_type_get_envelope !single
1184: args: -use_da 0 -simplex 0 -petscspace_degree 3 -qorder 3 -porder 1
1185: test:
1186: suffix: q3_2d_2
1187: requires: mpi_type_get_envelope !single
1188: args: -use_da 0 -simplex 0 -petscspace_degree 3 -qorder 3 -porder 2
1189: test:
1190: suffix: q3_2d_3
1191: requires: mpi_type_get_envelope !single
1192: args: -use_da 0 -simplex 0 -petscspace_degree 3 -qorder 3 -porder 3
1194: # 2D P_1disc on a triangle/quadrilateral
1195: test:
1196: suffix: p1d_2d_0
1197: requires: triangle
1198: args: -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -convergence
1199: test:
1200: suffix: p1d_2d_1
1201: requires: triangle
1202: args: -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -porder 1
1203: test:
1204: suffix: p1d_2d_2
1205: requires: triangle
1206: args: -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -porder 2
1207: test:
1208: suffix: p1d_2d_3
1209: requires: triangle
1210: args: -use_da 0 -simplex 0 -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -convergence
1211: filter: sed -e "s/convergence rate at refinement 0: 2/convergence rate at refinement 0: 1.9/g"
1212: test:
1213: suffix: p1d_2d_4
1214: requires: triangle
1215: args: -use_da 0 -simplex 0 -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -porder 1
1216: test:
1217: suffix: p1d_2d_5
1218: requires: triangle
1219: args: -use_da 0 -simplex 0 -petscspace_degree 1 -petscdualspace_lagrange_continuity 0 -qorder 1 -porder 2
1221: # 2D BDM_1 on a triangle
1222: test:
1223: suffix: bdm1_2d_0
1224: requires: triangle
1225: args: -petscspace_degree 1 -petscdualspace_type bdm \
1226: -num_comp 2 -qorder 1 -convergence
1227: test:
1228: suffix: bdm1_2d_1
1229: requires: triangle
1230: args: -petscspace_degree 1 -petscdualspace_type bdm \
1231: -num_comp 2 -qorder 1 -porder 1
1232: test:
1233: suffix: bdm1_2d_2
1234: requires: triangle
1235: args: -petscspace_degree 1 -petscdualspace_type bdm \
1236: -num_comp 2 -qorder 1 -porder 2
1238: # 2D BDM_1 on a quadrilateral
1239: test:
1240: suffix: bdm1q_2d_0
1241: requires: triangle
1242: args: -petscspace_degree 1 -petscdualspace_type bdm \
1243: -petscdualspace_lagrange_tensor 1 \
1244: -use_da 0 -simplex 0 -num_comp 2 -qorder 1 -convergence
1245: test:
1246: suffix: bdm1q_2d_1
1247: requires: triangle
1248: args: -petscspace_degree 1 -petscdualspace_type bdm \
1249: -petscdualspace_lagrange_tensor 1 \
1250: -use_da 0 -simplex 0 -num_comp 2 -qorder 1 -porder 1
1251: test:
1252: suffix: bdm1q_2d_2
1253: requires: triangle
1254: args: -petscspace_degree 1 -petscdualspace_type bdm \
1255: -petscdualspace_lagrange_tensor 1 \
1256: -use_da 0 -simplex 0 -num_comp 2 -qorder 1 -porder 2
1258: # Test high order quadrature
1259: test:
1260: suffix: p1_quad_2
1261: requires: triangle
1262: args: -petscspace_degree 1 -qorder 2 -porder 1
1263: test:
1264: suffix: p1_quad_5
1265: requires: triangle
1266: args: -petscspace_degree 1 -qorder 5 -porder 1
1267: test:
1268: suffix: p2_quad_3
1269: requires: triangle
1270: args: -petscspace_degree 2 -qorder 3 -porder 2
1271: test:
1272: suffix: p2_quad_5
1273: requires: triangle
1274: args: -petscspace_degree 2 -qorder 5 -porder 2
1275: test:
1276: suffix: q1_quad_2
1277: requires: mpi_type_get_envelope
1278: args: -use_da 0 -simplex 0 -petscspace_degree 1 -qorder 2 -porder 1
1279: test:
1280: suffix: q1_quad_5
1281: requires: mpi_type_get_envelope
1282: args: -use_da 0 -simplex 0 -petscspace_degree 1 -qorder 5 -porder 1
1283: test:
1284: suffix: q2_quad_3
1285: requires: mpi_type_get_envelope
1286: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 3 -porder 1
1287: test:
1288: suffix: q2_quad_5
1289: requires: mpi_type_get_envelope
1290: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 5 -porder 1
1293: # Nonconforming tests
1294: test:
1295: suffix: constraints
1296: args: -simplex 0 -petscspace_type tensor -petscspace_degree 1 -qorder 0 -constraints
1297: test:
1298: suffix: nonconforming_tensor_2
1299: nsize: 4
1300: args: -test_fe_jacobian -test_injector -petscpartitioner_type simple -tree -simplex 0 -dim 2 -dm_plex_max_projection_height 1 -petscspace_type tensor -petscspace_degree 2 -qorder 2 -dm_view ascii::ASCII_INFO_DETAIL
1301: test:
1302: suffix: nonconforming_tensor_3
1303: nsize: 4
1304: args: -test_fe_jacobian -petscpartitioner_type simple -tree -simplex 0 -dim 3 -dm_plex_max_projection_height 2 -petscspace_type tensor -petscspace_degree 1 -qorder 1 -dm_view ascii::ASCII_INFO_DETAIL
1305: test:
1306: suffix: nonconforming_tensor_2_fv
1307: nsize: 4
1308: args: -test_fv_grad -test_injector -petsclimiter_type none -petscpartitioner_type simple -tree -simplex 0 -dim 2 -num_comp 2
1309: test:
1310: suffix: nonconforming_tensor_3_fv
1311: nsize: 4
1312: args: -test_fv_grad -test_injector -petsclimiter_type none -petscpartitioner_type simple -tree -simplex 0 -dim 3 -num_comp 3
1313: test:
1314: suffix: nonconforming_tensor_2_hi
1315: requires: !single
1316: nsize: 4
1317: args: -test_fe_jacobian -petscpartitioner_type simple -tree -simplex 0 -dim 2 -dm_plex_max_projection_height 1 -petscspace_type tensor -petscspace_degree 4 -qorder 4
1318: test:
1319: suffix: nonconforming_tensor_3_hi
1320: requires: !single skip
1321: nsize: 4
1322: args: -test_fe_jacobian -petscpartitioner_type simple -tree -simplex 0 -dim 3 -dm_plex_max_projection_height 2 -petscspace_type tensor -petscspace_degree 4 -qorder 4
1323: test:
1324: suffix: nonconforming_simplex_2
1325: requires: triangle
1326: nsize: 4
1327: args: -test_fe_jacobian -test_injector -petscpartitioner_type simple -tree -simplex 1 -dim 2 -dm_plex_max_projection_height 1 -petscspace_degree 2 -qorder 2 -dm_view ascii::ASCII_INFO_DETAIL
1328: test:
1329: suffix: nonconforming_simplex_2_hi
1330: requires: triangle !single
1331: nsize: 4
1332: args: -test_fe_jacobian -petscpartitioner_type simple -tree -simplex 1 -dim 2 -dm_plex_max_projection_height 1 -petscspace_degree 4 -qorder 4
1333: test:
1334: suffix: nonconforming_simplex_2_fv
1335: requires: triangle
1336: nsize: 4
1337: args: -test_fv_grad -test_injector -petsclimiter_type none -petscpartitioner_type simple -tree -simplex 1 -dim 2 -num_comp 2
1338: test:
1339: suffix: nonconforming_simplex_3
1340: requires: ctetgen
1341: nsize: 4
1342: args: -test_fe_jacobian -test_injector -petscpartitioner_type simple -tree -simplex 1 -dim 3 -dm_plex_max_projection_height 2 -petscspace_degree 2 -qorder 2 -dm_view ascii::ASCII_INFO_DETAIL
1343: test:
1344: suffix: nonconforming_simplex_3_hi
1345: requires: ctetgen skip
1346: nsize: 4
1347: args: -test_fe_jacobian -petscpartitioner_type simple -tree -simplex 1 -dim 3 -dm_plex_max_projection_height 2 -petscspace_degree 4 -qorder 4
1348: test:
1349: suffix: nonconforming_simplex_3_fv
1350: requires: ctetgen
1351: nsize: 4
1352: args: -test_fv_grad -test_injector -petsclimiter_type none -petscpartitioner_type simple -tree -simplex 1 -dim 3 -num_comp 3
1354: TEST*/
1356: /*
1357: # 2D Q_2 on a quadrilaterial Plex
1358: test:
1359: suffix: q2_2d_plex_0
1360: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 2 -convergence
1361: test:
1362: suffix: q2_2d_plex_1
1363: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 2 -porder 1
1364: test:
1365: suffix: q2_2d_plex_2
1366: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 2 -porder 2
1367: test:
1368: suffix: q2_2d_plex_3
1369: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 2 -porder 1 -shear_coords
1370: test:
1371: suffix: q2_2d_plex_4
1372: args: -use_da 0 -simplex 0 -petscspace_degree 2 -qorder 2 -porder 2 -shear_coords
1373: test:
1374: suffix: q2_2d_plex_5
1375: args: -use_da 0 -simplex 0 -petscspace_degree 2 -petscspace_poly_tensor 1 -qorder 2 -porder 0 -non_affine_coords
1376: test:
1377: suffix: q2_2d_plex_6
1378: args: -use_da 0 -simplex 0 -petscspace_degree 2 -petscspace_poly_tensor 1 -qorder 2 -porder 1 -non_affine_coords
1379: test:
1380: suffix: q2_2d_plex_7
1381: args: -use_da 0 -simplex 0 -petscspace_degree 2 -petscspace_poly_tensor 1 -qorder 2 -porder 2 -non_affine_coords
1383: test:
1384: suffix: p1d_2d_6
1385: requires: pragmatic
1386: args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -convergence -conv_refine 0
1387: test:
1388: suffix: p1d_2d_7
1389: requires: pragmatic
1390: args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 1 -conv_refine 0
1391: test:
1392: suffix: p1d_2d_8
1393: requires: pragmatic
1394: args: -petscspace_degree 1 -qorder 1 -dm_plex_hash_location -porder 2 -conv_refine 0
1395: */