Actual source code: ex12.c
petsc-dev 2014-02-02
1: static char help[] = "Poisson Problem in 2d and 3d with simplicial finite elements.\n\
2: We solve the Poisson problem in a rectangular\n\
3: domain, using a parallel unstructured mesh (DMPLEX) to discretize it.\n\n\n";
5: #include <petscdmplex.h>
6: #include <petscsnes.h>
7: #if defined(PETSC_HAVE_EXODUSII)
8: #include <exodusII.h>
9: #endif
11: #define NUM_FIELDS 1
12: PetscInt spatialDim = 0;
14: typedef enum {NEUMANN, DIRICHLET, NONE} BCType;
15: typedef enum {RUN_FULL, RUN_TEST, RUN_PERF} RunType;
16: typedef enum {COEFF_NONE, COEFF_ANALYTIC, COEFF_FIELD} CoeffType;
18: typedef struct {
19: PetscFEM fem; /* REQUIRED to use DMPlexComputeResidualFEM() */
20: PetscInt debug; /* The debugging level */
21: PetscMPIInt rank; /* The process rank */
22: PetscMPIInt numProcs; /* The number of processes */
23: RunType runType; /* Whether to run tests, or solve the full problem */
24: PetscBool jacobianMF; /* Whether to calculate the Jacobian action on the fly */
25: PetscLogEvent createMeshEvent;
26: PetscBool showInitial, showSolution;
27: /* Domain and mesh definition */
28: PetscInt dim; /* The topological mesh dimension */
29: char filename[2048]; /* The optional ExodusII file */
30: PetscBool interpolate; /* Generate intermediate mesh elements */
31: PetscReal refinementLimit; /* The largest allowable cell volume */
32: PetscBool refinementUniform; /* Uniformly refine the mesh */
33: PetscInt refinementRounds; /* The number of uniform refinements */
34: char partitioner[2048]; /* The graph partitioner */
35: /* Element definition */
36: PetscFE fe[NUM_FIELDS];
37: PetscFE feBd[NUM_FIELDS];
38: PetscFE feAux[1];
39: /* Problem definition */
40: 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) */
41: 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) */
42: 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) */
43: 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) */
44: 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) */
45: 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) */
46: 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) */
47: void (*f0BdFuncs[NUM_FIELDS])(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], const PetscReal n[], PetscScalar f0[]); /* f0_u(x,y,z), and f0_p(x,y,z) */
48: void (*f1BdFuncs[NUM_FIELDS])(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], const PetscReal n[], PetscScalar f1[]); /* f1_u(x,y,z), and f1_p(x,y,z) */
49: BCType bcType;
50: CoeffType variableCoefficient;
51: } AppCtx;
53: void zero(const PetscReal coords[], PetscScalar *u, void *ctx)
54: {
55: *u = 0.0;
56: }
58: /*
59: In 2D for Dirichlet conditions, we use exact solution:
61: u = x^2 + y^2
62: f = 4
64: so that
66: -\Delta u + f = -4 + 4 = 0
68: For Neumann conditions, we have
70: -\nabla u \cdot -\hat y |_{y=0} = (2y)|_{y=0} = 0 (bottom)
71: -\nabla u \cdot \hat y |_{y=1} = -(2y)|_{y=1} = -2 (top)
72: -\nabla u \cdot -\hat x |_{x=0} = (2x)|_{x=0} = 0 (left)
73: -\nabla u \cdot \hat x |_{x=1} = -(2x)|_{x=1} = -2 (right)
75: Which we can express as
77: \nabla u \cdot \hat n|_\Gamma = {2 x, 2 y} \cdot \hat n = 2 (x + y)
78: */
79: void quadratic_u_2d(const PetscReal x[], PetscScalar *u, void *ctx)
80: {
81: *u = x[0]*x[0] + x[1]*x[1];
82: }
84: void f0_u(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar f0[])
85: {
86: f0[0] = 4.0;
87: }
89: void f0_bd_u(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], const PetscReal n[], PetscScalar f0[])
90: {
91: PetscInt d;
92: for (d = 0, f0[0] = 0.0; d < spatialDim; ++d) f0[0] += -n[d]*2.0*x[d];
93: }
95: void f0_bd_zero(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], const PetscReal n[], PetscScalar f0[])
96: {
97: f0[0] = 0.0;
98: }
100: void f1_bd_zero(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], const PetscReal n[], PetscScalar f1[])
101: {
102: const PetscInt Ncomp = spatialDim;
103: PetscInt comp;
105: for (comp = 0; comp < Ncomp; ++comp) f1[comp] = 0.0;
106: }
108: /* gradU[comp*dim+d] = {u_x, u_y} or {u_x, u_y, u_z} */
109: void f1_u(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar f1[])
110: {
111: PetscInt d;
113: for (d = 0; d < spatialDim; ++d) f1[d] = gradU[d];
114: }
116: /* < \nabla v, \nabla u + {\nabla u}^T >
117: This just gives \nabla u, give the perdiagonal for the transpose */
118: void g3_uu(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar g3[])
119: {
120: PetscInt d;
122: for (d = 0; d < spatialDim; ++d) g3[d*spatialDim+d] = 1.0;
123: }
125: /*
126: In 2D for Dirichlet conditions with a variable coefficient, we use exact solution:
128: u = x^2 + y^2
129: f = 6 (x + y)
130: nu = (x + y)
132: so that
134: -\div \nu \grad u + f = -6 (x + y) + 6 (x + y) = 0
135: */
136: void nu_2d(const PetscReal x[], PetscScalar *u, void *ctx)
137: {
138: *u = x[0] + x[1];
139: }
141: void f0_analytic_u(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar f0[])
142: {
143: f0[0] = 6.0*(x[0] + x[1]);
144: }
146: /* gradU[comp*dim+d] = {u_x, u_y} or {u_x, u_y, u_z} */
147: void f1_analytic_u(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar f1[])
148: {
149: PetscInt d;
151: for (d = 0; d < spatialDim; ++d) f1[d] = (x[0] + x[1])*gradU[d];
152: }
153: void f1_field_u(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar f1[])
154: {
155: PetscInt d;
157: for (d = 0; d < spatialDim; ++d) f1[d] = a[0]*gradU[d];
158: }
160: /* < \nabla v, \nabla u + {\nabla u}^T >
161: This just gives \nabla u, give the perdiagonal for the transpose */
162: void g3_analytic_uu(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar g3[])
163: {
164: PetscInt d;
166: for (d = 0; d < spatialDim; ++d) g3[d*spatialDim+d] = x[0] + x[1];
167: }
168: void g3_field_uu(const PetscScalar u[], const PetscScalar gradU[], const PetscScalar a[], const PetscScalar gradA[], const PetscReal x[], PetscScalar g3[])
169: {
170: PetscInt d;
172: for (d = 0; d < spatialDim; ++d) g3[d*spatialDim+d] = a[0];
173: }
175: /*
176: In 3D for Dirichlet conditions we use exact solution:
178: u = x^2 + y^2 + z^2
179: f = 6
181: so that
183: -\Delta u + f = -6 + 6 = 0
185: For Neumann conditions, we have
187: -\nabla u \cdot -\hat z |_{z=0} = (2z)|_{z=0} = 0 (bottom)
188: -\nabla u \cdot \hat z |_{z=1} = -(2z)|_{z=1} = -2 (top)
189: -\nabla u \cdot -\hat y |_{y=0} = (2y)|_{y=0} = 0 (front)
190: -\nabla u \cdot \hat y |_{y=1} = -(2y)|_{y=1} = -2 (back)
191: -\nabla u \cdot -\hat x |_{x=0} = (2x)|_{x=0} = 0 (left)
192: -\nabla u \cdot \hat x |_{x=1} = -(2x)|_{x=1} = -2 (right)
194: Which we can express as
196: \nabla u \cdot \hat n|_\Gamma = {2 x, 2 y, 2z} \cdot \hat n = 2 (x + y + z)
197: */
198: void quadratic_u_3d(const PetscReal x[], PetscScalar *u, void *ctx)
199: {
200: *u = x[0]*x[0] + x[1]*x[1] + x[2]*x[2];
201: }
205: PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
206: {
207: const char *bcTypes[3] = {"neumann", "dirichlet", "none"};
208: const char *runTypes[3] = {"full", "test", "perf"};
209: const char *coeffTypes[3] = {"none", "analytic", "field"};
210: PetscInt bc, run, coeff;
211: PetscBool flg;
215: options->debug = 0;
216: options->runType = RUN_FULL;
217: options->dim = 2;
218: options->filename[0] = '\0';
219: options->interpolate = PETSC_FALSE;
220: options->refinementLimit = 0.0;
221: options->refinementUniform = PETSC_FALSE;
222: options->refinementRounds = 1;
223: options->bcType = DIRICHLET;
224: options->variableCoefficient = COEFF_NONE;
225: options->jacobianMF = PETSC_FALSE;
226: options->showInitial = PETSC_FALSE;
227: options->showSolution = PETSC_FALSE;
229: options->fem.f0Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->f0Funcs;
230: options->fem.f1Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->f1Funcs;
231: options->fem.g0Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->g0Funcs;
232: options->fem.g1Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->g1Funcs;
233: options->fem.g2Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->g2Funcs;
234: options->fem.g3Funcs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[])) &options->g3Funcs;
235: options->fem.f0BdFuncs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], const PetscReal[], PetscScalar[])) &options->f0BdFuncs;
236: options->fem.f1BdFuncs = (void (**)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], const PetscReal[], PetscScalar[])) &options->f1BdFuncs;
238: MPI_Comm_size(comm, &options->numProcs);
239: MPI_Comm_rank(comm, &options->rank);
240: PetscOptionsBegin(comm, "", "Poisson Problem Options", "DMPLEX");
241: PetscOptionsInt("-debug", "The debugging level", "ex12.c", options->debug, &options->debug, NULL);
242: run = options->runType;
243: PetscOptionsEList("-run_type", "The run type", "ex12.c", runTypes, 3, runTypes[options->runType], &run, NULL);
245: options->runType = (RunType) run;
247: PetscOptionsInt("-dim", "The topological mesh dimension", "ex12.c", options->dim, &options->dim, NULL);
248: spatialDim = options->dim;
249: PetscOptionsString("-f", "Exodus.II filename to read", "ex12.c", options->filename, options->filename, sizeof(options->filename), &flg);
250: #if !defined(PETSC_HAVE_EXODUSII)
251: if (flg) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "This option requires ExodusII support. Reconfigure using --download-exodusii");
252: #endif
253: PetscOptionsBool("-interpolate", "Generate intermediate mesh elements", "ex12.c", options->interpolate, &options->interpolate, NULL);
254: PetscOptionsReal("-refinement_limit", "The largest allowable cell volume", "ex12.c", options->refinementLimit, &options->refinementLimit, NULL);
255: PetscOptionsBool("-refinement_uniform", "Uniformly refine the mesh", "ex52.c", options->refinementUniform, &options->refinementUniform, NULL);
256: PetscOptionsInt("-refinement_rounds", "The number of uniform refinements", "ex52.c", options->refinementRounds, &options->refinementRounds, NULL);
257: PetscStrcpy(options->partitioner, "chaco");
258: PetscOptionsString("-partitioner", "The graph partitioner", "pflotran.cxx", options->partitioner, options->partitioner, 2048, NULL);
259: bc = options->bcType;
260: PetscOptionsEList("-bc_type","Type of boundary condition","ex12.c",bcTypes,3,bcTypes[options->bcType],&bc,NULL);
261: options->bcType = (BCType) bc;
262: coeff = options->variableCoefficient;
263: PetscOptionsEList("-variable_coefficient","Type of variable coefficent","ex12.c",coeffTypes,3,coeffTypes[options->variableCoefficient],&coeff,NULL);
264: options->variableCoefficient = (CoeffType) coeff;
266: PetscOptionsBool("-jacobian_mf", "Calculate the action of the Jacobian on the fly", "ex12.c", options->jacobianMF, &options->jacobianMF, NULL);
267: PetscOptionsBool("-show_initial", "Output the initial guess for verification", "ex12.c", options->showInitial, &options->showInitial, NULL);
268: PetscOptionsBool("-show_solution", "Output the solution for verification", "ex12.c", options->showSolution, &options->showSolution, NULL);
269: PetscOptionsEnd();
271: PetscLogEventRegister("CreateMesh", DM_CLASSID, &options->createMeshEvent);
272: return(0);
273: }
277: PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
278: {
279: PetscInt dim = user->dim;
280: const char *filename = user->filename;
281: PetscBool interpolate = user->interpolate;
282: PetscReal refinementLimit = user->refinementLimit;
283: PetscBool refinementUniform = user->refinementUniform;
284: PetscInt refinementRounds = user->refinementRounds;
285: const char *partitioner = user->partitioner;
286: size_t len;
290: PetscLogEventBegin(user->createMeshEvent,0,0,0,0);
291: PetscStrlen(filename, &len);
292: if (!len) {
293: DMLabel label;
295: DMPlexCreateBoxMesh(comm, dim, interpolate, dm);
296: PetscObjectSetName((PetscObject) *dm, "Mesh");
297: DMPlexGetLabel(*dm, "marker", &label);
298: if (label) {DMPlexLabelComplete(*dm, label);}
299: } else {
300: #if defined(PETSC_HAVE_EXODUSII)
301: int CPU_word_size = 0, IO_word_size = 0, exoid;
302: float version;
303: PetscMPIInt rank;
305: MPI_Comm_rank(comm, &rank);
306: if (!rank) {
307: exoid = ex_open(filename, EX_READ, &CPU_word_size, &IO_word_size, &version);
308: if (exoid <= 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "ex_open(\"%s\",...) did not return a valid file ID", filename);
309: } else exoid = -1; /* Not used */
310: DMPlexCreateExodus(comm, exoid, interpolate, dm);
311: DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
312: if (!rank) {ex_close(exoid);}
313: /* Must have boundary marker for Dirichlet conditions */
314: #endif
315: }
316: {
317: DM refinedMesh = NULL;
318: DM distributedMesh = NULL;
320: /* Refine mesh using a volume constraint */
321: DMPlexSetRefinementLimit(*dm, refinementLimit);
322: DMRefine(*dm, comm, &refinedMesh);
323: if (refinedMesh) {
324: const char *name;
326: PetscObjectGetName((PetscObject) *dm, &name);
327: PetscObjectSetName((PetscObject) refinedMesh, name);
328: DMDestroy(dm);
329: *dm = refinedMesh;
330: }
331: /* Distribute mesh over processes */
332: DMPlexDistribute(*dm, partitioner, 0, NULL, &distributedMesh);
333: if (distributedMesh) {
334: DMDestroy(dm);
335: *dm = distributedMesh;
336: }
337: /* Use regular refinement in parallel */
338: if (refinementUniform) {
339: PetscInt r;
341: DMPlexSetRefinementUniform(*dm, refinementUniform);
342: for (r = 0; r < refinementRounds; ++r) {
343: DMRefine(*dm, comm, &refinedMesh);
344: if (refinedMesh) {
345: DMDestroy(dm);
346: *dm = refinedMesh;
347: }
348: }
349: }
350: }
351: DMSetFromOptions(*dm);
352: DMViewFromOptions(*dm, NULL, "-dm_view");
353: PetscLogEventEnd(user->createMeshEvent,0,0,0,0);
354: return(0);
355: }
359: PetscErrorCode SetupElement(DM dm, AppCtx *user)
360: {
361: const PetscInt dim = user->dim;
362: PetscFE fem;
363: PetscQuadrature q;
364: DM K;
365: PetscSpace P;
366: PetscDualSpace Q;
367: PetscInt order;
368: PetscErrorCode ierr;
371: /* Create space */
372: PetscSpaceCreate(PetscObjectComm((PetscObject) dm), &P);
373: PetscSpaceSetFromOptions(P);
374: PetscSpacePolynomialSetNumVariables(P, dim);
375: PetscSpaceSetUp(P);
376: PetscSpaceGetOrder(P, &order);
377: /* Create dual space */
378: PetscDualSpaceCreate(PetscObjectComm((PetscObject) dm), &Q);
379: PetscDualSpaceCreateReferenceCell(Q, dim, PETSC_TRUE, &K);
380: PetscDualSpaceSetDM(Q, K);
381: DMDestroy(&K);
382: PetscDualSpaceSetOrder(Q, order);
383: PetscDualSpaceSetFromOptions(Q);
384: PetscDualSpaceSetUp(Q);
385: /* Create element */
386: PetscFECreate(PetscObjectComm((PetscObject) dm), &fem);
387: PetscFESetFromOptions(fem);
388: PetscFESetBasisSpace(fem, P);
389: PetscFESetDualSpace(fem, Q);
390: PetscFESetNumComponents(fem, 1);
391: PetscSpaceDestroy(&P);
392: PetscDualSpaceDestroy(&Q);
393: /* Create quadrature */
394: PetscDTGaussJacobiQuadrature(dim, order, -1.0, 1.0, &q);
395: PetscFESetQuadrature(fem, q);
396: user->fe[0] = fem;
397: user->fem.fe = user->fe;
398: return(0);
399: }
403: PetscErrorCode SetupMaterialElement(DM dm, AppCtx *user)
404: {
405: const PetscInt dim = user->dim;
406: const char *prefix = "mat_";
407: PetscFE fem;
408: PetscQuadrature q;
409: DM K;
410: PetscSpace P;
411: PetscDualSpace Q;
412: PetscInt order, qorder;
413: PetscErrorCode ierr;
416: if (user->variableCoefficient != COEFF_FIELD) {user->fem.feAux = NULL; user->feAux[0] = NULL; return(0);}
417: /* Create space */
418: PetscSpaceCreate(PetscObjectComm((PetscObject) dm), &P);
419: PetscObjectSetOptionsPrefix((PetscObject) P, prefix);
420: PetscSpaceSetFromOptions(P);
421: PetscSpacePolynomialSetNumVariables(P, dim);
422: PetscSpaceSetUp(P);
423: PetscSpaceGetOrder(P, &order);
424: /* Create dual space */
425: PetscDualSpaceCreate(PetscObjectComm((PetscObject) dm), &Q);
426: PetscObjectSetOptionsPrefix((PetscObject) Q, prefix);
427: PetscDualSpaceCreateReferenceCell(Q, dim, PETSC_TRUE, &K);
428: PetscDualSpaceSetDM(Q, K);
429: DMDestroy(&K);
430: PetscDualSpaceSetOrder(Q, order);
431: PetscDualSpaceSetFromOptions(Q);
432: PetscDualSpaceSetUp(Q);
433: /* Create element */
434: PetscFECreate(PetscObjectComm((PetscObject) dm), &fem);
435: PetscObjectSetOptionsPrefix((PetscObject) fem, prefix);
436: PetscFESetFromOptions(fem);
437: PetscFESetBasisSpace(fem, P);
438: PetscFESetDualSpace(fem, Q);
439: PetscFESetNumComponents(fem, 1);
440: PetscSpaceDestroy(&P);
441: PetscDualSpaceDestroy(&Q);
442: /* Create quadrature, must agree with solution quadrature */
443: PetscFEGetBasisSpace(user->fe[0], &P);
444: PetscSpaceGetOrder(P, &qorder);
445: PetscDTGaussJacobiQuadrature(dim, qorder, -1.0, 1.0, &q);
446: PetscFESetQuadrature(fem, q);
447: user->feAux[0] = fem;
448: user->fem.feAux = user->feAux;
449: return(0);
450: }
454: PetscErrorCode SetupBdElement(DM dm, AppCtx *user)
455: {
456: const PetscInt dim = user->dim-1;
457: const char *prefix = "bd_";
458: PetscFE fem;
459: PetscQuadrature q;
460: DM K;
461: PetscSpace P;
462: PetscDualSpace Q;
463: PetscInt order;
464: PetscErrorCode ierr;
467: if (user->bcType != NEUMANN) {user->fem.feBd = NULL; user->feBd[0] = NULL; return(0);}
468: /* Create space */
469: PetscSpaceCreate(PetscObjectComm((PetscObject) dm), &P);
470: PetscObjectSetOptionsPrefix((PetscObject) P, prefix);
471: PetscSpaceSetFromOptions(P);
472: PetscSpacePolynomialSetNumVariables(P, dim);
473: PetscSpaceSetUp(P);
474: PetscSpaceGetOrder(P, &order);
475: /* Create dual space */
476: PetscDualSpaceCreate(PetscObjectComm((PetscObject) dm), &Q);
477: PetscObjectSetOptionsPrefix((PetscObject) Q, prefix);
478: PetscDualSpaceCreateReferenceCell(Q, dim, PETSC_TRUE, &K);
479: PetscDualSpaceSetDM(Q, K);
480: DMDestroy(&K);
481: PetscDualSpaceSetOrder(Q, order);
482: PetscDualSpaceSetFromOptions(Q);
483: PetscDualSpaceSetUp(Q);
484: /* Create element */
485: PetscFECreate(PetscObjectComm((PetscObject) dm), &fem);
486: PetscObjectSetOptionsPrefix((PetscObject) fem, prefix);
487: PetscFESetFromOptions(fem);
488: PetscFESetBasisSpace(fem, P);
489: PetscFESetDualSpace(fem, Q);
490: PetscFESetNumComponents(fem, 1);
491: PetscSpaceDestroy(&P);
492: PetscDualSpaceDestroy(&Q);
493: /* Create quadrature */
494: PetscDTGaussJacobiQuadrature(dim, order, -1.0, 1.0, &q);
495: PetscFESetQuadrature(fem, q);
496: user->feBd[0] = fem;
497: user->fem.feBd = user->feBd;
498: return(0);
499: }
503: PetscErrorCode DestroyElement(AppCtx *user)
504: {
508: PetscFEDestroy(&user->fe[0]);
509: PetscFEDestroy(&user->feBd[0]);
510: PetscFEDestroy(&user->feAux[0]);
511: return(0);
512: }
516: PetscErrorCode SetupExactSolution(DM dm, AppCtx *user)
517: {
518: PetscFEM *fem = &user->fem;
521: switch (user->variableCoefficient) {
522: case COEFF_NONE:
523: fem->f0Funcs[0] = f0_u;
524: fem->f1Funcs[0] = f1_u;
525: fem->g0Funcs[0] = NULL;
526: fem->g1Funcs[0] = NULL;
527: fem->g2Funcs[0] = NULL;
528: fem->g3Funcs[0] = g3_uu; /* < \nabla v, \nabla u > */
529: break;
530: case COEFF_ANALYTIC:
531: fem->f0Funcs[0] = f0_analytic_u;
532: fem->f1Funcs[0] = f1_analytic_u;
533: fem->g0Funcs[0] = NULL;
534: fem->g1Funcs[0] = NULL;
535: fem->g2Funcs[0] = NULL;
536: fem->g3Funcs[0] = g3_analytic_uu;
537: break;
538: case COEFF_FIELD:
539: fem->f0Funcs[0] = f0_analytic_u;
540: fem->f1Funcs[0] = f1_field_u;
541: fem->g0Funcs[0] = NULL;
542: fem->g1Funcs[0] = NULL;
543: fem->g2Funcs[0] = NULL;
544: fem->g3Funcs[0] = g3_analytic_uu /*g3_field_uu*/;
545: break;
546: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid variable coefficient type %d", user->variableCoefficient);
547: }
548: fem->f0BdFuncs[0] = f0_bd_zero;
549: fem->f1BdFuncs[0] = f1_bd_zero;
550: switch (user->dim) {
551: case 2:
552: user->exactFuncs[0] = quadratic_u_2d;
553: if (user->bcType == NEUMANN) fem->f0BdFuncs[0] = f0_bd_u;
554: break;
555: case 3:
556: user->exactFuncs[0] = quadratic_u_3d;
557: if (user->bcType == NEUMANN) fem->f0BdFuncs[0] = f0_bd_u;
558: break;
559: default:
560: SETERRQ1(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d", user->dim);
561: }
562: return(0);
563: }
567: PetscErrorCode SetupSection(DM dm, AppCtx *user)
568: {
569: PetscSection section;
570: DMLabel label;
571: PetscInt dim = user->dim;
572: const char *bdLabel = user->bcType == NEUMANN ? "boundary" : "marker";
573: PetscInt numBC = user->bcType == DIRICHLET ? 1 : 0;
574: PetscInt bcFields[1] = {0};
575: IS bcPoints[1] = {NULL};
576: PetscInt numComp[1];
577: const PetscInt *numDof;
578: PetscBool has;
579: PetscErrorCode ierr;
582: PetscFEGetNumComponents(user->fe[0], &numComp[0]);
583: PetscFEGetNumDof(user->fe[0], &numDof);
584: DMPlexHasLabel(dm, bdLabel, &has);
585: if (!has) {
586: DMPlexCreateLabel(dm, bdLabel);
587: DMPlexGetLabel(dm, bdLabel, &label);
588: DMPlexMarkBoundaryFaces(dm, label);
589: }
590: DMPlexGetLabel(dm, bdLabel, &label);
591: DMPlexLabelComplete(dm, label);
592: if (user->bcType == DIRICHLET) {DMPlexGetStratumIS(dm, bdLabel, 1, &bcPoints[0]);}
593: DMPlexCreateSection(dm, dim, NUM_FIELDS, numComp, numDof, numBC, bcFields, bcPoints, §ion);
594: PetscSectionSetFieldName(section, 0, "potential");
595: DMSetDefaultSection(dm, section);
596: PetscSectionDestroy(§ion);
597: if (user->bcType == DIRICHLET) {ISDestroy(&bcPoints[0]);}
598: return(0);
599: }
603: PetscErrorCode SetupMaterialSection(DM dm, AppCtx *user)
604: {
605: PetscSection section;
606: PetscInt dim = user->dim;
607: PetscInt numBC = 0;
608: PetscInt numComp[1];
609: const PetscInt *numDof;
610: PetscErrorCode ierr;
613: if (user->variableCoefficient != COEFF_FIELD) return(0);
614: PetscFEGetNumComponents(user->feAux[0], &numComp[0]);
615: PetscFEGetNumDof(user->feAux[0], &numDof);
616: DMPlexCreateSection(dm, dim, 1, numComp, numDof, numBC, NULL, NULL, §ion);
617: DMSetDefaultSection(dm, section);
618: PetscSectionDestroy(§ion);
619: return(0);
620: }
624: PetscErrorCode SetupMaterial(DM dm, DM dmAux, AppCtx *user)
625: {
626: void (*matFuncs[1])(const PetscReal x[], PetscScalar *u, void *ctx) = {nu_2d};
627: Vec nu;
631: if (user->variableCoefficient != COEFF_FIELD) return(0);
632: DMCreateLocalVector(dmAux, &nu);
633: DMPlexProjectFunctionLocal(dmAux, user->feAux, matFuncs, NULL, INSERT_ALL_VALUES, nu);
634: PetscObjectCompose((PetscObject) dm, "dmAux", (PetscObject) dmAux);
635: PetscObjectCompose((PetscObject) dm, "A", (PetscObject) nu);
636: VecDestroy(&nu);
637: return(0);
638: }
642: int main(int argc, char **argv)
643: {
644: DM dm; /* Problem specification */
645: DM dmAux; /* Material specification */
646: SNES snes; /* nonlinear solver */
647: Vec u,r; /* solution, residual vectors */
648: Mat A,J; /* Jacobian matrix */
649: MatNullSpace nullSpace; /* May be necessary for Neumann conditions */
650: AppCtx user; /* user-defined work context */
651: JacActionCtx userJ; /* context for Jacobian MF action */
652: PetscInt its; /* iterations for convergence */
653: PetscReal error = 0.0; /* L_2 error in the solution */
654: PetscInt numComponents;
657: PetscInitialize(&argc, &argv, NULL, help);
658: ProcessOptions(PETSC_COMM_WORLD, &user);
659: SNESCreate(PETSC_COMM_WORLD, &snes);
660: CreateMesh(PETSC_COMM_WORLD, &user, &dm);
661: SNESSetDM(snes, dm);
663: DMClone(dm, &dmAux);
664: DMPlexCopyCoordinates(dm, dmAux);
665: SetupElement(dm, &user);
666: SetupBdElement(dm, &user);
667: PetscFEGetNumComponents(user.fe[0], &numComponents);
668: PetscMalloc(NUM_FIELDS * sizeof(void (*)(const PetscReal[], PetscScalar *, void *)), &user.exactFuncs);
669: user.fem.bcFuncs = user.exactFuncs;
670: user.fem.bcCtxs = NULL;
671: SetupExactSolution(dm, &user);
672: SetupSection(dm, &user);
673: SetupMaterialElement(dmAux, &user);
674: SetupMaterialSection(dmAux, &user);
675: SetupMaterial(dm, dmAux, &user);
676: DMDestroy(&dmAux);
678: DMCreateGlobalVector(dm, &u);
679: VecDuplicate(u, &r);
681: DMSetMatType(dm,MATAIJ);
682: DMCreateMatrix(dm, &J);
683: if (user.jacobianMF) {
684: PetscInt M, m, N, n;
686: MatGetSize(J, &M, &N);
687: MatGetLocalSize(J, &m, &n);
688: MatCreate(PETSC_COMM_WORLD, &A);
689: MatSetSizes(A, m, n, M, N);
690: MatSetType(A, MATSHELL);
691: MatSetUp(A);
692: #if 0
693: MatShellSetOperation(A, MATOP_MULT, (void (*)(void))FormJacobianAction);
694: #endif
696: userJ.dm = dm;
697: userJ.J = J;
698: userJ.user = &user;
700: DMCreateLocalVector(dm, &userJ.u);
701: DMPlexProjectFunctionLocal(dm, user.fe, user.exactFuncs, NULL, INSERT_BC_VALUES, userJ.u);
702: MatShellSetContext(A, &userJ);
703: } else {
704: A = J;
705: }
706: if (user.bcType == NEUMANN) {
707: MatNullSpaceCreate(PetscObjectComm((PetscObject) dm), PETSC_TRUE, 0, NULL, &nullSpace);
708: MatSetNullSpace(J, nullSpace);
709: if (A != J) {
710: MatSetNullSpace(A, nullSpace);
711: }
712: }
714: DMSNESSetFunctionLocal(dm, (PetscErrorCode (*)(DM,Vec,Vec,void*)) DMPlexComputeResidualFEM, &user);
715: DMSNESSetJacobianLocal(dm, (PetscErrorCode (*)(DM,Vec,Mat,Mat,MatStructure*,void*)) DMPlexComputeJacobianFEM, &user);
716: SNESSetJacobian(snes, A, J, NULL, NULL);
718: SNESSetFromOptions(snes);
720: DMPlexProjectFunction(dm, user.fe, user.exactFuncs, NULL, INSERT_ALL_VALUES, u);
721: if (user.showInitial) {
722: Vec lv;
723: DMGetLocalVector(dm, &lv);
724: DMGlobalToLocalBegin(dm, u, INSERT_VALUES, lv);
725: DMGlobalToLocalEnd(dm, u, INSERT_VALUES, lv);
726: DMPrintLocalVec(dm, "Local function", 1.0e-10, lv);
727: DMRestoreLocalVector(dm, &lv);
728: }
729: if (user.runType == RUN_FULL) {
730: void (*initialGuess[numComponents])(const PetscReal x[], PetscScalar *, void *ctx);
731: PetscInt c;
733: for (c = 0; c < numComponents; ++c) initialGuess[c] = zero;
734: DMPlexProjectFunction(dm, user.fe, initialGuess, NULL, INSERT_VALUES, u);
735: if (user.debug) {
736: PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");
737: VecView(u, PETSC_VIEWER_STDOUT_WORLD);
738: }
739: SNESSolve(snes, NULL, u);
740: SNESGetIterationNumber(snes, &its);
741: PetscPrintf(PETSC_COMM_WORLD, "Number of SNES iterations = %D\n", its);
742: DMPlexComputeL2Diff(dm, user.fe, user.exactFuncs, NULL, u, &error);
743: if (error < 1.0e-11) {PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: < 1.0e-11\n");}
744: else {PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: %g\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 if (user.runType == RUN_PERF) {
751: PetscReal res = 0.0;
753: SNESComputeFunction(snes, u, r);
754: PetscPrintf(PETSC_COMM_WORLD, "Initial Residual\n");
755: VecChop(r, 1.0e-10);
756: VecNorm(r, NORM_2, &res);
757: PetscPrintf(PETSC_COMM_WORLD, "L_2 Residual: %g\n", res);
758: } else {
759: PetscReal res = 0.0;
761: /* Check discretization error */
762: PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");
763: VecView(u, PETSC_VIEWER_STDOUT_WORLD);
764: DMPlexComputeL2Diff(dm, user.fe, user.exactFuncs, NULL, u, &error);
765: if (error < 1.0e-11) {PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: < 1.0e-11\n");}
766: else {PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: %g\n", error);}
767: /* Check residual */
768: SNESComputeFunction(snes, u, r);
769: PetscPrintf(PETSC_COMM_WORLD, "Initial Residual\n");
770: VecChop(r, 1.0e-10);
771: VecView(r, PETSC_VIEWER_STDOUT_WORLD);
772: VecNorm(r, NORM_2, &res);
773: PetscPrintf(PETSC_COMM_WORLD, "L_2 Residual: %g\n", res);
774: /* Check Jacobian */
775: {
776: Vec b;
777: MatStructure flag;
779: SNESComputeJacobian(snes, u, &A, &A, &flag);
780: VecDuplicate(u, &b);
781: VecSet(r, 0.0);
782: SNESComputeFunction(snes, r, b);
783: MatMult(A, u, r);
784: VecAXPY(r, 1.0, b);
785: VecDestroy(&b);
786: PetscPrintf(PETSC_COMM_WORLD, "Au - b = Au + F(0)\n");
787: VecChop(r, 1.0e-10);
788: VecView(r, PETSC_VIEWER_STDOUT_WORLD);
789: VecNorm(r, NORM_2, &res);
790: PetscPrintf(PETSC_COMM_WORLD, "Linear L_2 Residual: %g\n", res);
791: }
792: }
794: if (user.bcType == NEUMANN) {
795: MatNullSpaceDestroy(&nullSpace);
796: }
797: if (user.jacobianMF) {
798: VecDestroy(&userJ.u);
799: }
800: if (A != J) {MatDestroy(&A);}
801: DestroyElement(&user);
802: MatDestroy(&J);
803: VecDestroy(&u);
804: VecDestroy(&r);
805: SNESDestroy(&snes);
806: DMDestroy(&dm);
807: PetscFree(user.exactFuncs);
808: PetscFinalize();
809: return 0;
810: }