xref: /petsc/src/snes/utils/dmplexsnes.c (revision 28b400f66ebc7ae0049166a2294dfcd3df27e64b)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I "petscdmplex.h" I*/
2af0996ceSBarry Smith #include <petsc/private/snesimpl.h>     /*I "petscsnes.h"   I*/
324cdb843SMatthew G. Knepley #include <petscds.h>
4af0996ceSBarry Smith #include <petsc/private/petscimpl.h>
5af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
6552f7358SJed Brown 
7649ef022SMatthew Knepley static void pressure_Private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8649ef022SMatthew Knepley                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9649ef022SMatthew Knepley                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
10649ef022SMatthew Knepley                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar p[])
11649ef022SMatthew Knepley {
12649ef022SMatthew Knepley   p[0] = u[uOff[1]];
13649ef022SMatthew Knepley }
14649ef022SMatthew Knepley 
15649ef022SMatthew Knepley /*
16649ef022SMatthew Knepley   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.
17649ef022SMatthew Knepley 
18649ef022SMatthew Knepley   Collective on SNES
19649ef022SMatthew Knepley 
20649ef022SMatthew Knepley   Input Parameters:
21649ef022SMatthew Knepley + snes      - The SNES
22649ef022SMatthew Knepley . pfield    - The field number for pressure
23649ef022SMatthew Knepley . nullspace - The pressure nullspace
24649ef022SMatthew Knepley . u         - The solution vector
25649ef022SMatthew Knepley - ctx       - An optional user context
26649ef022SMatthew Knepley 
27649ef022SMatthew Knepley   Output Parameter:
28649ef022SMatthew Knepley . u         - The solution with a continuum pressure integral of zero
29649ef022SMatthew Knepley 
30649ef022SMatthew Knepley   Notes:
31649ef022SMatthew Knepley   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.
32649ef022SMatthew Knepley 
33649ef022SMatthew Knepley   Level: developer
34649ef022SMatthew Knepley 
35649ef022SMatthew Knepley .seealso: SNESConvergedCorrectPressure()
36649ef022SMatthew Knepley */
37649ef022SMatthew Knepley static PetscErrorCode SNESCorrectDiscretePressure_Private(SNES snes, PetscInt pfield, MatNullSpace nullspace, Vec u, void *ctx)
38649ef022SMatthew Knepley {
39649ef022SMatthew Knepley   DM             dm;
40649ef022SMatthew Knepley   PetscDS        ds;
41649ef022SMatthew Knepley   const Vec     *nullvecs;
42649ef022SMatthew Knepley   PetscScalar    pintd, *intc, *intn;
43649ef022SMatthew Knepley   MPI_Comm       comm;
44649ef022SMatthew Knepley   PetscInt       Nf, Nv;
45649ef022SMatthew Knepley 
46649ef022SMatthew Knepley   PetscFunctionBegin;
475f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm));
485f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetDM(snes, &dm));
49*28b400f6SJacob Faibussowitsch   PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a SNES DM");
50*28b400f6SJacob Faibussowitsch   PetscCheck(nullspace,comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a Jacobian nullspace");
515f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(dm, &ds));
525f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSSetObjective(ds, pfield, pressure_Private));
535f80ce2aSJacob Faibussowitsch   CHKERRQ(MatNullSpaceGetVecs(nullspace, NULL, &Nv, &nullvecs));
542c71b3e2SJacob Faibussowitsch   PetscCheckFalse(Nv != 1,comm, PETSC_ERR_ARG_OUTOFRANGE, "Can only handle a single null vector for pressure, not %D", Nv);
555f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDot(nullvecs[0], u, &pintd));
562c71b3e2SJacob Faibussowitsch   PetscCheckFalse(PetscAbsScalar(pintd) > PETSC_SMALL,comm, PETSC_ERR_ARG_WRONG, "Discrete integral of pressure: %g", (double) PetscRealPart(pintd));
575f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSGetNumFields(ds, &Nf));
585f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(Nf, &intc, Nf, &intn));
595f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexComputeIntegralFEM(dm, nullvecs[0], intn, ctx));
605f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexComputeIntegralFEM(dm, u, intc, ctx));
615f80ce2aSJacob Faibussowitsch   CHKERRQ(VecAXPY(u, -intc[pfield]/intn[pfield], nullvecs[0]));
62649ef022SMatthew Knepley #if defined (PETSC_USE_DEBUG)
635f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexComputeIntegralFEM(dm, u, intc, ctx));
642c71b3e2SJacob Faibussowitsch   PetscCheckFalse(PetscAbsScalar(intc[pfield]) > PETSC_SMALL,comm, PETSC_ERR_ARG_WRONG, "Continuum integral of pressure after correction: %g", (double) PetscRealPart(intc[pfield]));
65649ef022SMatthew Knepley #endif
665f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(intc, intn));
67649ef022SMatthew Knepley   PetscFunctionReturn(0);
68649ef022SMatthew Knepley }
69649ef022SMatthew Knepley 
70649ef022SMatthew Knepley /*@C
71649ef022SMatthew Knepley    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().
72649ef022SMatthew Knepley 
73649ef022SMatthew Knepley    Logically Collective on SNES
74649ef022SMatthew Knepley 
75649ef022SMatthew Knepley    Input Parameters:
76649ef022SMatthew Knepley +  snes - the SNES context
77649ef022SMatthew Knepley .  it - the iteration (0 indicates before any Newton steps)
78649ef022SMatthew Knepley .  xnorm - 2-norm of current iterate
79649ef022SMatthew Knepley .  snorm - 2-norm of current step
80649ef022SMatthew Knepley .  fnorm - 2-norm of function at current iterate
81649ef022SMatthew Knepley -  ctx   - Optional user context
82649ef022SMatthew Knepley 
83649ef022SMatthew Knepley    Output Parameter:
84649ef022SMatthew Knepley .  reason  - SNES_CONVERGED_ITERATING, SNES_CONVERGED_ITS, or SNES_DIVERGED_FNORM_NAN
85649ef022SMatthew Knepley 
86649ef022SMatthew Knepley    Notes:
87649ef022SMatthew Knepley    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.
88649ef022SMatthew Knepley 
89649ef022SMatthew Knepley    Level: advanced
90649ef022SMatthew Knepley 
91649ef022SMatthew Knepley .seealso: SNESConvergedDefault(), SNESSetConvergenceTest(), DMSetNullSpaceConstructor()
92649ef022SMatthew Knepley @*/
93649ef022SMatthew Knepley PetscErrorCode SNESConvergedCorrectPressure(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, void *ctx)
94649ef022SMatthew Knepley {
95649ef022SMatthew Knepley   PetscBool      monitorIntegral = PETSC_FALSE;
96649ef022SMatthew Knepley 
97649ef022SMatthew Knepley   PetscFunctionBegin;
985f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESConvergedDefault(snes, it, xnorm, gnorm, f, reason, ctx));
99649ef022SMatthew Knepley   if (monitorIntegral) {
100649ef022SMatthew Knepley     Mat          J;
101649ef022SMatthew Knepley     Vec          u;
102649ef022SMatthew Knepley     MatNullSpace nullspace;
103649ef022SMatthew Knepley     const Vec   *nullvecs;
104649ef022SMatthew Knepley     PetscScalar  pintd;
105649ef022SMatthew Knepley 
1065f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESGetSolution(snes, &u));
1075f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
1085f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetNullSpace(J, &nullspace));
1095f80ce2aSJacob Faibussowitsch     CHKERRQ(MatNullSpaceGetVecs(nullspace, NULL, NULL, &nullvecs));
1105f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDot(nullvecs[0], u, &pintd));
1115f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscInfo(snes, "SNES: Discrete integral of pressure: %g\n", (double) PetscRealPart(pintd)));
112649ef022SMatthew Knepley   }
113649ef022SMatthew Knepley   if (*reason > 0) {
114649ef022SMatthew Knepley     Mat          J;
115649ef022SMatthew Knepley     Vec          u;
116649ef022SMatthew Knepley     MatNullSpace nullspace;
117649ef022SMatthew Knepley     PetscInt     pfield = 1;
118649ef022SMatthew Knepley 
1195f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESGetSolution(snes, &u));
1205f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
1215f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetNullSpace(J, &nullspace));
1225f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESCorrectDiscretePressure_Private(snes, pfield, nullspace, u, ctx));
123649ef022SMatthew Knepley   }
124649ef022SMatthew Knepley   PetscFunctionReturn(0);
125649ef022SMatthew Knepley }
126649ef022SMatthew Knepley 
12724cdb843SMatthew G. Knepley /************************** Interpolation *******************************/
12824cdb843SMatthew G. Knepley 
1296da023fcSToby Isaac static PetscErrorCode DMSNESConvertPlex(DM dm, DM *plex, PetscBool copy)
1306da023fcSToby Isaac {
1316da023fcSToby Isaac   PetscBool      isPlex;
1326da023fcSToby Isaac 
1336da023fcSToby Isaac   PetscFunctionBegin;
1345f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex));
1356da023fcSToby Isaac   if (isPlex) {
1366da023fcSToby Isaac     *plex = dm;
1375f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject) dm));
138f7148743SMatthew G. Knepley   } else {
1395f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex));
140f7148743SMatthew G. Knepley     if (!*plex) {
1415f80ce2aSJacob Faibussowitsch       CHKERRQ(DMConvert(dm,DMPLEX,plex));
1425f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex));
1436da023fcSToby Isaac       if (copy) {
1445f80ce2aSJacob Faibussowitsch         CHKERRQ(DMCopyDMSNES(dm, *plex));
1455f80ce2aSJacob Faibussowitsch         CHKERRQ(DMCopyAuxiliaryVec(dm, *plex));
1466da023fcSToby Isaac       }
147f7148743SMatthew G. Knepley     } else {
1485f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectReference((PetscObject) *plex));
149f7148743SMatthew G. Knepley     }
1506da023fcSToby Isaac   }
1516da023fcSToby Isaac   PetscFunctionReturn(0);
1526da023fcSToby Isaac }
1536da023fcSToby Isaac 
1544267b1a3SMatthew G. Knepley /*@C
1554267b1a3SMatthew G. Knepley   DMInterpolationCreate - Creates a DMInterpolationInfo context
1564267b1a3SMatthew G. Knepley 
157d083f849SBarry Smith   Collective
1584267b1a3SMatthew G. Knepley 
1594267b1a3SMatthew G. Knepley   Input Parameter:
1604267b1a3SMatthew G. Knepley . comm - the communicator
1614267b1a3SMatthew G. Knepley 
1624267b1a3SMatthew G. Knepley   Output Parameter:
1634267b1a3SMatthew G. Knepley . ctx - the context
1644267b1a3SMatthew G. Knepley 
1654267b1a3SMatthew G. Knepley   Level: beginner
1664267b1a3SMatthew G. Knepley 
1674267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationDestroy()
1684267b1a3SMatthew G. Knepley @*/
1690adebc6cSBarry Smith PetscErrorCode DMInterpolationCreate(MPI_Comm comm, DMInterpolationInfo *ctx)
1700adebc6cSBarry Smith {
171552f7358SJed Brown   PetscFunctionBegin;
172552f7358SJed Brown   PetscValidPointer(ctx, 2);
1735f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscNew(ctx));
1741aa26658SKarl Rupp 
175552f7358SJed Brown   (*ctx)->comm   = comm;
176552f7358SJed Brown   (*ctx)->dim    = -1;
177552f7358SJed Brown   (*ctx)->nInput = 0;
1780298fd71SBarry Smith   (*ctx)->points = NULL;
1790298fd71SBarry Smith   (*ctx)->cells  = NULL;
180552f7358SJed Brown   (*ctx)->n      = -1;
1810298fd71SBarry Smith   (*ctx)->coords = NULL;
182552f7358SJed Brown   PetscFunctionReturn(0);
183552f7358SJed Brown }
184552f7358SJed Brown 
1854267b1a3SMatthew G. Knepley /*@C
1864267b1a3SMatthew G. Knepley   DMInterpolationSetDim - Sets the spatial dimension for the interpolation context
1874267b1a3SMatthew G. Knepley 
1884267b1a3SMatthew G. Knepley   Not collective
1894267b1a3SMatthew G. Knepley 
1904267b1a3SMatthew G. Knepley   Input Parameters:
1914267b1a3SMatthew G. Knepley + ctx - the context
1924267b1a3SMatthew G. Knepley - dim - the spatial dimension
1934267b1a3SMatthew G. Knepley 
1944267b1a3SMatthew G. Knepley   Level: intermediate
1954267b1a3SMatthew G. Knepley 
1964267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetDim(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
1974267b1a3SMatthew G. Knepley @*/
1980adebc6cSBarry Smith PetscErrorCode DMInterpolationSetDim(DMInterpolationInfo ctx, PetscInt dim)
1990adebc6cSBarry Smith {
200552f7358SJed Brown   PetscFunctionBegin;
2012c71b3e2SJacob Faibussowitsch   PetscCheckFalse((dim < 1) || (dim > 3),ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension for points: %D", dim);
202552f7358SJed Brown   ctx->dim = dim;
203552f7358SJed Brown   PetscFunctionReturn(0);
204552f7358SJed Brown }
205552f7358SJed Brown 
2064267b1a3SMatthew G. Knepley /*@C
2074267b1a3SMatthew G. Knepley   DMInterpolationGetDim - Gets the spatial dimension for the interpolation context
2084267b1a3SMatthew G. Knepley 
2094267b1a3SMatthew G. Knepley   Not collective
2104267b1a3SMatthew G. Knepley 
2114267b1a3SMatthew G. Knepley   Input Parameter:
2124267b1a3SMatthew G. Knepley . ctx - the context
2134267b1a3SMatthew G. Knepley 
2144267b1a3SMatthew G. Knepley   Output Parameter:
2154267b1a3SMatthew G. Knepley . dim - the spatial dimension
2164267b1a3SMatthew G. Knepley 
2174267b1a3SMatthew G. Knepley   Level: intermediate
2184267b1a3SMatthew G. Knepley 
2194267b1a3SMatthew G. Knepley .seealso: DMInterpolationSetDim(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
2204267b1a3SMatthew G. Knepley @*/
2210adebc6cSBarry Smith PetscErrorCode DMInterpolationGetDim(DMInterpolationInfo ctx, PetscInt *dim)
2220adebc6cSBarry Smith {
223552f7358SJed Brown   PetscFunctionBegin;
224552f7358SJed Brown   PetscValidIntPointer(dim, 2);
225552f7358SJed Brown   *dim = ctx->dim;
226552f7358SJed Brown   PetscFunctionReturn(0);
227552f7358SJed Brown }
228552f7358SJed Brown 
2294267b1a3SMatthew G. Knepley /*@C
2304267b1a3SMatthew G. Knepley   DMInterpolationSetDof - Sets the number of fields interpolated at a point for the interpolation context
2314267b1a3SMatthew G. Knepley 
2324267b1a3SMatthew G. Knepley   Not collective
2334267b1a3SMatthew G. Knepley 
2344267b1a3SMatthew G. Knepley   Input Parameters:
2354267b1a3SMatthew G. Knepley + ctx - the context
2364267b1a3SMatthew G. Knepley - dof - the number of fields
2374267b1a3SMatthew G. Knepley 
2384267b1a3SMatthew G. Knepley   Level: intermediate
2394267b1a3SMatthew G. Knepley 
2404267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetDof(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
2414267b1a3SMatthew G. Knepley @*/
2420adebc6cSBarry Smith PetscErrorCode DMInterpolationSetDof(DMInterpolationInfo ctx, PetscInt dof)
2430adebc6cSBarry Smith {
244552f7358SJed Brown   PetscFunctionBegin;
2452c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dof < 1,ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of components: %D", dof);
246552f7358SJed Brown   ctx->dof = dof;
247552f7358SJed Brown   PetscFunctionReturn(0);
248552f7358SJed Brown }
249552f7358SJed Brown 
2504267b1a3SMatthew G. Knepley /*@C
2514267b1a3SMatthew G. Knepley   DMInterpolationGetDof - Gets the number of fields interpolated at a point for the interpolation context
2524267b1a3SMatthew G. Knepley 
2534267b1a3SMatthew G. Knepley   Not collective
2544267b1a3SMatthew G. Knepley 
2554267b1a3SMatthew G. Knepley   Input Parameter:
2564267b1a3SMatthew G. Knepley . ctx - the context
2574267b1a3SMatthew G. Knepley 
2584267b1a3SMatthew G. Knepley   Output Parameter:
2594267b1a3SMatthew G. Knepley . dof - the number of fields
2604267b1a3SMatthew G. Knepley 
2614267b1a3SMatthew G. Knepley   Level: intermediate
2624267b1a3SMatthew G. Knepley 
2634267b1a3SMatthew G. Knepley .seealso: DMInterpolationSetDof(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
2644267b1a3SMatthew G. Knepley @*/
2650adebc6cSBarry Smith PetscErrorCode DMInterpolationGetDof(DMInterpolationInfo ctx, PetscInt *dof)
2660adebc6cSBarry Smith {
267552f7358SJed Brown   PetscFunctionBegin;
268552f7358SJed Brown   PetscValidIntPointer(dof, 2);
269552f7358SJed Brown   *dof = ctx->dof;
270552f7358SJed Brown   PetscFunctionReturn(0);
271552f7358SJed Brown }
272552f7358SJed Brown 
2734267b1a3SMatthew G. Knepley /*@C
2744267b1a3SMatthew G. Knepley   DMInterpolationAddPoints - Add points at which we will interpolate the fields
2754267b1a3SMatthew G. Knepley 
2764267b1a3SMatthew G. Knepley   Not collective
2774267b1a3SMatthew G. Knepley 
2784267b1a3SMatthew G. Knepley   Input Parameters:
2794267b1a3SMatthew G. Knepley + ctx    - the context
2804267b1a3SMatthew G. Knepley . n      - the number of points
2814267b1a3SMatthew G. Knepley - points - the coordinates for each point, an array of size n * dim
2824267b1a3SMatthew G. Knepley 
2834267b1a3SMatthew G. Knepley   Note: The coordinate information is copied.
2844267b1a3SMatthew G. Knepley 
2854267b1a3SMatthew G. Knepley   Level: intermediate
2864267b1a3SMatthew G. Knepley 
2874267b1a3SMatthew G. Knepley .seealso: DMInterpolationSetDim(), DMInterpolationEvaluate(), DMInterpolationCreate()
2884267b1a3SMatthew G. Knepley @*/
2890adebc6cSBarry Smith PetscErrorCode DMInterpolationAddPoints(DMInterpolationInfo ctx, PetscInt n, PetscReal points[])
2900adebc6cSBarry Smith {
291552f7358SJed Brown   PetscFunctionBegin;
2922c71b3e2SJacob Faibussowitsch   PetscCheckFalse(ctx->dim < 0,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
293*28b400f6SJacob Faibussowitsch   PetscCheck(!ctx->points,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot add points multiple times yet");
294552f7358SJed Brown   ctx->nInput = n;
2951aa26658SKarl Rupp 
2965f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(n*ctx->dim, &ctx->points));
2975f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscArraycpy(ctx->points, points, n*ctx->dim));
298552f7358SJed Brown   PetscFunctionReturn(0);
299552f7358SJed Brown }
300552f7358SJed Brown 
3014267b1a3SMatthew G. Knepley /*@C
30252aa1562SMatthew G. Knepley   DMInterpolationSetUp - Compute spatial indices for point location during interpolation
3034267b1a3SMatthew G. Knepley 
3044267b1a3SMatthew G. Knepley   Collective on ctx
3054267b1a3SMatthew G. Knepley 
3064267b1a3SMatthew G. Knepley   Input Parameters:
3074267b1a3SMatthew G. Knepley + ctx - the context
3084267b1a3SMatthew G. Knepley . dm  - the DM for the function space used for interpolation
30952aa1562SMatthew G. Knepley . redundantPoints - If PETSC_TRUE, all processes are passing in the same array of points. Otherwise, points need to be communicated among processes.
3107deeda50SSatish Balay - ignoreOutsideDomain - If PETSC_TRUE, ignore points outside the domain, otherwise return an error
3114267b1a3SMatthew G. Knepley 
3124267b1a3SMatthew G. Knepley   Level: intermediate
3134267b1a3SMatthew G. Knepley 
3144267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
3154267b1a3SMatthew G. Knepley @*/
31652aa1562SMatthew G. Knepley PetscErrorCode DMInterpolationSetUp(DMInterpolationInfo ctx, DM dm, PetscBool redundantPoints, PetscBool ignoreOutsideDomain)
3170adebc6cSBarry Smith {
318552f7358SJed Brown   MPI_Comm          comm = ctx->comm;
319552f7358SJed Brown   PetscScalar       *a;
320552f7358SJed Brown   PetscInt          p, q, i;
321552f7358SJed Brown   PetscMPIInt       rank, size;
322552f7358SJed Brown   Vec               pointVec;
3233a93e3b7SToby Isaac   PetscSF           cellSF;
324552f7358SJed Brown   PetscLayout       layout;
325552f7358SJed Brown   PetscReal         *globalPoints;
326cb313848SJed Brown   PetscScalar       *globalPointsScalar;
327552f7358SJed Brown   const PetscInt    *ranges;
328552f7358SJed Brown   PetscMPIInt       *counts, *displs;
3293a93e3b7SToby Isaac   const PetscSFNode *foundCells;
3303a93e3b7SToby Isaac   const PetscInt    *foundPoints;
331552f7358SJed Brown   PetscMPIInt       *foundProcs, *globalProcs;
3323a93e3b7SToby Isaac   PetscInt          n, N, numFound;
333552f7358SJed Brown 
33419436ca2SJed Brown   PetscFunctionBegin;
335064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
3365f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_size(comm, &size));
3375f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm, &rank));
3382c71b3e2SJacob Faibussowitsch   PetscCheckFalse(ctx->dim < 0,comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
33919436ca2SJed Brown   /* Locate points */
34019436ca2SJed Brown   n = ctx->nInput;
341552f7358SJed Brown   if (!redundantPoints) {
3425f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLayoutCreate(comm, &layout));
3435f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLayoutSetBlockSize(layout, 1));
3445f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLayoutSetLocalSize(layout, n));
3455f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLayoutSetUp(layout));
3465f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLayoutGetSize(layout, &N));
347552f7358SJed Brown     /* Communicate all points to all processes */
3485f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc3(N*ctx->dim,&globalPoints,size,&counts,size,&displs));
3495f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLayoutGetRanges(layout, &ranges));
350552f7358SJed Brown     for (p = 0; p < size; ++p) {
351552f7358SJed Brown       counts[p] = (ranges[p+1] - ranges[p])*ctx->dim;
352552f7358SJed Brown       displs[p] = ranges[p]*ctx->dim;
353552f7358SJed Brown     }
3545f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Allgatherv(ctx->points, n*ctx->dim, MPIU_REAL, globalPoints, counts, displs, MPIU_REAL, comm));
355552f7358SJed Brown   } else {
356552f7358SJed Brown     N = n;
357552f7358SJed Brown     globalPoints = ctx->points;
35838ea73c8SJed Brown     counts = displs = NULL;
35938ea73c8SJed Brown     layout = NULL;
360552f7358SJed Brown   }
361552f7358SJed Brown #if 0
3625f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc3(N,&foundCells,N,&foundProcs,N,&globalProcs));
36319436ca2SJed Brown   /* foundCells[p] = m->locatePoint(&globalPoints[p*ctx->dim]); */
364552f7358SJed Brown #else
365cb313848SJed Brown #if defined(PETSC_USE_COMPLEX)
3665f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(N*ctx->dim,&globalPointsScalar));
36746b3086cSToby Isaac   for (i=0; i<N*ctx->dim; i++) globalPointsScalar[i] = globalPoints[i];
368cb313848SJed Brown #else
369cb313848SJed Brown   globalPointsScalar = globalPoints;
370cb313848SJed Brown #endif
3715f80ce2aSJacob Faibussowitsch   CHKERRQ(VecCreateSeqWithArray(PETSC_COMM_SELF, ctx->dim, N*ctx->dim, globalPointsScalar, &pointVec));
3725f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(N,&foundProcs,N,&globalProcs));
3737b5f2079SMatthew G. Knepley   for (p = 0; p < N; ++p) {foundProcs[p] = size;}
3743a93e3b7SToby Isaac   cellSF = NULL;
3755f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLocatePoints(dm, pointVec, DM_POINTLOCATION_REMOVE, &cellSF));
3765f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFGetGraph(cellSF,NULL,&numFound,&foundPoints,&foundCells));
377552f7358SJed Brown #endif
3783a93e3b7SToby Isaac   for (p = 0; p < numFound; ++p) {
3793a93e3b7SToby Isaac     if (foundCells[p].index >= 0) foundProcs[foundPoints ? foundPoints[p] : p] = rank;
380552f7358SJed Brown   }
381552f7358SJed Brown   /* Let the lowest rank process own each point */
3825f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPIU_Allreduce(foundProcs, globalProcs, N, MPI_INT, MPI_MIN, comm));
383552f7358SJed Brown   ctx->n = 0;
384552f7358SJed Brown   for (p = 0; p < N; ++p) {
38552aa1562SMatthew G. Knepley     if (globalProcs[p] == size) {
386*28b400f6SJacob Faibussowitsch       PetscCheck(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));
387dd400576SPatrick Sanan       else if (rank == 0) ++ctx->n;
38852aa1562SMatthew G. Knepley     } else if (globalProcs[p] == rank) ++ctx->n;
389552f7358SJed Brown   }
390552f7358SJed Brown   /* Create coordinates vector and array of owned cells */
3915f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(ctx->n, &ctx->cells));
3925f80ce2aSJacob Faibussowitsch   CHKERRQ(VecCreate(comm, &ctx->coords));
3935f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetSizes(ctx->coords, ctx->n*ctx->dim, PETSC_DECIDE));
3945f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetBlockSize(ctx->coords, ctx->dim));
3955f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetType(ctx->coords,VECSTANDARD));
3965f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(ctx->coords, &a));
397552f7358SJed Brown   for (p = 0, q = 0, i = 0; p < N; ++p) {
398552f7358SJed Brown     if (globalProcs[p] == rank) {
399552f7358SJed Brown       PetscInt d;
400552f7358SJed Brown 
4011aa26658SKarl Rupp       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = globalPoints[p*ctx->dim+d];
402f317b747SMatthew G. Knepley       ctx->cells[q] = foundCells[q].index;
403f317b747SMatthew G. Knepley       ++q;
404552f7358SJed Brown     }
405dd400576SPatrick Sanan     if (globalProcs[p] == size && rank == 0) {
40652aa1562SMatthew G. Knepley       PetscInt d;
40752aa1562SMatthew G. Knepley 
40852aa1562SMatthew G. Knepley       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = 0.;
40952aa1562SMatthew G. Knepley       ctx->cells[q] = -1;
41052aa1562SMatthew G. Knepley       ++q;
41152aa1562SMatthew G. Knepley     }
412552f7358SJed Brown   }
4135f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(ctx->coords, &a));
414552f7358SJed Brown #if 0
4155f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree3(foundCells,foundProcs,globalProcs));
416552f7358SJed Brown #else
4175f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(foundProcs,globalProcs));
4185f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFDestroy(&cellSF));
4195f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&pointVec));
420552f7358SJed Brown #endif
4215f80ce2aSJacob Faibussowitsch   if ((void*)globalPointsScalar != (void*)globalPoints) CHKERRQ(PetscFree(globalPointsScalar));
4225f80ce2aSJacob Faibussowitsch   if (!redundantPoints) CHKERRQ(PetscFree3(globalPoints,counts,displs));
4235f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutDestroy(&layout));
424552f7358SJed Brown   PetscFunctionReturn(0);
425552f7358SJed Brown }
426552f7358SJed Brown 
4274267b1a3SMatthew G. Knepley /*@C
4284267b1a3SMatthew G. Knepley   DMInterpolationGetCoordinates - Gets a Vec with the coordinates of each interpolation point
4294267b1a3SMatthew G. Knepley 
4304267b1a3SMatthew G. Knepley   Collective on ctx
4314267b1a3SMatthew G. Knepley 
4324267b1a3SMatthew G. Knepley   Input Parameter:
4334267b1a3SMatthew G. Knepley . ctx - the context
4344267b1a3SMatthew G. Knepley 
4354267b1a3SMatthew G. Knepley   Output Parameter:
4364267b1a3SMatthew G. Knepley . coordinates  - the coordinates of interpolation points
4374267b1a3SMatthew G. Knepley 
4384267b1a3SMatthew G. Knepley   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.
4394267b1a3SMatthew G. Knepley 
4404267b1a3SMatthew G. Knepley   Level: intermediate
4414267b1a3SMatthew G. Knepley 
4424267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
4434267b1a3SMatthew G. Knepley @*/
4440adebc6cSBarry Smith PetscErrorCode DMInterpolationGetCoordinates(DMInterpolationInfo ctx, Vec *coordinates)
4450adebc6cSBarry Smith {
446552f7358SJed Brown   PetscFunctionBegin;
447552f7358SJed Brown   PetscValidPointer(coordinates, 2);
448*28b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
449552f7358SJed Brown   *coordinates = ctx->coords;
450552f7358SJed Brown   PetscFunctionReturn(0);
451552f7358SJed Brown }
452552f7358SJed Brown 
4534267b1a3SMatthew G. Knepley /*@C
4544267b1a3SMatthew G. Knepley   DMInterpolationGetVector - Gets a Vec which can hold all the interpolated field values
4554267b1a3SMatthew G. Knepley 
4564267b1a3SMatthew G. Knepley   Collective on ctx
4574267b1a3SMatthew G. Knepley 
4584267b1a3SMatthew G. Knepley   Input Parameter:
4594267b1a3SMatthew G. Knepley . ctx - the context
4604267b1a3SMatthew G. Knepley 
4614267b1a3SMatthew G. Knepley   Output Parameter:
4624267b1a3SMatthew G. Knepley . v  - a vector capable of holding the interpolated field values
4634267b1a3SMatthew G. Knepley 
4644267b1a3SMatthew G. Knepley   Note: This vector should be returned using DMInterpolationRestoreVector().
4654267b1a3SMatthew G. Knepley 
4664267b1a3SMatthew G. Knepley   Level: intermediate
4674267b1a3SMatthew G. Knepley 
4684267b1a3SMatthew G. Knepley .seealso: DMInterpolationRestoreVector(), DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
4694267b1a3SMatthew G. Knepley @*/
4700adebc6cSBarry Smith PetscErrorCode DMInterpolationGetVector(DMInterpolationInfo ctx, Vec *v)
4710adebc6cSBarry Smith {
472552f7358SJed Brown   PetscFunctionBegin;
473552f7358SJed Brown   PetscValidPointer(v, 2);
474*28b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
4755f80ce2aSJacob Faibussowitsch   CHKERRQ(VecCreate(ctx->comm, v));
4765f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetSizes(*v, ctx->n*ctx->dof, PETSC_DECIDE));
4775f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetBlockSize(*v, ctx->dof));
4785f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetType(*v,VECSTANDARD));
479552f7358SJed Brown   PetscFunctionReturn(0);
480552f7358SJed Brown }
481552f7358SJed Brown 
4824267b1a3SMatthew G. Knepley /*@C
4834267b1a3SMatthew G. Knepley   DMInterpolationRestoreVector - Returns a Vec which can hold all the interpolated field values
4844267b1a3SMatthew G. Knepley 
4854267b1a3SMatthew G. Knepley   Collective on ctx
4864267b1a3SMatthew G. Knepley 
4874267b1a3SMatthew G. Knepley   Input Parameters:
4884267b1a3SMatthew G. Knepley + ctx - the context
4894267b1a3SMatthew G. Knepley - v  - a vector capable of holding the interpolated field values
4904267b1a3SMatthew G. Knepley 
4914267b1a3SMatthew G. Knepley   Level: intermediate
4924267b1a3SMatthew G. Knepley 
4934267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetVector(), DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
4944267b1a3SMatthew G. Knepley @*/
4950adebc6cSBarry Smith PetscErrorCode DMInterpolationRestoreVector(DMInterpolationInfo ctx, Vec *v)
4960adebc6cSBarry Smith {
497552f7358SJed Brown   PetscFunctionBegin;
498552f7358SJed Brown   PetscValidPointer(v, 2);
499*28b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
5005f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(v));
501552f7358SJed Brown   PetscFunctionReturn(0);
502552f7358SJed Brown }
503552f7358SJed Brown 
504cfe5744fSMatthew G. Knepley static inline PetscErrorCode DMInterpolate_Segment_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
505cfe5744fSMatthew G. Knepley {
506cfe5744fSMatthew G. Knepley   PetscReal          v0, J, invJ, detJ;
507cfe5744fSMatthew G. Knepley   const PetscInt     dof = ctx->dof;
508cfe5744fSMatthew G. Knepley   const PetscScalar *coords;
509cfe5744fSMatthew G. Knepley   PetscScalar       *a;
510cfe5744fSMatthew G. Knepley   PetscInt           p;
511cfe5744fSMatthew G. Knepley 
512cfe5744fSMatthew G. Knepley   PetscFunctionBegin;
5135f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
5145f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(v, &a));
515cfe5744fSMatthew G. Knepley   for (p = 0; p < ctx->n; ++p) {
516cfe5744fSMatthew G. Knepley     PetscInt     c = ctx->cells[p];
517cfe5744fSMatthew G. Knepley     PetscScalar *x = NULL;
518cfe5744fSMatthew G. Knepley     PetscReal    xir[1];
519cfe5744fSMatthew G. Knepley     PetscInt     xSize, comp;
520cfe5744fSMatthew G. Knepley 
5215f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ));
522cfe5744fSMatthew G. Knepley     PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double) detJ, c);
523cfe5744fSMatthew G. Knepley     xir[0] = invJ*PetscRealPart(coords[p] - v0);
5245f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
525cfe5744fSMatthew G. Knepley     if (2*dof == xSize) {
526cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp]*(1 - xir[0]) + x[1*dof+comp]*xir[0];
527cfe5744fSMatthew G. Knepley     } else if (dof == xSize) {
528cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp];
529cfe5744fSMatthew G. Knepley     } 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);
5305f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
531cfe5744fSMatthew G. Knepley   }
5325f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(v, &a));
5335f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
534cfe5744fSMatthew G. Knepley   PetscFunctionReturn(0);
535cfe5744fSMatthew G. Knepley }
536cfe5744fSMatthew G. Knepley 
5379fbee547SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Triangle_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
538a6dfd86eSKarl Rupp {
539552f7358SJed Brown   PetscReal      *v0, *J, *invJ, detJ;
54056044e6dSMatthew G. Knepley   const PetscScalar *coords;
54156044e6dSMatthew G. Knepley   PetscScalar    *a;
542552f7358SJed Brown   PetscInt       p;
543552f7358SJed Brown 
544552f7358SJed Brown   PetscFunctionBegin;
5455f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc3(ctx->dim,&v0,ctx->dim*ctx->dim,&J,ctx->dim*ctx->dim,&invJ));
5465f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
5475f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(v, &a));
548552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
549552f7358SJed Brown     PetscInt     c = ctx->cells[p];
550a1e44745SMatthew G. Knepley     PetscScalar *x = NULL;
551552f7358SJed Brown     PetscReal    xi[4];
552552f7358SJed Brown     PetscInt     d, f, comp;
553552f7358SJed Brown 
5545f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
5552c71b3e2SJacob Faibussowitsch     PetscCheckFalse(detJ <= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D", (double)detJ, c);
5565f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
5571aa26658SKarl Rupp     for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp];
5581aa26658SKarl Rupp 
559552f7358SJed Brown     for (d = 0; d < ctx->dim; ++d) {
560552f7358SJed Brown       xi[d] = 0.0;
5611aa26658SKarl Rupp       for (f = 0; f < ctx->dim; ++f) xi[d] += invJ[d*ctx->dim+f]*0.5*PetscRealPart(coords[p*ctx->dim+f] - v0[f]);
5621aa26658SKarl Rupp       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];
563552f7358SJed Brown     }
5645f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
565552f7358SJed Brown   }
5665f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(v, &a));
5675f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
5685f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree3(v0, J, invJ));
569552f7358SJed Brown   PetscFunctionReturn(0);
570552f7358SJed Brown }
571552f7358SJed Brown 
5729fbee547SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Tetrahedron_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
5737a1931ceSMatthew G. Knepley {
5747a1931ceSMatthew G. Knepley   PetscReal      *v0, *J, *invJ, detJ;
57556044e6dSMatthew G. Knepley   const PetscScalar *coords;
57656044e6dSMatthew G. Knepley   PetscScalar    *a;
5777a1931ceSMatthew G. Knepley   PetscInt       p;
5787a1931ceSMatthew G. Knepley 
5797a1931ceSMatthew G. Knepley   PetscFunctionBegin;
5805f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc3(ctx->dim,&v0,ctx->dim*ctx->dim,&J,ctx->dim*ctx->dim,&invJ));
5815f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
5825f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(v, &a));
5837a1931ceSMatthew G. Knepley   for (p = 0; p < ctx->n; ++p) {
5847a1931ceSMatthew G. Knepley     PetscInt       c = ctx->cells[p];
5857a1931ceSMatthew G. Knepley     const PetscInt order[3] = {2, 1, 3};
5862584bbe8SMatthew G. Knepley     PetscScalar   *x = NULL;
5877a1931ceSMatthew G. Knepley     PetscReal      xi[4];
5887a1931ceSMatthew G. Knepley     PetscInt       d, f, comp;
5897a1931ceSMatthew G. Knepley 
5905f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
5912c71b3e2SJacob Faibussowitsch     PetscCheckFalse(detJ <= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D", (double)detJ, c);
5925f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
5937a1931ceSMatthew G. Knepley     for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp];
5947a1931ceSMatthew G. Knepley 
5957a1931ceSMatthew G. Knepley     for (d = 0; d < ctx->dim; ++d) {
5967a1931ceSMatthew G. Knepley       xi[d] = 0.0;
5977a1931ceSMatthew G. Knepley       for (f = 0; f < ctx->dim; ++f) xi[d] += invJ[d*ctx->dim+f]*0.5*PetscRealPart(coords[p*ctx->dim+f] - v0[f]);
5987a1931ceSMatthew G. Knepley       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];
5997a1931ceSMatthew G. Knepley     }
6005f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
6017a1931ceSMatthew G. Knepley   }
6025f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(v, &a));
6035f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
6045f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree3(v0, J, invJ));
6057a1931ceSMatthew G. Knepley   PetscFunctionReturn(0);
6067a1931ceSMatthew G. Knepley }
6077a1931ceSMatthew G. Knepley 
6089fbee547SJacob Faibussowitsch static inline PetscErrorCode QuadMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
609552f7358SJed Brown {
610552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
611552f7358SJed Brown   const PetscScalar x0        = vertices[0];
612552f7358SJed Brown   const PetscScalar y0        = vertices[1];
613552f7358SJed Brown   const PetscScalar x1        = vertices[2];
614552f7358SJed Brown   const PetscScalar y1        = vertices[3];
615552f7358SJed Brown   const PetscScalar x2        = vertices[4];
616552f7358SJed Brown   const PetscScalar y2        = vertices[5];
617552f7358SJed Brown   const PetscScalar x3        = vertices[6];
618552f7358SJed Brown   const PetscScalar y3        = vertices[7];
619552f7358SJed Brown   const PetscScalar f_1       = x1 - x0;
620552f7358SJed Brown   const PetscScalar g_1       = y1 - y0;
621552f7358SJed Brown   const PetscScalar f_3       = x3 - x0;
622552f7358SJed Brown   const PetscScalar g_3       = y3 - y0;
623552f7358SJed Brown   const PetscScalar f_01      = x2 - x1 - x3 + x0;
624552f7358SJed Brown   const PetscScalar g_01      = y2 - y1 - y3 + y0;
62556044e6dSMatthew G. Knepley   const PetscScalar *ref;
62656044e6dSMatthew G. Knepley   PetscScalar       *real;
627552f7358SJed Brown 
628552f7358SJed Brown   PetscFunctionBegin;
6295f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(Xref,  &ref));
6305f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(Xreal, &real));
631552f7358SJed Brown   {
632552f7358SJed Brown     const PetscScalar p0 = ref[0];
633552f7358SJed Brown     const PetscScalar p1 = ref[1];
634552f7358SJed Brown 
635552f7358SJed Brown     real[0] = x0 + f_1 * p0 + f_3 * p1 + f_01 * p0 * p1;
636552f7358SJed Brown     real[1] = y0 + g_1 * p0 + g_3 * p1 + g_01 * p0 * p1;
637552f7358SJed Brown   }
6385f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogFlops(28));
6395f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(Xref,  &ref));
6405f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(Xreal, &real));
641552f7358SJed Brown   PetscFunctionReturn(0);
642552f7358SJed Brown }
643552f7358SJed Brown 
644af0996ceSBarry Smith #include <petsc/private/dmimpl.h>
6459fbee547SJacob Faibussowitsch static inline PetscErrorCode QuadJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
646552f7358SJed Brown {
647552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
648552f7358SJed Brown   const PetscScalar x0        = vertices[0];
649552f7358SJed Brown   const PetscScalar y0        = vertices[1];
650552f7358SJed Brown   const PetscScalar x1        = vertices[2];
651552f7358SJed Brown   const PetscScalar y1        = vertices[3];
652552f7358SJed Brown   const PetscScalar x2        = vertices[4];
653552f7358SJed Brown   const PetscScalar y2        = vertices[5];
654552f7358SJed Brown   const PetscScalar x3        = vertices[6];
655552f7358SJed Brown   const PetscScalar y3        = vertices[7];
656552f7358SJed Brown   const PetscScalar f_01      = x2 - x1 - x3 + x0;
657552f7358SJed Brown   const PetscScalar g_01      = y2 - y1 - y3 + y0;
65856044e6dSMatthew G. Knepley   const PetscScalar *ref;
659552f7358SJed Brown 
660552f7358SJed Brown   PetscFunctionBegin;
6615f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(Xref,  &ref));
662552f7358SJed Brown   {
663552f7358SJed Brown     const PetscScalar x       = ref[0];
664552f7358SJed Brown     const PetscScalar y       = ref[1];
665552f7358SJed Brown     const PetscInt    rows[2] = {0, 1};
666da80777bSKarl Rupp     PetscScalar       values[4];
667da80777bSKarl Rupp 
668da80777bSKarl Rupp     values[0] = (x1 - x0 + f_01*y) * 0.5; values[1] = (x3 - x0 + f_01*x) * 0.5;
669da80777bSKarl Rupp     values[2] = (y1 - y0 + g_01*y) * 0.5; values[3] = (y3 - y0 + g_01*x) * 0.5;
6705f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetValues(J, 2, rows, 2, rows, values, INSERT_VALUES));
671552f7358SJed Brown   }
6725f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogFlops(30));
6735f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(Xref,  &ref));
6745f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
6755f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
676552f7358SJed Brown   PetscFunctionReturn(0);
677552f7358SJed Brown }
678552f7358SJed Brown 
6799fbee547SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Quad_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
680a6dfd86eSKarl Rupp {
681fafc0619SMatthew G Knepley   DM                 dmCoord;
682de73a395SMatthew G. Knepley   PetscFE            fem = NULL;
683552f7358SJed Brown   SNES               snes;
684552f7358SJed Brown   KSP                ksp;
685552f7358SJed Brown   PC                 pc;
686552f7358SJed Brown   Vec                coordsLocal, r, ref, real;
687552f7358SJed Brown   Mat                J;
688716009bfSMatthew G. Knepley   PetscTabulation    T = NULL;
68956044e6dSMatthew G. Knepley   const PetscScalar *coords;
69056044e6dSMatthew G. Knepley   PetscScalar        *a;
691716009bfSMatthew G. Knepley   PetscReal          xir[2] = {0., 0.};
692de73a395SMatthew G. Knepley   PetscInt           Nf, p;
6935509d985SMatthew G. Knepley   const PetscInt     dof = ctx->dof;
694552f7358SJed Brown 
695552f7358SJed Brown   PetscFunctionBegin;
6965f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetNumFields(dm, &Nf));
697716009bfSMatthew G. Knepley   if (Nf) {
698cfe5744fSMatthew G. Knepley     PetscObject  obj;
699cfe5744fSMatthew G. Knepley     PetscClassId id;
700cfe5744fSMatthew G. Knepley 
7015f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetField(dm, 0, NULL, &obj));
7025f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectGetClassId(obj, &id));
7035f80ce2aSJacob Faibussowitsch     if (id == PETSCFE_CLASSID) {fem = (PetscFE) obj; CHKERRQ(PetscFECreateTabulation(fem, 1, 1, xir, 0, &T));}
704716009bfSMatthew G. Knepley   }
7055f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinatesLocal(dm, &coordsLocal));
7065f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinateDM(dm, &dmCoord));
7075f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESCreate(PETSC_COMM_SELF, &snes));
7085f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetOptionsPrefix(snes, "quad_interp_"));
7095f80ce2aSJacob Faibussowitsch   CHKERRQ(VecCreate(PETSC_COMM_SELF, &r));
7105f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetSizes(r, 2, 2));
7115f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetType(r,dm->vectype));
7125f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDuplicate(r, &ref));
7135f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDuplicate(r, &real));
7145f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreate(PETSC_COMM_SELF, &J));
7155f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetSizes(J, 2, 2, 2, 2));
7165f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetType(J, MATSEQDENSE));
7175f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetUp(J));
7185f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetFunction(snes, r, QuadMap_Private, NULL));
7195f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetJacobian(snes, J, J, QuadJacobian_Private, NULL));
7205f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetKSP(snes, &ksp));
7215f80ce2aSJacob Faibussowitsch   CHKERRQ(KSPGetPC(ksp, &pc));
7225f80ce2aSJacob Faibussowitsch   CHKERRQ(PCSetType(pc, PCLU));
7235f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetFromOptions(snes));
724552f7358SJed Brown 
7255f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
7265f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(v, &a));
727552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
728a1e44745SMatthew G. Knepley     PetscScalar *x = NULL, *vertices = NULL;
729552f7358SJed Brown     PetscScalar *xi;
730552f7358SJed Brown     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
731552f7358SJed Brown 
732552f7358SJed Brown     /* Can make this do all points at once */
7335f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
7342c71b3e2SJacob Faibussowitsch     PetscCheckFalse(4*2 != coordSize,ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %D should be %d", coordSize, 4*2);
7355f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
7365f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESSetFunction(snes, NULL, NULL, vertices));
7375f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
7385f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArray(real, &xi));
739552f7358SJed Brown     xi[0]  = coords[p*ctx->dim+0];
740552f7358SJed Brown     xi[1]  = coords[p*ctx->dim+1];
7415f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArray(real, &xi));
7425f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESSolve(snes, real, ref));
7435f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArray(ref, &xi));
744cb313848SJed Brown     xir[0] = PetscRealPart(xi[0]);
745cb313848SJed Brown     xir[1] = PetscRealPart(xi[1]);
746cfe5744fSMatthew G. Knepley     if (4*dof == xSize) {
747cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp)
748cfe5744fSMatthew G. Knepley         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];
749cfe5744fSMatthew G. Knepley     } else if (dof == xSize) {
750cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp];
751cfe5744fSMatthew G. Knepley     } else {
7525509d985SMatthew G. Knepley       PetscInt d;
7531aa26658SKarl Rupp 
7542c71b3e2SJacob Faibussowitsch       PetscCheck(fem, ctx->comm, PETSC_ERR_ARG_WRONG, "Cannot have a higher order interpolant if the discretization is not PetscFE");
7555509d985SMatthew G. Knepley       xir[0] = 2.0*xir[0] - 1.0; xir[1] = 2.0*xir[1] - 1.0;
7565f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFEComputeTabulation(fem, 1, xir, 0, T));
7575509d985SMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) {
7585509d985SMatthew G. Knepley         a[p*dof+comp] = 0.0;
7595509d985SMatthew G. Knepley         for (d = 0; d < xSize/dof; ++d) {
760ef0bb6c7SMatthew G. Knepley           a[p*dof+comp] += x[d*dof+comp]*T->T[0][d*dof+comp];
7615509d985SMatthew G. Knepley         }
7625509d985SMatthew G. Knepley       }
7635509d985SMatthew G. Knepley     }
7645f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArray(ref, &xi));
7655f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
7665f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
767552f7358SJed Brown   }
7685f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTabulationDestroy(&T));
7695f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(v, &a));
7705f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
771552f7358SJed Brown 
7725f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESDestroy(&snes));
7735f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&r));
7745f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&ref));
7755f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&real));
7765f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&J));
777552f7358SJed Brown   PetscFunctionReturn(0);
778552f7358SJed Brown }
779552f7358SJed Brown 
7809fbee547SJacob Faibussowitsch static inline PetscErrorCode HexMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
781552f7358SJed Brown {
782552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
783552f7358SJed Brown   const PetscScalar x0        = vertices[0];
784552f7358SJed Brown   const PetscScalar y0        = vertices[1];
785552f7358SJed Brown   const PetscScalar z0        = vertices[2];
7867a1931ceSMatthew G. Knepley   const PetscScalar x1        = vertices[9];
7877a1931ceSMatthew G. Knepley   const PetscScalar y1        = vertices[10];
7887a1931ceSMatthew G. Knepley   const PetscScalar z1        = vertices[11];
789552f7358SJed Brown   const PetscScalar x2        = vertices[6];
790552f7358SJed Brown   const PetscScalar y2        = vertices[7];
791552f7358SJed Brown   const PetscScalar z2        = vertices[8];
7927a1931ceSMatthew G. Knepley   const PetscScalar x3        = vertices[3];
7937a1931ceSMatthew G. Knepley   const PetscScalar y3        = vertices[4];
7947a1931ceSMatthew G. Knepley   const PetscScalar z3        = vertices[5];
795552f7358SJed Brown   const PetscScalar x4        = vertices[12];
796552f7358SJed Brown   const PetscScalar y4        = vertices[13];
797552f7358SJed Brown   const PetscScalar z4        = vertices[14];
798552f7358SJed Brown   const PetscScalar x5        = vertices[15];
799552f7358SJed Brown   const PetscScalar y5        = vertices[16];
800552f7358SJed Brown   const PetscScalar z5        = vertices[17];
801552f7358SJed Brown   const PetscScalar x6        = vertices[18];
802552f7358SJed Brown   const PetscScalar y6        = vertices[19];
803552f7358SJed Brown   const PetscScalar z6        = vertices[20];
804552f7358SJed Brown   const PetscScalar x7        = vertices[21];
805552f7358SJed Brown   const PetscScalar y7        = vertices[22];
806552f7358SJed Brown   const PetscScalar z7        = vertices[23];
807552f7358SJed Brown   const PetscScalar f_1       = x1 - x0;
808552f7358SJed Brown   const PetscScalar g_1       = y1 - y0;
809552f7358SJed Brown   const PetscScalar h_1       = z1 - z0;
810552f7358SJed Brown   const PetscScalar f_3       = x3 - x0;
811552f7358SJed Brown   const PetscScalar g_3       = y3 - y0;
812552f7358SJed Brown   const PetscScalar h_3       = z3 - z0;
813552f7358SJed Brown   const PetscScalar f_4       = x4 - x0;
814552f7358SJed Brown   const PetscScalar g_4       = y4 - y0;
815552f7358SJed Brown   const PetscScalar h_4       = z4 - z0;
816552f7358SJed Brown   const PetscScalar f_01      = x2 - x1 - x3 + x0;
817552f7358SJed Brown   const PetscScalar g_01      = y2 - y1 - y3 + y0;
818552f7358SJed Brown   const PetscScalar h_01      = z2 - z1 - z3 + z0;
819552f7358SJed Brown   const PetscScalar f_12      = x7 - x3 - x4 + x0;
820552f7358SJed Brown   const PetscScalar g_12      = y7 - y3 - y4 + y0;
821552f7358SJed Brown   const PetscScalar h_12      = z7 - z3 - z4 + z0;
822552f7358SJed Brown   const PetscScalar f_02      = x5 - x1 - x4 + x0;
823552f7358SJed Brown   const PetscScalar g_02      = y5 - y1 - y4 + y0;
824552f7358SJed Brown   const PetscScalar h_02      = z5 - z1 - z4 + z0;
825552f7358SJed Brown   const PetscScalar f_012     = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
826552f7358SJed Brown   const PetscScalar g_012     = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
827552f7358SJed Brown   const PetscScalar h_012     = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
82856044e6dSMatthew G. Knepley   const PetscScalar *ref;
82956044e6dSMatthew G. Knepley   PetscScalar       *real;
830552f7358SJed Brown 
831552f7358SJed Brown   PetscFunctionBegin;
8325f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(Xref,  &ref));
8335f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(Xreal, &real));
834552f7358SJed Brown   {
835552f7358SJed Brown     const PetscScalar p0 = ref[0];
836552f7358SJed Brown     const PetscScalar p1 = ref[1];
837552f7358SJed Brown     const PetscScalar p2 = ref[2];
838552f7358SJed Brown 
839552f7358SJed Brown     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;
840552f7358SJed Brown     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;
841552f7358SJed Brown     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;
842552f7358SJed Brown   }
8435f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogFlops(114));
8445f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(Xref,  &ref));
8455f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(Xreal, &real));
846552f7358SJed Brown   PetscFunctionReturn(0);
847552f7358SJed Brown }
848552f7358SJed Brown 
8499fbee547SJacob Faibussowitsch static inline PetscErrorCode HexJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
850552f7358SJed Brown {
851552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
852552f7358SJed Brown   const PetscScalar x0        = vertices[0];
853552f7358SJed Brown   const PetscScalar y0        = vertices[1];
854552f7358SJed Brown   const PetscScalar z0        = vertices[2];
8557a1931ceSMatthew G. Knepley   const PetscScalar x1        = vertices[9];
8567a1931ceSMatthew G. Knepley   const PetscScalar y1        = vertices[10];
8577a1931ceSMatthew G. Knepley   const PetscScalar z1        = vertices[11];
858552f7358SJed Brown   const PetscScalar x2        = vertices[6];
859552f7358SJed Brown   const PetscScalar y2        = vertices[7];
860552f7358SJed Brown   const PetscScalar z2        = vertices[8];
8617a1931ceSMatthew G. Knepley   const PetscScalar x3        = vertices[3];
8627a1931ceSMatthew G. Knepley   const PetscScalar y3        = vertices[4];
8637a1931ceSMatthew G. Knepley   const PetscScalar z3        = vertices[5];
864552f7358SJed Brown   const PetscScalar x4        = vertices[12];
865552f7358SJed Brown   const PetscScalar y4        = vertices[13];
866552f7358SJed Brown   const PetscScalar z4        = vertices[14];
867552f7358SJed Brown   const PetscScalar x5        = vertices[15];
868552f7358SJed Brown   const PetscScalar y5        = vertices[16];
869552f7358SJed Brown   const PetscScalar z5        = vertices[17];
870552f7358SJed Brown   const PetscScalar x6        = vertices[18];
871552f7358SJed Brown   const PetscScalar y6        = vertices[19];
872552f7358SJed Brown   const PetscScalar z6        = vertices[20];
873552f7358SJed Brown   const PetscScalar x7        = vertices[21];
874552f7358SJed Brown   const PetscScalar y7        = vertices[22];
875552f7358SJed Brown   const PetscScalar z7        = vertices[23];
876552f7358SJed Brown   const PetscScalar f_xy      = x2 - x1 - x3 + x0;
877552f7358SJed Brown   const PetscScalar g_xy      = y2 - y1 - y3 + y0;
878552f7358SJed Brown   const PetscScalar h_xy      = z2 - z1 - z3 + z0;
879552f7358SJed Brown   const PetscScalar f_yz      = x7 - x3 - x4 + x0;
880552f7358SJed Brown   const PetscScalar g_yz      = y7 - y3 - y4 + y0;
881552f7358SJed Brown   const PetscScalar h_yz      = z7 - z3 - z4 + z0;
882552f7358SJed Brown   const PetscScalar f_xz      = x5 - x1 - x4 + x0;
883552f7358SJed Brown   const PetscScalar g_xz      = y5 - y1 - y4 + y0;
884552f7358SJed Brown   const PetscScalar h_xz      = z5 - z1 - z4 + z0;
885552f7358SJed Brown   const PetscScalar f_xyz     = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
886552f7358SJed Brown   const PetscScalar g_xyz     = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
887552f7358SJed Brown   const PetscScalar h_xyz     = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
88856044e6dSMatthew G. Knepley   const PetscScalar *ref;
889552f7358SJed Brown 
890552f7358SJed Brown   PetscFunctionBegin;
8915f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(Xref,  &ref));
892552f7358SJed Brown   {
893552f7358SJed Brown     const PetscScalar x       = ref[0];
894552f7358SJed Brown     const PetscScalar y       = ref[1];
895552f7358SJed Brown     const PetscScalar z       = ref[2];
896552f7358SJed Brown     const PetscInt    rows[3] = {0, 1, 2};
897da80777bSKarl Rupp     PetscScalar       values[9];
898da80777bSKarl Rupp 
899da80777bSKarl Rupp     values[0] = (x1 - x0 + f_xy*y + f_xz*z + f_xyz*y*z) / 2.0;
900da80777bSKarl Rupp     values[1] = (x3 - x0 + f_xy*x + f_yz*z + f_xyz*x*z) / 2.0;
901da80777bSKarl Rupp     values[2] = (x4 - x0 + f_yz*y + f_xz*x + f_xyz*x*y) / 2.0;
902da80777bSKarl Rupp     values[3] = (y1 - y0 + g_xy*y + g_xz*z + g_xyz*y*z) / 2.0;
903da80777bSKarl Rupp     values[4] = (y3 - y0 + g_xy*x + g_yz*z + g_xyz*x*z) / 2.0;
904da80777bSKarl Rupp     values[5] = (y4 - y0 + g_yz*y + g_xz*x + g_xyz*x*y) / 2.0;
905da80777bSKarl Rupp     values[6] = (z1 - z0 + h_xy*y + h_xz*z + h_xyz*y*z) / 2.0;
906da80777bSKarl Rupp     values[7] = (z3 - z0 + h_xy*x + h_yz*z + h_xyz*x*z) / 2.0;
907da80777bSKarl Rupp     values[8] = (z4 - z0 + h_yz*y + h_xz*x + h_xyz*x*y) / 2.0;
9081aa26658SKarl Rupp 
9095f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetValues(J, 3, rows, 3, rows, values, INSERT_VALUES));
910552f7358SJed Brown   }
9115f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogFlops(152));
9125f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(Xref,  &ref));
9135f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
9145f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
915552f7358SJed Brown   PetscFunctionReturn(0);
916552f7358SJed Brown }
917552f7358SJed Brown 
9189fbee547SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Hex_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
919a6dfd86eSKarl Rupp {
920fafc0619SMatthew G Knepley   DM             dmCoord;
921552f7358SJed Brown   SNES           snes;
922552f7358SJed Brown   KSP            ksp;
923552f7358SJed Brown   PC             pc;
924552f7358SJed Brown   Vec            coordsLocal, r, ref, real;
925552f7358SJed Brown   Mat            J;
92656044e6dSMatthew G. Knepley   const PetscScalar *coords;
92756044e6dSMatthew G. Knepley   PetscScalar    *a;
928552f7358SJed Brown   PetscInt       p;
929552f7358SJed Brown 
930552f7358SJed Brown   PetscFunctionBegin;
9315f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinatesLocal(dm, &coordsLocal));
9325f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinateDM(dm, &dmCoord));
9335f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESCreate(PETSC_COMM_SELF, &snes));
9345f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetOptionsPrefix(snes, "hex_interp_"));
9355f80ce2aSJacob Faibussowitsch   CHKERRQ(VecCreate(PETSC_COMM_SELF, &r));
9365f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetSizes(r, 3, 3));
9375f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetType(r,dm->vectype));
9385f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDuplicate(r, &ref));
9395f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDuplicate(r, &real));
9405f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreate(PETSC_COMM_SELF, &J));
9415f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetSizes(J, 3, 3, 3, 3));
9425f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetType(J, MATSEQDENSE));
9435f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetUp(J));
9445f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetFunction(snes, r, HexMap_Private, NULL));
9455f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetJacobian(snes, J, J, HexJacobian_Private, NULL));
9465f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetKSP(snes, &ksp));
9475f80ce2aSJacob Faibussowitsch   CHKERRQ(KSPGetPC(ksp, &pc));
9485f80ce2aSJacob Faibussowitsch   CHKERRQ(PCSetType(pc, PCLU));
9495f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetFromOptions(snes));
950552f7358SJed Brown 
9515f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
9525f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(v, &a));
953552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
954a1e44745SMatthew G. Knepley     PetscScalar *x = NULL, *vertices = NULL;
955552f7358SJed Brown     PetscScalar *xi;
956cb313848SJed Brown     PetscReal    xir[3];
957552f7358SJed Brown     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
958552f7358SJed Brown 
959552f7358SJed Brown     /* Can make this do all points at once */
9605f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
961cfe5744fSMatthew G. Knepley     PetscCheck(8*3 == coordSize,ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid coordinate closure size %" PetscInt_FMT " should be %d", coordSize, 8*3);
9625f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
963cfe5744fSMatthew G. Knepley     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);
9645f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESSetFunction(snes, NULL, NULL, vertices));
9655f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
9665f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArray(real, &xi));
967552f7358SJed Brown     xi[0]  = coords[p*ctx->dim+0];
968552f7358SJed Brown     xi[1]  = coords[p*ctx->dim+1];
969552f7358SJed Brown     xi[2]  = coords[p*ctx->dim+2];
9705f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArray(real, &xi));
9715f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESSolve(snes, real, ref));
9725f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArray(ref, &xi));
973cb313848SJed Brown     xir[0] = PetscRealPart(xi[0]);
974cb313848SJed Brown     xir[1] = PetscRealPart(xi[1]);
975cb313848SJed Brown     xir[2] = PetscRealPart(xi[2]);
976cfe5744fSMatthew G. Knepley     if (8*ctx->dof == xSize) {
977552f7358SJed Brown       for (comp = 0; comp < ctx->dof; ++comp) {
978552f7358SJed Brown         a[p*ctx->dof+comp] =
979cb313848SJed Brown           x[0*ctx->dof+comp]*(1-xir[0])*(1-xir[1])*(1-xir[2]) +
9807a1931ceSMatthew G. Knepley           x[3*ctx->dof+comp]*    xir[0]*(1-xir[1])*(1-xir[2]) +
981cb313848SJed Brown           x[2*ctx->dof+comp]*    xir[0]*    xir[1]*(1-xir[2]) +
9827a1931ceSMatthew G. Knepley           x[1*ctx->dof+comp]*(1-xir[0])*    xir[1]*(1-xir[2]) +
983cb313848SJed Brown           x[4*ctx->dof+comp]*(1-xir[0])*(1-xir[1])*   xir[2] +
984cb313848SJed Brown           x[5*ctx->dof+comp]*    xir[0]*(1-xir[1])*   xir[2] +
985cb313848SJed Brown           x[6*ctx->dof+comp]*    xir[0]*    xir[1]*   xir[2] +
986cb313848SJed Brown           x[7*ctx->dof+comp]*(1-xir[0])*    xir[1]*   xir[2];
987552f7358SJed Brown       }
988cfe5744fSMatthew G. Knepley     } else {
989cfe5744fSMatthew G. Knepley       for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp];
990cfe5744fSMatthew G. Knepley     }
9915f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArray(ref, &xi));
9925f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
9935f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
994552f7358SJed Brown   }
9955f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(v, &a));
9965f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
997552f7358SJed Brown 
9985f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESDestroy(&snes));
9995f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&r));
10005f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&ref));
10015f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&real));
10025f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&J));
1003552f7358SJed Brown   PetscFunctionReturn(0);
1004552f7358SJed Brown }
1005552f7358SJed Brown 
10064267b1a3SMatthew G. Knepley /*@C
10074267b1a3SMatthew G. Knepley   DMInterpolationEvaluate - Using the input from dm and x, calculates interpolated field values at the interpolation points.
10084267b1a3SMatthew G. Knepley 
1009552f7358SJed Brown   Input Parameters:
1010552f7358SJed Brown + ctx - The DMInterpolationInfo context
1011552f7358SJed Brown . dm  - The DM
1012552f7358SJed Brown - x   - The local vector containing the field to be interpolated
1013552f7358SJed Brown 
1014552f7358SJed Brown   Output Parameters:
1015552f7358SJed Brown . v   - The vector containing the interpolated values
10164267b1a3SMatthew G. Knepley 
10174267b1a3SMatthew G. Knepley   Note: A suitable v can be obtained using DMInterpolationGetVector().
10184267b1a3SMatthew G. Knepley 
10194267b1a3SMatthew G. Knepley   Level: beginner
10204267b1a3SMatthew G. Knepley 
10214267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetVector(), DMInterpolationAddPoints(), DMInterpolationCreate()
10224267b1a3SMatthew G. Knepley @*/
10230adebc6cSBarry Smith PetscErrorCode DMInterpolationEvaluate(DMInterpolationInfo ctx, DM dm, Vec x, Vec v)
10240adebc6cSBarry Smith {
102566a0a883SMatthew G. Knepley   PetscDS        ds;
102666a0a883SMatthew G. Knepley   PetscInt       n, p, Nf, field;
102766a0a883SMatthew G. Knepley   PetscBool      useDS = PETSC_FALSE;
1028552f7358SJed Brown 
1029552f7358SJed Brown   PetscFunctionBegin;
1030552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1031552f7358SJed Brown   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
1032552f7358SJed Brown   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
10335f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetLocalSize(v, &n));
10342c71b3e2SJacob Faibussowitsch   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);
103566a0a883SMatthew G. Knepley   if (!n) PetscFunctionReturn(0);
10365f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(dm, &ds));
1037680d18d5SMatthew G. Knepley   if (ds) {
103866a0a883SMatthew G. Knepley     useDS = PETSC_TRUE;
10395f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDSGetNumFields(ds, &Nf));
1040680d18d5SMatthew G. Knepley     for (field = 0; field < Nf; ++field) {
104166a0a883SMatthew G. Knepley       PetscObject  obj;
1042680d18d5SMatthew G. Knepley       PetscClassId id;
1043680d18d5SMatthew G. Knepley 
10445f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDSGetDiscretization(ds, field, &obj));
10455f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectGetClassId(obj, &id));
104666a0a883SMatthew G. Knepley       if (id != PETSCFE_CLASSID) {useDS = PETSC_FALSE; break;}
104766a0a883SMatthew G. Knepley     }
104866a0a883SMatthew G. Knepley   }
104966a0a883SMatthew G. Knepley   if (useDS) {
105066a0a883SMatthew G. Knepley     const PetscScalar *coords;
105166a0a883SMatthew G. Knepley     PetscScalar       *interpolant;
105266a0a883SMatthew G. Knepley     PetscInt           cdim, d;
105366a0a883SMatthew G. Knepley 
10545f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinateDim(dm, &cdim));
10555f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArrayRead(ctx->coords, &coords));
10565f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArrayWrite(v, &interpolant));
1057680d18d5SMatthew G. Knepley     for (p = 0; p < ctx->n; ++p) {
105866a0a883SMatthew G. Knepley       PetscReal    pcoords[3], xi[3];
1059680d18d5SMatthew G. Knepley       PetscScalar *xa   = NULL;
106066a0a883SMatthew G. Knepley       PetscInt     coff = 0, foff = 0, clSize;
1061680d18d5SMatthew G. Knepley 
106252aa1562SMatthew G. Knepley       if (ctx->cells[p] < 0) continue;
1063680d18d5SMatthew G. Knepley       for (d = 0; d < cdim; ++d) pcoords[d] = PetscRealPart(coords[p*cdim+d]);
10645f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexCoordinatesToReference(dm, ctx->cells[p], 1, pcoords, xi));
10655f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexVecGetClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
106666a0a883SMatthew G. Knepley       for (field = 0; field < Nf; ++field) {
106766a0a883SMatthew G. Knepley         PetscTabulation T;
106866a0a883SMatthew G. Knepley         PetscFE         fe;
106966a0a883SMatthew G. Knepley 
10705f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscDSGetDiscretization(ds, field, (PetscObject *) &fe));
10715f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscFECreateTabulation(fe, 1, 1, xi, 0, &T));
1072680d18d5SMatthew G. Knepley         {
1073680d18d5SMatthew G. Knepley           const PetscReal *basis = T->T[0];
1074680d18d5SMatthew G. Knepley           const PetscInt   Nb    = T->Nb;
1075680d18d5SMatthew G. Knepley           const PetscInt   Nc    = T->Nc;
107666a0a883SMatthew G. Knepley           PetscInt         f, fc;
107766a0a883SMatthew G. Knepley 
1078680d18d5SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
107966a0a883SMatthew G. Knepley             interpolant[p*ctx->dof+coff+fc] = 0.0;
1080680d18d5SMatthew G. Knepley             for (f = 0; f < Nb; ++f) {
108166a0a883SMatthew G. Knepley               interpolant[p*ctx->dof+coff+fc] += xa[foff+f]*basis[(0*Nb + f)*Nc + fc];
1082552f7358SJed Brown             }
1083680d18d5SMatthew G. Knepley           }
108466a0a883SMatthew G. Knepley           coff += Nc;
108566a0a883SMatthew G. Knepley           foff += Nb;
1086680d18d5SMatthew G. Knepley         }
10875f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscTabulationDestroy(&T));
1088680d18d5SMatthew G. Knepley       }
10895f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
10902c71b3e2SJacob Faibussowitsch       PetscCheckFalse(coff != ctx->dof,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total components %D != %D dof specified for interpolation", coff, ctx->dof);
10912c71b3e2SJacob Faibussowitsch       PetscCheckFalse(foff != clSize,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total FE space size %D != %D closure size", foff, clSize);
109266a0a883SMatthew G. Knepley     }
10935f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords));
10945f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArrayWrite(v, &interpolant));
109566a0a883SMatthew G. Knepley   } else {
109666a0a883SMatthew G. Knepley     DMPolytopeType ct;
109766a0a883SMatthew G. Knepley 
1098680d18d5SMatthew G. Knepley     /* TODO Check each cell individually */
10995f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCellType(dm, ctx->cells[0], &ct));
1100680d18d5SMatthew G. Knepley     switch (ct) {
11015f80ce2aSJacob Faibussowitsch       case DM_POLYTOPE_SEGMENT:       CHKERRQ(DMInterpolate_Segment_Private(ctx, dm, x, v));break;
11025f80ce2aSJacob Faibussowitsch       case DM_POLYTOPE_TRIANGLE:      CHKERRQ(DMInterpolate_Triangle_Private(ctx, dm, x, v));break;
11035f80ce2aSJacob Faibussowitsch       case DM_POLYTOPE_QUADRILATERAL: CHKERRQ(DMInterpolate_Quad_Private(ctx, dm, x, v));break;
11045f80ce2aSJacob Faibussowitsch       case DM_POLYTOPE_TETRAHEDRON:   CHKERRQ(DMInterpolate_Tetrahedron_Private(ctx, dm, x, v));break;
11055f80ce2aSJacob Faibussowitsch       case DM_POLYTOPE_HEXAHEDRON:    CHKERRQ(DMInterpolate_Hex_Private(ctx, dm, x, v));break;
1106cfe5744fSMatthew G. Knepley       default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for cell type %s", DMPolytopeTypes[PetscMax(0, PetscMin(ct, DM_NUM_POLYTOPES))]);
1107680d18d5SMatthew G. Knepley     }
1108552f7358SJed Brown   }
1109552f7358SJed Brown   PetscFunctionReturn(0);
1110552f7358SJed Brown }
1111552f7358SJed Brown 
11124267b1a3SMatthew G. Knepley /*@C
11134267b1a3SMatthew G. Knepley   DMInterpolationDestroy - Destroys a DMInterpolationInfo context
11144267b1a3SMatthew G. Knepley 
11154267b1a3SMatthew G. Knepley   Collective on ctx
11164267b1a3SMatthew G. Knepley 
11174267b1a3SMatthew G. Knepley   Input Parameter:
11184267b1a3SMatthew G. Knepley . ctx - the context
11194267b1a3SMatthew G. Knepley 
11204267b1a3SMatthew G. Knepley   Level: beginner
11214267b1a3SMatthew G. Knepley 
11224267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
11234267b1a3SMatthew G. Knepley @*/
11240adebc6cSBarry Smith PetscErrorCode DMInterpolationDestroy(DMInterpolationInfo *ctx)
11250adebc6cSBarry Smith {
1126552f7358SJed Brown   PetscFunctionBegin;
1127064a246eSJacob Faibussowitsch   PetscValidPointer(ctx, 1);
11285f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&(*ctx)->coords));
11295f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree((*ctx)->points));
11305f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree((*ctx)->cells));
11315f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(*ctx));
11320298fd71SBarry Smith   *ctx = NULL;
1133552f7358SJed Brown   PetscFunctionReturn(0);
1134552f7358SJed Brown }
1135cc0c4584SMatthew G. Knepley 
1136cc0c4584SMatthew G. Knepley /*@C
1137cc0c4584SMatthew G. Knepley   SNESMonitorFields - Monitors the residual for each field separately
1138cc0c4584SMatthew G. Knepley 
1139cc0c4584SMatthew G. Knepley   Collective on SNES
1140cc0c4584SMatthew G. Knepley 
1141cc0c4584SMatthew G. Knepley   Input Parameters:
1142cc0c4584SMatthew G. Knepley + snes   - the SNES context
1143cc0c4584SMatthew G. Knepley . its    - iteration number
1144cc0c4584SMatthew G. Knepley . fgnorm - 2-norm of residual
1145d43b4f6eSBarry Smith - vf  - PetscViewerAndFormat of type ASCII
1146cc0c4584SMatthew G. Knepley 
1147cc0c4584SMatthew G. Knepley   Notes:
1148cc0c4584SMatthew G. Knepley   This routine prints the residual norm at each iteration.
1149cc0c4584SMatthew G. Knepley 
1150cc0c4584SMatthew G. Knepley   Level: intermediate
1151cc0c4584SMatthew G. Knepley 
1152cc0c4584SMatthew G. Knepley .seealso: SNESMonitorSet(), SNESMonitorDefault()
1153cc0c4584SMatthew G. Knepley @*/
1154d43b4f6eSBarry Smith PetscErrorCode SNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
1155cc0c4584SMatthew G. Knepley {
1156d43b4f6eSBarry Smith   PetscViewer        viewer = vf->viewer;
1157cc0c4584SMatthew G. Knepley   Vec                res;
1158cc0c4584SMatthew G. Knepley   DM                 dm;
1159cc0c4584SMatthew G. Knepley   PetscSection       s;
1160cc0c4584SMatthew G. Knepley   const PetscScalar *r;
1161cc0c4584SMatthew G. Knepley   PetscReal         *lnorms, *norms;
1162cc0c4584SMatthew G. Knepley   PetscInt           numFields, f, pStart, pEnd, p;
1163cc0c4584SMatthew G. Knepley 
1164cc0c4584SMatthew G. Knepley   PetscFunctionBegin;
11654d4332d5SBarry Smith   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
11665f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetFunction(snes, &res, NULL, NULL));
11675f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetDM(snes, &dm));
11685f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(dm, &s));
11695f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetNumFields(s, &numFields));
11705f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(s, &pStart, &pEnd));
11715f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc2(numFields, &lnorms, numFields, &norms));
11725f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(res, &r));
1173cc0c4584SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
1174cc0c4584SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
1175cc0c4584SMatthew G. Knepley       PetscInt fdof, foff, d;
1176cc0c4584SMatthew G. Knepley 
11775f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetFieldDof(s, p, f, &fdof));
11785f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetFieldOffset(s, p, f, &foff));
1179cc0c4584SMatthew G. Knepley       for (d = 0; d < fdof; ++d) lnorms[f] += PetscRealPart(PetscSqr(r[foff+d]));
1180cc0c4584SMatthew G. Knepley     }
1181cc0c4584SMatthew G. Knepley   }
11825f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(res, &r));
11835f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPIU_Allreduce(lnorms, norms, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject) dm)));
11845f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerPushFormat(viewer,vf->format));
11855f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerASCIIAddTab(viewer, ((PetscObject) snes)->tablevel));
11865f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerASCIIPrintf(viewer, "%3D SNES Function norm %14.12e [", its, (double) fgnorm));
1187cc0c4584SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
11885f80ce2aSJacob Faibussowitsch     if (f > 0) CHKERRQ(PetscViewerASCIIPrintf(viewer, ", "));
11895f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPrintf(viewer, "%14.12e", (double) PetscSqrtReal(norms[f])));
1190cc0c4584SMatthew G. Knepley   }
11915f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerASCIIPrintf(viewer, "]\n"));
11925f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerASCIISubtractTab(viewer, ((PetscObject) snes)->tablevel));
11935f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerPopFormat(viewer));
11945f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(lnorms, norms));
1195cc0c4584SMatthew G. Knepley   PetscFunctionReturn(0);
1196cc0c4584SMatthew G. Knepley }
119724cdb843SMatthew G. Knepley 
119824cdb843SMatthew G. Knepley /********************* Residual Computation **************************/
119924cdb843SMatthew G. Knepley 
12006528b96dSMatthew G. Knepley PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
12016528b96dSMatthew G. Knepley {
12026528b96dSMatthew G. Knepley   PetscInt       depth;
12036528b96dSMatthew G. Knepley 
12046528b96dSMatthew G. Knepley   PetscFunctionBegin;
12055f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepth(plex, &depth));
12065f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetStratumIS(plex, "dim", depth, cellIS));
12075f80ce2aSJacob Faibussowitsch   if (!*cellIS) CHKERRQ(DMGetStratumIS(plex, "depth", depth, cellIS));
12086528b96dSMatthew G. Knepley   PetscFunctionReturn(0);
12096528b96dSMatthew G. Knepley }
12106528b96dSMatthew G. Knepley 
121124cdb843SMatthew G. Knepley /*@
12128db23a53SJed Brown   DMPlexSNESComputeResidualFEM - Sums the local residual into vector F from the local input X using pointwise functions specified by the user
121324cdb843SMatthew G. Knepley 
121424cdb843SMatthew G. Knepley   Input Parameters:
121524cdb843SMatthew G. Knepley + dm - The mesh
121624cdb843SMatthew G. Knepley . X  - Local solution
121724cdb843SMatthew G. Knepley - user - The user context
121824cdb843SMatthew G. Knepley 
121924cdb843SMatthew G. Knepley   Output Parameter:
122024cdb843SMatthew G. Knepley . F  - Local output vector
122124cdb843SMatthew G. Knepley 
12228db23a53SJed Brown   Notes:
12238db23a53SJed Brown   The residual is summed into F; the caller is responsible for using VecZeroEntries() or otherwise ensuring that any data in F is intentional.
12248db23a53SJed Brown 
122524cdb843SMatthew G. Knepley   Level: developer
122624cdb843SMatthew G. Knepley 
12277a73cf09SMatthew G. Knepley .seealso: DMPlexComputeJacobianAction()
122824cdb843SMatthew G. Knepley @*/
122924cdb843SMatthew G. Knepley PetscErrorCode DMPlexSNESComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
123024cdb843SMatthew G. Knepley {
12316da023fcSToby Isaac   DM             plex;
1232083401c6SMatthew G. Knepley   IS             allcellIS;
12336528b96dSMatthew G. Knepley   PetscInt       Nds, s;
123424cdb843SMatthew G. Knepley 
123524cdb843SMatthew G. Knepley   PetscFunctionBegin;
12365f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
12375f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS));
12385f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetNumDS(dm, &Nds));
12396528b96dSMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
12406528b96dSMatthew G. Knepley     PetscDS          ds;
12416528b96dSMatthew G. Knepley     IS               cellIS;
124206ad1575SMatthew G. Knepley     PetscFormKey key;
12436528b96dSMatthew G. Knepley 
12445f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds));
12456528b96dSMatthew G. Knepley     key.value = 0;
12466528b96dSMatthew G. Knepley     key.field = 0;
124706ad1575SMatthew G. Knepley     key.part  = 0;
12486528b96dSMatthew G. Knepley     if (!key.label) {
12495f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectReference((PetscObject) allcellIS));
12506528b96dSMatthew G. Knepley       cellIS = allcellIS;
12516528b96dSMatthew G. Knepley     } else {
12526528b96dSMatthew G. Knepley       IS pointIS;
12536528b96dSMatthew G. Knepley 
12546528b96dSMatthew G. Knepley       key.value = 1;
12555f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelGetStratumIS(key.label, key.value, &pointIS));
12565f80ce2aSJacob Faibussowitsch       CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
12575f80ce2aSJacob Faibussowitsch       CHKERRQ(ISDestroy(&pointIS));
12586528b96dSMatthew G. Knepley     }
12595f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexComputeResidual_Internal(plex, key, cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user));
12605f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&cellIS));
12616528b96dSMatthew G. Knepley   }
12625f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&allcellIS));
12635f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&plex));
12646528b96dSMatthew G. Knepley   PetscFunctionReturn(0);
12656528b96dSMatthew G. Knepley }
12666528b96dSMatthew G. Knepley 
12676528b96dSMatthew G. Knepley PetscErrorCode DMSNESComputeResidual(DM dm, Vec X, Vec F, void *user)
12686528b96dSMatthew G. Knepley {
12696528b96dSMatthew G. Knepley   DM             plex;
12706528b96dSMatthew G. Knepley   IS             allcellIS;
12716528b96dSMatthew G. Knepley   PetscInt       Nds, s;
12726528b96dSMatthew G. Knepley 
12736528b96dSMatthew G. Knepley   PetscFunctionBegin;
12745f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
12755f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS));
12765f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetNumDS(dm, &Nds));
1277083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1278083401c6SMatthew G. Knepley     PetscDS ds;
1279083401c6SMatthew G. Knepley     DMLabel label;
1280083401c6SMatthew G. Knepley     IS      cellIS;
1281083401c6SMatthew G. Knepley 
12825f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetRegionNumDS(dm, s, &label, NULL, &ds));
12836528b96dSMatthew G. Knepley     {
128406ad1575SMatthew G. Knepley       PetscWeakFormKind resmap[2] = {PETSC_WF_F0, PETSC_WF_F1};
12856528b96dSMatthew G. Knepley       PetscWeakForm     wf;
12866528b96dSMatthew G. Knepley       PetscInt          Nm = 2, m, Nk = 0, k, kp, off = 0;
128706ad1575SMatthew G. Knepley       PetscFormKey *reskeys;
12886528b96dSMatthew G. Knepley 
12896528b96dSMatthew G. Knepley       /* Get unique residual keys */
12906528b96dSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
12916528b96dSMatthew G. Knepley         PetscInt Nkm;
12925f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscHMapFormGetSize(ds->wf->form[resmap[m]], &Nkm));
12936528b96dSMatthew G. Knepley         Nk  += Nkm;
12946528b96dSMatthew G. Knepley       }
12955f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(Nk, &reskeys));
12966528b96dSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
12975f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscHMapFormGetKeys(ds->wf->form[resmap[m]], &off, reskeys));
12986528b96dSMatthew G. Knepley       }
12992c71b3e2SJacob Faibussowitsch       PetscCheckFalse(off != Nk,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %D should be %D", off, Nk);
13005f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFormKeySort(Nk, reskeys));
13016528b96dSMatthew G. Knepley       for (k = 0, kp = 1; kp < Nk; ++kp) {
13026528b96dSMatthew G. Knepley         if ((reskeys[k].label != reskeys[kp].label) || (reskeys[k].value != reskeys[kp].value)) {
13036528b96dSMatthew G. Knepley           ++k;
13046528b96dSMatthew G. Knepley           if (kp != k) reskeys[k] = reskeys[kp];
13056528b96dSMatthew G. Knepley         }
13066528b96dSMatthew G. Knepley       }
13076528b96dSMatthew G. Knepley       Nk = k;
13086528b96dSMatthew G. Knepley 
13095f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDSGetWeakForm(ds, &wf));
13106528b96dSMatthew G. Knepley       for (k = 0; k < Nk; ++k) {
13116528b96dSMatthew G. Knepley         DMLabel  label = reskeys[k].label;
13126528b96dSMatthew G. Knepley         PetscInt val   = reskeys[k].value;
13136528b96dSMatthew G. Knepley 
1314083401c6SMatthew G. Knepley         if (!label) {
13155f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscObjectReference((PetscObject) allcellIS));
1316083401c6SMatthew G. Knepley           cellIS = allcellIS;
1317083401c6SMatthew G. Knepley         } else {
1318083401c6SMatthew G. Knepley           IS pointIS;
1319083401c6SMatthew G. Knepley 
13205f80ce2aSJacob Faibussowitsch           CHKERRQ(DMLabelGetStratumIS(label, val, &pointIS));
13215f80ce2aSJacob Faibussowitsch           CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
13225f80ce2aSJacob Faibussowitsch           CHKERRQ(ISDestroy(&pointIS));
13234a3e9fdbSToby Isaac         }
13245f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexComputeResidual_Internal(plex, reskeys[k], cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user));
13255f80ce2aSJacob Faibussowitsch         CHKERRQ(ISDestroy(&cellIS));
1326083401c6SMatthew G. Knepley       }
13275f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(reskeys));
13286528b96dSMatthew G. Knepley     }
13296528b96dSMatthew G. Knepley   }
13305f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&allcellIS));
13315f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&plex));
133224cdb843SMatthew G. Knepley   PetscFunctionReturn(0);
133324cdb843SMatthew G. Knepley }
133424cdb843SMatthew G. Knepley 
1335bdd6f66aSToby Isaac /*@
1336bdd6f66aSToby Isaac   DMPlexSNESComputeBoundaryFEM - Form the boundary values for the local input X
1337bdd6f66aSToby Isaac 
1338bdd6f66aSToby Isaac   Input Parameters:
1339bdd6f66aSToby Isaac + dm - The mesh
1340bdd6f66aSToby Isaac - user - The user context
1341bdd6f66aSToby Isaac 
1342bdd6f66aSToby Isaac   Output Parameter:
1343bdd6f66aSToby Isaac . X  - Local solution
1344bdd6f66aSToby Isaac 
1345bdd6f66aSToby Isaac   Level: developer
1346bdd6f66aSToby Isaac 
13477a73cf09SMatthew G. Knepley .seealso: DMPlexComputeJacobianAction()
1348bdd6f66aSToby Isaac @*/
1349bdd6f66aSToby Isaac PetscErrorCode DMPlexSNESComputeBoundaryFEM(DM dm, Vec X, void *user)
1350bdd6f66aSToby Isaac {
1351bdd6f66aSToby Isaac   DM             plex;
1352bdd6f66aSToby Isaac 
1353bdd6f66aSToby Isaac   PetscFunctionBegin;
13545f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESConvertPlex(dm,&plex,PETSC_TRUE));
13555f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, X, PETSC_MIN_REAL, NULL, NULL, NULL));
13565f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&plex));
1357bdd6f66aSToby Isaac   PetscFunctionReturn(0);
1358bdd6f66aSToby Isaac }
1359bdd6f66aSToby Isaac 
13607a73cf09SMatthew G. Knepley /*@
13618e3a2eefSMatthew G. Knepley   DMSNESComputeJacobianAction - Compute the action of the Jacobian J(X) on Y
13627a73cf09SMatthew G. Knepley 
13637a73cf09SMatthew G. Knepley   Input Parameters:
13648e3a2eefSMatthew G. Knepley + dm   - The DM
13657a73cf09SMatthew G. Knepley . X    - Local solution vector
13667a73cf09SMatthew G. Knepley . Y    - Local input vector
13677a73cf09SMatthew G. Knepley - user - The user context
13687a73cf09SMatthew G. Knepley 
13697a73cf09SMatthew G. Knepley   Output Parameter:
13708e3a2eefSMatthew G. Knepley . F    - lcoal output vector
13717a73cf09SMatthew G. Knepley 
13727a73cf09SMatthew G. Knepley   Level: developer
13737a73cf09SMatthew G. Knepley 
13748e3a2eefSMatthew G. Knepley   Notes:
13758e3a2eefSMatthew G. Knepley   Users will typically use DMSNESCreateJacobianMF() followed by MatMult() instead of calling this routine directly.
13768e3a2eefSMatthew G. Knepley 
1377a509fe9cSSatish Balay .seealso: DMSNESCreateJacobianMF(), DMPlexSNESComputeResidualFEM()
13787a73cf09SMatthew G. Knepley @*/
13798e3a2eefSMatthew G. Knepley PetscErrorCode DMSNESComputeJacobianAction(DM dm, Vec X, Vec Y, Vec F, void *user)
1380a925c78cSMatthew G. Knepley {
13818e3a2eefSMatthew G. Knepley   DM             plex;
13828e3a2eefSMatthew G. Knepley   IS             allcellIS;
13838e3a2eefSMatthew G. Knepley   PetscInt       Nds, s;
1384a925c78cSMatthew G. Knepley 
1385a925c78cSMatthew G. Knepley   PetscFunctionBegin;
13865f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
13875f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS));
13885f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetNumDS(dm, &Nds));
13898e3a2eefSMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
13908e3a2eefSMatthew G. Knepley     PetscDS ds;
13918e3a2eefSMatthew G. Knepley     DMLabel label;
13928e3a2eefSMatthew G. Knepley     IS      cellIS;
13937a73cf09SMatthew G. Knepley 
13945f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetRegionNumDS(dm, s, &label, NULL, &ds));
13958e3a2eefSMatthew G. Knepley     {
139606ad1575SMatthew G. Knepley       PetscWeakFormKind jacmap[4] = {PETSC_WF_G0, PETSC_WF_G1, PETSC_WF_G2, PETSC_WF_G3};
13978e3a2eefSMatthew G. Knepley       PetscWeakForm     wf;
13988e3a2eefSMatthew G. Knepley       PetscInt          Nm = 4, m, Nk = 0, k, kp, off = 0;
139906ad1575SMatthew G. Knepley       PetscFormKey *jackeys;
14008e3a2eefSMatthew G. Knepley 
14018e3a2eefSMatthew G. Knepley       /* Get unique Jacobian keys */
14028e3a2eefSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
14038e3a2eefSMatthew G. Knepley         PetscInt Nkm;
14045f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscHMapFormGetSize(ds->wf->form[jacmap[m]], &Nkm));
14058e3a2eefSMatthew G. Knepley         Nk  += Nkm;
14068e3a2eefSMatthew G. Knepley       }
14075f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(Nk, &jackeys));
14088e3a2eefSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
14095f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscHMapFormGetKeys(ds->wf->form[jacmap[m]], &off, jackeys));
14108e3a2eefSMatthew G. Knepley       }
14112c71b3e2SJacob Faibussowitsch       PetscCheckFalse(off != Nk,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %D should be %D", off, Nk);
14125f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFormKeySort(Nk, jackeys));
14138e3a2eefSMatthew G. Knepley       for (k = 0, kp = 1; kp < Nk; ++kp) {
14148e3a2eefSMatthew G. Knepley         if ((jackeys[k].label != jackeys[kp].label) || (jackeys[k].value != jackeys[kp].value)) {
14158e3a2eefSMatthew G. Knepley           ++k;
14168e3a2eefSMatthew G. Knepley           if (kp != k) jackeys[k] = jackeys[kp];
14178e3a2eefSMatthew G. Knepley         }
14188e3a2eefSMatthew G. Knepley       }
14198e3a2eefSMatthew G. Knepley       Nk = k;
14208e3a2eefSMatthew G. Knepley 
14215f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDSGetWeakForm(ds, &wf));
14228e3a2eefSMatthew G. Knepley       for (k = 0; k < Nk; ++k) {
14238e3a2eefSMatthew G. Knepley         DMLabel  label = jackeys[k].label;
14248e3a2eefSMatthew G. Knepley         PetscInt val   = jackeys[k].value;
14258e3a2eefSMatthew G. Knepley 
14268e3a2eefSMatthew G. Knepley         if (!label) {
14275f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscObjectReference((PetscObject) allcellIS));
14288e3a2eefSMatthew G. Knepley           cellIS = allcellIS;
14297a73cf09SMatthew G. Knepley         } else {
14308e3a2eefSMatthew G. Knepley           IS pointIS;
1431a925c78cSMatthew G. Knepley 
14325f80ce2aSJacob Faibussowitsch           CHKERRQ(DMLabelGetStratumIS(label, val, &pointIS));
14335f80ce2aSJacob Faibussowitsch           CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
14345f80ce2aSJacob Faibussowitsch           CHKERRQ(ISDestroy(&pointIS));
1435a925c78cSMatthew G. Knepley         }
14365f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexComputeJacobian_Action_Internal(plex, jackeys[k], cellIS, 0.0, 0.0, X, NULL, Y, F, user));
14375f80ce2aSJacob Faibussowitsch         CHKERRQ(ISDestroy(&cellIS));
14388e3a2eefSMatthew G. Knepley       }
14395f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(jackeys));
14408e3a2eefSMatthew G. Knepley     }
14418e3a2eefSMatthew G. Knepley   }
14425f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&allcellIS));
14435f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&plex));
1444a925c78cSMatthew G. Knepley   PetscFunctionReturn(0);
1445a925c78cSMatthew G. Knepley }
1446a925c78cSMatthew G. Knepley 
144724cdb843SMatthew G. Knepley /*@
144824cdb843SMatthew G. Knepley   DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
144924cdb843SMatthew G. Knepley 
145024cdb843SMatthew G. Knepley   Input Parameters:
145124cdb843SMatthew G. Knepley + dm - The mesh
145224cdb843SMatthew G. Knepley . X  - Local input vector
145324cdb843SMatthew G. Knepley - user - The user context
145424cdb843SMatthew G. Knepley 
145524cdb843SMatthew G. Knepley   Output Parameter:
145624cdb843SMatthew G. Knepley . Jac  - Jacobian matrix
145724cdb843SMatthew G. Knepley 
145824cdb843SMatthew G. Knepley   Note:
145924cdb843SMatthew G. Knepley   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
146024cdb843SMatthew G. Knepley   like a GPU, or vectorize on a multicore machine.
146124cdb843SMatthew G. Knepley 
146224cdb843SMatthew G. Knepley   Level: developer
146324cdb843SMatthew G. Knepley 
146424cdb843SMatthew G. Knepley .seealso: FormFunctionLocal()
146524cdb843SMatthew G. Knepley @*/
146624cdb843SMatthew G. Knepley PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP,void *user)
146724cdb843SMatthew G. Knepley {
14686da023fcSToby Isaac   DM             plex;
1469083401c6SMatthew G. Knepley   IS             allcellIS;
1470f04eb4edSMatthew G. Knepley   PetscBool      hasJac, hasPrec;
14716528b96dSMatthew G. Knepley   PetscInt       Nds, s;
147224cdb843SMatthew G. Knepley 
147324cdb843SMatthew G. Knepley   PetscFunctionBegin;
14745f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
14755f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS));
14765f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetNumDS(dm, &Nds));
1477083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1478083401c6SMatthew G. Knepley     PetscDS          ds;
1479083401c6SMatthew G. Knepley     IS               cellIS;
148006ad1575SMatthew G. Knepley     PetscFormKey key;
1481083401c6SMatthew G. Knepley 
14825f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds));
14836528b96dSMatthew G. Knepley     key.value = 0;
14846528b96dSMatthew G. Knepley     key.field = 0;
148506ad1575SMatthew G. Knepley     key.part  = 0;
14866528b96dSMatthew G. Knepley     if (!key.label) {
14875f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectReference((PetscObject) allcellIS));
1488083401c6SMatthew G. Knepley       cellIS = allcellIS;
1489083401c6SMatthew G. Knepley     } else {
1490083401c6SMatthew G. Knepley       IS pointIS;
1491083401c6SMatthew G. Knepley 
14926528b96dSMatthew G. Knepley       key.value = 1;
14935f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelGetStratumIS(key.label, key.value, &pointIS));
14945f80ce2aSJacob Faibussowitsch       CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
14955f80ce2aSJacob Faibussowitsch       CHKERRQ(ISDestroy(&pointIS));
1496083401c6SMatthew G. Knepley     }
1497083401c6SMatthew G. Knepley     if (!s) {
14985f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDSHasJacobian(ds, &hasJac));
14995f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
15005f80ce2aSJacob Faibussowitsch       if (hasJac && hasPrec) CHKERRQ(MatZeroEntries(Jac));
15015f80ce2aSJacob Faibussowitsch       CHKERRQ(MatZeroEntries(JacP));
1502083401c6SMatthew G. Knepley     }
15035f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexComputeJacobian_Internal(plex, key, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, user));
15045f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&cellIS));
1505083401c6SMatthew G. Knepley   }
15065f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&allcellIS));
15075f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&plex));
150824cdb843SMatthew G. Knepley   PetscFunctionReturn(0);
150924cdb843SMatthew G. Knepley }
15101878804aSMatthew G. Knepley 
15118e3a2eefSMatthew G. Knepley struct _DMSNESJacobianMFCtx
15128e3a2eefSMatthew G. Knepley {
15138e3a2eefSMatthew G. Knepley   DM    dm;
15148e3a2eefSMatthew G. Knepley   Vec   X;
15158e3a2eefSMatthew G. Knepley   void *ctx;
15168e3a2eefSMatthew G. Knepley };
15178e3a2eefSMatthew G. Knepley 
15188e3a2eefSMatthew G. Knepley static PetscErrorCode DMSNESJacobianMF_Destroy_Private(Mat A)
15198e3a2eefSMatthew G. Knepley {
15208e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15218e3a2eefSMatthew G. Knepley 
15228e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15235f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellGetContext(A, &ctx));
15245f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellSetContext(A, NULL));
15255f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&ctx->dm));
15265f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&ctx->X));
15275f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(ctx));
15288e3a2eefSMatthew G. Knepley   PetscFunctionReturn(0);
15298e3a2eefSMatthew G. Knepley }
15308e3a2eefSMatthew G. Knepley 
15318e3a2eefSMatthew G. Knepley static PetscErrorCode DMSNESJacobianMF_Mult_Private(Mat A, Vec Y, Vec Z)
15328e3a2eefSMatthew G. Knepley {
15338e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15348e3a2eefSMatthew G. Knepley 
15358e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15365f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellGetContext(A, &ctx));
15375f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESComputeJacobianAction(ctx->dm, ctx->X, Y, Z, ctx->ctx));
15388e3a2eefSMatthew G. Knepley   PetscFunctionReturn(0);
15398e3a2eefSMatthew G. Knepley }
15408e3a2eefSMatthew G. Knepley 
15418e3a2eefSMatthew G. Knepley /*@
15428e3a2eefSMatthew G. Knepley   DMSNESCreateJacobianMF - Create a Mat which computes the action of the Jacobian matrix-free
15438e3a2eefSMatthew G. Knepley 
15448e3a2eefSMatthew G. Knepley   Collective on dm
15458e3a2eefSMatthew G. Knepley 
15468e3a2eefSMatthew G. Knepley   Input Parameters:
15478e3a2eefSMatthew G. Knepley + dm   - The DM
15488e3a2eefSMatthew G. Knepley . X    - The evaluation point for the Jacobian
15498e3a2eefSMatthew G. Knepley - user - A user context, or NULL
15508e3a2eefSMatthew G. Knepley 
15518e3a2eefSMatthew G. Knepley   Output Parameter:
15528e3a2eefSMatthew G. Knepley . J    - The Mat
15538e3a2eefSMatthew G. Knepley 
15548e3a2eefSMatthew G. Knepley   Level: advanced
15558e3a2eefSMatthew G. Knepley 
15568e3a2eefSMatthew G. Knepley   Notes:
15578e3a2eefSMatthew G. Knepley   Vec X is kept in Mat J, so updating X then updates the evaluation point.
15588e3a2eefSMatthew G. Knepley 
15598e3a2eefSMatthew G. Knepley .seealso: DMSNESComputeJacobianAction()
15608e3a2eefSMatthew G. Knepley @*/
15618e3a2eefSMatthew G. Knepley PetscErrorCode DMSNESCreateJacobianMF(DM dm, Vec X, void *user, Mat *J)
15628e3a2eefSMatthew G. Knepley {
15638e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15648e3a2eefSMatthew G. Knepley   PetscInt                     n, N;
15658e3a2eefSMatthew G. Knepley 
15668e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15675f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreate(PetscObjectComm((PetscObject) dm), J));
15685f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetType(*J, MATSHELL));
15695f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetLocalSize(X, &n));
15705f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetSize(X, &N));
15715f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetSizes(*J, n, n, N, N));
15725f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectReference((PetscObject) dm));
15735f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectReference((PetscObject) X));
15745f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(1, &ctx));
15758e3a2eefSMatthew G. Knepley   ctx->dm  = dm;
15768e3a2eefSMatthew G. Knepley   ctx->X   = X;
15778e3a2eefSMatthew G. Knepley   ctx->ctx = user;
15785f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellSetContext(*J, ctx));
15795f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellSetOperation(*J, MATOP_DESTROY, (void (*)(void)) DMSNESJacobianMF_Destroy_Private));
15805f80ce2aSJacob Faibussowitsch   CHKERRQ(MatShellSetOperation(*J, MATOP_MULT,    (void (*)(void)) DMSNESJacobianMF_Mult_Private));
15818e3a2eefSMatthew G. Knepley   PetscFunctionReturn(0);
15828e3a2eefSMatthew G. Knepley }
15838e3a2eefSMatthew G. Knepley 
158438cfc46eSPierre Jolivet /*
158538cfc46eSPierre Jolivet      MatComputeNeumannOverlap - Computes an unassembled (Neumann) local overlapping Mat in nonlinear context.
158638cfc46eSPierre Jolivet 
158738cfc46eSPierre Jolivet    Input Parameters:
158838cfc46eSPierre Jolivet +     X - SNES linearization point
158938cfc46eSPierre Jolivet .     ovl - index set of overlapping subdomains
159038cfc46eSPierre Jolivet 
159138cfc46eSPierre Jolivet    Output Parameter:
159238cfc46eSPierre Jolivet .     J - unassembled (Neumann) local matrix
159338cfc46eSPierre Jolivet 
159438cfc46eSPierre Jolivet    Level: intermediate
159538cfc46eSPierre Jolivet 
159638cfc46eSPierre Jolivet .seealso: DMCreateNeumannOverlap(), MATIS, PCHPDDMSetAuxiliaryMat()
159738cfc46eSPierre Jolivet */
159838cfc46eSPierre Jolivet static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, void *ctx)
159938cfc46eSPierre Jolivet {
160038cfc46eSPierre Jolivet   SNES           snes;
160138cfc46eSPierre Jolivet   Mat            pJ;
160238cfc46eSPierre Jolivet   DM             ovldm,origdm;
160338cfc46eSPierre Jolivet   DMSNES         sdm;
160438cfc46eSPierre Jolivet   PetscErrorCode (*bfun)(DM,Vec,void*);
160538cfc46eSPierre Jolivet   PetscErrorCode (*jfun)(DM,Vec,Mat,Mat,void*);
160638cfc46eSPierre Jolivet   void           *bctx,*jctx;
160738cfc46eSPierre Jolivet 
160838cfc46eSPierre Jolivet   PetscFunctionBegin;
16095f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectQuery((PetscObject)ovl,"_DM_Overlap_HPDDM_MATIS",(PetscObject*)&pJ));
1610*28b400f6SJacob Faibussowitsch   PetscCheck(pJ,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing overlapping Mat");
16115f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectQuery((PetscObject)ovl,"_DM_Original_HPDDM",(PetscObject*)&origdm));
1612*28b400f6SJacob Faibussowitsch   PetscCheck(origdm,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing original DM");
16135f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetDM(pJ,&ovldm));
16145f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESGetBoundaryLocal(origdm,&bfun,&bctx));
16155f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESSetBoundaryLocal(ovldm,bfun,bctx));
16165f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESGetJacobianLocal(origdm,&jfun,&jctx));
16175f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESSetJacobianLocal(ovldm,jfun,jctx));
16185f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectQuery((PetscObject)ovl,"_DM_Overlap_HPDDM_SNES",(PetscObject*)&snes));
161938cfc46eSPierre Jolivet   if (!snes) {
16205f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESCreate(PetscObjectComm((PetscObject)ovl),&snes));
16215f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESSetDM(snes,ovldm));
16225f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectCompose((PetscObject)ovl,"_DM_Overlap_HPDDM_SNES",(PetscObject)snes));
16235f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectDereference((PetscObject)snes));
162438cfc46eSPierre Jolivet   }
16255f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDMSNES(ovldm,&sdm));
16265f80ce2aSJacob Faibussowitsch   CHKERRQ(VecLockReadPush(X));
162738cfc46eSPierre Jolivet   PetscStackPush("SNES user Jacobian function");
16285f80ce2aSJacob Faibussowitsch   CHKERRQ((*sdm->ops->computejacobian)(snes,X,pJ,pJ,sdm->jacobianctx));
162938cfc46eSPierre Jolivet   PetscStackPop;
16305f80ce2aSJacob Faibussowitsch   CHKERRQ(VecLockReadPop(X));
163138cfc46eSPierre Jolivet   /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */
163238cfc46eSPierre Jolivet   {
163338cfc46eSPierre Jolivet     Mat locpJ;
163438cfc46eSPierre Jolivet 
16355f80ce2aSJacob Faibussowitsch     CHKERRQ(MatISGetLocalMat(pJ,&locpJ));
16365f80ce2aSJacob Faibussowitsch     CHKERRQ(MatCopy(locpJ,J,SAME_NONZERO_PATTERN));
163738cfc46eSPierre Jolivet   }
163838cfc46eSPierre Jolivet   PetscFunctionReturn(0);
163938cfc46eSPierre Jolivet }
164038cfc46eSPierre Jolivet 
1641a925c78cSMatthew G. Knepley /*@
16429f520fc2SToby Isaac   DMPlexSetSNESLocalFEM - Use DMPlex's internal FEM routines to compute SNES boundary values, residual, and Jacobian.
16439f520fc2SToby Isaac 
16449f520fc2SToby Isaac   Input Parameters:
16459f520fc2SToby Isaac + dm - The DM object
1646dff059c6SToby Isaac . boundaryctx - the user context that will be passed to pointwise evaluation of boundary values (see PetscDSAddBoundary())
16479f520fc2SToby Isaac . residualctx - the user context that will be passed to pointwise evaluation of finite element residual computations (see PetscDSSetResidual())
16489f520fc2SToby Isaac - jacobianctx - the user context that will be passed to pointwise evaluation of finite element Jacobian construction (see PetscDSSetJacobian())
16491a244344SSatish Balay 
16501a244344SSatish Balay   Level: developer
16519f520fc2SToby Isaac @*/
16529f520fc2SToby Isaac PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, void *boundaryctx, void *residualctx, void *jacobianctx)
16539f520fc2SToby Isaac {
16549f520fc2SToby Isaac   PetscFunctionBegin;
16555f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESSetBoundaryLocal(dm,DMPlexSNESComputeBoundaryFEM,boundaryctx));
16565f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESSetFunctionLocal(dm,DMPlexSNESComputeResidualFEM,residualctx));
16575f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESSetJacobianLocal(dm,DMPlexSNESComputeJacobianFEM,jacobianctx));
16585f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",MatComputeNeumannOverlap_Plex));
16599f520fc2SToby Isaac   PetscFunctionReturn(0);
16609f520fc2SToby Isaac }
16619f520fc2SToby Isaac 
1662f017bcb6SMatthew G. Knepley /*@C
1663f017bcb6SMatthew G. Knepley   DMSNESCheckDiscretization - Check the discretization error of the exact solution
1664f017bcb6SMatthew G. Knepley 
1665f017bcb6SMatthew G. Knepley   Input Parameters:
1666f017bcb6SMatthew G. Knepley + snes - the SNES object
1667f017bcb6SMatthew G. Knepley . dm   - the DM
1668f2cacb80SMatthew G. Knepley . t    - the time
1669f017bcb6SMatthew G. Knepley . u    - a DM vector
1670f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1671f017bcb6SMatthew G. Knepley 
1672f3c94560SMatthew G. Knepley   Output Parameters:
1673f3c94560SMatthew G. Knepley . error - An array which holds the discretization error in each field, or NULL
1674f3c94560SMatthew G. Knepley 
16757f96f943SMatthew G. Knepley   Note: The user must call PetscDSSetExactSolution() beforehand
16767f96f943SMatthew G. Knepley 
1677f017bcb6SMatthew G. Knepley   Level: developer
1678f017bcb6SMatthew G. Knepley 
16797f96f943SMatthew G. Knepley .seealso: DNSNESCheckFromOptions(), DMSNESCheckResidual(), DMSNESCheckJacobian(), PetscDSSetExactSolution()
1680f017bcb6SMatthew G. Knepley @*/
1681f2cacb80SMatthew G. Knepley PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[])
16821878804aSMatthew G. Knepley {
1683f017bcb6SMatthew G. Knepley   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
1684f017bcb6SMatthew G. Knepley   void            **ectxs;
1685f3c94560SMatthew G. Knepley   PetscReal        *err;
16867f96f943SMatthew G. Knepley   MPI_Comm          comm;
16877f96f943SMatthew G. Knepley   PetscInt          Nf, f;
16881878804aSMatthew G. Knepley 
16891878804aSMatthew G. Knepley   PetscFunctionBegin;
1690f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1691f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1692064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(u, VEC_CLASSID, 4);
1693534a8f05SLisandro Dalcin   if (error) PetscValidRealPointer(error, 6);
16947f96f943SMatthew G. Knepley 
16955f80ce2aSJacob Faibussowitsch   CHKERRQ(DMComputeExactSolution(dm, t, u, NULL));
16965f80ce2aSJacob Faibussowitsch   CHKERRQ(VecViewFromOptions(u, NULL, "-vec_view"));
16977f96f943SMatthew G. Knepley 
16985f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm));
16995f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetNumFields(dm, &Nf));
17005f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err));
17017f96f943SMatthew G. Knepley   {
17027f96f943SMatthew G. Knepley     PetscInt Nds, s;
17037f96f943SMatthew G. Knepley 
17045f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetNumDS(dm, &Nds));
1705083401c6SMatthew G. Knepley     for (s = 0; s < Nds; ++s) {
17067f96f943SMatthew G. Knepley       PetscDS         ds;
1707083401c6SMatthew G. Knepley       DMLabel         label;
1708083401c6SMatthew G. Knepley       IS              fieldIS;
17097f96f943SMatthew G. Knepley       const PetscInt *fields;
17107f96f943SMatthew G. Knepley       PetscInt        dsNf, f;
1711083401c6SMatthew G. Knepley 
17125f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
17135f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDSGetNumFields(ds, &dsNf));
17145f80ce2aSJacob Faibussowitsch       CHKERRQ(ISGetIndices(fieldIS, &fields));
1715083401c6SMatthew G. Knepley       for (f = 0; f < dsNf; ++f) {
1716083401c6SMatthew G. Knepley         const PetscInt field = fields[f];
17175f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]));
1718083401c6SMatthew G. Knepley       }
17195f80ce2aSJacob Faibussowitsch       CHKERRQ(ISRestoreIndices(fieldIS, &fields));
1720083401c6SMatthew G. Knepley     }
1721083401c6SMatthew G. Knepley   }
1722f017bcb6SMatthew G. Knepley   if (Nf > 1) {
17235f80ce2aSJacob Faibussowitsch     CHKERRQ(DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err));
1724f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
1725f017bcb6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
17262c71b3e2SJacob Faibussowitsch         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);
17271878804aSMatthew G. Knepley       }
1728b878532fSMatthew G. Knepley     } else if (error) {
1729b878532fSMatthew G. Knepley       for (f = 0; f < Nf; ++f) error[f] = err[f];
17301878804aSMatthew G. Knepley     } else {
17315f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscPrintf(comm, "L_2 Error: ["));
1732f017bcb6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
17335f80ce2aSJacob Faibussowitsch         if (f) CHKERRQ(PetscPrintf(comm, ", "));
17345f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscPrintf(comm, "%g", (double)err[f]));
17351878804aSMatthew G. Knepley       }
17365f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscPrintf(comm, "]\n"));
1737f017bcb6SMatthew G. Knepley     }
1738f017bcb6SMatthew G. Knepley   } else {
17395f80ce2aSJacob Faibussowitsch     CHKERRQ(DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0]));
1740f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
17412c71b3e2SJacob Faibussowitsch       PetscCheckFalse(err[0] > tol,comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double) err[0], (double) tol);
1742b878532fSMatthew G. Knepley     } else if (error) {
1743b878532fSMatthew G. Knepley       error[0] = err[0];
1744f017bcb6SMatthew G. Knepley     } else {
17455f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscPrintf(comm, "L_2 Error: %g\n", (double) err[0]));
1746f017bcb6SMatthew G. Knepley     }
1747f017bcb6SMatthew G. Knepley   }
17485f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree3(exacts, ectxs, err));
1749f017bcb6SMatthew G. Knepley   PetscFunctionReturn(0);
1750f017bcb6SMatthew G. Knepley }
1751f017bcb6SMatthew G. Knepley 
1752f017bcb6SMatthew G. Knepley /*@C
1753f017bcb6SMatthew G. Knepley   DMSNESCheckResidual - Check the residual of the exact solution
1754f017bcb6SMatthew G. Knepley 
1755f017bcb6SMatthew G. Knepley   Input Parameters:
1756f017bcb6SMatthew G. Knepley + snes - the SNES object
1757f017bcb6SMatthew G. Knepley . dm   - the DM
1758f017bcb6SMatthew G. Knepley . u    - a DM vector
1759f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1760f017bcb6SMatthew G. Knepley 
1761f3c94560SMatthew G. Knepley   Output Parameters:
1762f3c94560SMatthew G. Knepley . residual - The residual norm of the exact solution, or NULL
1763f3c94560SMatthew G. Knepley 
1764f017bcb6SMatthew G. Knepley   Level: developer
1765f017bcb6SMatthew G. Knepley 
1766f017bcb6SMatthew G. Knepley .seealso: DNSNESCheckFromOptions(), DMSNESCheckDiscretization(), DMSNESCheckJacobian()
1767f017bcb6SMatthew G. Knepley @*/
1768f3c94560SMatthew G. Knepley PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual)
1769f017bcb6SMatthew G. Knepley {
1770f017bcb6SMatthew G. Knepley   MPI_Comm       comm;
1771f017bcb6SMatthew G. Knepley   Vec            r;
1772f017bcb6SMatthew G. Knepley   PetscReal      res;
1773f017bcb6SMatthew G. Knepley 
1774f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1775f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1776f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1777f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1778534a8f05SLisandro Dalcin   if (residual) PetscValidRealPointer(residual, 5);
17795f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm));
17805f80ce2aSJacob Faibussowitsch   CHKERRQ(DMComputeExactSolution(dm, 0.0, u, NULL));
17815f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDuplicate(u, &r));
17825f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESComputeFunction(snes, u, r));
17835f80ce2aSJacob Faibussowitsch   CHKERRQ(VecNorm(r, NORM_2, &res));
1784f017bcb6SMatthew G. Knepley   if (tol >= 0.0) {
17852c71b3e2SJacob Faibussowitsch     PetscCheckFalse(res > tol,comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double) res, (double) tol);
1786b878532fSMatthew G. Knepley   } else if (residual) {
1787b878532fSMatthew G. Knepley     *residual = res;
1788f017bcb6SMatthew G. Knepley   } else {
17895f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscPrintf(comm, "L_2 Residual: %g\n", (double)res));
17905f80ce2aSJacob Faibussowitsch     CHKERRQ(VecChop(r, 1.0e-10));
17915f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectSetName((PetscObject) r, "Initial Residual"));
17925f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject)r,"res_"));
17935f80ce2aSJacob Faibussowitsch     CHKERRQ(VecViewFromOptions(r, NULL, "-vec_view"));
1794f017bcb6SMatthew G. Knepley   }
17955f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&r));
1796f017bcb6SMatthew G. Knepley   PetscFunctionReturn(0);
1797f017bcb6SMatthew G. Knepley }
1798f017bcb6SMatthew G. Knepley 
1799f017bcb6SMatthew G. Knepley /*@C
1800f3c94560SMatthew G. Knepley   DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test
1801f017bcb6SMatthew G. Knepley 
1802f017bcb6SMatthew G. Knepley   Input Parameters:
1803f017bcb6SMatthew G. Knepley + snes - the SNES object
1804f017bcb6SMatthew G. Knepley . dm   - the DM
1805f017bcb6SMatthew G. Knepley . u    - a DM vector
1806f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1807f017bcb6SMatthew G. Knepley 
1808f3c94560SMatthew G. Knepley   Output Parameters:
1809f3c94560SMatthew G. Knepley + isLinear - Flag indicaing that the function looks linear, or NULL
1810f3c94560SMatthew G. Knepley - convRate - The rate of convergence of the linear model, or NULL
1811f3c94560SMatthew G. Knepley 
1812f017bcb6SMatthew G. Knepley   Level: developer
1813f017bcb6SMatthew G. Knepley 
1814f017bcb6SMatthew G. Knepley .seealso: DNSNESCheckFromOptions(), DMSNESCheckDiscretization(), DMSNESCheckResidual()
1815f017bcb6SMatthew G. Knepley @*/
1816f3c94560SMatthew G. Knepley PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate)
1817f017bcb6SMatthew G. Knepley {
1818f017bcb6SMatthew G. Knepley   MPI_Comm       comm;
1819f017bcb6SMatthew G. Knepley   PetscDS        ds;
1820f017bcb6SMatthew G. Knepley   Mat            J, M;
1821f017bcb6SMatthew G. Knepley   MatNullSpace   nullspace;
1822f3c94560SMatthew G. Knepley   PetscReal      slope, intercept;
18237f96f943SMatthew G. Knepley   PetscBool      hasJac, hasPrec, isLin = PETSC_FALSE;
1824f017bcb6SMatthew G. Knepley 
1825f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1826f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1827f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1828f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1829534a8f05SLisandro Dalcin   if (isLinear) PetscValidBoolPointer(isLinear, 5);
1830064a246eSJacob Faibussowitsch   if (convRate) PetscValidRealPointer(convRate, 6);
18315f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm));
18325f80ce2aSJacob Faibussowitsch   CHKERRQ(DMComputeExactSolution(dm, 0.0, u, NULL));
1833f017bcb6SMatthew G. Knepley   /* Create and view matrices */
18345f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateMatrix(dm, &J));
18355f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(dm, &ds));
18365f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSHasJacobian(ds, &hasJac));
18375f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
1838282e7bb4SMatthew G. Knepley   if (hasJac && hasPrec) {
18395f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCreateMatrix(dm, &M));
18405f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESComputeJacobian(snes, u, J, M));
18415f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectSetName((PetscObject) M, "Preconditioning Matrix"));
18425f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) M, "jacpre_"));
18435f80ce2aSJacob Faibussowitsch     CHKERRQ(MatViewFromOptions(M, NULL, "-mat_view"));
18445f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&M));
1845282e7bb4SMatthew G. Knepley   } else {
18465f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESComputeJacobian(snes, u, J, J));
1847282e7bb4SMatthew G. Knepley   }
18485f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectSetName((PetscObject) J, "Jacobian"));
18495f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) J, "jac_"));
18505f80ce2aSJacob Faibussowitsch   CHKERRQ(MatViewFromOptions(J, NULL, "-mat_view"));
1851f017bcb6SMatthew G. Knepley   /* Check nullspace */
18525f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetNullSpace(J, &nullspace));
1853f017bcb6SMatthew G. Knepley   if (nullspace) {
18541878804aSMatthew G. Knepley     PetscBool isNull;
18555f80ce2aSJacob Faibussowitsch     CHKERRQ(MatNullSpaceTest(nullspace, J, &isNull));
1856*28b400f6SJacob Faibussowitsch     PetscCheck(isNull,comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid.");
18571878804aSMatthew G. Knepley   }
1858f017bcb6SMatthew G. Knepley   /* Taylor test */
1859f017bcb6SMatthew G. Knepley   {
1860f017bcb6SMatthew G. Knepley     PetscRandom rand;
1861f017bcb6SMatthew G. Knepley     Vec         du, uhat, r, rhat, df;
1862f3c94560SMatthew G. Knepley     PetscReal   h;
1863f017bcb6SMatthew G. Knepley     PetscReal  *es, *hs, *errors;
1864f017bcb6SMatthew G. Knepley     PetscReal   hMax = 1.0, hMin = 1e-6, hMult = 0.1;
1865f017bcb6SMatthew G. Knepley     PetscInt    Nv, v;
1866f017bcb6SMatthew G. Knepley 
1867f017bcb6SMatthew G. Knepley     /* Choose a perturbation direction */
18685f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscRandomCreate(comm, &rand));
18695f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(u, &du));
18705f80ce2aSJacob Faibussowitsch     CHKERRQ(VecSetRandom(du, rand));
18715f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscRandomDestroy(&rand));
18725f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(u, &df));
18735f80ce2aSJacob Faibussowitsch     CHKERRQ(MatMult(J, du, df));
1874f017bcb6SMatthew G. Knepley     /* Evaluate residual at u, F(u), save in vector r */
18755f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(u, &r));
18765f80ce2aSJacob Faibussowitsch     CHKERRQ(SNESComputeFunction(snes, u, r));
1877f017bcb6SMatthew G. Knepley     /* Look at the convergence of our Taylor approximation as we approach u */
1878f017bcb6SMatthew G. Knepley     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv);
18795f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors));
18805f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(u, &uhat));
18815f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDuplicate(u, &rhat));
1882f017bcb6SMatthew G. Knepley     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) {
18835f80ce2aSJacob Faibussowitsch       CHKERRQ(VecWAXPY(uhat, h, du, u));
1884f017bcb6SMatthew G. Knepley       /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */
18855f80ce2aSJacob Faibussowitsch       CHKERRQ(SNESComputeFunction(snes, uhat, rhat));
18865f80ce2aSJacob Faibussowitsch       CHKERRQ(VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df));
18875f80ce2aSJacob Faibussowitsch       CHKERRQ(VecNorm(rhat, NORM_2, &errors[Nv]));
1888f017bcb6SMatthew G. Knepley 
1889f017bcb6SMatthew G. Knepley       es[Nv] = PetscLog10Real(errors[Nv]);
1890f017bcb6SMatthew G. Knepley       hs[Nv] = PetscLog10Real(h);
1891f017bcb6SMatthew G. Knepley     }
18925f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(&uhat));
18935f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(&rhat));
18945f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(&df));
18955f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(&r));
18965f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(&du));
1897f017bcb6SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1898f017bcb6SMatthew G. Knepley       if ((tol >= 0) && (errors[v] > tol)) break;
1899f017bcb6SMatthew G. Knepley       else if (errors[v] > PETSC_SMALL)    break;
1900f017bcb6SMatthew G. Knepley     }
1901f3c94560SMatthew G. Knepley     if (v == Nv) isLin = PETSC_TRUE;
19025f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLinearRegression(Nv, hs, es, &slope, &intercept));
19035f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree3(es, hs, errors));
1904f017bcb6SMatthew G. Knepley     /* Slope should be about 2 */
1905f017bcb6SMatthew G. Knepley     if (tol >= 0) {
19062c71b3e2SJacob Faibussowitsch       PetscCheckFalse(!isLin && PetscAbsReal(2 - slope) > tol,comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double) slope);
1907b878532fSMatthew G. Knepley     } else if (isLinear || convRate) {
1908b878532fSMatthew G. Knepley       if (isLinear) *isLinear = isLin;
1909b878532fSMatthew G. Knepley       if (convRate) *convRate = slope;
1910f017bcb6SMatthew G. Knepley     } else {
19115f80ce2aSJacob Faibussowitsch       if (!isLin) CHKERRQ(PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double) slope));
19125f80ce2aSJacob Faibussowitsch       else        CHKERRQ(PetscPrintf(comm, "Function appears to be linear\n"));
1913f017bcb6SMatthew G. Knepley     }
1914f017bcb6SMatthew G. Knepley   }
19155f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&J));
19161878804aSMatthew G. Knepley   PetscFunctionReturn(0);
19171878804aSMatthew G. Knepley }
19181878804aSMatthew G. Knepley 
19197f96f943SMatthew G. Knepley PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u)
1920f017bcb6SMatthew G. Knepley {
1921f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
19225f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL));
19235f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESCheckResidual(snes, dm, u, -1.0, NULL));
19245f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL));
1925f017bcb6SMatthew G. Knepley   PetscFunctionReturn(0);
1926f017bcb6SMatthew G. Knepley }
1927f017bcb6SMatthew G. Knepley 
1928bee9a294SMatthew G. Knepley /*@C
1929bee9a294SMatthew G. Knepley   DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information
1930bee9a294SMatthew G. Knepley 
1931bee9a294SMatthew G. Knepley   Input Parameters:
1932bee9a294SMatthew G. Knepley + snes - the SNES object
19337f96f943SMatthew G. Knepley - u    - representative SNES vector
19347f96f943SMatthew G. Knepley 
19357f96f943SMatthew G. Knepley   Note: The user must call PetscDSSetExactSolution() beforehand
1936bee9a294SMatthew G. Knepley 
1937bee9a294SMatthew G. Knepley   Level: developer
1938bee9a294SMatthew G. Knepley @*/
19397f96f943SMatthew G. Knepley PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u)
19401878804aSMatthew G. Knepley {
19411878804aSMatthew G. Knepley   DM             dm;
19421878804aSMatthew G. Knepley   Vec            sol;
19431878804aSMatthew G. Knepley   PetscBool      check;
19441878804aSMatthew G. Knepley 
19451878804aSMatthew G. Knepley   PetscFunctionBegin;
19465f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsHasName(((PetscObject)snes)->options,((PetscObject)snes)->prefix, "-dmsnes_check", &check));
19471878804aSMatthew G. Knepley   if (!check) PetscFunctionReturn(0);
19485f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetDM(snes, &dm));
19495f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDuplicate(u, &sol));
19505f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetSolution(snes, sol));
19515f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSNESCheck_Internal(snes, dm, sol));
19525f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&sol));
1953552f7358SJed Brown   PetscFunctionReturn(0);
1954552f7358SJed Brown }
1955