xref: /petsc/src/snes/utils/dmplexsnes.c (revision 40badf4fbc550ac1f60bd080eaff6de6d55b946d)
1 #include <petsc/private/dmpleximpl.h>   /*I "petscdmplex.h" I*/
2 #include <petsc/private/snesimpl.h>     /*I "petscsnes.h"   I*/
3 #include <petscds.h>
4 #include <petsc/private/petscimpl.h>
5 #include <petsc/private/petscfeimpl.h>
6 
7 static void pressure_Private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
10                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar p[])
11 {
12   p[0] = u[uOff[1]];
13 }
14 
15 /*
16   SNESCorrectDiscretePressure_Private - Add a vector in the nullspace to make the continuum integral of the pressure field equal to zero. This is normally used only to evaluate convergence rates for the pressure accurately.
17 
18   Collective on SNES
19 
20   Input Parameters:
21 + snes      - The SNES
22 . pfield    - The field number for pressure
23 . nullspace - The pressure nullspace
24 . u         - The solution vector
25 - ctx       - An optional user context
26 
27   Output Parameter:
28 . u         - The solution with a continuum pressure integral of zero
29 
30   Notes:
31   If int(u) = a and int(n) = b, then int(u - a/b n) = a - a/b b = 0. We assume that the nullspace is a single vector given explicitly.
32 
33   Level: developer
34 
35 .seealso: SNESConvergedCorrectPressure()
36 */
37 static PetscErrorCode SNESCorrectDiscretePressure_Private(SNES snes, PetscInt pfield, MatNullSpace nullspace, Vec u, void *ctx)
38 {
39   DM             dm;
40   PetscDS        ds;
41   const Vec     *nullvecs;
42   PetscScalar    pintd, *intc, *intn;
43   MPI_Comm       comm;
44   PetscInt       Nf, Nv;
45 
46   PetscFunctionBegin;
47   CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm));
48   CHKERRQ(SNESGetDM(snes, &dm));
49   PetscCheckFalse(!dm,comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a SNES DM");
50   PetscCheckFalse(!nullspace,comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a Jacobian nullspace");
51   CHKERRQ(DMGetDS(dm, &ds));
52   CHKERRQ(PetscDSSetObjective(ds, pfield, pressure_Private));
53   CHKERRQ(MatNullSpaceGetVecs(nullspace, NULL, &Nv, &nullvecs));
54   PetscCheckFalse(Nv != 1,comm, PETSC_ERR_ARG_OUTOFRANGE, "Can only handle a single null vector for pressure, not %D", Nv);
55   CHKERRQ(VecDot(nullvecs[0], u, &pintd));
56   PetscCheckFalse(PetscAbsScalar(pintd) > PETSC_SMALL,comm, PETSC_ERR_ARG_WRONG, "Discrete integral of pressure: %g", (double) PetscRealPart(pintd));
57   CHKERRQ(PetscDSGetNumFields(ds, &Nf));
58   CHKERRQ(PetscMalloc2(Nf, &intc, Nf, &intn));
59   CHKERRQ(DMPlexComputeIntegralFEM(dm, nullvecs[0], intn, ctx));
60   CHKERRQ(DMPlexComputeIntegralFEM(dm, u, intc, ctx));
61   CHKERRQ(VecAXPY(u, -intc[pfield]/intn[pfield], nullvecs[0]));
62 #if defined (PETSC_USE_DEBUG)
63   CHKERRQ(DMPlexComputeIntegralFEM(dm, u, intc, ctx));
64   PetscCheckFalse(PetscAbsScalar(intc[pfield]) > PETSC_SMALL,comm, PETSC_ERR_ARG_WRONG, "Continuum integral of pressure after correction: %g", (double) PetscRealPart(intc[pfield]));
65 #endif
66   CHKERRQ(PetscFree2(intc, intn));
67   PetscFunctionReturn(0);
68 }
69 
70 /*@C
71    SNESConvergedCorrectPressure - Convergence test that adds a vector in the nullspace to make the continuum integral of the pressure field equal to zero. This is normally used only to evaluate convergence rates for the pressure accurately. The convergence test itself just mimics SNESConvergedDefault().
72 
73    Logically Collective on SNES
74 
75    Input Parameters:
76 +  snes - the SNES context
77 .  it - the iteration (0 indicates before any Newton steps)
78 .  xnorm - 2-norm of current iterate
79 .  snorm - 2-norm of current step
80 .  fnorm - 2-norm of function at current iterate
81 -  ctx   - Optional user context
82 
83    Output Parameter:
84 .  reason  - SNES_CONVERGED_ITERATING, SNES_CONVERGED_ITS, or SNES_DIVERGED_FNORM_NAN
85 
86    Notes:
87    In order to use this monitor, you must setup several PETSc structures. First fields must be added to the DM, and a PetscDS must be created with discretizations of those fields. We currently assume that the pressure field has index 1. The pressure field must have a nullspace, likely created using the DMSetNullSpaceConstructor() interface. Last we must be able to integrate the pressure over the domain, so the DM attached to the SNES must be a Plex at this time.
88 
89    Level: advanced
90 
91 .seealso: SNESConvergedDefault(), SNESSetConvergenceTest(), DMSetNullSpaceConstructor()
92 @*/
93 PetscErrorCode SNESConvergedCorrectPressure(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, void *ctx)
94 {
95   PetscBool      monitorIntegral = PETSC_FALSE;
96 
97   PetscFunctionBegin;
98   CHKERRQ(SNESConvergedDefault(snes, it, xnorm, gnorm, f, reason, ctx));
99   if (monitorIntegral) {
100     Mat          J;
101     Vec          u;
102     MatNullSpace nullspace;
103     const Vec   *nullvecs;
104     PetscScalar  pintd;
105 
106     CHKERRQ(SNESGetSolution(snes, &u));
107     CHKERRQ(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
108     CHKERRQ(MatGetNullSpace(J, &nullspace));
109     CHKERRQ(MatNullSpaceGetVecs(nullspace, NULL, NULL, &nullvecs));
110     CHKERRQ(VecDot(nullvecs[0], u, &pintd));
111     CHKERRQ(PetscInfo(snes, "SNES: Discrete integral of pressure: %g\n", (double) PetscRealPart(pintd)));
112   }
113   if (*reason > 0) {
114     Mat          J;
115     Vec          u;
116     MatNullSpace nullspace;
117     PetscInt     pfield = 1;
118 
119     CHKERRQ(SNESGetSolution(snes, &u));
120     CHKERRQ(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
121     CHKERRQ(MatGetNullSpace(J, &nullspace));
122     CHKERRQ(SNESCorrectDiscretePressure_Private(snes, pfield, nullspace, u, ctx));
123   }
124   PetscFunctionReturn(0);
125 }
126 
127 /************************** Interpolation *******************************/
128 
129 static PetscErrorCode DMSNESConvertPlex(DM dm, DM *plex, PetscBool copy)
130 {
131   PetscBool      isPlex;
132 
133   PetscFunctionBegin;
134   CHKERRQ(PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex));
135   if (isPlex) {
136     *plex = dm;
137     CHKERRQ(PetscObjectReference((PetscObject) dm));
138   } else {
139     CHKERRQ(PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex));
140     if (!*plex) {
141       CHKERRQ(DMConvert(dm,DMPLEX,plex));
142       CHKERRQ(PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex));
143       if (copy) {
144         CHKERRQ(DMCopyDMSNES(dm, *plex));
145         CHKERRQ(DMCopyAuxiliaryVec(dm, *plex));
146       }
147     } else {
148       CHKERRQ(PetscObjectReference((PetscObject) *plex));
149     }
150   }
151   PetscFunctionReturn(0);
152 }
153 
154 /*@C
155   DMInterpolationCreate - Creates a DMInterpolationInfo context
156 
157   Collective
158 
159   Input Parameter:
160 . comm - the communicator
161 
162   Output Parameter:
163 . ctx - the context
164 
165   Level: beginner
166 
167 .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationDestroy()
168 @*/
169 PetscErrorCode DMInterpolationCreate(MPI_Comm comm, DMInterpolationInfo *ctx)
170 {
171   PetscFunctionBegin;
172   PetscValidPointer(ctx, 2);
173   CHKERRQ(PetscNew(ctx));
174 
175   (*ctx)->comm   = comm;
176   (*ctx)->dim    = -1;
177   (*ctx)->nInput = 0;
178   (*ctx)->points = NULL;
179   (*ctx)->cells  = NULL;
180   (*ctx)->n      = -1;
181   (*ctx)->coords = NULL;
182   PetscFunctionReturn(0);
183 }
184 
185 /*@C
186   DMInterpolationSetDim - Sets the spatial dimension for the interpolation context
187 
188   Not collective
189 
190   Input Parameters:
191 + ctx - the context
192 - dim - the spatial dimension
193 
194   Level: intermediate
195 
196 .seealso: DMInterpolationGetDim(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
197 @*/
198 PetscErrorCode DMInterpolationSetDim(DMInterpolationInfo ctx, PetscInt dim)
199 {
200   PetscFunctionBegin;
201   PetscCheckFalse((dim < 1) || (dim > 3),ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension for points: %D", dim);
202   ctx->dim = dim;
203   PetscFunctionReturn(0);
204 }
205 
206 /*@C
207   DMInterpolationGetDim - Gets the spatial dimension for the interpolation context
208 
209   Not collective
210 
211   Input Parameter:
212 . ctx - the context
213 
214   Output Parameter:
215 . dim - the spatial dimension
216 
217   Level: intermediate
218 
219 .seealso: DMInterpolationSetDim(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
220 @*/
221 PetscErrorCode DMInterpolationGetDim(DMInterpolationInfo ctx, PetscInt *dim)
222 {
223   PetscFunctionBegin;
224   PetscValidIntPointer(dim, 2);
225   *dim = ctx->dim;
226   PetscFunctionReturn(0);
227 }
228 
229 /*@C
230   DMInterpolationSetDof - Sets the number of fields interpolated at a point for the interpolation context
231 
232   Not collective
233 
234   Input Parameters:
235 + ctx - the context
236 - dof - the number of fields
237 
238   Level: intermediate
239 
240 .seealso: DMInterpolationGetDof(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
241 @*/
242 PetscErrorCode DMInterpolationSetDof(DMInterpolationInfo ctx, PetscInt dof)
243 {
244   PetscFunctionBegin;
245   PetscCheckFalse(dof < 1,ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of components: %D", dof);
246   ctx->dof = dof;
247   PetscFunctionReturn(0);
248 }
249 
250 /*@C
251   DMInterpolationGetDof - Gets the number of fields interpolated at a point for the interpolation context
252 
253   Not collective
254 
255   Input Parameter:
256 . ctx - the context
257 
258   Output Parameter:
259 . dof - the number of fields
260 
261   Level: intermediate
262 
263 .seealso: DMInterpolationSetDof(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
264 @*/
265 PetscErrorCode DMInterpolationGetDof(DMInterpolationInfo ctx, PetscInt *dof)
266 {
267   PetscFunctionBegin;
268   PetscValidIntPointer(dof, 2);
269   *dof = ctx->dof;
270   PetscFunctionReturn(0);
271 }
272 
273 /*@C
274   DMInterpolationAddPoints - Add points at which we will interpolate the fields
275 
276   Not collective
277 
278   Input Parameters:
279 + ctx    - the context
280 . n      - the number of points
281 - points - the coordinates for each point, an array of size n * dim
282 
283   Note: The coordinate information is copied.
284 
285   Level: intermediate
286 
287 .seealso: DMInterpolationSetDim(), DMInterpolationEvaluate(), DMInterpolationCreate()
288 @*/
289 PetscErrorCode DMInterpolationAddPoints(DMInterpolationInfo ctx, PetscInt n, PetscReal points[])
290 {
291   PetscFunctionBegin;
292   PetscCheckFalse(ctx->dim < 0,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
293   PetscCheckFalse(ctx->points,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot add points multiple times yet");
294   ctx->nInput = n;
295 
296   CHKERRQ(PetscMalloc1(n*ctx->dim, &ctx->points));
297   CHKERRQ(PetscArraycpy(ctx->points, points, n*ctx->dim));
298   PetscFunctionReturn(0);
299 }
300 
301 /*@C
302   DMInterpolationSetUp - Compute spatial indices for point location during interpolation
303 
304   Collective on ctx
305 
306   Input Parameters:
307 + ctx - the context
308 . dm  - the DM for the function space used for interpolation
309 . redundantPoints - If PETSC_TRUE, all processes are passing in the same array of points. Otherwise, points need to be communicated among processes.
310 - ignoreOutsideDomain - If PETSC_TRUE, ignore points outside the domain, otherwise return an error
311 
312   Level: intermediate
313 
314 .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
315 @*/
316 PetscErrorCode DMInterpolationSetUp(DMInterpolationInfo ctx, DM dm, PetscBool redundantPoints, PetscBool ignoreOutsideDomain)
317 {
318   MPI_Comm          comm = ctx->comm;
319   PetscScalar       *a;
320   PetscInt          p, q, i;
321   PetscMPIInt       rank, size;
322   Vec               pointVec;
323   PetscSF           cellSF;
324   PetscLayout       layout;
325   PetscReal         *globalPoints;
326   PetscScalar       *globalPointsScalar;
327   const PetscInt    *ranges;
328   PetscMPIInt       *counts, *displs;
329   const PetscSFNode *foundCells;
330   const PetscInt    *foundPoints;
331   PetscMPIInt       *foundProcs, *globalProcs;
332   PetscInt          n, N, numFound;
333 
334   PetscFunctionBegin;
335   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
336   CHKERRMPI(MPI_Comm_size(comm, &size));
337   CHKERRMPI(MPI_Comm_rank(comm, &rank));
338   PetscCheckFalse(ctx->dim < 0,comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
339   /* Locate points */
340   n = ctx->nInput;
341   if (!redundantPoints) {
342     CHKERRQ(PetscLayoutCreate(comm, &layout));
343     CHKERRQ(PetscLayoutSetBlockSize(layout, 1));
344     CHKERRQ(PetscLayoutSetLocalSize(layout, n));
345     CHKERRQ(PetscLayoutSetUp(layout));
346     CHKERRQ(PetscLayoutGetSize(layout, &N));
347     /* Communicate all points to all processes */
348     CHKERRQ(PetscMalloc3(N*ctx->dim,&globalPoints,size,&counts,size,&displs));
349     CHKERRQ(PetscLayoutGetRanges(layout, &ranges));
350     for (p = 0; p < size; ++p) {
351       counts[p] = (ranges[p+1] - ranges[p])*ctx->dim;
352       displs[p] = ranges[p]*ctx->dim;
353     }
354     CHKERRMPI(MPI_Allgatherv(ctx->points, n*ctx->dim, MPIU_REAL, globalPoints, counts, displs, MPIU_REAL, comm));
355   } else {
356     N = n;
357     globalPoints = ctx->points;
358     counts = displs = NULL;
359     layout = NULL;
360   }
361 #if 0
362   CHKERRQ(PetscMalloc3(N,&foundCells,N,&foundProcs,N,&globalProcs));
363   /* foundCells[p] = m->locatePoint(&globalPoints[p*ctx->dim]); */
364 #else
365 #if defined(PETSC_USE_COMPLEX)
366   CHKERRQ(PetscMalloc1(N*ctx->dim,&globalPointsScalar));
367   for (i=0; i<N*ctx->dim; i++) globalPointsScalar[i] = globalPoints[i];
368 #else
369   globalPointsScalar = globalPoints;
370 #endif
371   CHKERRQ(VecCreateSeqWithArray(PETSC_COMM_SELF, ctx->dim, N*ctx->dim, globalPointsScalar, &pointVec));
372   CHKERRQ(PetscMalloc2(N,&foundProcs,N,&globalProcs));
373   for (p = 0; p < N; ++p) {foundProcs[p] = size;}
374   cellSF = NULL;
375   CHKERRQ(DMLocatePoints(dm, pointVec, DM_POINTLOCATION_REMOVE, &cellSF));
376   CHKERRQ(PetscSFGetGraph(cellSF,NULL,&numFound,&foundPoints,&foundCells));
377 #endif
378   for (p = 0; p < numFound; ++p) {
379     if (foundCells[p].index >= 0) foundProcs[foundPoints ? foundPoints[p] : p] = rank;
380   }
381   /* Let the lowest rank process own each point */
382   CHKERRMPI(MPIU_Allreduce(foundProcs, globalProcs, N, MPI_INT, MPI_MIN, comm));
383   ctx->n = 0;
384   for (p = 0; p < N; ++p) {
385     if (globalProcs[p] == size) {
386       PetscCheckFalse(!ignoreOutsideDomain,comm, PETSC_ERR_PLIB, "Point %d: %g %g %g not located in mesh", p, (double)globalPoints[p*ctx->dim+0], (double)(ctx->dim > 1 ? globalPoints[p*ctx->dim+1] : 0.0), (double)(ctx->dim > 2 ? globalPoints[p*ctx->dim+2] : 0.0));
387       else if (rank == 0) ++ctx->n;
388     } else if (globalProcs[p] == rank) ++ctx->n;
389   }
390   /* Create coordinates vector and array of owned cells */
391   CHKERRQ(PetscMalloc1(ctx->n, &ctx->cells));
392   CHKERRQ(VecCreate(comm, &ctx->coords));
393   CHKERRQ(VecSetSizes(ctx->coords, ctx->n*ctx->dim, PETSC_DECIDE));
394   CHKERRQ(VecSetBlockSize(ctx->coords, ctx->dim));
395   CHKERRQ(VecSetType(ctx->coords,VECSTANDARD));
396   CHKERRQ(VecGetArray(ctx->coords, &a));
397   for (p = 0, q = 0, i = 0; p < N; ++p) {
398     if (globalProcs[p] == rank) {
399       PetscInt d;
400 
401       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = globalPoints[p*ctx->dim+d];
402       ctx->cells[q] = foundCells[q].index;
403       ++q;
404     }
405     if (globalProcs[p] == size && rank == 0) {
406       PetscInt d;
407 
408       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = 0.;
409       ctx->cells[q] = -1;
410       ++q;
411     }
412   }
413   CHKERRQ(VecRestoreArray(ctx->coords, &a));
414 #if 0
415   CHKERRQ(PetscFree3(foundCells,foundProcs,globalProcs));
416 #else
417   CHKERRQ(PetscFree2(foundProcs,globalProcs));
418   CHKERRQ(PetscSFDestroy(&cellSF));
419   CHKERRQ(VecDestroy(&pointVec));
420 #endif
421   if ((void*)globalPointsScalar != (void*)globalPoints) CHKERRQ(PetscFree(globalPointsScalar));
422   if (!redundantPoints) CHKERRQ(PetscFree3(globalPoints,counts,displs));
423   CHKERRQ(PetscLayoutDestroy(&layout));
424   PetscFunctionReturn(0);
425 }
426 
427 /*@C
428   DMInterpolationGetCoordinates - Gets a Vec with the coordinates of each interpolation point
429 
430   Collective on ctx
431 
432   Input Parameter:
433 . ctx - the context
434 
435   Output Parameter:
436 . coordinates  - the coordinates of interpolation points
437 
438   Note: The local vector entries correspond to interpolation points lying on this process, according to the associated DM. This is a borrowed vector that the user should not destroy.
439 
440   Level: intermediate
441 
442 .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
443 @*/
444 PetscErrorCode DMInterpolationGetCoordinates(DMInterpolationInfo ctx, Vec *coordinates)
445 {
446   PetscFunctionBegin;
447   PetscValidPointer(coordinates, 2);
448   PetscCheckFalse(!ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
449   *coordinates = ctx->coords;
450   PetscFunctionReturn(0);
451 }
452 
453 /*@C
454   DMInterpolationGetVector - Gets a Vec which can hold all the interpolated field values
455 
456   Collective on ctx
457 
458   Input Parameter:
459 . ctx - the context
460 
461   Output Parameter:
462 . v  - a vector capable of holding the interpolated field values
463 
464   Note: This vector should be returned using DMInterpolationRestoreVector().
465 
466   Level: intermediate
467 
468 .seealso: DMInterpolationRestoreVector(), DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
469 @*/
470 PetscErrorCode DMInterpolationGetVector(DMInterpolationInfo ctx, Vec *v)
471 {
472   PetscFunctionBegin;
473   PetscValidPointer(v, 2);
474   PetscCheckFalse(!ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
475   CHKERRQ(VecCreate(ctx->comm, v));
476   CHKERRQ(VecSetSizes(*v, ctx->n*ctx->dof, PETSC_DECIDE));
477   CHKERRQ(VecSetBlockSize(*v, ctx->dof));
478   CHKERRQ(VecSetType(*v,VECSTANDARD));
479   PetscFunctionReturn(0);
480 }
481 
482 /*@C
483   DMInterpolationRestoreVector - Returns a Vec which can hold all the interpolated field values
484 
485   Collective on ctx
486 
487   Input Parameters:
488 + ctx - the context
489 - v  - a vector capable of holding the interpolated field values
490 
491   Level: intermediate
492 
493 .seealso: DMInterpolationGetVector(), DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
494 @*/
495 PetscErrorCode DMInterpolationRestoreVector(DMInterpolationInfo ctx, Vec *v)
496 {
497   PetscFunctionBegin;
498   PetscValidPointer(v, 2);
499   PetscCheckFalse(!ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
500   CHKERRQ(VecDestroy(v));
501   PetscFunctionReturn(0);
502 }
503 
504 static inline PetscErrorCode DMInterpolate_Segment_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
505 {
506   PetscReal          v0, J, invJ, detJ;
507   const PetscInt     dof = ctx->dof;
508   const PetscScalar *coords;
509   PetscScalar       *a;
510   PetscInt           p;
511 
512   PetscFunctionBegin;
513   CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
514   CHKERRQ(VecGetArray(v, &a));
515   for (p = 0; p < ctx->n; ++p) {
516     PetscInt     c = ctx->cells[p];
517     PetscScalar *x = NULL;
518     PetscReal    xir[1];
519     PetscInt     xSize, comp;
520 
521     CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ));
522     PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double) detJ, c);
523     xir[0] = invJ*PetscRealPart(coords[p] - v0);
524     CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
525     if (2*dof == xSize) {
526       for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp]*(1 - xir[0]) + x[1*dof+comp]*xir[0];
527     } else if (dof == xSize) {
528       for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp];
529     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input closure size %" PetscInt_FMT " must be either %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 2*dof, dof);
530     CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
531   }
532   CHKERRQ(VecRestoreArray(v, &a));
533   CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
534   PetscFunctionReturn(0);
535 }
536 
537 static inline PetscErrorCode DMInterpolate_Triangle_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
538 {
539   PetscReal      *v0, *J, *invJ, detJ;
540   const PetscScalar *coords;
541   PetscScalar    *a;
542   PetscInt       p;
543 
544   PetscFunctionBegin;
545   CHKERRQ(PetscMalloc3(ctx->dim,&v0,ctx->dim*ctx->dim,&J,ctx->dim*ctx->dim,&invJ));
546   CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
547   CHKERRQ(VecGetArray(v, &a));
548   for (p = 0; p < ctx->n; ++p) {
549     PetscInt     c = ctx->cells[p];
550     PetscScalar *x = NULL;
551     PetscReal    xi[4];
552     PetscInt     d, f, comp;
553 
554     CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
555     PetscCheckFalse(detJ <= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D", (double)detJ, c);
556     CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
557     for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp];
558 
559     for (d = 0; d < ctx->dim; ++d) {
560       xi[d] = 0.0;
561       for (f = 0; f < ctx->dim; ++f) xi[d] += invJ[d*ctx->dim+f]*0.5*PetscRealPart(coords[p*ctx->dim+f] - v0[f]);
562       for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] += PetscRealPart(x[(d+1)*ctx->dof+comp] - x[0*ctx->dof+comp])*xi[d];
563     }
564     CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
565   }
566   CHKERRQ(VecRestoreArray(v, &a));
567   CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
568   CHKERRQ(PetscFree3(v0, J, invJ));
569   PetscFunctionReturn(0);
570 }
571 
572 static inline PetscErrorCode DMInterpolate_Tetrahedron_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
573 {
574   PetscReal      *v0, *J, *invJ, detJ;
575   const PetscScalar *coords;
576   PetscScalar    *a;
577   PetscInt       p;
578 
579   PetscFunctionBegin;
580   CHKERRQ(PetscMalloc3(ctx->dim,&v0,ctx->dim*ctx->dim,&J,ctx->dim*ctx->dim,&invJ));
581   CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
582   CHKERRQ(VecGetArray(v, &a));
583   for (p = 0; p < ctx->n; ++p) {
584     PetscInt       c = ctx->cells[p];
585     const PetscInt order[3] = {2, 1, 3};
586     PetscScalar   *x = NULL;
587     PetscReal      xi[4];
588     PetscInt       d, f, comp;
589 
590     CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
591     PetscCheckFalse(detJ <= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D", (double)detJ, c);
592     CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
593     for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp];
594 
595     for (d = 0; d < ctx->dim; ++d) {
596       xi[d] = 0.0;
597       for (f = 0; f < ctx->dim; ++f) xi[d] += invJ[d*ctx->dim+f]*0.5*PetscRealPart(coords[p*ctx->dim+f] - v0[f]);
598       for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] += PetscRealPart(x[order[d]*ctx->dof+comp] - x[0*ctx->dof+comp])*xi[d];
599     }
600     CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
601   }
602   CHKERRQ(VecRestoreArray(v, &a));
603   CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
604   CHKERRQ(PetscFree3(v0, J, invJ));
605   PetscFunctionReturn(0);
606 }
607 
608 static inline PetscErrorCode QuadMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
609 {
610   const PetscScalar *vertices = (const PetscScalar*) ctx;
611   const PetscScalar x0        = vertices[0];
612   const PetscScalar y0        = vertices[1];
613   const PetscScalar x1        = vertices[2];
614   const PetscScalar y1        = vertices[3];
615   const PetscScalar x2        = vertices[4];
616   const PetscScalar y2        = vertices[5];
617   const PetscScalar x3        = vertices[6];
618   const PetscScalar y3        = vertices[7];
619   const PetscScalar f_1       = x1 - x0;
620   const PetscScalar g_1       = y1 - y0;
621   const PetscScalar f_3       = x3 - x0;
622   const PetscScalar g_3       = y3 - y0;
623   const PetscScalar f_01      = x2 - x1 - x3 + x0;
624   const PetscScalar g_01      = y2 - y1 - y3 + y0;
625   const PetscScalar *ref;
626   PetscScalar       *real;
627 
628   PetscFunctionBegin;
629   CHKERRQ(VecGetArrayRead(Xref,  &ref));
630   CHKERRQ(VecGetArray(Xreal, &real));
631   {
632     const PetscScalar p0 = ref[0];
633     const PetscScalar p1 = ref[1];
634 
635     real[0] = x0 + f_1 * p0 + f_3 * p1 + f_01 * p0 * p1;
636     real[1] = y0 + g_1 * p0 + g_3 * p1 + g_01 * p0 * p1;
637   }
638   CHKERRQ(PetscLogFlops(28));
639   CHKERRQ(VecRestoreArrayRead(Xref,  &ref));
640   CHKERRQ(VecRestoreArray(Xreal, &real));
641   PetscFunctionReturn(0);
642 }
643 
644 #include <petsc/private/dmimpl.h>
645 static inline PetscErrorCode QuadJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
646 {
647   const PetscScalar *vertices = (const PetscScalar*) ctx;
648   const PetscScalar x0        = vertices[0];
649   const PetscScalar y0        = vertices[1];
650   const PetscScalar x1        = vertices[2];
651   const PetscScalar y1        = vertices[3];
652   const PetscScalar x2        = vertices[4];
653   const PetscScalar y2        = vertices[5];
654   const PetscScalar x3        = vertices[6];
655   const PetscScalar y3        = vertices[7];
656   const PetscScalar f_01      = x2 - x1 - x3 + x0;
657   const PetscScalar g_01      = y2 - y1 - y3 + y0;
658   const PetscScalar *ref;
659 
660   PetscFunctionBegin;
661   CHKERRQ(VecGetArrayRead(Xref,  &ref));
662   {
663     const PetscScalar x       = ref[0];
664     const PetscScalar y       = ref[1];
665     const PetscInt    rows[2] = {0, 1};
666     PetscScalar       values[4];
667 
668     values[0] = (x1 - x0 + f_01*y) * 0.5; values[1] = (x3 - x0 + f_01*x) * 0.5;
669     values[2] = (y1 - y0 + g_01*y) * 0.5; values[3] = (y3 - y0 + g_01*x) * 0.5;
670     CHKERRQ(MatSetValues(J, 2, rows, 2, rows, values, INSERT_VALUES));
671   }
672   CHKERRQ(PetscLogFlops(30));
673   CHKERRQ(VecRestoreArrayRead(Xref,  &ref));
674   CHKERRQ(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
675   CHKERRQ(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
676   PetscFunctionReturn(0);
677 }
678 
679 static inline PetscErrorCode DMInterpolate_Quad_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
680 {
681   DM                 dmCoord;
682   PetscFE            fem = NULL;
683   SNES               snes;
684   KSP                ksp;
685   PC                 pc;
686   Vec                coordsLocal, r, ref, real;
687   Mat                J;
688   PetscTabulation    T = NULL;
689   const PetscScalar *coords;
690   PetscScalar        *a;
691   PetscReal          xir[2] = {0., 0.};
692   PetscInt           Nf, p;
693   const PetscInt     dof = ctx->dof;
694 
695   PetscFunctionBegin;
696   CHKERRQ(DMGetNumFields(dm, &Nf));
697   if (Nf) {
698     PetscObject  obj;
699     PetscClassId id;
700 
701     CHKERRQ(DMGetField(dm, 0, NULL, &obj));
702     CHKERRQ(PetscObjectGetClassId(obj, &id));
703     if (id == PETSCFE_CLASSID) {fem = (PetscFE) obj; CHKERRQ(PetscFECreateTabulation(fem, 1, 1, xir, 0, &T));}
704   }
705   CHKERRQ(DMGetCoordinatesLocal(dm, &coordsLocal));
706   CHKERRQ(DMGetCoordinateDM(dm, &dmCoord));
707   CHKERRQ(SNESCreate(PETSC_COMM_SELF, &snes));
708   CHKERRQ(SNESSetOptionsPrefix(snes, "quad_interp_"));
709   CHKERRQ(VecCreate(PETSC_COMM_SELF, &r));
710   CHKERRQ(VecSetSizes(r, 2, 2));
711   CHKERRQ(VecSetType(r,dm->vectype));
712   CHKERRQ(VecDuplicate(r, &ref));
713   CHKERRQ(VecDuplicate(r, &real));
714   CHKERRQ(MatCreate(PETSC_COMM_SELF, &J));
715   CHKERRQ(MatSetSizes(J, 2, 2, 2, 2));
716   CHKERRQ(MatSetType(J, MATSEQDENSE));
717   CHKERRQ(MatSetUp(J));
718   CHKERRQ(SNESSetFunction(snes, r, QuadMap_Private, NULL));
719   CHKERRQ(SNESSetJacobian(snes, J, J, QuadJacobian_Private, NULL));
720   CHKERRQ(SNESGetKSP(snes, &ksp));
721   CHKERRQ(KSPGetPC(ksp, &pc));
722   CHKERRQ(PCSetType(pc, PCLU));
723   CHKERRQ(SNESSetFromOptions(snes));
724 
725   CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
726   CHKERRQ(VecGetArray(v, &a));
727   for (p = 0; p < ctx->n; ++p) {
728     PetscScalar *x = NULL, *vertices = NULL;
729     PetscScalar *xi;
730     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
731 
732     /* Can make this do all points at once */
733     CHKERRQ(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
734     PetscCheckFalse(4*2 != coordSize,ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %D should be %d", coordSize, 4*2);
735     CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
736     CHKERRQ(SNESSetFunction(snes, NULL, NULL, vertices));
737     CHKERRQ(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
738     CHKERRQ(VecGetArray(real, &xi));
739     xi[0]  = coords[p*ctx->dim+0];
740     xi[1]  = coords[p*ctx->dim+1];
741     CHKERRQ(VecRestoreArray(real, &xi));
742     CHKERRQ(SNESSolve(snes, real, ref));
743     CHKERRQ(VecGetArray(ref, &xi));
744     xir[0] = PetscRealPart(xi[0]);
745     xir[1] = PetscRealPart(xi[1]);
746     if (4*dof == xSize) {
747       for (comp = 0; comp < dof; ++comp)
748         a[p*dof+comp] = x[0*dof+comp]*(1 - xir[0])*(1 - xir[1]) + x[1*dof+comp]*xir[0]*(1 - xir[1]) + x[2*dof+comp]*xir[0]*xir[1] + x[3*dof+comp]*(1 - xir[0])*xir[1];
749     } else if (dof == xSize) {
750       for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp];
751     } else {
752       PetscInt d;
753 
754       PetscCheck(fem, ctx->comm, PETSC_ERR_ARG_WRONG, "Cannot have a higher order interpolant if the discretization is not PetscFE");
755       xir[0] = 2.0*xir[0] - 1.0; xir[1] = 2.0*xir[1] - 1.0;
756       CHKERRQ(PetscFEComputeTabulation(fem, 1, xir, 0, T));
757       for (comp = 0; comp < dof; ++comp) {
758         a[p*dof+comp] = 0.0;
759         for (d = 0; d < xSize/dof; ++d) {
760           a[p*dof+comp] += x[d*dof+comp]*T->T[0][d*dof+comp];
761         }
762       }
763     }
764     CHKERRQ(VecRestoreArray(ref, &xi));
765     CHKERRQ(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
766     CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
767   }
768   CHKERRQ(PetscTabulationDestroy(&T));
769   CHKERRQ(VecRestoreArray(v, &a));
770   CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
771 
772   CHKERRQ(SNESDestroy(&snes));
773   CHKERRQ(VecDestroy(&r));
774   CHKERRQ(VecDestroy(&ref));
775   CHKERRQ(VecDestroy(&real));
776   CHKERRQ(MatDestroy(&J));
777   PetscFunctionReturn(0);
778 }
779 
780 static inline PetscErrorCode HexMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
781 {
782   const PetscScalar *vertices = (const PetscScalar*) ctx;
783   const PetscScalar x0        = vertices[0];
784   const PetscScalar y0        = vertices[1];
785   const PetscScalar z0        = vertices[2];
786   const PetscScalar x1        = vertices[9];
787   const PetscScalar y1        = vertices[10];
788   const PetscScalar z1        = vertices[11];
789   const PetscScalar x2        = vertices[6];
790   const PetscScalar y2        = vertices[7];
791   const PetscScalar z2        = vertices[8];
792   const PetscScalar x3        = vertices[3];
793   const PetscScalar y3        = vertices[4];
794   const PetscScalar z3        = vertices[5];
795   const PetscScalar x4        = vertices[12];
796   const PetscScalar y4        = vertices[13];
797   const PetscScalar z4        = vertices[14];
798   const PetscScalar x5        = vertices[15];
799   const PetscScalar y5        = vertices[16];
800   const PetscScalar z5        = vertices[17];
801   const PetscScalar x6        = vertices[18];
802   const PetscScalar y6        = vertices[19];
803   const PetscScalar z6        = vertices[20];
804   const PetscScalar x7        = vertices[21];
805   const PetscScalar y7        = vertices[22];
806   const PetscScalar z7        = vertices[23];
807   const PetscScalar f_1       = x1 - x0;
808   const PetscScalar g_1       = y1 - y0;
809   const PetscScalar h_1       = z1 - z0;
810   const PetscScalar f_3       = x3 - x0;
811   const PetscScalar g_3       = y3 - y0;
812   const PetscScalar h_3       = z3 - z0;
813   const PetscScalar f_4       = x4 - x0;
814   const PetscScalar g_4       = y4 - y0;
815   const PetscScalar h_4       = z4 - z0;
816   const PetscScalar f_01      = x2 - x1 - x3 + x0;
817   const PetscScalar g_01      = y2 - y1 - y3 + y0;
818   const PetscScalar h_01      = z2 - z1 - z3 + z0;
819   const PetscScalar f_12      = x7 - x3 - x4 + x0;
820   const PetscScalar g_12      = y7 - y3 - y4 + y0;
821   const PetscScalar h_12      = z7 - z3 - z4 + z0;
822   const PetscScalar f_02      = x5 - x1 - x4 + x0;
823   const PetscScalar g_02      = y5 - y1 - y4 + y0;
824   const PetscScalar h_02      = z5 - z1 - z4 + z0;
825   const PetscScalar f_012     = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
826   const PetscScalar g_012     = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
827   const PetscScalar h_012     = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
828   const PetscScalar *ref;
829   PetscScalar       *real;
830 
831   PetscFunctionBegin;
832   CHKERRQ(VecGetArrayRead(Xref,  &ref));
833   CHKERRQ(VecGetArray(Xreal, &real));
834   {
835     const PetscScalar p0 = ref[0];
836     const PetscScalar p1 = ref[1];
837     const PetscScalar p2 = ref[2];
838 
839     real[0] = x0 + f_1*p0 + f_3*p1 + f_4*p2 + f_01*p0*p1 + f_12*p1*p2 + f_02*p0*p2 + f_012*p0*p1*p2;
840     real[1] = y0 + g_1*p0 + g_3*p1 + g_4*p2 + g_01*p0*p1 + g_01*p0*p1 + g_12*p1*p2 + g_02*p0*p2 + g_012*p0*p1*p2;
841     real[2] = z0 + h_1*p0 + h_3*p1 + h_4*p2 + h_01*p0*p1 + h_01*p0*p1 + h_12*p1*p2 + h_02*p0*p2 + h_012*p0*p1*p2;
842   }
843   CHKERRQ(PetscLogFlops(114));
844   CHKERRQ(VecRestoreArrayRead(Xref,  &ref));
845   CHKERRQ(VecRestoreArray(Xreal, &real));
846   PetscFunctionReturn(0);
847 }
848 
849 static inline PetscErrorCode HexJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
850 {
851   const PetscScalar *vertices = (const PetscScalar*) ctx;
852   const PetscScalar x0        = vertices[0];
853   const PetscScalar y0        = vertices[1];
854   const PetscScalar z0        = vertices[2];
855   const PetscScalar x1        = vertices[9];
856   const PetscScalar y1        = vertices[10];
857   const PetscScalar z1        = vertices[11];
858   const PetscScalar x2        = vertices[6];
859   const PetscScalar y2        = vertices[7];
860   const PetscScalar z2        = vertices[8];
861   const PetscScalar x3        = vertices[3];
862   const PetscScalar y3        = vertices[4];
863   const PetscScalar z3        = vertices[5];
864   const PetscScalar x4        = vertices[12];
865   const PetscScalar y4        = vertices[13];
866   const PetscScalar z4        = vertices[14];
867   const PetscScalar x5        = vertices[15];
868   const PetscScalar y5        = vertices[16];
869   const PetscScalar z5        = vertices[17];
870   const PetscScalar x6        = vertices[18];
871   const PetscScalar y6        = vertices[19];
872   const PetscScalar z6        = vertices[20];
873   const PetscScalar x7        = vertices[21];
874   const PetscScalar y7        = vertices[22];
875   const PetscScalar z7        = vertices[23];
876   const PetscScalar f_xy      = x2 - x1 - x3 + x0;
877   const PetscScalar g_xy      = y2 - y1 - y3 + y0;
878   const PetscScalar h_xy      = z2 - z1 - z3 + z0;
879   const PetscScalar f_yz      = x7 - x3 - x4 + x0;
880   const PetscScalar g_yz      = y7 - y3 - y4 + y0;
881   const PetscScalar h_yz      = z7 - z3 - z4 + z0;
882   const PetscScalar f_xz      = x5 - x1 - x4 + x0;
883   const PetscScalar g_xz      = y5 - y1 - y4 + y0;
884   const PetscScalar h_xz      = z5 - z1 - z4 + z0;
885   const PetscScalar f_xyz     = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
886   const PetscScalar g_xyz     = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
887   const PetscScalar h_xyz     = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
888   const PetscScalar *ref;
889 
890   PetscFunctionBegin;
891   CHKERRQ(VecGetArrayRead(Xref,  &ref));
892   {
893     const PetscScalar x       = ref[0];
894     const PetscScalar y       = ref[1];
895     const PetscScalar z       = ref[2];
896     const PetscInt    rows[3] = {0, 1, 2};
897     PetscScalar       values[9];
898 
899     values[0] = (x1 - x0 + f_xy*y + f_xz*z + f_xyz*y*z) / 2.0;
900     values[1] = (x3 - x0 + f_xy*x + f_yz*z + f_xyz*x*z) / 2.0;
901     values[2] = (x4 - x0 + f_yz*y + f_xz*x + f_xyz*x*y) / 2.0;
902     values[3] = (y1 - y0 + g_xy*y + g_xz*z + g_xyz*y*z) / 2.0;
903     values[4] = (y3 - y0 + g_xy*x + g_yz*z + g_xyz*x*z) / 2.0;
904     values[5] = (y4 - y0 + g_yz*y + g_xz*x + g_xyz*x*y) / 2.0;
905     values[6] = (z1 - z0 + h_xy*y + h_xz*z + h_xyz*y*z) / 2.0;
906     values[7] = (z3 - z0 + h_xy*x + h_yz*z + h_xyz*x*z) / 2.0;
907     values[8] = (z4 - z0 + h_yz*y + h_xz*x + h_xyz*x*y) / 2.0;
908 
909     CHKERRQ(MatSetValues(J, 3, rows, 3, rows, values, INSERT_VALUES));
910   }
911   CHKERRQ(PetscLogFlops(152));
912   CHKERRQ(VecRestoreArrayRead(Xref,  &ref));
913   CHKERRQ(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
914   CHKERRQ(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
915   PetscFunctionReturn(0);
916 }
917 
918 static inline PetscErrorCode DMInterpolate_Hex_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
919 {
920   DM             dmCoord;
921   SNES           snes;
922   KSP            ksp;
923   PC             pc;
924   Vec            coordsLocal, r, ref, real;
925   Mat            J;
926   const PetscScalar *coords;
927   PetscScalar    *a;
928   PetscInt       p;
929 
930   PetscFunctionBegin;
931   CHKERRQ(DMGetCoordinatesLocal(dm, &coordsLocal));
932   CHKERRQ(DMGetCoordinateDM(dm, &dmCoord));
933   CHKERRQ(SNESCreate(PETSC_COMM_SELF, &snes));
934   CHKERRQ(SNESSetOptionsPrefix(snes, "hex_interp_"));
935   CHKERRQ(VecCreate(PETSC_COMM_SELF, &r));
936   CHKERRQ(VecSetSizes(r, 3, 3));
937   CHKERRQ(VecSetType(r,dm->vectype));
938   CHKERRQ(VecDuplicate(r, &ref));
939   CHKERRQ(VecDuplicate(r, &real));
940   CHKERRQ(MatCreate(PETSC_COMM_SELF, &J));
941   CHKERRQ(MatSetSizes(J, 3, 3, 3, 3));
942   CHKERRQ(MatSetType(J, MATSEQDENSE));
943   CHKERRQ(MatSetUp(J));
944   CHKERRQ(SNESSetFunction(snes, r, HexMap_Private, NULL));
945   CHKERRQ(SNESSetJacobian(snes, J, J, HexJacobian_Private, NULL));
946   CHKERRQ(SNESGetKSP(snes, &ksp));
947   CHKERRQ(KSPGetPC(ksp, &pc));
948   CHKERRQ(PCSetType(pc, PCLU));
949   CHKERRQ(SNESSetFromOptions(snes));
950 
951   CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
952   CHKERRQ(VecGetArray(v, &a));
953   for (p = 0; p < ctx->n; ++p) {
954     PetscScalar *x = NULL, *vertices = NULL;
955     PetscScalar *xi;
956     PetscReal    xir[3];
957     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
958 
959     /* Can make this do all points at once */
960     CHKERRQ(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
961     PetscCheck(8*3 == coordSize,ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid coordinate closure size %" PetscInt_FMT " should be %d", coordSize, 8*3);
962     CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
963     PetscCheck((8*ctx->dof == xSize) || (ctx->dof == xSize),ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input closure size %" PetscInt_FMT " should be %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 8*ctx->dof, ctx->dof);
964     CHKERRQ(SNESSetFunction(snes, NULL, NULL, vertices));
965     CHKERRQ(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
966     CHKERRQ(VecGetArray(real, &xi));
967     xi[0]  = coords[p*ctx->dim+0];
968     xi[1]  = coords[p*ctx->dim+1];
969     xi[2]  = coords[p*ctx->dim+2];
970     CHKERRQ(VecRestoreArray(real, &xi));
971     CHKERRQ(SNESSolve(snes, real, ref));
972     CHKERRQ(VecGetArray(ref, &xi));
973     xir[0] = PetscRealPart(xi[0]);
974     xir[1] = PetscRealPart(xi[1]);
975     xir[2] = PetscRealPart(xi[2]);
976     if (8*ctx->dof == xSize) {
977       for (comp = 0; comp < ctx->dof; ++comp) {
978         a[p*ctx->dof+comp] =
979           x[0*ctx->dof+comp]*(1-xir[0])*(1-xir[1])*(1-xir[2]) +
980           x[3*ctx->dof+comp]*    xir[0]*(1-xir[1])*(1-xir[2]) +
981           x[2*ctx->dof+comp]*    xir[0]*    xir[1]*(1-xir[2]) +
982           x[1*ctx->dof+comp]*(1-xir[0])*    xir[1]*(1-xir[2]) +
983           x[4*ctx->dof+comp]*(1-xir[0])*(1-xir[1])*   xir[2] +
984           x[5*ctx->dof+comp]*    xir[0]*(1-xir[1])*   xir[2] +
985           x[6*ctx->dof+comp]*    xir[0]*    xir[1]*   xir[2] +
986           x[7*ctx->dof+comp]*(1-xir[0])*    xir[1]*   xir[2];
987       }
988     } else {
989       for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp];
990     }
991     CHKERRQ(VecRestoreArray(ref, &xi));
992     CHKERRQ(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
993     CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
994   }
995   CHKERRQ(VecRestoreArray(v, &a));
996   CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
997 
998   CHKERRQ(SNESDestroy(&snes));
999   CHKERRQ(VecDestroy(&r));
1000   CHKERRQ(VecDestroy(&ref));
1001   CHKERRQ(VecDestroy(&real));
1002   CHKERRQ(MatDestroy(&J));
1003   PetscFunctionReturn(0);
1004 }
1005 
1006 /*@C
1007   DMInterpolationEvaluate - Using the input from dm and x, calculates interpolated field values at the interpolation points.
1008 
1009   Input Parameters:
1010 + ctx - The DMInterpolationInfo context
1011 . dm  - The DM
1012 - x   - The local vector containing the field to be interpolated
1013 
1014   Output Parameters:
1015 . v   - The vector containing the interpolated values
1016 
1017   Note: A suitable v can be obtained using DMInterpolationGetVector().
1018 
1019   Level: beginner
1020 
1021 .seealso: DMInterpolationGetVector(), DMInterpolationAddPoints(), DMInterpolationCreate()
1022 @*/
1023 PetscErrorCode DMInterpolationEvaluate(DMInterpolationInfo ctx, DM dm, Vec x, Vec v)
1024 {
1025   PetscDS        ds;
1026   PetscInt       n, p, Nf, field;
1027   PetscBool      useDS = PETSC_FALSE;
1028 
1029   PetscFunctionBegin;
1030   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1031   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
1032   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
1033   CHKERRQ(VecGetLocalSize(v, &n));
1034   PetscCheckFalse(n != ctx->n*ctx->dof,ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input vector size %D should be %D", n, ctx->n*ctx->dof);
1035   if (!n) PetscFunctionReturn(0);
1036   CHKERRQ(DMGetDS(dm, &ds));
1037   if (ds) {
1038     useDS = PETSC_TRUE;
1039     CHKERRQ(PetscDSGetNumFields(ds, &Nf));
1040     for (field = 0; field < Nf; ++field) {
1041       PetscObject  obj;
1042       PetscClassId id;
1043 
1044       CHKERRQ(PetscDSGetDiscretization(ds, field, &obj));
1045       CHKERRQ(PetscObjectGetClassId(obj, &id));
1046       if (id != PETSCFE_CLASSID) {useDS = PETSC_FALSE; break;}
1047     }
1048   }
1049   if (useDS) {
1050     const PetscScalar *coords;
1051     PetscScalar       *interpolant;
1052     PetscInt           cdim, d;
1053 
1054     CHKERRQ(DMGetCoordinateDim(dm, &cdim));
1055     CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
1056     CHKERRQ(VecGetArrayWrite(v, &interpolant));
1057     for (p = 0; p < ctx->n; ++p) {
1058       PetscReal    pcoords[3], xi[3];
1059       PetscScalar *xa   = NULL;
1060       PetscInt     coff = 0, foff = 0, clSize;
1061 
1062       if (ctx->cells[p] < 0) continue;
1063       for (d = 0; d < cdim; ++d) pcoords[d] = PetscRealPart(coords[p*cdim+d]);
1064       CHKERRQ(DMPlexCoordinatesToReference(dm, ctx->cells[p], 1, pcoords, xi));
1065       CHKERRQ(DMPlexVecGetClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
1066       for (field = 0; field < Nf; ++field) {
1067         PetscTabulation T;
1068         PetscFE         fe;
1069 
1070         CHKERRQ(PetscDSGetDiscretization(ds, field, (PetscObject *) &fe));
1071         CHKERRQ(PetscFECreateTabulation(fe, 1, 1, xi, 0, &T));
1072         {
1073           const PetscReal *basis = T->T[0];
1074           const PetscInt   Nb    = T->Nb;
1075           const PetscInt   Nc    = T->Nc;
1076           PetscInt         f, fc;
1077 
1078           for (fc = 0; fc < Nc; ++fc) {
1079             interpolant[p*ctx->dof+coff+fc] = 0.0;
1080             for (f = 0; f < Nb; ++f) {
1081               interpolant[p*ctx->dof+coff+fc] += xa[foff+f]*basis[(0*Nb + f)*Nc + fc];
1082             }
1083           }
1084           coff += Nc;
1085           foff += Nb;
1086         }
1087         CHKERRQ(PetscTabulationDestroy(&T));
1088       }
1089       CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
1090       PetscCheckFalse(coff != ctx->dof,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total components %D != %D dof specified for interpolation", coff, ctx->dof);
1091       PetscCheckFalse(foff != clSize,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total FE space size %D != %D closure size", foff, clSize);
1092     }
1093     CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
1094     CHKERRQ(VecRestoreArrayWrite(v, &interpolant));
1095   } else {
1096     DMPolytopeType ct;
1097 
1098     /* TODO Check each cell individually */
1099     CHKERRQ(DMPlexGetCellType(dm, ctx->cells[0], &ct));
1100     switch (ct) {
1101       case DM_POLYTOPE_SEGMENT:       CHKERRQ(DMInterpolate_Segment_Private(ctx, dm, x, v));break;
1102       case DM_POLYTOPE_TRIANGLE:      CHKERRQ(DMInterpolate_Triangle_Private(ctx, dm, x, v));break;
1103       case DM_POLYTOPE_QUADRILATERAL: CHKERRQ(DMInterpolate_Quad_Private(ctx, dm, x, v));break;
1104       case DM_POLYTOPE_TETRAHEDRON:   CHKERRQ(DMInterpolate_Tetrahedron_Private(ctx, dm, x, v));break;
1105       case DM_POLYTOPE_HEXAHEDRON:    CHKERRQ(DMInterpolate_Hex_Private(ctx, dm, x, v));break;
1106       default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for cell type %s", DMPolytopeTypes[PetscMax(0, PetscMin(ct, DM_NUM_POLYTOPES))]);
1107     }
1108   }
1109   PetscFunctionReturn(0);
1110 }
1111 
1112 /*@C
1113   DMInterpolationDestroy - Destroys a DMInterpolationInfo context
1114 
1115   Collective on ctx
1116 
1117   Input Parameter:
1118 . ctx - the context
1119 
1120   Level: beginner
1121 
1122 .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
1123 @*/
1124 PetscErrorCode DMInterpolationDestroy(DMInterpolationInfo *ctx)
1125 {
1126   PetscFunctionBegin;
1127   PetscValidPointer(ctx, 1);
1128   CHKERRQ(VecDestroy(&(*ctx)->coords));
1129   CHKERRQ(PetscFree((*ctx)->points));
1130   CHKERRQ(PetscFree((*ctx)->cells));
1131   CHKERRQ(PetscFree(*ctx));
1132   *ctx = NULL;
1133   PetscFunctionReturn(0);
1134 }
1135 
1136 /*@C
1137   SNESMonitorFields - Monitors the residual for each field separately
1138 
1139   Collective on SNES
1140 
1141   Input Parameters:
1142 + snes   - the SNES context
1143 . its    - iteration number
1144 . fgnorm - 2-norm of residual
1145 - vf  - PetscViewerAndFormat of type ASCII
1146 
1147   Notes:
1148   This routine prints the residual norm at each iteration.
1149 
1150   Level: intermediate
1151 
1152 .seealso: SNESMonitorSet(), SNESMonitorDefault()
1153 @*/
1154 PetscErrorCode SNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
1155 {
1156   PetscViewer        viewer = vf->viewer;
1157   Vec                res;
1158   DM                 dm;
1159   PetscSection       s;
1160   const PetscScalar *r;
1161   PetscReal         *lnorms, *norms;
1162   PetscInt           numFields, f, pStart, pEnd, p;
1163 
1164   PetscFunctionBegin;
1165   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
1166   CHKERRQ(SNESGetFunction(snes, &res, NULL, NULL));
1167   CHKERRQ(SNESGetDM(snes, &dm));
1168   CHKERRQ(DMGetLocalSection(dm, &s));
1169   CHKERRQ(PetscSectionGetNumFields(s, &numFields));
1170   CHKERRQ(PetscSectionGetChart(s, &pStart, &pEnd));
1171   CHKERRQ(PetscCalloc2(numFields, &lnorms, numFields, &norms));
1172   CHKERRQ(VecGetArrayRead(res, &r));
1173   for (p = pStart; p < pEnd; ++p) {
1174     for (f = 0; f < numFields; ++f) {
1175       PetscInt fdof, foff, d;
1176 
1177       CHKERRQ(PetscSectionGetFieldDof(s, p, f, &fdof));
1178       CHKERRQ(PetscSectionGetFieldOffset(s, p, f, &foff));
1179       for (d = 0; d < fdof; ++d) lnorms[f] += PetscRealPart(PetscSqr(r[foff+d]));
1180     }
1181   }
1182   CHKERRQ(VecRestoreArrayRead(res, &r));
1183   CHKERRMPI(MPIU_Allreduce(lnorms, norms, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject) dm)));
1184   CHKERRQ(PetscViewerPushFormat(viewer,vf->format));
1185   CHKERRQ(PetscViewerASCIIAddTab(viewer, ((PetscObject) snes)->tablevel));
1186   CHKERRQ(PetscViewerASCIIPrintf(viewer, "%3D SNES Function norm %14.12e [", its, (double) fgnorm));
1187   for (f = 0; f < numFields; ++f) {
1188     if (f > 0) CHKERRQ(PetscViewerASCIIPrintf(viewer, ", "));
1189     CHKERRQ(PetscViewerASCIIPrintf(viewer, "%14.12e", (double) PetscSqrtReal(norms[f])));
1190   }
1191   CHKERRQ(PetscViewerASCIIPrintf(viewer, "]\n"));
1192   CHKERRQ(PetscViewerASCIISubtractTab(viewer, ((PetscObject) snes)->tablevel));
1193   CHKERRQ(PetscViewerPopFormat(viewer));
1194   CHKERRQ(PetscFree2(lnorms, norms));
1195   PetscFunctionReturn(0);
1196 }
1197 
1198 /********************* Residual Computation **************************/
1199 
1200 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
1201 {
1202   PetscInt       depth;
1203 
1204   PetscFunctionBegin;
1205   CHKERRQ(DMPlexGetDepth(plex, &depth));
1206   CHKERRQ(DMGetStratumIS(plex, "dim", depth, cellIS));
1207   if (!*cellIS) CHKERRQ(DMGetStratumIS(plex, "depth", depth, cellIS));
1208   PetscFunctionReturn(0);
1209 }
1210 
1211 /*@
1212   DMPlexSNESComputeResidualFEM - Sums the local residual into vector F from the local input X using pointwise functions specified by the user
1213 
1214   Input Parameters:
1215 + dm - The mesh
1216 . X  - Local solution
1217 - user - The user context
1218 
1219   Output Parameter:
1220 . F  - Local output vector
1221 
1222   Notes:
1223   The residual is summed into F; the caller is responsible for using VecZeroEntries() or otherwise ensuring that any data in F is intentional.
1224 
1225   Level: developer
1226 
1227 .seealso: DMPlexComputeJacobianAction()
1228 @*/
1229 PetscErrorCode DMPlexSNESComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
1230 {
1231   DM             plex;
1232   IS             allcellIS;
1233   PetscInt       Nds, s;
1234 
1235   PetscFunctionBegin;
1236   CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
1237   CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS));
1238   CHKERRQ(DMGetNumDS(dm, &Nds));
1239   for (s = 0; s < Nds; ++s) {
1240     PetscDS          ds;
1241     IS               cellIS;
1242     PetscFormKey key;
1243 
1244     CHKERRQ(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds));
1245     key.value = 0;
1246     key.field = 0;
1247     key.part  = 0;
1248     if (!key.label) {
1249       CHKERRQ(PetscObjectReference((PetscObject) allcellIS));
1250       cellIS = allcellIS;
1251     } else {
1252       IS pointIS;
1253 
1254       key.value = 1;
1255       CHKERRQ(DMLabelGetStratumIS(key.label, key.value, &pointIS));
1256       CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
1257       CHKERRQ(ISDestroy(&pointIS));
1258     }
1259     CHKERRQ(DMPlexComputeResidual_Internal(plex, key, cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user));
1260     CHKERRQ(ISDestroy(&cellIS));
1261   }
1262   CHKERRQ(ISDestroy(&allcellIS));
1263   CHKERRQ(DMDestroy(&plex));
1264   PetscFunctionReturn(0);
1265 }
1266 
1267 PetscErrorCode DMSNESComputeResidual(DM dm, Vec X, Vec F, void *user)
1268 {
1269   DM             plex;
1270   IS             allcellIS;
1271   PetscInt       Nds, s;
1272 
1273   PetscFunctionBegin;
1274   CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
1275   CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS));
1276   CHKERRQ(DMGetNumDS(dm, &Nds));
1277   for (s = 0; s < Nds; ++s) {
1278     PetscDS ds;
1279     DMLabel label;
1280     IS      cellIS;
1281 
1282     CHKERRQ(DMGetRegionNumDS(dm, s, &label, NULL, &ds));
1283     {
1284       PetscWeakFormKind resmap[2] = {PETSC_WF_F0, PETSC_WF_F1};
1285       PetscWeakForm     wf;
1286       PetscInt          Nm = 2, m, Nk = 0, k, kp, off = 0;
1287       PetscFormKey *reskeys;
1288 
1289       /* Get unique residual keys */
1290       for (m = 0; m < Nm; ++m) {
1291         PetscInt Nkm;
1292         CHKERRQ(PetscHMapFormGetSize(ds->wf->form[resmap[m]], &Nkm));
1293         Nk  += Nkm;
1294       }
1295       CHKERRQ(PetscMalloc1(Nk, &reskeys));
1296       for (m = 0; m < Nm; ++m) {
1297         CHKERRQ(PetscHMapFormGetKeys(ds->wf->form[resmap[m]], &off, reskeys));
1298       }
1299       PetscCheckFalse(off != Nk,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %D should be %D", off, Nk);
1300       CHKERRQ(PetscFormKeySort(Nk, reskeys));
1301       for (k = 0, kp = 1; kp < Nk; ++kp) {
1302         if ((reskeys[k].label != reskeys[kp].label) || (reskeys[k].value != reskeys[kp].value)) {
1303           ++k;
1304           if (kp != k) reskeys[k] = reskeys[kp];
1305         }
1306       }
1307       Nk = k;
1308 
1309       CHKERRQ(PetscDSGetWeakForm(ds, &wf));
1310       for (k = 0; k < Nk; ++k) {
1311         DMLabel  label = reskeys[k].label;
1312         PetscInt val   = reskeys[k].value;
1313 
1314         if (!label) {
1315           CHKERRQ(PetscObjectReference((PetscObject) allcellIS));
1316           cellIS = allcellIS;
1317         } else {
1318           IS pointIS;
1319 
1320           CHKERRQ(DMLabelGetStratumIS(label, val, &pointIS));
1321           CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
1322           CHKERRQ(ISDestroy(&pointIS));
1323         }
1324         CHKERRQ(DMPlexComputeResidual_Internal(plex, reskeys[k], cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user));
1325         CHKERRQ(ISDestroy(&cellIS));
1326       }
1327       CHKERRQ(PetscFree(reskeys));
1328     }
1329   }
1330   CHKERRQ(ISDestroy(&allcellIS));
1331   CHKERRQ(DMDestroy(&plex));
1332   PetscFunctionReturn(0);
1333 }
1334 
1335 /*@
1336   DMPlexSNESComputeBoundaryFEM - Form the boundary values for the local input X
1337 
1338   Input Parameters:
1339 + dm - The mesh
1340 - user - The user context
1341 
1342   Output Parameter:
1343 . X  - Local solution
1344 
1345   Level: developer
1346 
1347 .seealso: DMPlexComputeJacobianAction()
1348 @*/
1349 PetscErrorCode DMPlexSNESComputeBoundaryFEM(DM dm, Vec X, void *user)
1350 {
1351   DM             plex;
1352 
1353   PetscFunctionBegin;
1354   CHKERRQ(DMSNESConvertPlex(dm,&plex,PETSC_TRUE));
1355   CHKERRQ(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, X, PETSC_MIN_REAL, NULL, NULL, NULL));
1356   CHKERRQ(DMDestroy(&plex));
1357   PetscFunctionReturn(0);
1358 }
1359 
1360 /*@
1361   DMSNESComputeJacobianAction - Compute the action of the Jacobian J(X) on Y
1362 
1363   Input Parameters:
1364 + dm   - The DM
1365 . X    - Local solution vector
1366 . Y    - Local input vector
1367 - user - The user context
1368 
1369   Output Parameter:
1370 . F    - lcoal output vector
1371 
1372   Level: developer
1373 
1374   Notes:
1375   Users will typically use DMSNESCreateJacobianMF() followed by MatMult() instead of calling this routine directly.
1376 
1377 .seealso: DMSNESCreateJacobianMF(), DMPlexSNESComputeResidualFEM()
1378 @*/
1379 PetscErrorCode DMSNESComputeJacobianAction(DM dm, Vec X, Vec Y, Vec F, void *user)
1380 {
1381   DM             plex;
1382   IS             allcellIS;
1383   PetscInt       Nds, s;
1384 
1385   PetscFunctionBegin;
1386   CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
1387   CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS));
1388   CHKERRQ(DMGetNumDS(dm, &Nds));
1389   for (s = 0; s < Nds; ++s) {
1390     PetscDS ds;
1391     DMLabel label;
1392     IS      cellIS;
1393 
1394     CHKERRQ(DMGetRegionNumDS(dm, s, &label, NULL, &ds));
1395     {
1396       PetscWeakFormKind jacmap[4] = {PETSC_WF_G0, PETSC_WF_G1, PETSC_WF_G2, PETSC_WF_G3};
1397       PetscWeakForm     wf;
1398       PetscInt          Nm = 4, m, Nk = 0, k, kp, off = 0;
1399       PetscFormKey *jackeys;
1400 
1401       /* Get unique Jacobian keys */
1402       for (m = 0; m < Nm; ++m) {
1403         PetscInt Nkm;
1404         CHKERRQ(PetscHMapFormGetSize(ds->wf->form[jacmap[m]], &Nkm));
1405         Nk  += Nkm;
1406       }
1407       CHKERRQ(PetscMalloc1(Nk, &jackeys));
1408       for (m = 0; m < Nm; ++m) {
1409         CHKERRQ(PetscHMapFormGetKeys(ds->wf->form[jacmap[m]], &off, jackeys));
1410       }
1411       PetscCheckFalse(off != Nk,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %D should be %D", off, Nk);
1412       CHKERRQ(PetscFormKeySort(Nk, jackeys));
1413       for (k = 0, kp = 1; kp < Nk; ++kp) {
1414         if ((jackeys[k].label != jackeys[kp].label) || (jackeys[k].value != jackeys[kp].value)) {
1415           ++k;
1416           if (kp != k) jackeys[k] = jackeys[kp];
1417         }
1418       }
1419       Nk = k;
1420 
1421       CHKERRQ(PetscDSGetWeakForm(ds, &wf));
1422       for (k = 0; k < Nk; ++k) {
1423         DMLabel  label = jackeys[k].label;
1424         PetscInt val   = jackeys[k].value;
1425 
1426         if (!label) {
1427           CHKERRQ(PetscObjectReference((PetscObject) allcellIS));
1428           cellIS = allcellIS;
1429         } else {
1430           IS pointIS;
1431 
1432           CHKERRQ(DMLabelGetStratumIS(label, val, &pointIS));
1433           CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
1434           CHKERRQ(ISDestroy(&pointIS));
1435         }
1436         CHKERRQ(DMPlexComputeJacobian_Action_Internal(plex, jackeys[k], cellIS, 0.0, 0.0, X, NULL, Y, F, user));
1437         CHKERRQ(ISDestroy(&cellIS));
1438       }
1439       CHKERRQ(PetscFree(jackeys));
1440     }
1441   }
1442   CHKERRQ(ISDestroy(&allcellIS));
1443   CHKERRQ(DMDestroy(&plex));
1444   PetscFunctionReturn(0);
1445 }
1446 
1447 /*@
1448   DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
1449 
1450   Input Parameters:
1451 + dm - The mesh
1452 . X  - Local input vector
1453 - user - The user context
1454 
1455   Output Parameter:
1456 . Jac  - Jacobian matrix
1457 
1458   Note:
1459   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
1460   like a GPU, or vectorize on a multicore machine.
1461 
1462   Level: developer
1463 
1464 .seealso: FormFunctionLocal()
1465 @*/
1466 PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP,void *user)
1467 {
1468   DM             plex;
1469   IS             allcellIS;
1470   PetscBool      hasJac, hasPrec;
1471   PetscInt       Nds, s;
1472 
1473   PetscFunctionBegin;
1474   CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
1475   CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS));
1476   CHKERRQ(DMGetNumDS(dm, &Nds));
1477   for (s = 0; s < Nds; ++s) {
1478     PetscDS          ds;
1479     IS               cellIS;
1480     PetscFormKey key;
1481 
1482     CHKERRQ(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds));
1483     key.value = 0;
1484     key.field = 0;
1485     key.part  = 0;
1486     if (!key.label) {
1487       CHKERRQ(PetscObjectReference((PetscObject) allcellIS));
1488       cellIS = allcellIS;
1489     } else {
1490       IS pointIS;
1491 
1492       key.value = 1;
1493       CHKERRQ(DMLabelGetStratumIS(key.label, key.value, &pointIS));
1494       CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
1495       CHKERRQ(ISDestroy(&pointIS));
1496     }
1497     if (!s) {
1498       CHKERRQ(PetscDSHasJacobian(ds, &hasJac));
1499       CHKERRQ(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
1500       if (hasJac && hasPrec) CHKERRQ(MatZeroEntries(Jac));
1501       CHKERRQ(MatZeroEntries(JacP));
1502     }
1503     CHKERRQ(DMPlexComputeJacobian_Internal(plex, key, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, user));
1504     CHKERRQ(ISDestroy(&cellIS));
1505   }
1506   CHKERRQ(ISDestroy(&allcellIS));
1507   CHKERRQ(DMDestroy(&plex));
1508   PetscFunctionReturn(0);
1509 }
1510 
1511 struct _DMSNESJacobianMFCtx
1512 {
1513   DM    dm;
1514   Vec   X;
1515   void *ctx;
1516 };
1517 
1518 static PetscErrorCode DMSNESJacobianMF_Destroy_Private(Mat A)
1519 {
1520   struct _DMSNESJacobianMFCtx *ctx;
1521 
1522   PetscFunctionBegin;
1523   CHKERRQ(MatShellGetContext(A, &ctx));
1524   CHKERRQ(MatShellSetContext(A, NULL));
1525   CHKERRQ(DMDestroy(&ctx->dm));
1526   CHKERRQ(VecDestroy(&ctx->X));
1527   CHKERRQ(PetscFree(ctx));
1528   PetscFunctionReturn(0);
1529 }
1530 
1531 static PetscErrorCode DMSNESJacobianMF_Mult_Private(Mat A, Vec Y, Vec Z)
1532 {
1533   struct _DMSNESJacobianMFCtx *ctx;
1534 
1535   PetscFunctionBegin;
1536   CHKERRQ(MatShellGetContext(A, &ctx));
1537   CHKERRQ(DMSNESComputeJacobianAction(ctx->dm, ctx->X, Y, Z, ctx->ctx));
1538   PetscFunctionReturn(0);
1539 }
1540 
1541 /*@
1542   DMSNESCreateJacobianMF - Create a Mat which computes the action of the Jacobian matrix-free
1543 
1544   Collective on dm
1545 
1546   Input Parameters:
1547 + dm   - The DM
1548 . X    - The evaluation point for the Jacobian
1549 - user - A user context, or NULL
1550 
1551   Output Parameter:
1552 . J    - The Mat
1553 
1554   Level: advanced
1555 
1556   Notes:
1557   Vec X is kept in Mat J, so updating X then updates the evaluation point.
1558 
1559 .seealso: DMSNESComputeJacobianAction()
1560 @*/
1561 PetscErrorCode DMSNESCreateJacobianMF(DM dm, Vec X, void *user, Mat *J)
1562 {
1563   struct _DMSNESJacobianMFCtx *ctx;
1564   PetscInt                     n, N;
1565 
1566   PetscFunctionBegin;
1567   CHKERRQ(MatCreate(PetscObjectComm((PetscObject) dm), J));
1568   CHKERRQ(MatSetType(*J, MATSHELL));
1569   CHKERRQ(VecGetLocalSize(X, &n));
1570   CHKERRQ(VecGetSize(X, &N));
1571   CHKERRQ(MatSetSizes(*J, n, n, N, N));
1572   CHKERRQ(PetscObjectReference((PetscObject) dm));
1573   CHKERRQ(PetscObjectReference((PetscObject) X));
1574   CHKERRQ(PetscMalloc1(1, &ctx));
1575   ctx->dm  = dm;
1576   ctx->X   = X;
1577   ctx->ctx = user;
1578   CHKERRQ(MatShellSetContext(*J, ctx));
1579   CHKERRQ(MatShellSetOperation(*J, MATOP_DESTROY, (void (*)(void)) DMSNESJacobianMF_Destroy_Private));
1580   CHKERRQ(MatShellSetOperation(*J, MATOP_MULT,    (void (*)(void)) DMSNESJacobianMF_Mult_Private));
1581   PetscFunctionReturn(0);
1582 }
1583 
1584 /*
1585      MatComputeNeumannOverlap - Computes an unassembled (Neumann) local overlapping Mat in nonlinear context.
1586 
1587    Input Parameters:
1588 +     X - SNES linearization point
1589 .     ovl - index set of overlapping subdomains
1590 
1591    Output Parameter:
1592 .     J - unassembled (Neumann) local matrix
1593 
1594    Level: intermediate
1595 
1596 .seealso: DMCreateNeumannOverlap(), MATIS, PCHPDDMSetAuxiliaryMat()
1597 */
1598 static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, void *ctx)
1599 {
1600   SNES           snes;
1601   Mat            pJ;
1602   DM             ovldm,origdm;
1603   DMSNES         sdm;
1604   PetscErrorCode (*bfun)(DM,Vec,void*);
1605   PetscErrorCode (*jfun)(DM,Vec,Mat,Mat,void*);
1606   void           *bctx,*jctx;
1607 
1608   PetscFunctionBegin;
1609   CHKERRQ(PetscObjectQuery((PetscObject)ovl,"_DM_Overlap_HPDDM_MATIS",(PetscObject*)&pJ));
1610   PetscCheckFalse(!pJ,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing overlapping Mat");
1611   CHKERRQ(PetscObjectQuery((PetscObject)ovl,"_DM_Original_HPDDM",(PetscObject*)&origdm));
1612   PetscCheckFalse(!origdm,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing original DM");
1613   CHKERRQ(MatGetDM(pJ,&ovldm));
1614   CHKERRQ(DMSNESGetBoundaryLocal(origdm,&bfun,&bctx));
1615   CHKERRQ(DMSNESSetBoundaryLocal(ovldm,bfun,bctx));
1616   CHKERRQ(DMSNESGetJacobianLocal(origdm,&jfun,&jctx));
1617   CHKERRQ(DMSNESSetJacobianLocal(ovldm,jfun,jctx));
1618   CHKERRQ(PetscObjectQuery((PetscObject)ovl,"_DM_Overlap_HPDDM_SNES",(PetscObject*)&snes));
1619   if (!snes) {
1620     CHKERRQ(SNESCreate(PetscObjectComm((PetscObject)ovl),&snes));
1621     CHKERRQ(SNESSetDM(snes,ovldm));
1622     CHKERRQ(PetscObjectCompose((PetscObject)ovl,"_DM_Overlap_HPDDM_SNES",(PetscObject)snes));
1623     CHKERRQ(PetscObjectDereference((PetscObject)snes));
1624   }
1625   CHKERRQ(DMGetDMSNES(ovldm,&sdm));
1626   CHKERRQ(VecLockReadPush(X));
1627   PetscStackPush("SNES user Jacobian function");
1628   CHKERRQ((*sdm->ops->computejacobian)(snes,X,pJ,pJ,sdm->jacobianctx));
1629   PetscStackPop;
1630   CHKERRQ(VecLockReadPop(X));
1631   /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */
1632   {
1633     Mat locpJ;
1634 
1635     CHKERRQ(MatISGetLocalMat(pJ,&locpJ));
1636     CHKERRQ(MatCopy(locpJ,J,SAME_NONZERO_PATTERN));
1637   }
1638   PetscFunctionReturn(0);
1639 }
1640 
1641 /*@
1642   DMPlexSetSNESLocalFEM - Use DMPlex's internal FEM routines to compute SNES boundary values, residual, and Jacobian.
1643 
1644   Input Parameters:
1645 + dm - The DM object
1646 . boundaryctx - the user context that will be passed to pointwise evaluation of boundary values (see PetscDSAddBoundary())
1647 . residualctx - the user context that will be passed to pointwise evaluation of finite element residual computations (see PetscDSSetResidual())
1648 - jacobianctx - the user context that will be passed to pointwise evaluation of finite element Jacobian construction (see PetscDSSetJacobian())
1649 
1650   Level: developer
1651 @*/
1652 PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, void *boundaryctx, void *residualctx, void *jacobianctx)
1653 {
1654   PetscFunctionBegin;
1655   CHKERRQ(DMSNESSetBoundaryLocal(dm,DMPlexSNESComputeBoundaryFEM,boundaryctx));
1656   CHKERRQ(DMSNESSetFunctionLocal(dm,DMPlexSNESComputeResidualFEM,residualctx));
1657   CHKERRQ(DMSNESSetJacobianLocal(dm,DMPlexSNESComputeJacobianFEM,jacobianctx));
1658   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",MatComputeNeumannOverlap_Plex));
1659   PetscFunctionReturn(0);
1660 }
1661 
1662 /*@C
1663   DMSNESCheckDiscretization - Check the discretization error of the exact solution
1664 
1665   Input Parameters:
1666 + snes - the SNES object
1667 . dm   - the DM
1668 . t    - the time
1669 . u    - a DM vector
1670 - tol  - A tolerance for the check, or -1 to print the results instead
1671 
1672   Output Parameters:
1673 . error - An array which holds the discretization error in each field, or NULL
1674 
1675   Note: The user must call PetscDSSetExactSolution() beforehand
1676 
1677   Level: developer
1678 
1679 .seealso: DNSNESCheckFromOptions(), DMSNESCheckResidual(), DMSNESCheckJacobian(), PetscDSSetExactSolution()
1680 @*/
1681 PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[])
1682 {
1683   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
1684   void            **ectxs;
1685   PetscReal        *err;
1686   MPI_Comm          comm;
1687   PetscInt          Nf, f;
1688 
1689   PetscFunctionBegin;
1690   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1691   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1692   PetscValidHeaderSpecific(u, VEC_CLASSID, 4);
1693   if (error) PetscValidRealPointer(error, 6);
1694 
1695   CHKERRQ(DMComputeExactSolution(dm, t, u, NULL));
1696   CHKERRQ(VecViewFromOptions(u, NULL, "-vec_view"));
1697 
1698   CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm));
1699   CHKERRQ(DMGetNumFields(dm, &Nf));
1700   CHKERRQ(PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err));
1701   {
1702     PetscInt Nds, s;
1703 
1704     CHKERRQ(DMGetNumDS(dm, &Nds));
1705     for (s = 0; s < Nds; ++s) {
1706       PetscDS         ds;
1707       DMLabel         label;
1708       IS              fieldIS;
1709       const PetscInt *fields;
1710       PetscInt        dsNf, f;
1711 
1712       CHKERRQ(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
1713       CHKERRQ(PetscDSGetNumFields(ds, &dsNf));
1714       CHKERRQ(ISGetIndices(fieldIS, &fields));
1715       for (f = 0; f < dsNf; ++f) {
1716         const PetscInt field = fields[f];
1717         CHKERRQ(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]));
1718       }
1719       CHKERRQ(ISRestoreIndices(fieldIS, &fields));
1720     }
1721   }
1722   if (Nf > 1) {
1723     CHKERRQ(DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err));
1724     if (tol >= 0.0) {
1725       for (f = 0; f < Nf; ++f) {
1726         PetscCheckFalse(err[f] > tol,comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g for field %D exceeds tolerance %g", (double) err[f], f, (double) tol);
1727       }
1728     } else if (error) {
1729       for (f = 0; f < Nf; ++f) error[f] = err[f];
1730     } else {
1731       CHKERRQ(PetscPrintf(comm, "L_2 Error: ["));
1732       for (f = 0; f < Nf; ++f) {
1733         if (f) CHKERRQ(PetscPrintf(comm, ", "));
1734         CHKERRQ(PetscPrintf(comm, "%g", (double)err[f]));
1735       }
1736       CHKERRQ(PetscPrintf(comm, "]\n"));
1737     }
1738   } else {
1739     CHKERRQ(DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0]));
1740     if (tol >= 0.0) {
1741       PetscCheckFalse(err[0] > tol,comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double) err[0], (double) tol);
1742     } else if (error) {
1743       error[0] = err[0];
1744     } else {
1745       CHKERRQ(PetscPrintf(comm, "L_2 Error: %g\n", (double) err[0]));
1746     }
1747   }
1748   CHKERRQ(PetscFree3(exacts, ectxs, err));
1749   PetscFunctionReturn(0);
1750 }
1751 
1752 /*@C
1753   DMSNESCheckResidual - Check the residual of the exact solution
1754 
1755   Input Parameters:
1756 + snes - the SNES object
1757 . dm   - the DM
1758 . u    - a DM vector
1759 - tol  - A tolerance for the check, or -1 to print the results instead
1760 
1761   Output Parameters:
1762 . residual - The residual norm of the exact solution, or NULL
1763 
1764   Level: developer
1765 
1766 .seealso: DNSNESCheckFromOptions(), DMSNESCheckDiscretization(), DMSNESCheckJacobian()
1767 @*/
1768 PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual)
1769 {
1770   MPI_Comm       comm;
1771   Vec            r;
1772   PetscReal      res;
1773 
1774   PetscFunctionBegin;
1775   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1776   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1777   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1778   if (residual) PetscValidRealPointer(residual, 5);
1779   CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm));
1780   CHKERRQ(DMComputeExactSolution(dm, 0.0, u, NULL));
1781   CHKERRQ(VecDuplicate(u, &r));
1782   CHKERRQ(SNESComputeFunction(snes, u, r));
1783   CHKERRQ(VecNorm(r, NORM_2, &res));
1784   if (tol >= 0.0) {
1785     PetscCheckFalse(res > tol,comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double) res, (double) tol);
1786   } else if (residual) {
1787     *residual = res;
1788   } else {
1789     CHKERRQ(PetscPrintf(comm, "L_2 Residual: %g\n", (double)res));
1790     CHKERRQ(VecChop(r, 1.0e-10));
1791     CHKERRQ(PetscObjectSetName((PetscObject) r, "Initial Residual"));
1792     CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject)r,"res_"));
1793     CHKERRQ(VecViewFromOptions(r, NULL, "-vec_view"));
1794   }
1795   CHKERRQ(VecDestroy(&r));
1796   PetscFunctionReturn(0);
1797 }
1798 
1799 /*@C
1800   DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test
1801 
1802   Input Parameters:
1803 + snes - the SNES object
1804 . dm   - the DM
1805 . u    - a DM vector
1806 - tol  - A tolerance for the check, or -1 to print the results instead
1807 
1808   Output Parameters:
1809 + isLinear - Flag indicaing that the function looks linear, or NULL
1810 - convRate - The rate of convergence of the linear model, or NULL
1811 
1812   Level: developer
1813 
1814 .seealso: DNSNESCheckFromOptions(), DMSNESCheckDiscretization(), DMSNESCheckResidual()
1815 @*/
1816 PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate)
1817 {
1818   MPI_Comm       comm;
1819   PetscDS        ds;
1820   Mat            J, M;
1821   MatNullSpace   nullspace;
1822   PetscReal      slope, intercept;
1823   PetscBool      hasJac, hasPrec, isLin = PETSC_FALSE;
1824 
1825   PetscFunctionBegin;
1826   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1827   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1828   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1829   if (isLinear) PetscValidBoolPointer(isLinear, 5);
1830   if (convRate) PetscValidRealPointer(convRate, 6);
1831   CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm));
1832   CHKERRQ(DMComputeExactSolution(dm, 0.0, u, NULL));
1833   /* Create and view matrices */
1834   CHKERRQ(DMCreateMatrix(dm, &J));
1835   CHKERRQ(DMGetDS(dm, &ds));
1836   CHKERRQ(PetscDSHasJacobian(ds, &hasJac));
1837   CHKERRQ(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
1838   if (hasJac && hasPrec) {
1839     CHKERRQ(DMCreateMatrix(dm, &M));
1840     CHKERRQ(SNESComputeJacobian(snes, u, J, M));
1841     CHKERRQ(PetscObjectSetName((PetscObject) M, "Preconditioning Matrix"));
1842     CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) M, "jacpre_"));
1843     CHKERRQ(MatViewFromOptions(M, NULL, "-mat_view"));
1844     CHKERRQ(MatDestroy(&M));
1845   } else {
1846     CHKERRQ(SNESComputeJacobian(snes, u, J, J));
1847   }
1848   CHKERRQ(PetscObjectSetName((PetscObject) J, "Jacobian"));
1849   CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) J, "jac_"));
1850   CHKERRQ(MatViewFromOptions(J, NULL, "-mat_view"));
1851   /* Check nullspace */
1852   CHKERRQ(MatGetNullSpace(J, &nullspace));
1853   if (nullspace) {
1854     PetscBool isNull;
1855     CHKERRQ(MatNullSpaceTest(nullspace, J, &isNull));
1856     PetscCheckFalse(!isNull,comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid.");
1857   }
1858   /* Taylor test */
1859   {
1860     PetscRandom rand;
1861     Vec         du, uhat, r, rhat, df;
1862     PetscReal   h;
1863     PetscReal  *es, *hs, *errors;
1864     PetscReal   hMax = 1.0, hMin = 1e-6, hMult = 0.1;
1865     PetscInt    Nv, v;
1866 
1867     /* Choose a perturbation direction */
1868     CHKERRQ(PetscRandomCreate(comm, &rand));
1869     CHKERRQ(VecDuplicate(u, &du));
1870     CHKERRQ(VecSetRandom(du, rand));
1871     CHKERRQ(PetscRandomDestroy(&rand));
1872     CHKERRQ(VecDuplicate(u, &df));
1873     CHKERRQ(MatMult(J, du, df));
1874     /* Evaluate residual at u, F(u), save in vector r */
1875     CHKERRQ(VecDuplicate(u, &r));
1876     CHKERRQ(SNESComputeFunction(snes, u, r));
1877     /* Look at the convergence of our Taylor approximation as we approach u */
1878     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv);
1879     CHKERRQ(PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors));
1880     CHKERRQ(VecDuplicate(u, &uhat));
1881     CHKERRQ(VecDuplicate(u, &rhat));
1882     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) {
1883       CHKERRQ(VecWAXPY(uhat, h, du, u));
1884       /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */
1885       CHKERRQ(SNESComputeFunction(snes, uhat, rhat));
1886       CHKERRQ(VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df));
1887       CHKERRQ(VecNorm(rhat, NORM_2, &errors[Nv]));
1888 
1889       es[Nv] = PetscLog10Real(errors[Nv]);
1890       hs[Nv] = PetscLog10Real(h);
1891     }
1892     CHKERRQ(VecDestroy(&uhat));
1893     CHKERRQ(VecDestroy(&rhat));
1894     CHKERRQ(VecDestroy(&df));
1895     CHKERRQ(VecDestroy(&r));
1896     CHKERRQ(VecDestroy(&du));
1897     for (v = 0; v < Nv; ++v) {
1898       if ((tol >= 0) && (errors[v] > tol)) break;
1899       else if (errors[v] > PETSC_SMALL)    break;
1900     }
1901     if (v == Nv) isLin = PETSC_TRUE;
1902     CHKERRQ(PetscLinearRegression(Nv, hs, es, &slope, &intercept));
1903     CHKERRQ(PetscFree3(es, hs, errors));
1904     /* Slope should be about 2 */
1905     if (tol >= 0) {
1906       PetscCheckFalse(!isLin && PetscAbsReal(2 - slope) > tol,comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double) slope);
1907     } else if (isLinear || convRate) {
1908       if (isLinear) *isLinear = isLin;
1909       if (convRate) *convRate = slope;
1910     } else {
1911       if (!isLin) CHKERRQ(PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double) slope));
1912       else        CHKERRQ(PetscPrintf(comm, "Function appears to be linear\n"));
1913     }
1914   }
1915   CHKERRQ(MatDestroy(&J));
1916   PetscFunctionReturn(0);
1917 }
1918 
1919 PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u)
1920 {
1921   PetscFunctionBegin;
1922   CHKERRQ(DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL));
1923   CHKERRQ(DMSNESCheckResidual(snes, dm, u, -1.0, NULL));
1924   CHKERRQ(DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL));
1925   PetscFunctionReturn(0);
1926 }
1927 
1928 /*@C
1929   DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information
1930 
1931   Input Parameters:
1932 + snes - the SNES object
1933 - u    - representative SNES vector
1934 
1935   Note: The user must call PetscDSSetExactSolution() beforehand
1936 
1937   Level: developer
1938 @*/
1939 PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u)
1940 {
1941   DM             dm;
1942   Vec            sol;
1943   PetscBool      check;
1944 
1945   PetscFunctionBegin;
1946   CHKERRQ(PetscOptionsHasName(((PetscObject)snes)->options,((PetscObject)snes)->prefix, "-dmsnes_check", &check));
1947   if (!check) PetscFunctionReturn(0);
1948   CHKERRQ(SNESGetDM(snes, &dm));
1949   CHKERRQ(VecDuplicate(u, &sol));
1950   CHKERRQ(SNESSetSolution(snes, sol));
1951   CHKERRQ(DMSNESCheck_Internal(snes, dm, sol));
1952   CHKERRQ(VecDestroy(&sol));
1953   PetscFunctionReturn(0);
1954 }
1955