Actual source code: ex62.c
petsc-dev 2014-02-02
1: static char help[] = "Stokes Problem in 2d and 3d with simplicial finite elements.\n\
2: We solve the Stokes problem in a rectangular\n\
3: domain, using a parallel unstructured mesh (DMPLEX) to discretize it.\n\n\n";
5: /*
6: The isoviscous Stokes problem, which we discretize using the finite
7: element method on an unstructured mesh. The weak form equations are
9: < \nabla v, \nabla u + {\nabla u}^T > - < \nabla\cdot v, p > + < v, f > = 0
10: < q, \nabla\cdot v > = 0
12: We start with homogeneous Dirichlet conditions. We will expand this as the set
13: of test problems is developed.
15: Discretization:
17: We use PetscFE to generate a tabulation of the finite element basis functions
18: at quadrature points. We can currently generate an arbitrary order Lagrange
19: element.
21: Field Data:
23: DMPLEX data is organized by point, and the closure operation just stacks up the
24: data from each sieve point in the closure. Thus, for a P_2-P_1 Stokes element, we
25: have
27: cl{e} = {f e_0 e_1 e_2 v_0 v_1 v_2}
28: x = [u_{e_0} v_{e_0} u_{e_1} v_{e_1} u_{e_2} v_{e_2} u_{v_0} v_{v_0} p_{v_0} u_{v_1} v_{v_1} p_{v_1} u_{v_2} v_{v_2} p_{v_2}]
30: The problem here is that we would like to loop over each field separately for
31: integration. Therefore, the closure visitor in DMPlexVecGetClosure() reorders
32: the data so that each field is contiguous
34: x' = [u_{e_0} v_{e_0} u_{e_1} v_{e_1} u_{e_2} v_{e_2} u_{v_0} v_{v_0} u_{v_1} v_{v_1} u_{v_2} v_{v_2} p_{v_0} p_{v_1} p_{v_2}]
36: Likewise, DMPlexVecSetClosure() takes data partitioned by field, and correctly
37: puts it into the Sieve ordering.
39: Next Steps:
41: - Refine and show convergence of correct order automatically (use femTest.py)
42: - Fix InitialGuess for arbitrary disc (means making dual application work again)
43: - Redo slides from GUCASTutorial for this new example
45: For tensor product meshes, see SNES ex67, ex72
46: */
48: #include <petscdmplex.h>
49: #include <petscdt.h>
50: #include <petscfe.h>
51: #include <petscsnes.h>
53: #define NUM_FIELDS 2
54: PetscInt spatialDim = 0;
56: typedef enum {NEUMANN, DIRICHLET} BCType;
57: typedef enum {RUN_FULL, RUN_TEST} RunType;
59: typedef struct {
60: PetscFEM fem; /* REQUIRED to use DMPlexComputeResidualFEM() */
61: PetscInt debug; /* The debugging level */
62: PetscMPIInt rank; /* The process rank */
63: PetscMPIInt numProcs; /* The number of processes */
64: RunType runType; /* Whether to run tests, or solve the full problem */
65: PetscBool jacobianMF; /* Whether to calculate the Jacobian action on the fly */
66: PetscLogEvent createMeshEvent;
67: PetscBool showInitial, showSolution;
68: /* Domain and mesh definition */
69: PetscInt dim; /* The topological mesh dimension */
70: PetscBool interpolate; /* Generate intermediate mesh elements */
71: PetscReal refinementLimit; /* The largest allowable cell volume */
72: char partitioner[2048]; /* The graph partitioner */
73: /* GPU partitioning */
74: PetscInt numBatches; /* The number of cell batches per kernel */
75: PetscInt numBlocks; /* The number of concurrent blocks per kernel */
76: /* Element quadrature */
77: PetscFE fe[NUM_FIELDS]; /* Element definitions for each field */
78: PetscQuadrature q[NUM_FIELDS];
79: /* Problem definition */
80: void (*f0Funcs[NUM_FIELDS])(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar f0[]); /* f0_u(x,y,z), and f0_p(x,y,z) */
81: void (*f1Funcs[NUM_FIELDS])(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar f1[]); /* f1_u(x,y,z), and f1_p(x,y,z) */
82: void (*g0Funcs[NUM_FIELDS*NUM_FIELDS])(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar g0[]); /* g0_uu(x,y,z), g0_up(x,y,z), g0_pu(x,y,z), and g0_pp(x,y,z) */
83: void (*g1Funcs[NUM_FIELDS*NUM_FIELDS])(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar g1[]); /* g1_uu(x,y,z), g1_up(x,y,z), g1_pu(x,y,z), and g1_pp(x,y,z) */
84: void (*g2Funcs[NUM_FIELDS*NUM_FIELDS])(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar g2[]); /* g2_uu(x,y,z), g2_up(x,y,z), g2_pu(x,y,z), and g2_pp(x,y,z) */
85: void (*g3Funcs[NUM_FIELDS*NUM_FIELDS])(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar g3[]); /* g3_uu(x,y,z), g3_up(x,y,z), g3_pu(x,y,z), and g3_pp(x,y,z) */
86: void (**exactFuncs)(const PetscReal x[], PetscScalar *u, void *ctx); /* The exact solution function u(x,y,z), v(x,y,z), and p(x,y,z) */
87: void (*initialGuess[NUM_FIELDS])(const PetscReal x[], PetscScalar *u, void* ctx);
88: BCType bcType;
89: } AppCtx;
91: void zero_1d(const PetscReal coords[], PetscScalar *u, void *ctx)
92: {
93: u[0] = 0.0;
94: }
95: void zero_2d(const PetscReal coords[], PetscScalar *u, void *ctx)
96: {
97: u[0] = 0.0; u[1] = 0.0;
98: }
99: void zero_3d(const PetscReal coords[], PetscScalar *u, void *ctx)
100: {
101: u[0] = 0.0; u[1] = 0.0; u[2] = 0.0;
102: }
104: /*
105: In 2D we use exact solution:
107: u = x^2 + y^2
108: v = 2 x^2 - 2xy
109: p = x + y - 1
110: f_x = f_y = 3
112: so that
114: -\Delta u + \nabla p + f = <-4, -4> + <1, 1> + <3, 3> = 0
115: \nabla \cdot u = 2x - 2x = 0
116: */
117: void quadratic_u_2d(const PetscReal x[], PetscScalar *u, void *ctx)
118: {
119: u[0] = x[0]*x[0] + x[1]*x[1];
120: u[1] = 2.0*x[0]*x[0] - 2.0*x[0]*x[1];
121: }
123: void linear_p_2d(const PetscReal x[], PetscScalar *p, void *ctx)
124: {
125: *p = x[0] + x[1] - 1.0;
126: }
128: void f0_u(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar f0[])
129: {
130: const PetscInt Ncomp = spatialDim;
131: PetscInt comp;
133: for (comp = 0; comp < Ncomp; ++comp) f0[comp] = 3.0;
134: }
136: /* gradU[comp*dim+d] = {u_x, u_y, v_x, v_y} or {u_x, u_y, u_z, v_x, v_y, v_z, w_x, w_y, w_z}
137: u[Ncomp] = {p} */
138: void f1_u(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar f1[])
139: {
140: const PetscInt dim = spatialDim;
141: const PetscInt Ncomp = spatialDim;
142: PetscInt comp, d;
144: for (comp = 0; comp < Ncomp; ++comp) {
145: for (d = 0; d < dim; ++d) {
146: /* f1[comp*dim+d] = 0.5*(gradU[comp*dim+d] + gradU[d*dim+comp]); */
147: f1[comp*dim+d] = gradU[comp*dim+d];
148: }
149: f1[comp*dim+comp] -= u[Ncomp];
150: }
151: }
153: /* gradU[comp*dim+d] = {u_x, u_y, v_x, v_y} or {u_x, u_y, u_z, v_x, v_y, v_z, w_x, w_y, w_z} */
154: void f0_p(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar f0[])
155: {
156: const PetscInt dim = spatialDim;
157: PetscInt d;
159: f0[0] = 0.0;
160: for (d = 0; d < dim; ++d) f0[0] += gradU[d*dim+d];
161: }
163: void f1_p(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar f1[])
164: {
165: const PetscInt dim = spatialDim;
166: PetscInt d;
168: for (d = 0; d < dim; ++d) f1[d] = 0.0;
169: }
171: /* < q, \nabla\cdot v >
172: NcompI = 1, NcompJ = dim */
173: void g1_pu(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar g1[])
174: {
175: const PetscInt dim = spatialDim;
176: PetscInt d;
178: for (d = 0; d < dim; ++d) g1[d*dim+d] = 1.0; /* \frac{\partial\phi^{u_d}}{\partial x_d} */
179: }
181: /* -< \nabla\cdot v, p >
182: NcompI = dim, NcompJ = 1 */
183: void g2_up(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar g2[])
184: {
185: const PetscInt dim = spatialDim;
186: PetscInt d;
188: for (d = 0; d < dim; ++d) g2[d*dim+d] = -1.0; /* \frac{\partial\psi^{u_d}}{\partial x_d} */
189: }
191: /* < \nabla v, \nabla u + {\nabla u}^T >
192: This just gives \nabla u, give the perdiagonal for the transpose */
193: void g3_uu(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar g3[])
194: {
195: const PetscInt dim = spatialDim;
196: const PetscInt Ncomp = spatialDim;
197: PetscInt compI, d;
199: for (compI = 0; compI < Ncomp; ++compI) {
200: for (d = 0; d < dim; ++d) {
201: g3[((compI*Ncomp+compI)*dim+d)*dim+d] = 1.0;
202: }
203: }
204: }
206: /*
207: In 3D we use exact solution:
209: u = x^2 + y^2
210: v = y^2 + z^2
211: w = x^2 + y^2 - 2(x+y)z
212: p = x + y + z - 3/2
213: f_x = f_y = f_z = 3
215: so that
217: -\Delta u + \nabla p + f = <-4, -4, -4> + <1, 1, 1> + <3, 3, 3> = 0
218: \nabla \cdot u = 2x + 2y - 2(x + y) = 0
219: */
220: void quadratic_u_3d(const PetscReal x[], PetscScalar *u, void *ctx)
221: {
222: u[0] = x[0]*x[0] + x[1]*x[1];
223: u[1] = x[1]*x[1] + x[2]*x[2];
224: u[2] = x[0]*x[0] + x[1]*x[1] - 2.0*(x[0] + x[1])*x[2];
225: }
227: void linear_p_3d(const PetscReal x[], PetscScalar *p, void *ctx)
228: {
229: *p = x[0] + x[1] + x[2] - 1.5;
230: }
234: PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
235: {
236: const char *bcTypes[2] = {"neumann", "dirichlet"};
237: const char *runTypes[2] = {"full", "test"};
238: PetscInt bc, run;
242: options->debug = 0;
243: options->runType = RUN_FULL;
244: options->dim = 2;
245: options->interpolate = PETSC_FALSE;
246: options->refinementLimit = 0.0;
247: options->bcType = DIRICHLET;
248: options->numBatches = 1;
249: options->numBlocks = 1;
250: options->jacobianMF = PETSC_FALSE;
251: options->showInitial = PETSC_FALSE;
252: options->showSolution = PETSC_TRUE;
254: options->fem.f0Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->f0Funcs;
255: options->fem.f1Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->f1Funcs;
256: options->fem.g0Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->g0Funcs;
257: options->fem.g1Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->g1Funcs;
258: options->fem.g2Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->g2Funcs;
259: options->fem.g3Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->g3Funcs;
261: MPI_Comm_size(comm, &options->numProcs);
262: MPI_Comm_rank(comm, &options->rank);
263: PetscOptionsBegin(comm, "", "Stokes Problem Options", "DMPLEX");
264: PetscOptionsInt("-debug", "The debugging level", "ex62.c", options->debug, &options->debug, NULL);
265: run = options->runType;
266: PetscOptionsEList("-run_type", "The run type", "ex62.c", runTypes, 2, runTypes[options->runType], &run, NULL);
268: options->runType = (RunType) run;
270: PetscOptionsInt("-dim", "The topological mesh dimension", "ex62.c", options->dim, &options->dim, NULL);
271: spatialDim = options->dim;
272: PetscOptionsBool("-interpolate", "Generate intermediate mesh elements", "ex62.c", options->interpolate, &options->interpolate, NULL);
273: PetscOptionsReal("-refinement_limit", "The largest allowable cell volume", "ex62.c", options->refinementLimit, &options->refinementLimit, NULL);
274: PetscStrcpy(options->partitioner, "chaco");
275: PetscOptionsString("-partitioner", "The graph partitioner", "pflotran.cxx", options->partitioner, options->partitioner, 2048, NULL);
276: bc = options->bcType;
277: PetscOptionsEList("-bc_type","Type of boundary condition","ex62.c",bcTypes,2,bcTypes[options->bcType],&bc,NULL);
279: options->bcType = (BCType) bc;
281: PetscOptionsInt("-gpu_batches", "The number of cell batches per kernel", "ex62.c", options->numBatches, &options->numBatches, NULL);
282: PetscOptionsInt("-gpu_blocks", "The number of concurrent blocks per kernel", "ex62.c", options->numBlocks, &options->numBlocks, NULL);
283: PetscOptionsBool("-jacobian_mf", "Calculate the action of the Jacobian on the fly", "ex62.c", options->jacobianMF, &options->jacobianMF, NULL);
284: PetscOptionsBool("-show_initial", "Output the initial guess for verification", "ex62.c", options->showInitial, &options->showInitial, NULL);
285: PetscOptionsBool("-show_solution", "Output the solution for verification", "ex62.c", options->showSolution, &options->showSolution, NULL);
286: PetscOptionsEnd();
288: PetscLogEventRegister("CreateMesh", DM_CLASSID, &options->createMeshEvent);
289: return(0);
290: }
294: PetscErrorCode DMVecViewLocal(DM dm, Vec v, PetscViewer viewer)
295: {
296: Vec lv;
297: PetscInt p;
298: PetscMPIInt rank, numProcs;
302: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
303: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);
304: DMGetLocalVector(dm, &lv);
305: DMGlobalToLocalBegin(dm, v, INSERT_VALUES, lv);
306: DMGlobalToLocalEnd(dm, v, INSERT_VALUES, lv);
307: PetscPrintf(PETSC_COMM_WORLD, "Local function\n");
308: for (p = 0; p < numProcs; ++p) {
309: if (p == rank) {VecView(lv, PETSC_VIEWER_STDOUT_SELF);}
310: PetscBarrier((PetscObject) dm);
311: }
312: DMRestoreLocalVector(dm, &lv);
313: return(0);
314: }
318: PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
319: {
320: DMLabel label;
321: PetscInt dim = user->dim;
322: PetscBool interpolate = user->interpolate;
323: PetscReal refinementLimit = user->refinementLimit;
324: const char *partitioner = user->partitioner;
328: PetscLogEventBegin(user->createMeshEvent,0,0,0,0);
329: DMPlexCreateBoxMesh(comm, dim, interpolate, dm);
330: DMPlexGetLabel(*dm, "marker", &label);
331: if (label) {DMPlexLabelComplete(*dm, label);}
332: {
333: DM refinedMesh = NULL;
334: DM distributedMesh = NULL;
336: /* Refine mesh using a volume constraint */
337: DMPlexSetRefinementLimit(*dm, refinementLimit);
338: DMRefine(*dm, comm, &refinedMesh);
339: if (refinedMesh) {
340: DMDestroy(dm);
341: *dm = refinedMesh;
342: }
343: /* Distribute mesh over processes */
344: DMPlexDistribute(*dm, partitioner, 0, NULL, &distributedMesh);
345: if (distributedMesh) {
346: DMDestroy(dm);
347: *dm = distributedMesh;
348: }
349: }
350: DMSetFromOptions(*dm);
351: PetscLogEventEnd(user->createMeshEvent,0,0,0,0);
352: return(0);
353: }
357: PetscErrorCode SetupElement(DM dm, AppCtx *user)
358: {
359: const PetscInt dim = user->dim, numFields = 2;
360: const char *prefix[2] = {"vel_", "pres_"};
361: PetscInt qorder = 0, f;
362: PetscErrorCode ierr;
365: for (f = 0; f < numFields; ++f) {
366: PetscFE fem;
367: DM K;
368: PetscSpace P;
369: PetscDualSpace Q;
370: PetscInt order;
372: /* Create space */
373: PetscSpaceCreate(PetscObjectComm((PetscObject) dm), &P);
374: PetscObjectSetOptionsPrefix((PetscObject) P, prefix[f]);
375: PetscSpaceSetFromOptions(P);
376: PetscSpacePolynomialSetNumVariables(P, dim);
377: PetscSpaceSetUp(P);
378: PetscSpaceGetOrder(P, &order);
379: qorder = PetscMax(qorder, order);
380: /* Create dual space */
381: PetscDualSpaceCreate(PetscObjectComm((PetscObject) dm), &Q);
382: PetscObjectSetOptionsPrefix((PetscObject) Q, prefix[f]);
383: PetscDualSpaceCreateReferenceCell(Q, dim, PETSC_TRUE, &K);
384: PetscDualSpaceSetDM(Q, K);
385: DMDestroy(&K);
386: PetscDualSpaceSetOrder(Q, order);
387: PetscDualSpaceSetFromOptions(Q);
388: PetscDualSpaceSetUp(Q);
389: /* Create element */
390: PetscFECreate(PetscObjectComm((PetscObject) dm), &fem);
391: PetscObjectSetOptionsPrefix((PetscObject) fem, prefix[f]);
392: PetscFESetFromOptions(fem);
393: PetscFESetBasisSpace(fem, P);
394: PetscFESetDualSpace(fem, Q);
395: PetscFESetNumComponents(fem, f ? 1 : dim);
397: PetscSpaceDestroy(&P);
398: PetscDualSpaceDestroy(&Q);
399: user->fe[f] = fem;
400: }
401: for (f = 0; f < numFields; ++f) {
402: PetscQuadrature q;
404: /* Create quadrature */
405: PetscDTGaussJacobiQuadrature(dim, qorder, -1.0, 1.0, &q);
406: PetscFESetQuadrature(user->fe[f], q);
407: }
408: user->fem.fe = user->fe;
409: user->fem.feAux = NULL;
410: return(0);
411: }
415: PetscErrorCode DestroyElement(AppCtx *user)
416: {
417: PetscInt numFields = 2, f;
421: for (f = 0; f < numFields; ++f) {
422: PetscFEDestroy(&user->fe[f]);
423: }
424: return(0);
425: }
429: /*
430: There is a problem here with uninterpolated meshes. The index in numDof[] is not dimension in this case,
431: but sieve depth.
432: */
433: PetscErrorCode SetupSection(DM dm, AppCtx *user)
434: {
435: PetscSection section;
436: const PetscInt numFields = NUM_FIELDS;
437: PetscInt dim = user->dim;
438: PetscInt numBC = 0;
439: PetscInt bcFields[1] = {0};
440: IS bcPoints[1] = {NULL};
441: PetscInt numComp[NUM_FIELDS];
442: const PetscInt *numFieldDof[NUM_FIELDS];
443: PetscInt *numDof;
444: PetscInt f, d;
445: PetscErrorCode ierr;
448: PetscFEGetNumComponents(user->fe[0], &numComp[0]);
449: PetscFEGetNumComponents(user->fe[1], &numComp[1]);
450: PetscFEGetNumDof(user->fe[0], &numFieldDof[0]);
451: PetscFEGetNumDof(user->fe[1], &numFieldDof[1]);
452: PetscMalloc1(NUM_FIELDS*(dim+1), &numDof);
453: for (f = 0; f < NUM_FIELDS; ++f) {
454: for (d = 0; d <= dim; ++d) {
455: numDof[f*(dim+1)+d] = numFieldDof[f][d];
456: }
457: }
458: for (f = 0; f < numFields; ++f) {
459: for (d = 1; d < dim; ++d) {
460: if ((numDof[f*(dim+1)+d] > 0) && !user->interpolate) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated when unknowns are specified on edges or faces.");
461: }
462: }
463: if (user->bcType == DIRICHLET) {
464: numBC = 1;
465: DMPlexGetStratumIS(dm, "marker", 1, &bcPoints[0]);
466: }
467: DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcPoints, §ion);
468: PetscSectionSetFieldName(section, 0, "velocity");
469: PetscSectionSetFieldName(section, 1, "pressure");
470: DMSetDefaultSection(dm, section);
471: PetscSectionDestroy(§ion);
472: if (user->bcType == DIRICHLET) {
473: ISDestroy(&bcPoints[0]);
474: }
475: PetscFree(numDof);
476: return(0);
477: }
481: PetscErrorCode SetupExactSolution(DM dm, AppCtx *user)
482: {
483: PetscFEM *fem = &user->fem;
486: fem->f0Funcs[0] = f0_u;
487: fem->f0Funcs[1] = f0_p;
488: fem->f1Funcs[0] = f1_u;
489: fem->f1Funcs[1] = f1_p;
490: fem->g0Funcs[0] = NULL;
491: fem->g0Funcs[1] = NULL;
492: fem->g0Funcs[2] = NULL;
493: fem->g0Funcs[3] = NULL;
494: fem->g1Funcs[0] = NULL;
495: fem->g1Funcs[1] = NULL;
496: fem->g1Funcs[2] = g1_pu; /* < q, \nabla\cdot v > */
497: fem->g1Funcs[3] = NULL;
498: fem->g2Funcs[0] = NULL;
499: fem->g2Funcs[1] = g2_up; /* < \nabla\cdot v, p > */
500: fem->g2Funcs[2] = NULL;
501: fem->g2Funcs[3] = NULL;
502: fem->g3Funcs[0] = g3_uu; /* < \nabla v, \nabla u + {\nabla u}^T > */
503: fem->g3Funcs[1] = NULL;
504: fem->g3Funcs[2] = NULL;
505: fem->g3Funcs[3] = NULL;
506: switch (user->dim) {
507: case 2:
508: user->exactFuncs[0] = quadratic_u_2d;
509: user->exactFuncs[1] = linear_p_2d;
510: user->initialGuess[0] = zero_2d;
511: user->initialGuess[1] = zero_1d;
512: break;
513: case 3:
514: user->exactFuncs[0] = quadratic_u_3d;
515: user->exactFuncs[1] = linear_p_3d;
516: user->initialGuess[0] = zero_3d;
517: user->initialGuess[1] = zero_1d;
518: break;
519: default:
520: SETERRQ1(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d", user->dim);
521: }
522: return(0);
523: }
527: PetscErrorCode CreatePressureNullSpace(DM dm, AppCtx *user, MatNullSpace *nullSpace)
528: {
529: Vec vec, localVec;
533: DMGetGlobalVector(dm, &vec);
534: DMGetLocalVector(dm, &localVec);
535: VecSet(vec, 0.0);
536: /* Put a constant in for all pressures
537: Could change this to project the constant function onto the pressure space (when that is finished) */
538: {
539: PetscSection section;
540: PetscInt pStart, pEnd, p;
541: PetscScalar *a;
543: DMGetDefaultSection(dm, §ion);
544: PetscSectionGetChart(section, &pStart, &pEnd);
545: VecGetArray(localVec, &a);
546: for (p = pStart; p < pEnd; ++p) {
547: PetscInt fDim, off, d;
549: PetscSectionGetFieldDof(section, p, 1, &fDim);
550: PetscSectionGetFieldOffset(section, p, 1, &off);
551: for (d = 0; d < fDim; ++d) a[off+d] = 1.0;
552: }
553: VecRestoreArray(localVec, &a);
554: }
555: DMLocalToGlobalBegin(dm, localVec, INSERT_VALUES, vec);
556: DMLocalToGlobalEnd(dm, localVec, INSERT_VALUES, vec);
557: DMRestoreLocalVector(dm, &localVec);
558: VecNormalize(vec, NULL);
559: if (user->debug) {
560: PetscPrintf(PetscObjectComm((PetscObject)dm), "Pressure Null Space\n");
561: VecView(vec, PETSC_VIEWER_STDOUT_WORLD);
562: }
563: MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_FALSE, 1, &vec, nullSpace);
564: DMRestoreGlobalVector(dm, &vec);
565: /* New style for field null spaces */
566: {
567: PetscObject pressure;
568: MatNullSpace nullSpacePres;
570: DMGetField(dm, 1, &pressure);
571: MatNullSpaceCreate(PetscObjectComm(pressure), PETSC_TRUE, 0, NULL, &nullSpacePres);
572: PetscObjectCompose(pressure, "nullspace", (PetscObject) nullSpacePres);
573: MatNullSpaceDestroy(&nullSpacePres);
574: }
575: return(0);
576: }
580: /*
581: FormJacobianAction - Form the global Jacobian action Y = JX from the global input X
583: Input Parameters:
584: + mat - The Jacobian shell matrix
585: - X - Global input vector
587: Output Parameter:
588: . Y - Local output vector
590: Note:
591: We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
592: like a GPU, or vectorize on a multicore machine.
594: .seealso: FormJacobianActionLocal()
595: */
596: PetscErrorCode FormJacobianAction(Mat J, Vec X, Vec Y)
597: {
598: JacActionCtx *ctx;
599: DM dm;
600: Vec localX, localY;
601: PetscInt N, n;
605: #if 0
606: /* Needs petscimpl.h */
610: #endif
611: MatShellGetContext(J, &ctx);
612: dm = ctx->dm;
614: /* determine whether X = localX */
615: DMGetLocalVector(dm, &localX);
616: DMGetLocalVector(dm, &localY);
617: VecGetSize(X, &N);
618: VecGetSize(localX, &n);
620: if (n != N) { /* X != localX */
621: VecSet(localX, 0.0);
622: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
623: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
624: } else {
625: DMRestoreLocalVector(dm, &localX);
626: localX = X;
627: }
628: DMPlexComputeJacobianActionFEM(dm, J, localX, localY, ctx->user);
629: if (n != N) {
630: DMRestoreLocalVector(dm, &localX);
631: }
632: VecSet(Y, 0.0);
633: DMLocalToGlobalBegin(dm, localY, ADD_VALUES, Y);
634: DMLocalToGlobalEnd(dm, localY, ADD_VALUES, Y);
635: DMRestoreLocalVector(dm, &localY);
636: if (0) {
637: Vec r;
638: PetscReal norm;
640: VecDuplicate(X, &r);
641: MatMult(ctx->J, X, r);
642: VecAXPY(r, -1.0, Y);
643: VecNorm(r, NORM_2, &norm);
644: if (norm > 1.0e-8) {
645: PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action Input:\n");
646: VecView(X, PETSC_VIEWER_STDOUT_WORLD);
647: PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action Result:\n");
648: VecView(Y, PETSC_VIEWER_STDOUT_WORLD);
649: PetscPrintf(PETSC_COMM_WORLD, "Difference:\n");
650: VecView(r, PETSC_VIEWER_STDOUT_WORLD);
651: SETERRQ1(PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_WRONG, "The difference with assembled multiply is too large %g", norm);
652: }
653: VecDestroy(&r);
654: }
655: return(0);
656: }
660: int main(int argc, char **argv)
661: {
662: SNES snes; /* nonlinear solver */
663: DM dm; /* problem definition */
664: Vec u,r; /* solution, residual vectors */
665: Mat A,J; /* Jacobian matrix */
666: MatNullSpace nullSpace; /* May be necessary for pressure */
667: AppCtx user; /* user-defined work context */
668: JacActionCtx userJ; /* context for Jacobian MF action */
669: PetscInt its; /* iterations for convergence */
670: PetscReal error = 0.0; /* L_2 error in the solution */
671: PetscInt numComponents = 0, f;
674: PetscInitialize(&argc, &argv, NULL, help);
675: ProcessOptions(PETSC_COMM_WORLD, &user);
676: SNESCreate(PETSC_COMM_WORLD, &snes);
677: CreateMesh(PETSC_COMM_WORLD, &user, &dm);
678: SNESSetDM(snes, dm);
680: SetupElement(dm, &user);
681: for (f = 0; f < NUM_FIELDS; ++f) {
682: PetscInt numComp;
683: PetscFEGetNumComponents(user.fe[f], &numComp);
684: numComponents += numComp;
685: }
686: PetscMalloc(NUM_FIELDS * sizeof(void (*)(const PetscReal[], PetscScalar *, void *)), &user.exactFuncs);
687: user.fem.bcFuncs = user.exactFuncs;
688: user.fem.bcCtxs = NULL;
689: SetupExactSolution(dm, &user);
690: SetupSection(dm, &user);
691: DMPlexCreateClosureIndex(dm, NULL);
693: DMCreateGlobalVector(dm, &u);
694: VecDuplicate(u, &r);
696: DMSetMatType(dm,MATAIJ);
697: DMCreateMatrix(dm, &J);
698: if (user.jacobianMF) {
699: PetscInt M, m, N, n;
701: MatGetSize(J, &M, &N);
702: MatGetLocalSize(J, &m, &n);
703: MatCreate(PETSC_COMM_WORLD, &A);
704: MatSetSizes(A, m, n, M, N);
705: MatSetType(A, MATSHELL);
706: MatSetUp(A);
707: MatShellSetOperation(A, MATOP_MULT, (void (*)(void))FormJacobianAction);
709: userJ.dm = dm;
710: userJ.J = J;
711: userJ.user = &user;
713: DMCreateLocalVector(dm, &userJ.u);
714: DMPlexProjectFunctionLocal(dm, user.fe, user.exactFuncs, NULL, INSERT_BC_VALUES, userJ.u);
715: MatShellSetContext(A, &userJ);
716: } else {
717: A = J;
718: }
719: CreatePressureNullSpace(dm, &user, &nullSpace);
720: MatSetNullSpace(J, nullSpace);
721: if (A != J) {
722: MatSetNullSpace(A, nullSpace);
723: }
725: DMSNESSetFunctionLocal(dm, (PetscErrorCode (*)(DM,Vec,Vec,void*))DMPlexComputeResidualFEM,&user);
726: DMSNESSetJacobianLocal(dm, (PetscErrorCode (*)(DM,Vec,Mat,Mat,MatStructure*,void*))DMPlexComputeJacobianFEM,&user);
727: SNESSetJacobian(snes, A, J, NULL, NULL);
729: SNESSetFromOptions(snes);
731: DMPlexProjectFunction(dm, user.fe, user.exactFuncs, NULL, INSERT_ALL_VALUES, u);
732: if (user.showInitial) {DMVecViewLocal(dm, u, PETSC_VIEWER_STDOUT_SELF);}
733: if (user.runType == RUN_FULL) {
734: DMPlexProjectFunction(dm, user.fe, user.initialGuess, NULL, INSERT_VALUES, u);
735: if (user.showInitial) {DMVecViewLocal(dm, u, PETSC_VIEWER_STDOUT_SELF);}
736: if (user.debug) {
737: PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");
738: VecView(u, PETSC_VIEWER_STDOUT_WORLD);
739: }
740: SNESSolve(snes, NULL, u);
741: SNESGetIterationNumber(snes, &its);
742: PetscPrintf(PETSC_COMM_WORLD, "Number of SNES iterations = %D\n", its);
743: DMPlexComputeL2Diff(dm, user.fe, user.exactFuncs, NULL, u, &error);
744: PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: %.3g\n", error);
745: if (user.showSolution) {
746: PetscPrintf(PETSC_COMM_WORLD, "Solution\n");
747: VecChop(u, 3.0e-9);
748: VecView(u, PETSC_VIEWER_STDOUT_WORLD);
749: }
750: } else {
751: PetscReal res = 0.0;
753: /* Check discretization error */
754: PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");
755: VecView(u, PETSC_VIEWER_STDOUT_WORLD);
756: DMPlexComputeL2Diff(dm, user.fe, user.exactFuncs, NULL, u, &error);
757: if (error >= 1.0e-11) {
758: PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: %g\n", error);
759: } else {
760: PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: < 1.0e-11\n", error);
761: }
762: /* Check residual */
763: SNESComputeFunction(snes, u, r);
764: PetscPrintf(PETSC_COMM_WORLD, "Initial Residual\n");
765: VecChop(r, 1.0e-10);
766: VecView(r, PETSC_VIEWER_STDOUT_WORLD);
767: VecNorm(r, NORM_2, &res);
768: PetscPrintf(PETSC_COMM_WORLD, "L_2 Residual: %g\n", res);
769: /* Check Jacobian */
770: {
771: Vec b;
772: MatStructure flag;
773: PetscBool isNull;
775: SNESComputeJacobian(snes, u, &A, &A, &flag);
776: MatNullSpaceTest(nullSpace, J, &isNull);
777: if (!isNull) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid.");
778: VecDuplicate(u, &b);
779: VecSet(r, 0.0);
780: SNESComputeFunction(snes, r, b);
781: MatMult(A, u, r);
782: VecAXPY(r, 1.0, b);
783: VecDestroy(&b);
784: PetscPrintf(PETSC_COMM_WORLD, "Au - b = Au + F(0)\n");
785: VecChop(r, 1.0e-10);
786: VecView(r, PETSC_VIEWER_STDOUT_WORLD);
787: VecNorm(r, NORM_2, &res);
788: PetscPrintf(PETSC_COMM_WORLD, "Linear L_2 Residual: %g\n", res);
789: }
790: }
792: if (user.runType == RUN_FULL) {
793: PetscViewer viewer;
794: Vec uLocal;
795: const char *name;
797: PetscViewerCreate(PETSC_COMM_WORLD, &viewer);
798: PetscViewerSetType(viewer, PETSCVIEWERVTK);
799: PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_VTK);
800: PetscViewerFileSetName(viewer, "ex62_sol.vtk");
802: DMGetLocalVector(dm, &uLocal);
803: PetscObjectGetName((PetscObject) u, &name);
804: PetscObjectSetName((PetscObject) uLocal, name);
805: DMGlobalToLocalBegin(dm, u, INSERT_VALUES, uLocal);
806: DMGlobalToLocalEnd(dm, u, INSERT_VALUES, uLocal);
807: VecView(uLocal, viewer);
808: DMRestoreLocalVector(dm, &uLocal);
810: PetscViewerDestroy(&viewer);
811: }
813: PetscFree(user.exactFuncs);
814: DestroyElement(&user);
815: MatNullSpaceDestroy(&nullSpace);
816: if (user.jacobianMF) {
817: VecDestroy(&userJ.u);
818: }
819: if (A != J) {
820: MatDestroy(&A);
821: }
822: MatDestroy(&J);
823: VecDestroy(&u);
824: VecDestroy(&r);
825: SNESDestroy(&snes);
826: DMDestroy(&dm);
827: PetscFinalize();
828: return 0;
829: }