Actual source code: ex12.c

petsc-dev 2014-02-02
Report Typos and Errors
  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, &section);
594:   PetscSectionSetFieldName(section, 0, "potential");
595:   DMSetDefaultSection(dm, section);
596:   PetscSectionDestroy(&section);
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, &section);
617:   DMSetDefaultSection(dm, section);
618:   PetscSectionDestroy(&section);
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: }