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