xref: /petsc/src/snes/utils/dmplexsnes.c (revision ffc4695bcb29f4b022f59a5fd6bc99fc280ff6d8)
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>
4a925c78cSMatthew G. Knepley #include <petscblaslapack.h>
5af0996ceSBarry Smith #include <petsc/private/petscimpl.h>
6af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
7552f7358SJed Brown 
8649ef022SMatthew Knepley static void pressure_Private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
9649ef022SMatthew Knepley                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
10649ef022SMatthew Knepley                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
11649ef022SMatthew Knepley                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar p[])
12649ef022SMatthew Knepley {
13649ef022SMatthew Knepley   p[0] = u[uOff[1]];
14649ef022SMatthew Knepley }
15649ef022SMatthew Knepley 
16649ef022SMatthew Knepley /*
17649ef022SMatthew 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.
18649ef022SMatthew Knepley 
19649ef022SMatthew Knepley   Collective on SNES
20649ef022SMatthew Knepley 
21649ef022SMatthew Knepley   Input Parameters:
22649ef022SMatthew Knepley + snes      - The SNES
23649ef022SMatthew Knepley . pfield    - The field number for pressure
24649ef022SMatthew Knepley . nullspace - The pressure nullspace
25649ef022SMatthew Knepley . u         - The solution vector
26649ef022SMatthew Knepley - ctx       - An optional user context
27649ef022SMatthew Knepley 
28649ef022SMatthew Knepley   Output Parameter:
29649ef022SMatthew Knepley . u         - The solution with a continuum pressure integral of zero
30649ef022SMatthew Knepley 
31649ef022SMatthew Knepley   Notes:
32649ef022SMatthew 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.
33649ef022SMatthew Knepley 
34649ef022SMatthew Knepley   Level: developer
35649ef022SMatthew Knepley 
36649ef022SMatthew Knepley .seealso: SNESConvergedCorrectPressure()
37649ef022SMatthew Knepley */
38649ef022SMatthew Knepley static PetscErrorCode SNESCorrectDiscretePressure_Private(SNES snes, PetscInt pfield, MatNullSpace nullspace, Vec u, void *ctx)
39649ef022SMatthew Knepley {
40649ef022SMatthew Knepley   DM             dm;
41649ef022SMatthew Knepley   PetscDS        ds;
42649ef022SMatthew Knepley   const Vec     *nullvecs;
43649ef022SMatthew Knepley   PetscScalar    pintd, *intc, *intn;
44649ef022SMatthew Knepley   MPI_Comm       comm;
45649ef022SMatthew Knepley   PetscInt       Nf, Nv;
46649ef022SMatthew Knepley   PetscErrorCode ierr;
47649ef022SMatthew Knepley 
48649ef022SMatthew Knepley   PetscFunctionBegin;
49649ef022SMatthew Knepley   ierr = PetscObjectGetComm((PetscObject) snes, &comm);CHKERRQ(ierr);
50649ef022SMatthew Knepley   ierr = SNESGetDM(snes, &dm);CHKERRQ(ierr);
51649ef022SMatthew Knepley   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a SNES DM");
52649ef022SMatthew Knepley   if (!nullspace) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a Jacobian nullspace");
53649ef022SMatthew Knepley   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
54649ef022SMatthew Knepley   ierr = PetscDSSetObjective(ds, pfield, pressure_Private);CHKERRQ(ierr);
55649ef022SMatthew Knepley   ierr = MatNullSpaceGetVecs(nullspace, NULL, &Nv, &nullvecs);CHKERRQ(ierr);
56649ef022SMatthew Knepley   if (Nv != 1) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Can only handle a single null vector for pressure, not %D", Nv);
57649ef022SMatthew Knepley   ierr = VecDot(nullvecs[0], u, &pintd);CHKERRQ(ierr);
58649ef022SMatthew Knepley   if (PetscAbsScalar(pintd) > PETSC_SMALL) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Discrete integral of pressure: %g\n", (double) PetscRealPart(pintd));
59649ef022SMatthew Knepley   ierr = PetscDSGetNumFields(ds, &Nf);CHKERRQ(ierr);
60649ef022SMatthew Knepley   ierr = PetscMalloc2(Nf, &intc, Nf, &intn);CHKERRQ(ierr);
61649ef022SMatthew Knepley   ierr = DMPlexComputeIntegralFEM(dm, nullvecs[0], intn, ctx);CHKERRQ(ierr);
62649ef022SMatthew Knepley   ierr = DMPlexComputeIntegralFEM(dm, u, intc, ctx);CHKERRQ(ierr);
63649ef022SMatthew Knepley   ierr = VecAXPY(u, -intc[pfield]/intn[pfield], nullvecs[0]);CHKERRQ(ierr);
64649ef022SMatthew Knepley #if defined (PETSC_USE_DEBUG)
65649ef022SMatthew Knepley   ierr = DMPlexComputeIntegralFEM(dm, u, intc, ctx);CHKERRQ(ierr);
66649ef022SMatthew Knepley   if (PetscAbsScalar(intc[pfield]) > PETSC_SMALL) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Continuum integral of pressure after correction: %g\n", (double) PetscRealPart(intc[pfield]));
67649ef022SMatthew Knepley #endif
68649ef022SMatthew Knepley   ierr = PetscFree2(intc, intn);CHKERRQ(ierr);
69649ef022SMatthew Knepley   PetscFunctionReturn(0);
70649ef022SMatthew Knepley }
71649ef022SMatthew Knepley 
72649ef022SMatthew Knepley /*@C
73649ef022SMatthew 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().
74649ef022SMatthew Knepley 
75649ef022SMatthew Knepley    Logically Collective on SNES
76649ef022SMatthew Knepley 
77649ef022SMatthew Knepley    Input Parameters:
78649ef022SMatthew Knepley +  snes - the SNES context
79649ef022SMatthew Knepley .  it - the iteration (0 indicates before any Newton steps)
80649ef022SMatthew Knepley .  xnorm - 2-norm of current iterate
81649ef022SMatthew Knepley .  snorm - 2-norm of current step
82649ef022SMatthew Knepley .  fnorm - 2-norm of function at current iterate
83649ef022SMatthew Knepley -  ctx   - Optional user context
84649ef022SMatthew Knepley 
85649ef022SMatthew Knepley    Output Parameter:
86649ef022SMatthew Knepley .  reason  - SNES_CONVERGED_ITERATING, SNES_CONVERGED_ITS, or SNES_DIVERGED_FNORM_NAN
87649ef022SMatthew Knepley 
88649ef022SMatthew Knepley    Notes:
89649ef022SMatthew 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.
90649ef022SMatthew Knepley 
91649ef022SMatthew Knepley    Level: advanced
92649ef022SMatthew Knepley 
93649ef022SMatthew Knepley .seealso: SNESConvergedDefault(), SNESSetConvergenceTest(), DMSetNullSpaceConstructor()
94649ef022SMatthew Knepley @*/
95649ef022SMatthew Knepley PetscErrorCode SNESConvergedCorrectPressure(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, void *ctx)
96649ef022SMatthew Knepley {
97649ef022SMatthew Knepley   PetscBool      monitorIntegral = PETSC_FALSE;
98649ef022SMatthew Knepley   PetscErrorCode ierr;
99649ef022SMatthew Knepley 
100649ef022SMatthew Knepley   PetscFunctionBegin;
101649ef022SMatthew Knepley   ierr = SNESConvergedDefault(snes, it, xnorm, gnorm, f, reason, ctx);CHKERRQ(ierr);
102649ef022SMatthew Knepley   if (monitorIntegral) {
103649ef022SMatthew Knepley     Mat          J;
104649ef022SMatthew Knepley     Vec          u;
105649ef022SMatthew Knepley     MatNullSpace nullspace;
106649ef022SMatthew Knepley     const Vec   *nullvecs;
107649ef022SMatthew Knepley     PetscScalar  pintd;
108649ef022SMatthew Knepley 
109649ef022SMatthew Knepley     ierr = SNESGetSolution(snes, &u);CHKERRQ(ierr);
110649ef022SMatthew Knepley     ierr = SNESGetJacobian(snes, &J, NULL, NULL, NULL);CHKERRQ(ierr);
111649ef022SMatthew Knepley     ierr = MatGetNullSpace(J, &nullspace);CHKERRQ(ierr);
112649ef022SMatthew Knepley     ierr = MatNullSpaceGetVecs(nullspace, NULL, NULL, &nullvecs);CHKERRQ(ierr);
113649ef022SMatthew Knepley     ierr = VecDot(nullvecs[0], u, &pintd);CHKERRQ(ierr);
114649ef022SMatthew Knepley     ierr = PetscInfo1(snes, "SNES: Discrete integral of pressure: %g\n", (double) PetscRealPart(pintd));CHKERRQ(ierr);
115649ef022SMatthew Knepley   }
116649ef022SMatthew Knepley   if (*reason > 0) {
117649ef022SMatthew Knepley     Mat          J;
118649ef022SMatthew Knepley     Vec          u;
119649ef022SMatthew Knepley     MatNullSpace nullspace;
120649ef022SMatthew Knepley     PetscInt     pfield = 1;
121649ef022SMatthew Knepley 
122649ef022SMatthew Knepley     ierr = SNESGetSolution(snes, &u);CHKERRQ(ierr);
123649ef022SMatthew Knepley     ierr = SNESGetJacobian(snes, &J, NULL, NULL, NULL);CHKERRQ(ierr);
124649ef022SMatthew Knepley     ierr = MatGetNullSpace(J, &nullspace);CHKERRQ(ierr);
125649ef022SMatthew Knepley     ierr = SNESCorrectDiscretePressure_Private(snes, pfield, nullspace, u, ctx);CHKERRQ(ierr);
126649ef022SMatthew Knepley   }
127649ef022SMatthew Knepley   PetscFunctionReturn(0);
128649ef022SMatthew Knepley }
129649ef022SMatthew Knepley 
13024cdb843SMatthew G. Knepley /************************** Interpolation *******************************/
13124cdb843SMatthew G. Knepley 
1326da023fcSToby Isaac static PetscErrorCode DMSNESConvertPlex(DM dm, DM *plex, PetscBool copy)
1336da023fcSToby Isaac {
1346da023fcSToby Isaac   PetscBool      isPlex;
1356da023fcSToby Isaac   PetscErrorCode ierr;
1366da023fcSToby Isaac 
1376da023fcSToby Isaac   PetscFunctionBegin;
1386da023fcSToby Isaac   ierr = PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);CHKERRQ(ierr);
1396da023fcSToby Isaac   if (isPlex) {
1406da023fcSToby Isaac     *plex = dm;
1416da023fcSToby Isaac     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr);
142f7148743SMatthew G. Knepley   } else {
143f7148743SMatthew G. Knepley     ierr = PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);CHKERRQ(ierr);
144f7148743SMatthew G. Knepley     if (!*plex) {
1456da023fcSToby Isaac       ierr = DMConvert(dm,DMPLEX,plex);CHKERRQ(ierr);
146f7148743SMatthew G. Knepley       ierr = PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);CHKERRQ(ierr);
1476da023fcSToby Isaac       if (copy) {
1486da023fcSToby Isaac         PetscInt    i;
1496da023fcSToby Isaac         PetscObject obj;
1506da023fcSToby Isaac         const char *comps[3] = {"A","dmAux","dmCh"};
1516da023fcSToby Isaac 
1526da023fcSToby Isaac         ierr = DMCopyDMSNES(dm, *plex);CHKERRQ(ierr);
1536da023fcSToby Isaac         for (i = 0; i < 3; i++) {
1546da023fcSToby Isaac           ierr = PetscObjectQuery((PetscObject) dm, comps[i], &obj);CHKERRQ(ierr);
1556da023fcSToby Isaac           ierr = PetscObjectCompose((PetscObject) *plex, comps[i], obj);CHKERRQ(ierr);
1566da023fcSToby Isaac         }
1576da023fcSToby Isaac       }
158f7148743SMatthew G. Knepley     } else {
159f7148743SMatthew G. Knepley       ierr = PetscObjectReference((PetscObject) *plex);CHKERRQ(ierr);
160f7148743SMatthew G. Knepley     }
1616da023fcSToby Isaac   }
1626da023fcSToby Isaac   PetscFunctionReturn(0);
1636da023fcSToby Isaac }
1646da023fcSToby Isaac 
1654267b1a3SMatthew G. Knepley /*@C
1664267b1a3SMatthew G. Knepley   DMInterpolationCreate - Creates a DMInterpolationInfo context
1674267b1a3SMatthew G. Knepley 
168d083f849SBarry Smith   Collective
1694267b1a3SMatthew G. Knepley 
1704267b1a3SMatthew G. Knepley   Input Parameter:
1714267b1a3SMatthew G. Knepley . comm - the communicator
1724267b1a3SMatthew G. Knepley 
1734267b1a3SMatthew G. Knepley   Output Parameter:
1744267b1a3SMatthew G. Knepley . ctx - the context
1754267b1a3SMatthew G. Knepley 
1764267b1a3SMatthew G. Knepley   Level: beginner
1774267b1a3SMatthew G. Knepley 
1784267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationDestroy()
1794267b1a3SMatthew G. Knepley @*/
1800adebc6cSBarry Smith PetscErrorCode DMInterpolationCreate(MPI_Comm comm, DMInterpolationInfo *ctx)
1810adebc6cSBarry Smith {
182552f7358SJed Brown   PetscErrorCode ierr;
183552f7358SJed Brown 
184552f7358SJed Brown   PetscFunctionBegin;
185552f7358SJed Brown   PetscValidPointer(ctx, 2);
18695dccacaSBarry Smith   ierr = PetscNew(ctx);CHKERRQ(ierr);
1871aa26658SKarl Rupp 
188552f7358SJed Brown   (*ctx)->comm   = comm;
189552f7358SJed Brown   (*ctx)->dim    = -1;
190552f7358SJed Brown   (*ctx)->nInput = 0;
1910298fd71SBarry Smith   (*ctx)->points = NULL;
1920298fd71SBarry Smith   (*ctx)->cells  = NULL;
193552f7358SJed Brown   (*ctx)->n      = -1;
1940298fd71SBarry Smith   (*ctx)->coords = NULL;
195552f7358SJed Brown   PetscFunctionReturn(0);
196552f7358SJed Brown }
197552f7358SJed Brown 
1984267b1a3SMatthew G. Knepley /*@C
1994267b1a3SMatthew G. Knepley   DMInterpolationSetDim - Sets the spatial dimension for the interpolation context
2004267b1a3SMatthew G. Knepley 
2014267b1a3SMatthew G. Knepley   Not collective
2024267b1a3SMatthew G. Knepley 
2034267b1a3SMatthew G. Knepley   Input Parameters:
2044267b1a3SMatthew G. Knepley + ctx - the context
2054267b1a3SMatthew G. Knepley - dim - the spatial dimension
2064267b1a3SMatthew G. Knepley 
2074267b1a3SMatthew G. Knepley   Level: intermediate
2084267b1a3SMatthew G. Knepley 
2094267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetDim(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
2104267b1a3SMatthew G. Knepley @*/
2110adebc6cSBarry Smith PetscErrorCode DMInterpolationSetDim(DMInterpolationInfo ctx, PetscInt dim)
2120adebc6cSBarry Smith {
213552f7358SJed Brown   PetscFunctionBegin;
214ff1e0c32SBarry Smith   if ((dim < 1) || (dim > 3)) SETERRQ1(ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension for points: %D", dim);
215552f7358SJed Brown   ctx->dim = dim;
216552f7358SJed Brown   PetscFunctionReturn(0);
217552f7358SJed Brown }
218552f7358SJed Brown 
2194267b1a3SMatthew G. Knepley /*@C
2204267b1a3SMatthew G. Knepley   DMInterpolationGetDim - Gets the spatial dimension for the interpolation context
2214267b1a3SMatthew G. Knepley 
2224267b1a3SMatthew G. Knepley   Not collective
2234267b1a3SMatthew G. Knepley 
2244267b1a3SMatthew G. Knepley   Input Parameter:
2254267b1a3SMatthew G. Knepley . ctx - the context
2264267b1a3SMatthew G. Knepley 
2274267b1a3SMatthew G. Knepley   Output Parameter:
2284267b1a3SMatthew G. Knepley . dim - the spatial dimension
2294267b1a3SMatthew G. Knepley 
2304267b1a3SMatthew G. Knepley   Level: intermediate
2314267b1a3SMatthew G. Knepley 
2324267b1a3SMatthew G. Knepley .seealso: DMInterpolationSetDim(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
2334267b1a3SMatthew G. Knepley @*/
2340adebc6cSBarry Smith PetscErrorCode DMInterpolationGetDim(DMInterpolationInfo ctx, PetscInt *dim)
2350adebc6cSBarry Smith {
236552f7358SJed Brown   PetscFunctionBegin;
237552f7358SJed Brown   PetscValidIntPointer(dim, 2);
238552f7358SJed Brown   *dim = ctx->dim;
239552f7358SJed Brown   PetscFunctionReturn(0);
240552f7358SJed Brown }
241552f7358SJed Brown 
2424267b1a3SMatthew G. Knepley /*@C
2434267b1a3SMatthew G. Knepley   DMInterpolationSetDof - Sets the number of fields interpolated at a point for the interpolation context
2444267b1a3SMatthew G. Knepley 
2454267b1a3SMatthew G. Knepley   Not collective
2464267b1a3SMatthew G. Knepley 
2474267b1a3SMatthew G. Knepley   Input Parameters:
2484267b1a3SMatthew G. Knepley + ctx - the context
2494267b1a3SMatthew G. Knepley - dof - the number of fields
2504267b1a3SMatthew G. Knepley 
2514267b1a3SMatthew G. Knepley   Level: intermediate
2524267b1a3SMatthew G. Knepley 
2534267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetDof(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
2544267b1a3SMatthew G. Knepley @*/
2550adebc6cSBarry Smith PetscErrorCode DMInterpolationSetDof(DMInterpolationInfo ctx, PetscInt dof)
2560adebc6cSBarry Smith {
257552f7358SJed Brown   PetscFunctionBegin;
258ff1e0c32SBarry Smith   if (dof < 1) SETERRQ1(ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of components: %D", dof);
259552f7358SJed Brown   ctx->dof = dof;
260552f7358SJed Brown   PetscFunctionReturn(0);
261552f7358SJed Brown }
262552f7358SJed Brown 
2634267b1a3SMatthew G. Knepley /*@C
2644267b1a3SMatthew G. Knepley   DMInterpolationGetDof - Gets the number of fields interpolated at a point for the interpolation context
2654267b1a3SMatthew G. Knepley 
2664267b1a3SMatthew G. Knepley   Not collective
2674267b1a3SMatthew G. Knepley 
2684267b1a3SMatthew G. Knepley   Input Parameter:
2694267b1a3SMatthew G. Knepley . ctx - the context
2704267b1a3SMatthew G. Knepley 
2714267b1a3SMatthew G. Knepley   Output Parameter:
2724267b1a3SMatthew G. Knepley . dof - the number of fields
2734267b1a3SMatthew G. Knepley 
2744267b1a3SMatthew G. Knepley   Level: intermediate
2754267b1a3SMatthew G. Knepley 
2764267b1a3SMatthew G. Knepley .seealso: DMInterpolationSetDof(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
2774267b1a3SMatthew G. Knepley @*/
2780adebc6cSBarry Smith PetscErrorCode DMInterpolationGetDof(DMInterpolationInfo ctx, PetscInt *dof)
2790adebc6cSBarry Smith {
280552f7358SJed Brown   PetscFunctionBegin;
281552f7358SJed Brown   PetscValidIntPointer(dof, 2);
282552f7358SJed Brown   *dof = ctx->dof;
283552f7358SJed Brown   PetscFunctionReturn(0);
284552f7358SJed Brown }
285552f7358SJed Brown 
2864267b1a3SMatthew G. Knepley /*@C
2874267b1a3SMatthew G. Knepley   DMInterpolationAddPoints - Add points at which we will interpolate the fields
2884267b1a3SMatthew G. Knepley 
2894267b1a3SMatthew G. Knepley   Not collective
2904267b1a3SMatthew G. Knepley 
2914267b1a3SMatthew G. Knepley   Input Parameters:
2924267b1a3SMatthew G. Knepley + ctx    - the context
2934267b1a3SMatthew G. Knepley . n      - the number of points
2944267b1a3SMatthew G. Knepley - points - the coordinates for each point, an array of size n * dim
2954267b1a3SMatthew G. Knepley 
2964267b1a3SMatthew G. Knepley   Note: The coordinate information is copied.
2974267b1a3SMatthew G. Knepley 
2984267b1a3SMatthew G. Knepley   Level: intermediate
2994267b1a3SMatthew G. Knepley 
3004267b1a3SMatthew G. Knepley .seealso: DMInterpolationSetDim(), DMInterpolationEvaluate(), DMInterpolationCreate()
3014267b1a3SMatthew G. Knepley @*/
3020adebc6cSBarry Smith PetscErrorCode DMInterpolationAddPoints(DMInterpolationInfo ctx, PetscInt n, PetscReal points[])
3030adebc6cSBarry Smith {
304552f7358SJed Brown   PetscErrorCode ierr;
305552f7358SJed Brown 
306552f7358SJed Brown   PetscFunctionBegin;
3070adebc6cSBarry Smith   if (ctx->dim < 0) SETERRQ(ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
3080adebc6cSBarry Smith   if (ctx->points)  SETERRQ(ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot add points multiple times yet");
309552f7358SJed Brown   ctx->nInput = n;
3101aa26658SKarl Rupp 
311785e854fSJed Brown   ierr = PetscMalloc1(n*ctx->dim, &ctx->points);CHKERRQ(ierr);
312580bdb30SBarry Smith   ierr = PetscArraycpy(ctx->points, points, n*ctx->dim);CHKERRQ(ierr);
313552f7358SJed Brown   PetscFunctionReturn(0);
314552f7358SJed Brown }
315552f7358SJed Brown 
3164267b1a3SMatthew G. Knepley /*@C
3174267b1a3SMatthew G. Knepley   DMInterpolationSetUp - Computea spatial indices that add in point location during interpolation
3184267b1a3SMatthew G. Knepley 
3194267b1a3SMatthew G. Knepley   Collective on ctx
3204267b1a3SMatthew G. Knepley 
3214267b1a3SMatthew G. Knepley   Input Parameters:
3224267b1a3SMatthew G. Knepley + ctx - the context
3234267b1a3SMatthew G. Knepley . dm  - the DM for the function space used for interpolation
3244267b1a3SMatthew G. Knepley - redundantPoints - If PETSC_TRUE, all processes are passing in the same array of points. Otherwise, points need to be communicated among processes.
3254267b1a3SMatthew G. Knepley 
3264267b1a3SMatthew G. Knepley   Level: intermediate
3274267b1a3SMatthew G. Knepley 
3284267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
3294267b1a3SMatthew G. Knepley @*/
3300adebc6cSBarry Smith PetscErrorCode DMInterpolationSetUp(DMInterpolationInfo ctx, DM dm, PetscBool redundantPoints)
3310adebc6cSBarry Smith {
332552f7358SJed Brown   MPI_Comm          comm = ctx->comm;
333552f7358SJed Brown   PetscScalar       *a;
334552f7358SJed Brown   PetscInt          p, q, i;
335552f7358SJed Brown   PetscMPIInt       rank, size;
336552f7358SJed Brown   PetscErrorCode    ierr;
337552f7358SJed Brown   Vec               pointVec;
3383a93e3b7SToby Isaac   PetscSF           cellSF;
339552f7358SJed Brown   PetscLayout       layout;
340552f7358SJed Brown   PetscReal         *globalPoints;
341cb313848SJed Brown   PetscScalar       *globalPointsScalar;
342552f7358SJed Brown   const PetscInt    *ranges;
343552f7358SJed Brown   PetscMPIInt       *counts, *displs;
3443a93e3b7SToby Isaac   const PetscSFNode *foundCells;
3453a93e3b7SToby Isaac   const PetscInt    *foundPoints;
346552f7358SJed Brown   PetscMPIInt       *foundProcs, *globalProcs;
3473a93e3b7SToby Isaac   PetscInt          n, N, numFound;
348552f7358SJed Brown 
34919436ca2SJed Brown   PetscFunctionBegin;
35019436ca2SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
351*ffc4695bSBarry Smith   ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
352*ffc4695bSBarry Smith   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
3530adebc6cSBarry Smith   if (ctx->dim < 0) SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
35419436ca2SJed Brown   /* Locate points */
35519436ca2SJed Brown   n = ctx->nInput;
356552f7358SJed Brown   if (!redundantPoints) {
357552f7358SJed Brown     ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
358552f7358SJed Brown     ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
359552f7358SJed Brown     ierr = PetscLayoutSetLocalSize(layout, n);CHKERRQ(ierr);
360552f7358SJed Brown     ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
361552f7358SJed Brown     ierr = PetscLayoutGetSize(layout, &N);CHKERRQ(ierr);
362552f7358SJed Brown     /* Communicate all points to all processes */
363dcca6d9dSJed Brown     ierr = PetscMalloc3(N*ctx->dim,&globalPoints,size,&counts,size,&displs);CHKERRQ(ierr);
364552f7358SJed Brown     ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
365552f7358SJed Brown     for (p = 0; p < size; ++p) {
366552f7358SJed Brown       counts[p] = (ranges[p+1] - ranges[p])*ctx->dim;
367552f7358SJed Brown       displs[p] = ranges[p]*ctx->dim;
368552f7358SJed Brown     }
369*ffc4695bSBarry Smith     ierr = MPI_Allgatherv(ctx->points, n*ctx->dim, MPIU_REAL, globalPoints, counts, displs, MPIU_REAL, comm);CHKERRMPI(ierr);
370552f7358SJed Brown   } else {
371552f7358SJed Brown     N = n;
372552f7358SJed Brown     globalPoints = ctx->points;
37338ea73c8SJed Brown     counts = displs = NULL;
37438ea73c8SJed Brown     layout = NULL;
375552f7358SJed Brown   }
376552f7358SJed Brown #if 0
377dcca6d9dSJed Brown   ierr = PetscMalloc3(N,&foundCells,N,&foundProcs,N,&globalProcs);CHKERRQ(ierr);
37819436ca2SJed Brown   /* foundCells[p] = m->locatePoint(&globalPoints[p*ctx->dim]); */
379552f7358SJed Brown #else
380cb313848SJed Brown #if defined(PETSC_USE_COMPLEX)
38146b3086cSToby Isaac   ierr = PetscMalloc1(N*ctx->dim,&globalPointsScalar);CHKERRQ(ierr);
38246b3086cSToby Isaac   for (i=0; i<N*ctx->dim; i++) globalPointsScalar[i] = globalPoints[i];
383cb313848SJed Brown #else
384cb313848SJed Brown   globalPointsScalar = globalPoints;
385cb313848SJed Brown #endif
38604706141SMatthew G Knepley   ierr = VecCreateSeqWithArray(PETSC_COMM_SELF, ctx->dim, N*ctx->dim, globalPointsScalar, &pointVec);CHKERRQ(ierr);
387dcca6d9dSJed Brown   ierr = PetscMalloc2(N,&foundProcs,N,&globalProcs);CHKERRQ(ierr);
3887b5f2079SMatthew G. Knepley   for (p = 0; p < N; ++p) {foundProcs[p] = size;}
3893a93e3b7SToby Isaac   cellSF = NULL;
3902d1fa6caSMatthew G. Knepley   ierr = DMLocatePoints(dm, pointVec, DM_POINTLOCATION_REMOVE, &cellSF);CHKERRQ(ierr);
3913a93e3b7SToby Isaac   ierr = PetscSFGetGraph(cellSF,NULL,&numFound,&foundPoints,&foundCells);CHKERRQ(ierr);
392552f7358SJed Brown #endif
3933a93e3b7SToby Isaac   for (p = 0; p < numFound; ++p) {
3943a93e3b7SToby Isaac     if (foundCells[p].index >= 0) foundProcs[foundPoints ? foundPoints[p] : p] = rank;
395552f7358SJed Brown   }
396552f7358SJed Brown   /* Let the lowest rank process own each point */
397b2566f29SBarry Smith   ierr   = MPIU_Allreduce(foundProcs, globalProcs, N, MPI_INT, MPI_MIN, comm);CHKERRQ(ierr);
398552f7358SJed Brown   ctx->n = 0;
399552f7358SJed Brown   for (p = 0; p < N; ++p) {
400e5b268a4SToby Isaac     if (globalProcs[p] == size) SETERRQ4(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));
4011aa26658SKarl Rupp     else if (globalProcs[p] == rank) ctx->n++;
402552f7358SJed Brown   }
403552f7358SJed Brown   /* Create coordinates vector and array of owned cells */
404785e854fSJed Brown   ierr = PetscMalloc1(ctx->n, &ctx->cells);CHKERRQ(ierr);
405552f7358SJed Brown   ierr = VecCreate(comm, &ctx->coords);CHKERRQ(ierr);
406552f7358SJed Brown   ierr = VecSetSizes(ctx->coords, ctx->n*ctx->dim, PETSC_DECIDE);CHKERRQ(ierr);
407552f7358SJed Brown   ierr = VecSetBlockSize(ctx->coords, ctx->dim);CHKERRQ(ierr);
408c0dedaeaSBarry Smith   ierr = VecSetType(ctx->coords,VECSTANDARD);CHKERRQ(ierr);
409552f7358SJed Brown   ierr = VecGetArray(ctx->coords, &a);CHKERRQ(ierr);
410552f7358SJed Brown   for (p = 0, q = 0, i = 0; p < N; ++p) {
411552f7358SJed Brown     if (globalProcs[p] == rank) {
412552f7358SJed Brown       PetscInt d;
413552f7358SJed Brown 
4141aa26658SKarl Rupp       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = globalPoints[p*ctx->dim+d];
415f317b747SMatthew G. Knepley       ctx->cells[q] = foundCells[q].index;
416f317b747SMatthew G. Knepley       ++q;
417552f7358SJed Brown     }
418552f7358SJed Brown   }
419552f7358SJed Brown   ierr = VecRestoreArray(ctx->coords, &a);CHKERRQ(ierr);
420552f7358SJed Brown #if 0
421552f7358SJed Brown   ierr = PetscFree3(foundCells,foundProcs,globalProcs);CHKERRQ(ierr);
422552f7358SJed Brown #else
423552f7358SJed Brown   ierr = PetscFree2(foundProcs,globalProcs);CHKERRQ(ierr);
4243a93e3b7SToby Isaac   ierr = PetscSFDestroy(&cellSF);CHKERRQ(ierr);
425552f7358SJed Brown   ierr = VecDestroy(&pointVec);CHKERRQ(ierr);
426552f7358SJed Brown #endif
427cb313848SJed Brown   if ((void*)globalPointsScalar != (void*)globalPoints) {ierr = PetscFree(globalPointsScalar);CHKERRQ(ierr);}
428d343d804SMatthew G. Knepley   if (!redundantPoints) {ierr = PetscFree3(globalPoints,counts,displs);CHKERRQ(ierr);}
429552f7358SJed Brown   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
430552f7358SJed Brown   PetscFunctionReturn(0);
431552f7358SJed Brown }
432552f7358SJed Brown 
4334267b1a3SMatthew G. Knepley /*@C
4344267b1a3SMatthew G. Knepley   DMInterpolationGetCoordinates - Gets a Vec with the coordinates of each interpolation point
4354267b1a3SMatthew G. Knepley 
4364267b1a3SMatthew G. Knepley   Collective on ctx
4374267b1a3SMatthew G. Knepley 
4384267b1a3SMatthew G. Knepley   Input Parameter:
4394267b1a3SMatthew G. Knepley . ctx - the context
4404267b1a3SMatthew G. Knepley 
4414267b1a3SMatthew G. Knepley   Output Parameter:
4424267b1a3SMatthew G. Knepley . coordinates  - the coordinates of interpolation points
4434267b1a3SMatthew G. Knepley 
4444267b1a3SMatthew 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.
4454267b1a3SMatthew G. Knepley 
4464267b1a3SMatthew G. Knepley   Level: intermediate
4474267b1a3SMatthew G. Knepley 
4484267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
4494267b1a3SMatthew G. Knepley @*/
4500adebc6cSBarry Smith PetscErrorCode DMInterpolationGetCoordinates(DMInterpolationInfo ctx, Vec *coordinates)
4510adebc6cSBarry Smith {
452552f7358SJed Brown   PetscFunctionBegin;
453552f7358SJed Brown   PetscValidPointer(coordinates, 2);
4540adebc6cSBarry Smith   if (!ctx->coords) SETERRQ(ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
455552f7358SJed Brown   *coordinates = ctx->coords;
456552f7358SJed Brown   PetscFunctionReturn(0);
457552f7358SJed Brown }
458552f7358SJed Brown 
4594267b1a3SMatthew G. Knepley /*@C
4604267b1a3SMatthew G. Knepley   DMInterpolationGetVector - Gets a Vec which can hold all the interpolated field values
4614267b1a3SMatthew G. Knepley 
4624267b1a3SMatthew G. Knepley   Collective on ctx
4634267b1a3SMatthew G. Knepley 
4644267b1a3SMatthew G. Knepley   Input Parameter:
4654267b1a3SMatthew G. Knepley . ctx - the context
4664267b1a3SMatthew G. Knepley 
4674267b1a3SMatthew G. Knepley   Output Parameter:
4684267b1a3SMatthew G. Knepley . v  - a vector capable of holding the interpolated field values
4694267b1a3SMatthew G. Knepley 
4704267b1a3SMatthew G. Knepley   Note: This vector should be returned using DMInterpolationRestoreVector().
4714267b1a3SMatthew G. Knepley 
4724267b1a3SMatthew G. Knepley   Level: intermediate
4734267b1a3SMatthew G. Knepley 
4744267b1a3SMatthew G. Knepley .seealso: DMInterpolationRestoreVector(), DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
4754267b1a3SMatthew G. Knepley @*/
4760adebc6cSBarry Smith PetscErrorCode DMInterpolationGetVector(DMInterpolationInfo ctx, Vec *v)
4770adebc6cSBarry Smith {
478552f7358SJed Brown   PetscErrorCode ierr;
479552f7358SJed Brown 
480552f7358SJed Brown   PetscFunctionBegin;
481552f7358SJed Brown   PetscValidPointer(v, 2);
4820adebc6cSBarry Smith   if (!ctx->coords) SETERRQ(ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
483552f7358SJed Brown   ierr = VecCreate(ctx->comm, v);CHKERRQ(ierr);
484552f7358SJed Brown   ierr = VecSetSizes(*v, ctx->n*ctx->dof, PETSC_DECIDE);CHKERRQ(ierr);
485552f7358SJed Brown   ierr = VecSetBlockSize(*v, ctx->dof);CHKERRQ(ierr);
486c0dedaeaSBarry Smith   ierr = VecSetType(*v,VECSTANDARD);CHKERRQ(ierr);
487552f7358SJed Brown   PetscFunctionReturn(0);
488552f7358SJed Brown }
489552f7358SJed Brown 
4904267b1a3SMatthew G. Knepley /*@C
4914267b1a3SMatthew G. Knepley   DMInterpolationRestoreVector - Returns a Vec which can hold all the interpolated field values
4924267b1a3SMatthew G. Knepley 
4934267b1a3SMatthew G. Knepley   Collective on ctx
4944267b1a3SMatthew G. Knepley 
4954267b1a3SMatthew G. Knepley   Input Parameters:
4964267b1a3SMatthew G. Knepley + ctx - the context
4974267b1a3SMatthew G. Knepley - v  - a vector capable of holding the interpolated field values
4984267b1a3SMatthew G. Knepley 
4994267b1a3SMatthew G. Knepley   Level: intermediate
5004267b1a3SMatthew G. Knepley 
5014267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetVector(), DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
5024267b1a3SMatthew G. Knepley @*/
5030adebc6cSBarry Smith PetscErrorCode DMInterpolationRestoreVector(DMInterpolationInfo ctx, Vec *v)
5040adebc6cSBarry Smith {
505552f7358SJed Brown   PetscErrorCode ierr;
506552f7358SJed Brown 
507552f7358SJed Brown   PetscFunctionBegin;
508552f7358SJed Brown   PetscValidPointer(v, 2);
5090adebc6cSBarry Smith   if (!ctx->coords) SETERRQ(ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
510552f7358SJed Brown   ierr = VecDestroy(v);CHKERRQ(ierr);
511552f7358SJed Brown   PetscFunctionReturn(0);
512552f7358SJed Brown }
513552f7358SJed Brown 
5147a1931ceSMatthew G. Knepley PETSC_STATIC_INLINE PetscErrorCode DMInterpolate_Triangle_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
515a6dfd86eSKarl Rupp {
516552f7358SJed Brown   PetscReal      *v0, *J, *invJ, detJ;
51756044e6dSMatthew G. Knepley   const PetscScalar *coords;
51856044e6dSMatthew G. Knepley   PetscScalar    *a;
519552f7358SJed Brown   PetscInt       p;
520552f7358SJed Brown   PetscErrorCode ierr;
521552f7358SJed Brown 
522552f7358SJed Brown   PetscFunctionBegin;
523dcca6d9dSJed Brown   ierr = PetscMalloc3(ctx->dim,&v0,ctx->dim*ctx->dim,&J,ctx->dim*ctx->dim,&invJ);CHKERRQ(ierr);
52456044e6dSMatthew G. Knepley   ierr = VecGetArrayRead(ctx->coords, &coords);CHKERRQ(ierr);
525552f7358SJed Brown   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
526552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
527552f7358SJed Brown     PetscInt     c = ctx->cells[p];
528a1e44745SMatthew G. Knepley     PetscScalar *x = NULL;
529552f7358SJed Brown     PetscReal    xi[4];
530552f7358SJed Brown     PetscInt     d, f, comp;
531552f7358SJed Brown 
5328e0841e0SMatthew G. Knepley     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
533ff1e0c32SBarry Smith     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D", (double)detJ, c);
5340298fd71SBarry Smith     ierr = DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x);CHKERRQ(ierr);
5351aa26658SKarl Rupp     for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp];
5361aa26658SKarl Rupp 
537552f7358SJed Brown     for (d = 0; d < ctx->dim; ++d) {
538552f7358SJed Brown       xi[d] = 0.0;
5391aa26658SKarl 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]);
5401aa26658SKarl 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];
541552f7358SJed Brown     }
5420298fd71SBarry Smith     ierr = DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x);CHKERRQ(ierr);
543552f7358SJed Brown   }
544552f7358SJed Brown   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
54556044e6dSMatthew G. Knepley   ierr = VecRestoreArrayRead(ctx->coords, &coords);CHKERRQ(ierr);
546552f7358SJed Brown   ierr = PetscFree3(v0, J, invJ);CHKERRQ(ierr);
547552f7358SJed Brown   PetscFunctionReturn(0);
548552f7358SJed Brown }
549552f7358SJed Brown 
5507a1931ceSMatthew G. Knepley PETSC_STATIC_INLINE PetscErrorCode DMInterpolate_Tetrahedron_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
5517a1931ceSMatthew G. Knepley {
5527a1931ceSMatthew G. Knepley   PetscReal      *v0, *J, *invJ, detJ;
55356044e6dSMatthew G. Knepley   const PetscScalar *coords;
55456044e6dSMatthew G. Knepley   PetscScalar    *a;
5557a1931ceSMatthew G. Knepley   PetscInt       p;
5567a1931ceSMatthew G. Knepley   PetscErrorCode ierr;
5577a1931ceSMatthew G. Knepley 
5587a1931ceSMatthew G. Knepley   PetscFunctionBegin;
559dcca6d9dSJed Brown   ierr = PetscMalloc3(ctx->dim,&v0,ctx->dim*ctx->dim,&J,ctx->dim*ctx->dim,&invJ);CHKERRQ(ierr);
56056044e6dSMatthew G. Knepley   ierr = VecGetArrayRead(ctx->coords, &coords);CHKERRQ(ierr);
5617a1931ceSMatthew G. Knepley   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
5627a1931ceSMatthew G. Knepley   for (p = 0; p < ctx->n; ++p) {
5637a1931ceSMatthew G. Knepley     PetscInt       c = ctx->cells[p];
5647a1931ceSMatthew G. Knepley     const PetscInt order[3] = {2, 1, 3};
5652584bbe8SMatthew G. Knepley     PetscScalar   *x = NULL;
5667a1931ceSMatthew G. Knepley     PetscReal      xi[4];
5677a1931ceSMatthew G. Knepley     PetscInt       d, f, comp;
5687a1931ceSMatthew G. Knepley 
5698e0841e0SMatthew G. Knepley     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
570ff1e0c32SBarry Smith     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D", (double)detJ, c);
5717a1931ceSMatthew G. Knepley     ierr = DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x);CHKERRQ(ierr);
5727a1931ceSMatthew G. Knepley     for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp];
5737a1931ceSMatthew G. Knepley 
5747a1931ceSMatthew G. Knepley     for (d = 0; d < ctx->dim; ++d) {
5757a1931ceSMatthew G. Knepley       xi[d] = 0.0;
5767a1931ceSMatthew 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]);
5777a1931ceSMatthew 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];
5787a1931ceSMatthew G. Knepley     }
5797a1931ceSMatthew G. Knepley     ierr = DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x);CHKERRQ(ierr);
5807a1931ceSMatthew G. Knepley   }
5817a1931ceSMatthew G. Knepley   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
58256044e6dSMatthew G. Knepley   ierr = VecRestoreArrayRead(ctx->coords, &coords);CHKERRQ(ierr);
5837a1931ceSMatthew G. Knepley   ierr = PetscFree3(v0, J, invJ);CHKERRQ(ierr);
5847a1931ceSMatthew G. Knepley   PetscFunctionReturn(0);
5857a1931ceSMatthew G. Knepley }
5867a1931ceSMatthew G. Knepley 
5875820edbdSMatthew G Knepley PETSC_STATIC_INLINE PetscErrorCode QuadMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
588552f7358SJed Brown {
589552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
590552f7358SJed Brown   const PetscScalar x0        = vertices[0];
591552f7358SJed Brown   const PetscScalar y0        = vertices[1];
592552f7358SJed Brown   const PetscScalar x1        = vertices[2];
593552f7358SJed Brown   const PetscScalar y1        = vertices[3];
594552f7358SJed Brown   const PetscScalar x2        = vertices[4];
595552f7358SJed Brown   const PetscScalar y2        = vertices[5];
596552f7358SJed Brown   const PetscScalar x3        = vertices[6];
597552f7358SJed Brown   const PetscScalar y3        = vertices[7];
598552f7358SJed Brown   const PetscScalar f_1       = x1 - x0;
599552f7358SJed Brown   const PetscScalar g_1       = y1 - y0;
600552f7358SJed Brown   const PetscScalar f_3       = x3 - x0;
601552f7358SJed Brown   const PetscScalar g_3       = y3 - y0;
602552f7358SJed Brown   const PetscScalar f_01      = x2 - x1 - x3 + x0;
603552f7358SJed Brown   const PetscScalar g_01      = y2 - y1 - y3 + y0;
60456044e6dSMatthew G. Knepley   const PetscScalar *ref;
60556044e6dSMatthew G. Knepley   PetscScalar       *real;
606552f7358SJed Brown   PetscErrorCode    ierr;
607552f7358SJed Brown 
608552f7358SJed Brown   PetscFunctionBegin;
60956044e6dSMatthew G. Knepley   ierr = VecGetArrayRead(Xref,  &ref);CHKERRQ(ierr);
610552f7358SJed Brown   ierr = VecGetArray(Xreal, &real);CHKERRQ(ierr);
611552f7358SJed Brown   {
612552f7358SJed Brown     const PetscScalar p0 = ref[0];
613552f7358SJed Brown     const PetscScalar p1 = ref[1];
614552f7358SJed Brown 
615552f7358SJed Brown     real[0] = x0 + f_1 * p0 + f_3 * p1 + f_01 * p0 * p1;
616552f7358SJed Brown     real[1] = y0 + g_1 * p0 + g_3 * p1 + g_01 * p0 * p1;
617552f7358SJed Brown   }
618552f7358SJed Brown   ierr = PetscLogFlops(28);CHKERRQ(ierr);
61956044e6dSMatthew G. Knepley   ierr = VecRestoreArrayRead(Xref,  &ref);CHKERRQ(ierr);
620552f7358SJed Brown   ierr = VecRestoreArray(Xreal, &real);CHKERRQ(ierr);
621552f7358SJed Brown   PetscFunctionReturn(0);
622552f7358SJed Brown }
623552f7358SJed Brown 
624af0996ceSBarry Smith #include <petsc/private/dmimpl.h>
625d1e9a80fSBarry Smith PETSC_STATIC_INLINE PetscErrorCode QuadJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
626552f7358SJed Brown {
627552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
628552f7358SJed Brown   const PetscScalar x0        = vertices[0];
629552f7358SJed Brown   const PetscScalar y0        = vertices[1];
630552f7358SJed Brown   const PetscScalar x1        = vertices[2];
631552f7358SJed Brown   const PetscScalar y1        = vertices[3];
632552f7358SJed Brown   const PetscScalar x2        = vertices[4];
633552f7358SJed Brown   const PetscScalar y2        = vertices[5];
634552f7358SJed Brown   const PetscScalar x3        = vertices[6];
635552f7358SJed Brown   const PetscScalar y3        = vertices[7];
636552f7358SJed Brown   const PetscScalar f_01      = x2 - x1 - x3 + x0;
637552f7358SJed Brown   const PetscScalar g_01      = y2 - y1 - y3 + y0;
63856044e6dSMatthew G. Knepley   const PetscScalar *ref;
639552f7358SJed Brown   PetscErrorCode    ierr;
640552f7358SJed Brown 
641552f7358SJed Brown   PetscFunctionBegin;
64256044e6dSMatthew G. Knepley   ierr = VecGetArrayRead(Xref,  &ref);CHKERRQ(ierr);
643552f7358SJed Brown   {
644552f7358SJed Brown     const PetscScalar x       = ref[0];
645552f7358SJed Brown     const PetscScalar y       = ref[1];
646552f7358SJed Brown     const PetscInt    rows[2] = {0, 1};
647da80777bSKarl Rupp     PetscScalar       values[4];
648da80777bSKarl Rupp 
649da80777bSKarl Rupp     values[0] = (x1 - x0 + f_01*y) * 0.5; values[1] = (x3 - x0 + f_01*x) * 0.5;
650da80777bSKarl Rupp     values[2] = (y1 - y0 + g_01*y) * 0.5; values[3] = (y3 - y0 + g_01*x) * 0.5;
65194ab13aaSBarry Smith     ierr      = MatSetValues(J, 2, rows, 2, rows, values, INSERT_VALUES);CHKERRQ(ierr);
652552f7358SJed Brown   }
653552f7358SJed Brown   ierr = PetscLogFlops(30);CHKERRQ(ierr);
65456044e6dSMatthew G. Knepley   ierr = VecRestoreArrayRead(Xref,  &ref);CHKERRQ(ierr);
65594ab13aaSBarry Smith   ierr = MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
65694ab13aaSBarry Smith   ierr = MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
657552f7358SJed Brown   PetscFunctionReturn(0);
658552f7358SJed Brown }
659552f7358SJed Brown 
660a6dfd86eSKarl Rupp PETSC_STATIC_INLINE PetscErrorCode DMInterpolate_Quad_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
661a6dfd86eSKarl Rupp {
662fafc0619SMatthew G Knepley   DM             dmCoord;
663de73a395SMatthew G. Knepley   PetscFE        fem = NULL;
664552f7358SJed Brown   SNES           snes;
665552f7358SJed Brown   KSP            ksp;
666552f7358SJed Brown   PC             pc;
667552f7358SJed Brown   Vec            coordsLocal, r, ref, real;
668552f7358SJed Brown   Mat            J;
669ef0bb6c7SMatthew G. Knepley   PetscTabulation    T;
67056044e6dSMatthew G. Knepley   const PetscScalar *coords;
67156044e6dSMatthew G. Knepley   PetscScalar    *a;
672ef0bb6c7SMatthew G. Knepley   PetscReal      xir[2];
673de73a395SMatthew G. Knepley   PetscInt       Nf, p;
6745509d985SMatthew G. Knepley   const PetscInt dof = ctx->dof;
675552f7358SJed Brown   PetscErrorCode ierr;
676552f7358SJed Brown 
677552f7358SJed Brown   PetscFunctionBegin;
678de73a395SMatthew G. Knepley   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
67944a7f3ddSMatthew G. Knepley   if (Nf) {ierr = DMGetField(dm, 0, NULL, (PetscObject *) &fem);CHKERRQ(ierr);}
680552f7358SJed Brown   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
681fafc0619SMatthew G Knepley   ierr = DMGetCoordinateDM(dm, &dmCoord);CHKERRQ(ierr);
682552f7358SJed Brown   ierr = SNESCreate(PETSC_COMM_SELF, &snes);CHKERRQ(ierr);
683552f7358SJed Brown   ierr = SNESSetOptionsPrefix(snes, "quad_interp_");CHKERRQ(ierr);
684552f7358SJed Brown   ierr = VecCreate(PETSC_COMM_SELF, &r);CHKERRQ(ierr);
685552f7358SJed Brown   ierr = VecSetSizes(r, 2, 2);CHKERRQ(ierr);
686c0dedaeaSBarry Smith   ierr = VecSetType(r,dm->vectype);CHKERRQ(ierr);
687552f7358SJed Brown   ierr = VecDuplicate(r, &ref);CHKERRQ(ierr);
688552f7358SJed Brown   ierr = VecDuplicate(r, &real);CHKERRQ(ierr);
689552f7358SJed Brown   ierr = MatCreate(PETSC_COMM_SELF, &J);CHKERRQ(ierr);
690552f7358SJed Brown   ierr = MatSetSizes(J, 2, 2, 2, 2);CHKERRQ(ierr);
691552f7358SJed Brown   ierr = MatSetType(J, MATSEQDENSE);CHKERRQ(ierr);
692552f7358SJed Brown   ierr = MatSetUp(J);CHKERRQ(ierr);
6930298fd71SBarry Smith   ierr = SNESSetFunction(snes, r, QuadMap_Private, NULL);CHKERRQ(ierr);
6940298fd71SBarry Smith   ierr = SNESSetJacobian(snes, J, J, QuadJacobian_Private, NULL);CHKERRQ(ierr);
695552f7358SJed Brown   ierr = SNESGetKSP(snes, &ksp);CHKERRQ(ierr);
696552f7358SJed Brown   ierr = KSPGetPC(ksp, &pc);CHKERRQ(ierr);
697552f7358SJed Brown   ierr = PCSetType(pc, PCLU);CHKERRQ(ierr);
698552f7358SJed Brown   ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
699552f7358SJed Brown 
70056044e6dSMatthew G. Knepley   ierr = VecGetArrayRead(ctx->coords, &coords);CHKERRQ(ierr);
701552f7358SJed Brown   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
702ef0bb6c7SMatthew G. Knepley   ierr = PetscFECreateTabulation(fem, 1, 1, xir, 0, &T);CHKERRQ(ierr);
703552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
704a1e44745SMatthew G. Knepley     PetscScalar *x = NULL, *vertices = NULL;
705552f7358SJed Brown     PetscScalar *xi;
706552f7358SJed Brown     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
707552f7358SJed Brown 
708552f7358SJed Brown     /* Can make this do all points at once */
7090298fd71SBarry Smith     ierr = DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices);CHKERRQ(ierr);
710ff1e0c32SBarry Smith     if (4*2 != coordSize) SETERRQ2(ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %D should be %d", coordSize, 4*2);
7110298fd71SBarry Smith     ierr   = DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x);CHKERRQ(ierr);
7120298fd71SBarry Smith     ierr   = SNESSetFunction(snes, NULL, NULL, (void*) vertices);CHKERRQ(ierr);
7130298fd71SBarry Smith     ierr   = SNESSetJacobian(snes, NULL, NULL, NULL, (void*) vertices);CHKERRQ(ierr);
714552f7358SJed Brown     ierr   = VecGetArray(real, &xi);CHKERRQ(ierr);
715552f7358SJed Brown     xi[0]  = coords[p*ctx->dim+0];
716552f7358SJed Brown     xi[1]  = coords[p*ctx->dim+1];
717552f7358SJed Brown     ierr   = VecRestoreArray(real, &xi);CHKERRQ(ierr);
718552f7358SJed Brown     ierr   = SNESSolve(snes, real, ref);CHKERRQ(ierr);
719552f7358SJed Brown     ierr   = VecGetArray(ref, &xi);CHKERRQ(ierr);
720cb313848SJed Brown     xir[0] = PetscRealPart(xi[0]);
721cb313848SJed Brown     xir[1] = PetscRealPart(xi[1]);
7225509d985SMatthew G. Knepley     if (4*dof != xSize) {
7235509d985SMatthew G. Knepley       PetscInt d;
7241aa26658SKarl Rupp 
7255509d985SMatthew G. Knepley       xir[0] = 2.0*xir[0] - 1.0; xir[1] = 2.0*xir[1] - 1.0;
726ef0bb6c7SMatthew G. Knepley       ierr = PetscFEComputeTabulation(fem, 1, xir, 0, T);CHKERRQ(ierr);
7275509d985SMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) {
7285509d985SMatthew G. Knepley         a[p*dof+comp] = 0.0;
7295509d985SMatthew G. Knepley         for (d = 0; d < xSize/dof; ++d) {
730ef0bb6c7SMatthew G. Knepley           a[p*dof+comp] += x[d*dof+comp]*T->T[0][d*dof+comp];
7315509d985SMatthew G. Knepley         }
7325509d985SMatthew G. Knepley       }
7335509d985SMatthew G. Knepley     } else {
7345509d985SMatthew G. Knepley       for (comp = 0; comp < dof; ++comp)
7355509d985SMatthew 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];
7365509d985SMatthew G. Knepley     }
737552f7358SJed Brown     ierr = VecRestoreArray(ref, &xi);CHKERRQ(ierr);
7380298fd71SBarry Smith     ierr = DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices);CHKERRQ(ierr);
7390298fd71SBarry Smith     ierr = DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x);CHKERRQ(ierr);
740552f7358SJed Brown   }
741ef0bb6c7SMatthew G. Knepley   ierr = PetscTabulationDestroy(&T);CHKERRQ(ierr);
742552f7358SJed Brown   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
74356044e6dSMatthew G. Knepley   ierr = VecRestoreArrayRead(ctx->coords, &coords);CHKERRQ(ierr);
744552f7358SJed Brown 
745552f7358SJed Brown   ierr = SNESDestroy(&snes);CHKERRQ(ierr);
746552f7358SJed Brown   ierr = VecDestroy(&r);CHKERRQ(ierr);
747552f7358SJed Brown   ierr = VecDestroy(&ref);CHKERRQ(ierr);
748552f7358SJed Brown   ierr = VecDestroy(&real);CHKERRQ(ierr);
749552f7358SJed Brown   ierr = MatDestroy(&J);CHKERRQ(ierr);
750552f7358SJed Brown   PetscFunctionReturn(0);
751552f7358SJed Brown }
752552f7358SJed Brown 
7535820edbdSMatthew G Knepley PETSC_STATIC_INLINE PetscErrorCode HexMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
754552f7358SJed Brown {
755552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
756552f7358SJed Brown   const PetscScalar x0        = vertices[0];
757552f7358SJed Brown   const PetscScalar y0        = vertices[1];
758552f7358SJed Brown   const PetscScalar z0        = vertices[2];
7597a1931ceSMatthew G. Knepley   const PetscScalar x1        = vertices[9];
7607a1931ceSMatthew G. Knepley   const PetscScalar y1        = vertices[10];
7617a1931ceSMatthew G. Knepley   const PetscScalar z1        = vertices[11];
762552f7358SJed Brown   const PetscScalar x2        = vertices[6];
763552f7358SJed Brown   const PetscScalar y2        = vertices[7];
764552f7358SJed Brown   const PetscScalar z2        = vertices[8];
7657a1931ceSMatthew G. Knepley   const PetscScalar x3        = vertices[3];
7667a1931ceSMatthew G. Knepley   const PetscScalar y3        = vertices[4];
7677a1931ceSMatthew G. Knepley   const PetscScalar z3        = vertices[5];
768552f7358SJed Brown   const PetscScalar x4        = vertices[12];
769552f7358SJed Brown   const PetscScalar y4        = vertices[13];
770552f7358SJed Brown   const PetscScalar z4        = vertices[14];
771552f7358SJed Brown   const PetscScalar x5        = vertices[15];
772552f7358SJed Brown   const PetscScalar y5        = vertices[16];
773552f7358SJed Brown   const PetscScalar z5        = vertices[17];
774552f7358SJed Brown   const PetscScalar x6        = vertices[18];
775552f7358SJed Brown   const PetscScalar y6        = vertices[19];
776552f7358SJed Brown   const PetscScalar z6        = vertices[20];
777552f7358SJed Brown   const PetscScalar x7        = vertices[21];
778552f7358SJed Brown   const PetscScalar y7        = vertices[22];
779552f7358SJed Brown   const PetscScalar z7        = vertices[23];
780552f7358SJed Brown   const PetscScalar f_1       = x1 - x0;
781552f7358SJed Brown   const PetscScalar g_1       = y1 - y0;
782552f7358SJed Brown   const PetscScalar h_1       = z1 - z0;
783552f7358SJed Brown   const PetscScalar f_3       = x3 - x0;
784552f7358SJed Brown   const PetscScalar g_3       = y3 - y0;
785552f7358SJed Brown   const PetscScalar h_3       = z3 - z0;
786552f7358SJed Brown   const PetscScalar f_4       = x4 - x0;
787552f7358SJed Brown   const PetscScalar g_4       = y4 - y0;
788552f7358SJed Brown   const PetscScalar h_4       = z4 - z0;
789552f7358SJed Brown   const PetscScalar f_01      = x2 - x1 - x3 + x0;
790552f7358SJed Brown   const PetscScalar g_01      = y2 - y1 - y3 + y0;
791552f7358SJed Brown   const PetscScalar h_01      = z2 - z1 - z3 + z0;
792552f7358SJed Brown   const PetscScalar f_12      = x7 - x3 - x4 + x0;
793552f7358SJed Brown   const PetscScalar g_12      = y7 - y3 - y4 + y0;
794552f7358SJed Brown   const PetscScalar h_12      = z7 - z3 - z4 + z0;
795552f7358SJed Brown   const PetscScalar f_02      = x5 - x1 - x4 + x0;
796552f7358SJed Brown   const PetscScalar g_02      = y5 - y1 - y4 + y0;
797552f7358SJed Brown   const PetscScalar h_02      = z5 - z1 - z4 + z0;
798552f7358SJed Brown   const PetscScalar f_012     = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
799552f7358SJed Brown   const PetscScalar g_012     = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
800552f7358SJed Brown   const PetscScalar h_012     = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
80156044e6dSMatthew G. Knepley   const PetscScalar *ref;
80256044e6dSMatthew G. Knepley   PetscScalar       *real;
803552f7358SJed Brown   PetscErrorCode    ierr;
804552f7358SJed Brown 
805552f7358SJed Brown   PetscFunctionBegin;
80656044e6dSMatthew G. Knepley   ierr = VecGetArrayRead(Xref,  &ref);CHKERRQ(ierr);
807552f7358SJed Brown   ierr = VecGetArray(Xreal, &real);CHKERRQ(ierr);
808552f7358SJed Brown   {
809552f7358SJed Brown     const PetscScalar p0 = ref[0];
810552f7358SJed Brown     const PetscScalar p1 = ref[1];
811552f7358SJed Brown     const PetscScalar p2 = ref[2];
812552f7358SJed Brown 
813552f7358SJed 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;
814552f7358SJed 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;
815552f7358SJed 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;
816552f7358SJed Brown   }
817552f7358SJed Brown   ierr = PetscLogFlops(114);CHKERRQ(ierr);
81856044e6dSMatthew G. Knepley   ierr = VecRestoreArrayRead(Xref,  &ref);CHKERRQ(ierr);
819552f7358SJed Brown   ierr = VecRestoreArray(Xreal, &real);CHKERRQ(ierr);
820552f7358SJed Brown   PetscFunctionReturn(0);
821552f7358SJed Brown }
822552f7358SJed Brown 
823d1e9a80fSBarry Smith PETSC_STATIC_INLINE PetscErrorCode HexJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
824552f7358SJed Brown {
825552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
826552f7358SJed Brown   const PetscScalar x0        = vertices[0];
827552f7358SJed Brown   const PetscScalar y0        = vertices[1];
828552f7358SJed Brown   const PetscScalar z0        = vertices[2];
8297a1931ceSMatthew G. Knepley   const PetscScalar x1        = vertices[9];
8307a1931ceSMatthew G. Knepley   const PetscScalar y1        = vertices[10];
8317a1931ceSMatthew G. Knepley   const PetscScalar z1        = vertices[11];
832552f7358SJed Brown   const PetscScalar x2        = vertices[6];
833552f7358SJed Brown   const PetscScalar y2        = vertices[7];
834552f7358SJed Brown   const PetscScalar z2        = vertices[8];
8357a1931ceSMatthew G. Knepley   const PetscScalar x3        = vertices[3];
8367a1931ceSMatthew G. Knepley   const PetscScalar y3        = vertices[4];
8377a1931ceSMatthew G. Knepley   const PetscScalar z3        = vertices[5];
838552f7358SJed Brown   const PetscScalar x4        = vertices[12];
839552f7358SJed Brown   const PetscScalar y4        = vertices[13];
840552f7358SJed Brown   const PetscScalar z4        = vertices[14];
841552f7358SJed Brown   const PetscScalar x5        = vertices[15];
842552f7358SJed Brown   const PetscScalar y5        = vertices[16];
843552f7358SJed Brown   const PetscScalar z5        = vertices[17];
844552f7358SJed Brown   const PetscScalar x6        = vertices[18];
845552f7358SJed Brown   const PetscScalar y6        = vertices[19];
846552f7358SJed Brown   const PetscScalar z6        = vertices[20];
847552f7358SJed Brown   const PetscScalar x7        = vertices[21];
848552f7358SJed Brown   const PetscScalar y7        = vertices[22];
849552f7358SJed Brown   const PetscScalar z7        = vertices[23];
850552f7358SJed Brown   const PetscScalar f_xy      = x2 - x1 - x3 + x0;
851552f7358SJed Brown   const PetscScalar g_xy      = y2 - y1 - y3 + y0;
852552f7358SJed Brown   const PetscScalar h_xy      = z2 - z1 - z3 + z0;
853552f7358SJed Brown   const PetscScalar f_yz      = x7 - x3 - x4 + x0;
854552f7358SJed Brown   const PetscScalar g_yz      = y7 - y3 - y4 + y0;
855552f7358SJed Brown   const PetscScalar h_yz      = z7 - z3 - z4 + z0;
856552f7358SJed Brown   const PetscScalar f_xz      = x5 - x1 - x4 + x0;
857552f7358SJed Brown   const PetscScalar g_xz      = y5 - y1 - y4 + y0;
858552f7358SJed Brown   const PetscScalar h_xz      = z5 - z1 - z4 + z0;
859552f7358SJed Brown   const PetscScalar f_xyz     = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
860552f7358SJed Brown   const PetscScalar g_xyz     = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
861552f7358SJed Brown   const PetscScalar h_xyz     = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
86256044e6dSMatthew G. Knepley   const PetscScalar *ref;
863552f7358SJed Brown   PetscErrorCode    ierr;
864552f7358SJed Brown 
865552f7358SJed Brown   PetscFunctionBegin;
86656044e6dSMatthew G. Knepley   ierr = VecGetArrayRead(Xref,  &ref);CHKERRQ(ierr);
867552f7358SJed Brown   {
868552f7358SJed Brown     const PetscScalar x       = ref[0];
869552f7358SJed Brown     const PetscScalar y       = ref[1];
870552f7358SJed Brown     const PetscScalar z       = ref[2];
871552f7358SJed Brown     const PetscInt    rows[3] = {0, 1, 2};
872da80777bSKarl Rupp     PetscScalar       values[9];
873da80777bSKarl Rupp 
874da80777bSKarl Rupp     values[0] = (x1 - x0 + f_xy*y + f_xz*z + f_xyz*y*z) / 2.0;
875da80777bSKarl Rupp     values[1] = (x3 - x0 + f_xy*x + f_yz*z + f_xyz*x*z) / 2.0;
876da80777bSKarl Rupp     values[2] = (x4 - x0 + f_yz*y + f_xz*x + f_xyz*x*y) / 2.0;
877da80777bSKarl Rupp     values[3] = (y1 - y0 + g_xy*y + g_xz*z + g_xyz*y*z) / 2.0;
878da80777bSKarl Rupp     values[4] = (y3 - y0 + g_xy*x + g_yz*z + g_xyz*x*z) / 2.0;
879da80777bSKarl Rupp     values[5] = (y4 - y0 + g_yz*y + g_xz*x + g_xyz*x*y) / 2.0;
880da80777bSKarl Rupp     values[6] = (z1 - z0 + h_xy*y + h_xz*z + h_xyz*y*z) / 2.0;
881da80777bSKarl Rupp     values[7] = (z3 - z0 + h_xy*x + h_yz*z + h_xyz*x*z) / 2.0;
882da80777bSKarl Rupp     values[8] = (z4 - z0 + h_yz*y + h_xz*x + h_xyz*x*y) / 2.0;
8831aa26658SKarl Rupp 
88494ab13aaSBarry Smith     ierr = MatSetValues(J, 3, rows, 3, rows, values, INSERT_VALUES);CHKERRQ(ierr);
885552f7358SJed Brown   }
886552f7358SJed Brown   ierr = PetscLogFlops(152);CHKERRQ(ierr);
88756044e6dSMatthew G. Knepley   ierr = VecRestoreArrayRead(Xref,  &ref);CHKERRQ(ierr);
88894ab13aaSBarry Smith   ierr = MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
88994ab13aaSBarry Smith   ierr = MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
890552f7358SJed Brown   PetscFunctionReturn(0);
891552f7358SJed Brown }
892552f7358SJed Brown 
893a6dfd86eSKarl Rupp PETSC_STATIC_INLINE PetscErrorCode DMInterpolate_Hex_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
894a6dfd86eSKarl Rupp {
895fafc0619SMatthew G Knepley   DM             dmCoord;
896552f7358SJed Brown   SNES           snes;
897552f7358SJed Brown   KSP            ksp;
898552f7358SJed Brown   PC             pc;
899552f7358SJed Brown   Vec            coordsLocal, r, ref, real;
900552f7358SJed Brown   Mat            J;
90156044e6dSMatthew G. Knepley   const PetscScalar *coords;
90256044e6dSMatthew G. Knepley   PetscScalar    *a;
903552f7358SJed Brown   PetscInt       p;
904552f7358SJed Brown   PetscErrorCode ierr;
905552f7358SJed Brown 
906552f7358SJed Brown   PetscFunctionBegin;
907552f7358SJed Brown   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
908fafc0619SMatthew G Knepley   ierr = DMGetCoordinateDM(dm, &dmCoord);CHKERRQ(ierr);
909552f7358SJed Brown   ierr = SNESCreate(PETSC_COMM_SELF, &snes);CHKERRQ(ierr);
910552f7358SJed Brown   ierr = SNESSetOptionsPrefix(snes, "hex_interp_");CHKERRQ(ierr);
911552f7358SJed Brown   ierr = VecCreate(PETSC_COMM_SELF, &r);CHKERRQ(ierr);
912552f7358SJed Brown   ierr = VecSetSizes(r, 3, 3);CHKERRQ(ierr);
913c0dedaeaSBarry Smith   ierr = VecSetType(r,dm->vectype);CHKERRQ(ierr);
914552f7358SJed Brown   ierr = VecDuplicate(r, &ref);CHKERRQ(ierr);
915552f7358SJed Brown   ierr = VecDuplicate(r, &real);CHKERRQ(ierr);
916552f7358SJed Brown   ierr = MatCreate(PETSC_COMM_SELF, &J);CHKERRQ(ierr);
917552f7358SJed Brown   ierr = MatSetSizes(J, 3, 3, 3, 3);CHKERRQ(ierr);
918552f7358SJed Brown   ierr = MatSetType(J, MATSEQDENSE);CHKERRQ(ierr);
919552f7358SJed Brown   ierr = MatSetUp(J);CHKERRQ(ierr);
9200298fd71SBarry Smith   ierr = SNESSetFunction(snes, r, HexMap_Private, NULL);CHKERRQ(ierr);
9210298fd71SBarry Smith   ierr = SNESSetJacobian(snes, J, J, HexJacobian_Private, NULL);CHKERRQ(ierr);
922552f7358SJed Brown   ierr = SNESGetKSP(snes, &ksp);CHKERRQ(ierr);
923552f7358SJed Brown   ierr = KSPGetPC(ksp, &pc);CHKERRQ(ierr);
924552f7358SJed Brown   ierr = PCSetType(pc, PCLU);CHKERRQ(ierr);
925552f7358SJed Brown   ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
926552f7358SJed Brown 
92756044e6dSMatthew G. Knepley   ierr = VecGetArrayRead(ctx->coords, &coords);CHKERRQ(ierr);
928552f7358SJed Brown   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
929552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
930a1e44745SMatthew G. Knepley     PetscScalar *x = NULL, *vertices = NULL;
931552f7358SJed Brown     PetscScalar *xi;
932cb313848SJed Brown     PetscReal    xir[3];
933552f7358SJed Brown     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
934552f7358SJed Brown 
935552f7358SJed Brown     /* Can make this do all points at once */
9360298fd71SBarry Smith     ierr = DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices);CHKERRQ(ierr);
937ff1e0c32SBarry Smith     if (8*3 != coordSize) SETERRQ2(ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %D should be %d", coordSize, 8*3);
9380298fd71SBarry Smith     ierr = DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x);CHKERRQ(ierr);
939ff1e0c32SBarry Smith     if (8*ctx->dof != xSize) SETERRQ2(ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %D should be %D", xSize, 8*ctx->dof);
9400298fd71SBarry Smith     ierr   = SNESSetFunction(snes, NULL, NULL, (void*) vertices);CHKERRQ(ierr);
9410298fd71SBarry Smith     ierr   = SNESSetJacobian(snes, NULL, NULL, NULL, (void*) vertices);CHKERRQ(ierr);
942552f7358SJed Brown     ierr   = VecGetArray(real, &xi);CHKERRQ(ierr);
943552f7358SJed Brown     xi[0]  = coords[p*ctx->dim+0];
944552f7358SJed Brown     xi[1]  = coords[p*ctx->dim+1];
945552f7358SJed Brown     xi[2]  = coords[p*ctx->dim+2];
946552f7358SJed Brown     ierr   = VecRestoreArray(real, &xi);CHKERRQ(ierr);
947552f7358SJed Brown     ierr   = SNESSolve(snes, real, ref);CHKERRQ(ierr);
948552f7358SJed Brown     ierr   = VecGetArray(ref, &xi);CHKERRQ(ierr);
949cb313848SJed Brown     xir[0] = PetscRealPart(xi[0]);
950cb313848SJed Brown     xir[1] = PetscRealPart(xi[1]);
951cb313848SJed Brown     xir[2] = PetscRealPart(xi[2]);
952552f7358SJed Brown     for (comp = 0; comp < ctx->dof; ++comp) {
953552f7358SJed Brown       a[p*ctx->dof+comp] =
954cb313848SJed Brown         x[0*ctx->dof+comp]*(1-xir[0])*(1-xir[1])*(1-xir[2]) +
9557a1931ceSMatthew G. Knepley         x[3*ctx->dof+comp]*    xir[0]*(1-xir[1])*(1-xir[2]) +
956cb313848SJed Brown         x[2*ctx->dof+comp]*    xir[0]*    xir[1]*(1-xir[2]) +
9577a1931ceSMatthew G. Knepley         x[1*ctx->dof+comp]*(1-xir[0])*    xir[1]*(1-xir[2]) +
958cb313848SJed Brown         x[4*ctx->dof+comp]*(1-xir[0])*(1-xir[1])*   xir[2] +
959cb313848SJed Brown         x[5*ctx->dof+comp]*    xir[0]*(1-xir[1])*   xir[2] +
960cb313848SJed Brown         x[6*ctx->dof+comp]*    xir[0]*    xir[1]*   xir[2] +
961cb313848SJed Brown         x[7*ctx->dof+comp]*(1-xir[0])*    xir[1]*   xir[2];
962552f7358SJed Brown     }
963552f7358SJed Brown     ierr = VecRestoreArray(ref, &xi);CHKERRQ(ierr);
9640298fd71SBarry Smith     ierr = DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices);CHKERRQ(ierr);
9650298fd71SBarry Smith     ierr = DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x);CHKERRQ(ierr);
966552f7358SJed Brown   }
967552f7358SJed Brown   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
96856044e6dSMatthew G. Knepley   ierr = VecRestoreArrayRead(ctx->coords, &coords);CHKERRQ(ierr);
969552f7358SJed Brown 
970552f7358SJed Brown   ierr = SNESDestroy(&snes);CHKERRQ(ierr);
971552f7358SJed Brown   ierr = VecDestroy(&r);CHKERRQ(ierr);
972552f7358SJed Brown   ierr = VecDestroy(&ref);CHKERRQ(ierr);
973552f7358SJed Brown   ierr = VecDestroy(&real);CHKERRQ(ierr);
974552f7358SJed Brown   ierr = MatDestroy(&J);CHKERRQ(ierr);
975552f7358SJed Brown   PetscFunctionReturn(0);
976552f7358SJed Brown }
977552f7358SJed Brown 
9784267b1a3SMatthew G. Knepley /*@C
9794267b1a3SMatthew G. Knepley   DMInterpolationEvaluate - Using the input from dm and x, calculates interpolated field values at the interpolation points.
9804267b1a3SMatthew G. Knepley 
981552f7358SJed Brown   Input Parameters:
982552f7358SJed Brown + ctx - The DMInterpolationInfo context
983552f7358SJed Brown . dm  - The DM
984552f7358SJed Brown - x   - The local vector containing the field to be interpolated
985552f7358SJed Brown 
986552f7358SJed Brown   Output Parameters:
987552f7358SJed Brown . v   - The vector containing the interpolated values
9884267b1a3SMatthew G. Knepley 
9894267b1a3SMatthew G. Knepley   Note: A suitable v can be obtained using DMInterpolationGetVector().
9904267b1a3SMatthew G. Knepley 
9914267b1a3SMatthew G. Knepley   Level: beginner
9924267b1a3SMatthew G. Knepley 
9934267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetVector(), DMInterpolationAddPoints(), DMInterpolationCreate()
9944267b1a3SMatthew G. Knepley @*/
9950adebc6cSBarry Smith PetscErrorCode DMInterpolationEvaluate(DMInterpolationInfo ctx, DM dm, Vec x, Vec v)
9960adebc6cSBarry Smith {
997552f7358SJed Brown   PetscInt       dim, coneSize, n;
998552f7358SJed Brown   PetscErrorCode ierr;
999552f7358SJed Brown 
1000552f7358SJed Brown   PetscFunctionBegin;
1001552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1002552f7358SJed Brown   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
1003552f7358SJed Brown   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
1004552f7358SJed Brown   ierr = VecGetLocalSize(v, &n);CHKERRQ(ierr);
1005ff1e0c32SBarry Smith   if (n != ctx->n*ctx->dof) SETERRQ2(ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input vector size %D should be %D", n, ctx->n*ctx->dof);
1006552f7358SJed Brown   if (n) {
1007c73cfb54SMatthew G. Knepley     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1008552f7358SJed Brown     ierr = DMPlexGetConeSize(dm, ctx->cells[0], &coneSize);CHKERRQ(ierr);
1009552f7358SJed Brown     if (dim == 2) {
1010552f7358SJed Brown       if (coneSize == 3) {
10117a1931ceSMatthew G. Knepley         ierr = DMInterpolate_Triangle_Private(ctx, dm, x, v);CHKERRQ(ierr);
1012552f7358SJed Brown       } else if (coneSize == 4) {
1013552f7358SJed Brown         ierr = DMInterpolate_Quad_Private(ctx, dm, x, v);CHKERRQ(ierr);
1014ff1e0c32SBarry Smith       } else SETERRQ1(ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dimension %D for point interpolation", dim);
1015552f7358SJed Brown     } else if (dim == 3) {
1016552f7358SJed Brown       if (coneSize == 4) {
10177a1931ceSMatthew G. Knepley         ierr = DMInterpolate_Tetrahedron_Private(ctx, dm, x, v);CHKERRQ(ierr);
1018552f7358SJed Brown       } else {
1019552f7358SJed Brown         ierr = DMInterpolate_Hex_Private(ctx, dm, x, v);CHKERRQ(ierr);
1020552f7358SJed Brown       }
1021ff1e0c32SBarry Smith     } else SETERRQ1(ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dimension %D for point interpolation", dim);
1022552f7358SJed Brown   }
1023552f7358SJed Brown   PetscFunctionReturn(0);
1024552f7358SJed Brown }
1025552f7358SJed Brown 
10264267b1a3SMatthew G. Knepley /*@C
10274267b1a3SMatthew G. Knepley   DMInterpolationDestroy - Destroys a DMInterpolationInfo context
10284267b1a3SMatthew G. Knepley 
10294267b1a3SMatthew G. Knepley   Collective on ctx
10304267b1a3SMatthew G. Knepley 
10314267b1a3SMatthew G. Knepley   Input Parameter:
10324267b1a3SMatthew G. Knepley . ctx - the context
10334267b1a3SMatthew G. Knepley 
10344267b1a3SMatthew G. Knepley   Level: beginner
10354267b1a3SMatthew G. Knepley 
10364267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
10374267b1a3SMatthew G. Knepley @*/
10380adebc6cSBarry Smith PetscErrorCode DMInterpolationDestroy(DMInterpolationInfo *ctx)
10390adebc6cSBarry Smith {
1040552f7358SJed Brown   PetscErrorCode ierr;
1041552f7358SJed Brown 
1042552f7358SJed Brown   PetscFunctionBegin;
1043552f7358SJed Brown   PetscValidPointer(ctx, 2);
1044552f7358SJed Brown   ierr = VecDestroy(&(*ctx)->coords);CHKERRQ(ierr);
1045552f7358SJed Brown   ierr = PetscFree((*ctx)->points);CHKERRQ(ierr);
1046552f7358SJed Brown   ierr = PetscFree((*ctx)->cells);CHKERRQ(ierr);
1047552f7358SJed Brown   ierr = PetscFree(*ctx);CHKERRQ(ierr);
10480298fd71SBarry Smith   *ctx = NULL;
1049552f7358SJed Brown   PetscFunctionReturn(0);
1050552f7358SJed Brown }
1051cc0c4584SMatthew G. Knepley 
1052cc0c4584SMatthew G. Knepley /*@C
1053cc0c4584SMatthew G. Knepley   SNESMonitorFields - Monitors the residual for each field separately
1054cc0c4584SMatthew G. Knepley 
1055cc0c4584SMatthew G. Knepley   Collective on SNES
1056cc0c4584SMatthew G. Knepley 
1057cc0c4584SMatthew G. Knepley   Input Parameters:
1058cc0c4584SMatthew G. Knepley + snes   - the SNES context
1059cc0c4584SMatthew G. Knepley . its    - iteration number
1060cc0c4584SMatthew G. Knepley . fgnorm - 2-norm of residual
1061d43b4f6eSBarry Smith - vf  - PetscViewerAndFormat of type ASCII
1062cc0c4584SMatthew G. Knepley 
1063cc0c4584SMatthew G. Knepley   Notes:
1064cc0c4584SMatthew G. Knepley   This routine prints the residual norm at each iteration.
1065cc0c4584SMatthew G. Knepley 
1066cc0c4584SMatthew G. Knepley   Level: intermediate
1067cc0c4584SMatthew G. Knepley 
1068cc0c4584SMatthew G. Knepley .seealso: SNESMonitorSet(), SNESMonitorDefault()
1069cc0c4584SMatthew G. Knepley @*/
1070d43b4f6eSBarry Smith PetscErrorCode SNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
1071cc0c4584SMatthew G. Knepley {
1072d43b4f6eSBarry Smith   PetscViewer        viewer = vf->viewer;
1073cc0c4584SMatthew G. Knepley   Vec                res;
1074cc0c4584SMatthew G. Knepley   DM                 dm;
1075cc0c4584SMatthew G. Knepley   PetscSection       s;
1076cc0c4584SMatthew G. Knepley   const PetscScalar *r;
1077cc0c4584SMatthew G. Knepley   PetscReal         *lnorms, *norms;
1078cc0c4584SMatthew G. Knepley   PetscInt           numFields, f, pStart, pEnd, p;
1079cc0c4584SMatthew G. Knepley   PetscErrorCode     ierr;
1080cc0c4584SMatthew G. Knepley 
1081cc0c4584SMatthew G. Knepley   PetscFunctionBegin;
10824d4332d5SBarry Smith   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
10839e5d0892SLisandro Dalcin   ierr = SNESGetFunction(snes, &res, NULL, NULL);CHKERRQ(ierr);
1084cc0c4584SMatthew G. Knepley   ierr = SNESGetDM(snes, &dm);CHKERRQ(ierr);
108592fd8e1eSJed Brown   ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr);
1086cc0c4584SMatthew G. Knepley   ierr = PetscSectionGetNumFields(s, &numFields);CHKERRQ(ierr);
1087cc0c4584SMatthew G. Knepley   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
1088cc0c4584SMatthew G. Knepley   ierr = PetscCalloc2(numFields, &lnorms, numFields, &norms);CHKERRQ(ierr);
1089cc0c4584SMatthew G. Knepley   ierr = VecGetArrayRead(res, &r);CHKERRQ(ierr);
1090cc0c4584SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
1091cc0c4584SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
1092cc0c4584SMatthew G. Knepley       PetscInt fdof, foff, d;
1093cc0c4584SMatthew G. Knepley 
1094cc0c4584SMatthew G. Knepley       ierr = PetscSectionGetFieldDof(s, p, f, &fdof);CHKERRQ(ierr);
1095cc0c4584SMatthew G. Knepley       ierr = PetscSectionGetFieldOffset(s, p, f, &foff);CHKERRQ(ierr);
1096cc0c4584SMatthew G. Knepley       for (d = 0; d < fdof; ++d) lnorms[f] += PetscRealPart(PetscSqr(r[foff+d]));
1097cc0c4584SMatthew G. Knepley     }
1098cc0c4584SMatthew G. Knepley   }
1099cc0c4584SMatthew G. Knepley   ierr = VecRestoreArrayRead(res, &r);CHKERRQ(ierr);
1100b2566f29SBarry Smith   ierr = MPIU_Allreduce(lnorms, norms, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
1101d43b4f6eSBarry Smith   ierr = PetscViewerPushFormat(viewer,vf->format);CHKERRQ(ierr);
1102cc0c4584SMatthew G. Knepley   ierr = PetscViewerASCIIAddTab(viewer, ((PetscObject) snes)->tablevel);CHKERRQ(ierr);
1103cc0c4584SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "%3D SNES Function norm %14.12e [", its, (double) fgnorm);CHKERRQ(ierr);
1104cc0c4584SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
1105cc0c4584SMatthew G. Knepley     if (f > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
1106cc0c4584SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(viewer, "%14.12e", (double) PetscSqrtReal(norms[f]));CHKERRQ(ierr);
1107cc0c4584SMatthew G. Knepley   }
1108cc0c4584SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "]\n");CHKERRQ(ierr);
1109cc0c4584SMatthew G. Knepley   ierr = PetscViewerASCIISubtractTab(viewer, ((PetscObject) snes)->tablevel);CHKERRQ(ierr);
1110d43b4f6eSBarry Smith   ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
1111cc0c4584SMatthew G. Knepley   ierr = PetscFree2(lnorms, norms);CHKERRQ(ierr);
1112cc0c4584SMatthew G. Knepley   PetscFunctionReturn(0);
1113cc0c4584SMatthew G. Knepley }
111424cdb843SMatthew G. Knepley 
111524cdb843SMatthew G. Knepley /********************* Residual Computation **************************/
111624cdb843SMatthew G. Knepley 
111724cdb843SMatthew G. Knepley /*@
111824cdb843SMatthew G. Knepley   DMPlexSNESComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
111924cdb843SMatthew G. Knepley 
112024cdb843SMatthew G. Knepley   Input Parameters:
112124cdb843SMatthew G. Knepley + dm - The mesh
112224cdb843SMatthew G. Knepley . X  - Local solution
112324cdb843SMatthew G. Knepley - user - The user context
112424cdb843SMatthew G. Knepley 
112524cdb843SMatthew G. Knepley   Output Parameter:
112624cdb843SMatthew G. Knepley . F  - Local output vector
112724cdb843SMatthew G. Knepley 
112824cdb843SMatthew G. Knepley   Level: developer
112924cdb843SMatthew G. Knepley 
11307a73cf09SMatthew G. Knepley .seealso: DMPlexComputeJacobianAction()
113124cdb843SMatthew G. Knepley @*/
113224cdb843SMatthew G. Knepley PetscErrorCode DMPlexSNESComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
113324cdb843SMatthew G. Knepley {
11346da023fcSToby Isaac   DM             plex;
1135083401c6SMatthew G. Knepley   IS             allcellIS;
1136083401c6SMatthew G. Knepley   PetscInt       Nds, s, depth;
113724cdb843SMatthew G. Knepley   PetscErrorCode ierr;
113824cdb843SMatthew G. Knepley 
113924cdb843SMatthew G. Knepley   PetscFunctionBegin;
1140083401c6SMatthew G. Knepley   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
11416da023fcSToby Isaac   ierr = DMSNESConvertPlex(dm, &plex, PETSC_TRUE);CHKERRQ(ierr);
11424a3e9fdbSToby Isaac   ierr = DMPlexGetDepth(plex, &depth);CHKERRQ(ierr);
1143083401c6SMatthew G. Knepley   ierr = DMGetStratumIS(plex, "dim", depth, &allcellIS);CHKERRQ(ierr);
1144083401c6SMatthew G. Knepley   if (!allcellIS) {ierr = DMGetStratumIS(plex, "depth", depth, &allcellIS);CHKERRQ(ierr);}
1145083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1146083401c6SMatthew G. Knepley     PetscDS ds;
1147083401c6SMatthew G. Knepley     DMLabel label;
1148083401c6SMatthew G. Knepley     IS      cellIS;
1149083401c6SMatthew G. Knepley 
1150083401c6SMatthew G. Knepley     ierr = DMGetRegionNumDS(dm, s, &label, NULL, &ds);CHKERRQ(ierr);
1151083401c6SMatthew G. Knepley     if (!label) {
1152083401c6SMatthew G. Knepley       ierr = PetscObjectReference((PetscObject) allcellIS);CHKERRQ(ierr);
1153083401c6SMatthew G. Knepley       cellIS = allcellIS;
1154083401c6SMatthew G. Knepley     } else {
1155083401c6SMatthew G. Knepley       IS pointIS;
1156083401c6SMatthew G. Knepley 
1157083401c6SMatthew G. Knepley       ierr = DMLabelGetStratumIS(label, 1, &pointIS);CHKERRQ(ierr);
1158083401c6SMatthew G. Knepley       ierr = ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS);CHKERRQ(ierr);
1159083401c6SMatthew G. Knepley       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
11604a3e9fdbSToby Isaac     }
11614bee2e38SMatthew G. Knepley     ierr = DMPlexComputeResidual_Internal(plex, cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user);CHKERRQ(ierr);
11624a3e9fdbSToby Isaac     ierr = ISDestroy(&cellIS);CHKERRQ(ierr);
1163083401c6SMatthew G. Knepley   }
1164083401c6SMatthew G. Knepley   ierr = ISDestroy(&allcellIS);CHKERRQ(ierr);
11659a81d013SToby Isaac   ierr = DMDestroy(&plex);CHKERRQ(ierr);
116624cdb843SMatthew G. Knepley   PetscFunctionReturn(0);
116724cdb843SMatthew G. Knepley }
116824cdb843SMatthew G. Knepley 
1169bdd6f66aSToby Isaac /*@
1170bdd6f66aSToby Isaac   DMPlexSNESComputeBoundaryFEM - Form the boundary values for the local input X
1171bdd6f66aSToby Isaac 
1172bdd6f66aSToby Isaac   Input Parameters:
1173bdd6f66aSToby Isaac + dm - The mesh
1174bdd6f66aSToby Isaac - user - The user context
1175bdd6f66aSToby Isaac 
1176bdd6f66aSToby Isaac   Output Parameter:
1177bdd6f66aSToby Isaac . X  - Local solution
1178bdd6f66aSToby Isaac 
1179bdd6f66aSToby Isaac   Level: developer
1180bdd6f66aSToby Isaac 
11817a73cf09SMatthew G. Knepley .seealso: DMPlexComputeJacobianAction()
1182bdd6f66aSToby Isaac @*/
1183bdd6f66aSToby Isaac PetscErrorCode DMPlexSNESComputeBoundaryFEM(DM dm, Vec X, void *user)
1184bdd6f66aSToby Isaac {
1185bdd6f66aSToby Isaac   DM             plex;
1186bdd6f66aSToby Isaac   PetscErrorCode ierr;
1187bdd6f66aSToby Isaac 
1188bdd6f66aSToby Isaac   PetscFunctionBegin;
1189bdd6f66aSToby Isaac   ierr = DMSNESConvertPlex(dm,&plex,PETSC_TRUE);CHKERRQ(ierr);
1190bdd6f66aSToby Isaac   ierr = DMPlexInsertBoundaryValues(plex, PETSC_TRUE, X, PETSC_MIN_REAL, NULL, NULL, NULL);CHKERRQ(ierr);
1191bdd6f66aSToby Isaac   ierr = DMDestroy(&plex);CHKERRQ(ierr);
1192bdd6f66aSToby Isaac   PetscFunctionReturn(0);
1193bdd6f66aSToby Isaac }
1194bdd6f66aSToby Isaac 
11957a73cf09SMatthew G. Knepley /*@
11967a73cf09SMatthew G. Knepley   DMPlexComputeJacobianAction - Form the local portion of the Jacobian action Z = J(X) Y at the local solution X using pointwise functions specified by the user.
11977a73cf09SMatthew G. Knepley 
11987a73cf09SMatthew G. Knepley   Input Parameters:
11997a73cf09SMatthew G. Knepley + dm - The mesh
12007a73cf09SMatthew G. Knepley . cellIS -
12017a73cf09SMatthew G. Knepley . t  - The time
12027a73cf09SMatthew G. Knepley . X_tShift - The multiplier for the Jacobian with repsect to X_t
12037a73cf09SMatthew G. Knepley . X  - Local solution vector
12047a73cf09SMatthew G. Knepley . X_t  - Time-derivative of the local solution vector
12057a73cf09SMatthew G. Knepley . Y  - Local input vector
12067a73cf09SMatthew G. Knepley - user - The user context
12077a73cf09SMatthew G. Knepley 
12087a73cf09SMatthew G. Knepley   Output Parameter:
12097a73cf09SMatthew G. Knepley . Z - Local output vector
12107a73cf09SMatthew G. Knepley 
12117a73cf09SMatthew G. Knepley   Note:
12127a73cf09SMatthew G. Knepley   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
12137a73cf09SMatthew G. Knepley   like a GPU, or vectorize on a multicore machine.
12147a73cf09SMatthew G. Knepley 
12157a73cf09SMatthew G. Knepley   Level: developer
12167a73cf09SMatthew G. Knepley 
12177a73cf09SMatthew G. Knepley .seealso: FormFunctionLocal()
12187a73cf09SMatthew G. Knepley @*/
12197a73cf09SMatthew G. Knepley PetscErrorCode DMPlexComputeJacobianAction(DM dm, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Vec Y, Vec Z, void *user)
1220a925c78cSMatthew G. Knepley {
1221a925c78cSMatthew G. Knepley   DM_Plex          *mesh  = (DM_Plex *) dm->data;
1222a925c78cSMatthew G. Knepley   const char       *name  = "Jacobian";
12237a73cf09SMatthew G. Knepley   DM                dmAux, plex, plexAux = NULL;
1224a6e0b375SMatthew G. Knepley   DMEnclosureType   encAux;
1225c330f8ffSToby Isaac   Vec               A;
1226a925c78cSMatthew G. Knepley   PetscDS           prob, probAux = NULL;
1227a925c78cSMatthew G. Knepley   PetscQuadrature   quad;
1228a925c78cSMatthew G. Knepley   PetscSection      section, globalSection, sectionAux;
1229a925c78cSMatthew G. Knepley   PetscScalar      *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z;
12309044fa66SMatthew G. Knepley   PetscInt          Nf, fieldI, fieldJ;
12314d0b9603SSander Arens   PetscInt          totDim, totDimAux = 0;
12329044fa66SMatthew G. Knepley   const PetscInt   *cells;
12339044fa66SMatthew G. Knepley   PetscInt          cStart, cEnd, numCells, c;
123475b37a90SMatthew G. Knepley   PetscBool         hasDyn;
1235c330f8ffSToby Isaac   DMField           coordField;
1236a925c78cSMatthew G. Knepley   PetscErrorCode    ierr;
1237a925c78cSMatthew G. Knepley 
1238a925c78cSMatthew G. Knepley   PetscFunctionBegin;
1239a925c78cSMatthew G. Knepley   ierr = PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr);
12407a73cf09SMatthew G. Knepley   ierr = DMSNESConvertPlex(dm, &plex, PETSC_TRUE);CHKERRQ(ierr);
12417a73cf09SMatthew G. Knepley   if (!cellIS) {
12427a73cf09SMatthew G. Knepley     PetscInt depth;
12437a73cf09SMatthew G. Knepley 
12447a73cf09SMatthew G. Knepley     ierr = DMPlexGetDepth(plex, &depth);CHKERRQ(ierr);
12457a73cf09SMatthew G. Knepley     ierr = DMGetStratumIS(plex, "dim", depth, &cellIS);CHKERRQ(ierr);
12467a73cf09SMatthew G. Knepley     if (!cellIS) {ierr = DMGetStratumIS(plex, "depth", depth, &cellIS);CHKERRQ(ierr);}
12477a73cf09SMatthew G. Knepley   } else {
12487a73cf09SMatthew G. Knepley     ierr = PetscObjectReference((PetscObject) cellIS);CHKERRQ(ierr);
12497a73cf09SMatthew G. Knepley   }
125092fd8e1eSJed Brown   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
1251e87a4003SBarry Smith   ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);
1252d28747ceSMatthew G. Knepley   ierr = ISGetLocalSize(cellIS, &numCells);CHKERRQ(ierr);
1253d28747ceSMatthew G. Knepley   ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr);
1254d28747ceSMatthew G. Knepley   ierr = DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);CHKERRQ(ierr);
1255d28747ceSMatthew G. Knepley   ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr);
1256a925c78cSMatthew G. Knepley   ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr);
1257a925c78cSMatthew G. Knepley   ierr = PetscDSHasDynamicJacobian(prob, &hasDyn);CHKERRQ(ierr);
1258a925c78cSMatthew G. Knepley   hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
1259a925c78cSMatthew G. Knepley   ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr);
1260a925c78cSMatthew G. Knepley   ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr);
1261a925c78cSMatthew G. Knepley   if (dmAux) {
1262a6e0b375SMatthew G. Knepley     ierr = DMGetEnclosureRelation(dmAux, dm, &encAux);CHKERRQ(ierr);
12637a73cf09SMatthew G. Knepley     ierr = DMConvert(dmAux, DMPLEX, &plexAux);CHKERRQ(ierr);
126492fd8e1eSJed Brown     ierr = DMGetLocalSection(plexAux, &sectionAux);CHKERRQ(ierr);
1265a925c78cSMatthew G. Knepley     ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr);
1266a925c78cSMatthew G. Knepley     ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr);
1267a925c78cSMatthew G. Knepley   }
1268a925c78cSMatthew G. Knepley   ierr = VecSet(Z, 0.0);CHKERRQ(ierr);
1269a925c78cSMatthew G. Knepley   ierr = PetscMalloc6(numCells*totDim,&u,X_t ? numCells*totDim : 0,&u_t,numCells*totDim*totDim,&elemMat,hasDyn ? numCells*totDim*totDim : 0, &elemMatD,numCells*totDim,&y,totDim,&z);CHKERRQ(ierr);
1270a925c78cSMatthew G. Knepley   if (dmAux) {ierr = PetscMalloc1(numCells*totDimAux, &a);CHKERRQ(ierr);}
12714a3e9fdbSToby Isaac   ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr);
1272a925c78cSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
12739044fa66SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
12749044fa66SMatthew G. Knepley     const PetscInt cind = c - cStart;
1275a925c78cSMatthew G. Knepley     PetscScalar   *x = NULL,  *x_t = NULL;
1276a925c78cSMatthew G. Knepley     PetscInt       i;
1277a925c78cSMatthew G. Knepley 
12789044fa66SMatthew G. Knepley     ierr = DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);CHKERRQ(ierr);
12799044fa66SMatthew G. Knepley     for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i];
12809044fa66SMatthew G. Knepley     ierr = DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);CHKERRQ(ierr);
1281a925c78cSMatthew G. Knepley     if (X_t) {
12829044fa66SMatthew G. Knepley       ierr = DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);CHKERRQ(ierr);
12839044fa66SMatthew G. Knepley       for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i];
12849044fa66SMatthew G. Knepley       ierr = DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);CHKERRQ(ierr);
1285a925c78cSMatthew G. Knepley     }
1286a925c78cSMatthew G. Knepley     if (dmAux) {
128744171101SMatthew G. Knepley       PetscInt subcell;
1288a6e0b375SMatthew G. Knepley       ierr = DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell);CHKERRQ(ierr);
128944171101SMatthew G. Knepley       ierr = DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x);CHKERRQ(ierr);
12909044fa66SMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i];
129144171101SMatthew G. Knepley       ierr = DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x);CHKERRQ(ierr);
1292a925c78cSMatthew G. Knepley     }
12939044fa66SMatthew G. Knepley     ierr = DMPlexVecGetClosure(dm, section, Y, cell, NULL, &x);CHKERRQ(ierr);
12949044fa66SMatthew G. Knepley     for (i = 0; i < totDim; ++i) y[cind*totDim+i] = x[i];
12959044fa66SMatthew G. Knepley     ierr = DMPlexVecRestoreClosure(dm, section, Y, cell, NULL, &x);CHKERRQ(ierr);
1296a925c78cSMatthew G. Knepley   }
1297580bdb30SBarry Smith   ierr = PetscArrayzero(elemMat, numCells*totDim*totDim);CHKERRQ(ierr);
1298580bdb30SBarry Smith   if (hasDyn)  {ierr = PetscArrayzero(elemMatD, numCells*totDim*totDim);CHKERRQ(ierr);}
1299a925c78cSMatthew G. Knepley   for (fieldI = 0; fieldI < Nf; ++fieldI) {
1300a925c78cSMatthew G. Knepley     PetscFE  fe;
1301c330f8ffSToby Isaac     PetscInt Nb;
1302a925c78cSMatthew G. Knepley     /* Conforming batches */
1303a925c78cSMatthew G. Knepley     PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
1304a925c78cSMatthew G. Knepley     /* Remainder */
1305c330f8ffSToby Isaac     PetscInt Nr, offset, Nq;
1306c330f8ffSToby Isaac     PetscQuadrature qGeom = NULL;
1307b7260050SToby Isaac     PetscInt    maxDegree;
1308c330f8ffSToby Isaac     PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
1309a925c78cSMatthew G. Knepley 
1310a925c78cSMatthew G. Knepley     ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);CHKERRQ(ierr);
1311a925c78cSMatthew G. Knepley     ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr);
1312a925c78cSMatthew G. Knepley     ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr);
1313a925c78cSMatthew G. Knepley     ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr);
1314b7260050SToby Isaac     ierr = DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);CHKERRQ(ierr);
1315b7260050SToby Isaac     if (maxDegree <= 1) {ierr = DMFieldCreateDefaultQuadrature(coordField,cellIS,&qGeom);CHKERRQ(ierr);}
1316c330f8ffSToby Isaac     if (!qGeom) {
1317c330f8ffSToby Isaac       ierr = PetscFEGetQuadrature(fe,&qGeom);CHKERRQ(ierr);
1318c330f8ffSToby Isaac       ierr = PetscObjectReference((PetscObject)qGeom);CHKERRQ(ierr);
1319c330f8ffSToby Isaac     }
1320c330f8ffSToby Isaac     ierr = PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr);
13214a3e9fdbSToby Isaac     ierr = DMSNESGetFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);CHKERRQ(ierr);
1322c330f8ffSToby Isaac     blockSize = Nb;
1323a925c78cSMatthew G. Knepley     batchSize = numBlocks * blockSize;
1324a925c78cSMatthew G. Knepley     ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr);
1325a925c78cSMatthew G. Knepley     numChunks = numCells / (numBatches*batchSize);
1326a925c78cSMatthew G. Knepley     Ne        = numChunks*numBatches*batchSize;
1327a925c78cSMatthew G. Knepley     Nr        = numCells % (numBatches*batchSize);
1328a925c78cSMatthew G. Knepley     offset    = numCells - Nr;
1329c330f8ffSToby Isaac     ierr = PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);CHKERRQ(ierr);
1330c330f8ffSToby Isaac     ierr = PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&remGeom);CHKERRQ(ierr);
1331a925c78cSMatthew G. Knepley     for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
13324bee2e38SMatthew G. Knepley       ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);CHKERRQ(ierr);
13334bee2e38SMatthew G. Knepley       ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMat[offset*totDim*totDim]);CHKERRQ(ierr);
1334a925c78cSMatthew G. Knepley       if (hasDyn) {
13354bee2e38SMatthew G. Knepley         ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD);CHKERRQ(ierr);
13364bee2e38SMatthew G. Knepley         ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatD[offset*totDim*totDim]);CHKERRQ(ierr);
1337a925c78cSMatthew G. Knepley       }
1338a925c78cSMatthew G. Knepley     }
1339c330f8ffSToby Isaac     ierr = PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&remGeom);CHKERRQ(ierr);
1340c330f8ffSToby Isaac     ierr = PetscFEGeomRestoreChunk(cgeomFEM,0,offset,&chunkGeom);CHKERRQ(ierr);
13414a3e9fdbSToby Isaac     ierr = DMSNESRestoreFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);CHKERRQ(ierr);
1342c330f8ffSToby Isaac     ierr = PetscQuadratureDestroy(&qGeom);CHKERRQ(ierr);
1343a925c78cSMatthew G. Knepley   }
1344a925c78cSMatthew G. Knepley   if (hasDyn) {
13459044fa66SMatthew G. Knepley     for (c = 0; c < numCells*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];
1346a925c78cSMatthew G. Knepley   }
1347a925c78cSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
13489044fa66SMatthew G. Knepley     const PetscInt     cell = cells ? cells[c] : c;
13499044fa66SMatthew G. Knepley     const PetscInt     cind = c - cStart;
1350a925c78cSMatthew G. Knepley     const PetscBLASInt M = totDim, one = 1;
1351a925c78cSMatthew G. Knepley     const PetscScalar  a = 1.0, b = 0.0;
1352a925c78cSMatthew G. Knepley 
13539044fa66SMatthew G. Knepley     PetscStackCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind*totDim*totDim], &M, &y[cind*totDim], &one, &b, z, &one));
1354a925c78cSMatthew G. Knepley     if (mesh->printFEM > 1) {
13559044fa66SMatthew G. Knepley       ierr = DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind*totDim*totDim]);CHKERRQ(ierr);
13569044fa66SMatthew G. Knepley       ierr = DMPrintCellVector(c, "Y",  totDim, &y[cind*totDim]);CHKERRQ(ierr);
1357a925c78cSMatthew G. Knepley       ierr = DMPrintCellVector(c, "Z",  totDim, z);CHKERRQ(ierr);
1358a925c78cSMatthew G. Knepley     }
13599044fa66SMatthew G. Knepley     ierr = DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES);CHKERRQ(ierr);
1360a925c78cSMatthew G. Knepley   }
1361a925c78cSMatthew G. Knepley   ierr = PetscFree6(u,u_t,elemMat,elemMatD,y,z);CHKERRQ(ierr);
1362a925c78cSMatthew G. Knepley   if (mesh->printFEM) {
1363ea13f565SStefano Zampini     ierr = PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n");CHKERRQ(ierr);
1364a8c5bd36SStefano Zampini     ierr = VecView(Z, NULL);CHKERRQ(ierr);
1365a925c78cSMatthew G. Knepley   }
13667a73cf09SMatthew G. Knepley   ierr = PetscFree(a);CHKERRQ(ierr);
13677a73cf09SMatthew G. Knepley   ierr = ISDestroy(&cellIS);CHKERRQ(ierr);
13687a73cf09SMatthew G. Knepley   ierr = DMDestroy(&plexAux);CHKERRQ(ierr);
13697a73cf09SMatthew G. Knepley   ierr = DMDestroy(&plex);CHKERRQ(ierr);
1370a925c78cSMatthew G. Knepley   ierr = PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr);
1371a925c78cSMatthew G. Knepley   PetscFunctionReturn(0);
1372a925c78cSMatthew G. Knepley }
1373a925c78cSMatthew G. Knepley 
137424cdb843SMatthew G. Knepley /*@
137524cdb843SMatthew G. Knepley   DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
137624cdb843SMatthew G. Knepley 
137724cdb843SMatthew G. Knepley   Input Parameters:
137824cdb843SMatthew G. Knepley + dm - The mesh
137924cdb843SMatthew G. Knepley . X  - Local input vector
138024cdb843SMatthew G. Knepley - user - The user context
138124cdb843SMatthew G. Knepley 
138224cdb843SMatthew G. Knepley   Output Parameter:
138324cdb843SMatthew G. Knepley . Jac  - Jacobian matrix
138424cdb843SMatthew G. Knepley 
138524cdb843SMatthew G. Knepley   Note:
138624cdb843SMatthew G. Knepley   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
138724cdb843SMatthew G. Knepley   like a GPU, or vectorize on a multicore machine.
138824cdb843SMatthew G. Knepley 
138924cdb843SMatthew G. Knepley   Level: developer
139024cdb843SMatthew G. Knepley 
139124cdb843SMatthew G. Knepley .seealso: FormFunctionLocal()
139224cdb843SMatthew G. Knepley @*/
139324cdb843SMatthew G. Knepley PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP,void *user)
139424cdb843SMatthew G. Knepley {
13956da023fcSToby Isaac   DM             plex;
1396083401c6SMatthew G. Knepley   IS             allcellIS;
1397f04eb4edSMatthew G. Knepley   PetscBool      hasJac, hasPrec;
1398083401c6SMatthew G. Knepley   PetscInt       Nds, s, depth;
139924cdb843SMatthew G. Knepley   PetscErrorCode ierr;
140024cdb843SMatthew G. Knepley 
140124cdb843SMatthew G. Knepley   PetscFunctionBegin;
1402083401c6SMatthew G. Knepley   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
14036da023fcSToby Isaac   ierr = DMSNESConvertPlex(dm, &plex, PETSC_TRUE);CHKERRQ(ierr);
14044a3e9fdbSToby Isaac   ierr = DMPlexGetDepth(plex, &depth);CHKERRQ(ierr);
1405083401c6SMatthew G. Knepley   ierr = DMGetStratumIS(plex, "dim", depth, &allcellIS);CHKERRQ(ierr);
1406083401c6SMatthew G. Knepley   if (!allcellIS) {ierr = DMGetStratumIS(plex, "depth", depth, &allcellIS);CHKERRQ(ierr);}
1407083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1408083401c6SMatthew G. Knepley     PetscDS ds;
1409083401c6SMatthew G. Knepley     DMLabel label;
1410083401c6SMatthew G. Knepley     IS      cellIS;
1411083401c6SMatthew G. Knepley 
1412083401c6SMatthew G. Knepley     ierr = DMGetRegionNumDS(dm, s, &label, NULL, &ds);CHKERRQ(ierr);
1413083401c6SMatthew G. Knepley     if (!label) {
1414083401c6SMatthew G. Knepley       ierr = PetscObjectReference((PetscObject) allcellIS);CHKERRQ(ierr);
1415083401c6SMatthew G. Knepley       cellIS = allcellIS;
1416083401c6SMatthew G. Knepley     } else {
1417083401c6SMatthew G. Knepley       IS pointIS;
1418083401c6SMatthew G. Knepley 
1419083401c6SMatthew G. Knepley       ierr = DMLabelGetStratumIS(label, 1, &pointIS);CHKERRQ(ierr);
1420083401c6SMatthew G. Knepley       ierr = ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS);CHKERRQ(ierr);
1421083401c6SMatthew G. Knepley       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1422083401c6SMatthew G. Knepley     }
1423083401c6SMatthew G. Knepley     if (!s) {
1424083401c6SMatthew G. Knepley       ierr = PetscDSHasJacobian(ds, &hasJac);CHKERRQ(ierr);
1425083401c6SMatthew G. Knepley       ierr = PetscDSHasJacobianPreconditioner(ds, &hasPrec);CHKERRQ(ierr);
1426f04eb4edSMatthew G. Knepley       if (hasJac && hasPrec) {ierr = MatZeroEntries(Jac);CHKERRQ(ierr);}
1427f04eb4edSMatthew G. Knepley       ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
1428083401c6SMatthew G. Knepley     }
14294a3e9fdbSToby Isaac     ierr = DMPlexComputeJacobian_Internal(plex, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, user);CHKERRQ(ierr);
14304a3e9fdbSToby Isaac     ierr = ISDestroy(&cellIS);CHKERRQ(ierr);
1431083401c6SMatthew G. Knepley   }
1432083401c6SMatthew G. Knepley   ierr = ISDestroy(&allcellIS);CHKERRQ(ierr);
14339a81d013SToby Isaac   ierr = DMDestroy(&plex);CHKERRQ(ierr);
143424cdb843SMatthew G. Knepley   PetscFunctionReturn(0);
143524cdb843SMatthew G. Knepley }
14361878804aSMatthew G. Knepley 
143738cfc46eSPierre Jolivet /*
143838cfc46eSPierre Jolivet      MatComputeNeumannOverlap - Computes an unassembled (Neumann) local overlapping Mat in nonlinear context.
143938cfc46eSPierre Jolivet 
144038cfc46eSPierre Jolivet    Input Parameters:
144138cfc46eSPierre Jolivet +     X - SNES linearization point
144238cfc46eSPierre Jolivet .     ovl - index set of overlapping subdomains
144338cfc46eSPierre Jolivet 
144438cfc46eSPierre Jolivet    Output Parameter:
144538cfc46eSPierre Jolivet .     J - unassembled (Neumann) local matrix
144638cfc46eSPierre Jolivet 
144738cfc46eSPierre Jolivet    Level: intermediate
144838cfc46eSPierre Jolivet 
144938cfc46eSPierre Jolivet .seealso: DMCreateNeumannOverlap(), MATIS, PCHPDDMSetAuxiliaryMat()
145038cfc46eSPierre Jolivet */
145138cfc46eSPierre Jolivet static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, void *ctx)
145238cfc46eSPierre Jolivet {
145338cfc46eSPierre Jolivet   SNES           snes;
145438cfc46eSPierre Jolivet   Mat            pJ;
145538cfc46eSPierre Jolivet   DM             ovldm,origdm;
145638cfc46eSPierre Jolivet   DMSNES         sdm;
145738cfc46eSPierre Jolivet   PetscErrorCode (*bfun)(DM,Vec,void*);
145838cfc46eSPierre Jolivet   PetscErrorCode (*jfun)(DM,Vec,Mat,Mat,void*);
145938cfc46eSPierre Jolivet   void           *bctx,*jctx;
146038cfc46eSPierre Jolivet   PetscErrorCode ierr;
146138cfc46eSPierre Jolivet 
146238cfc46eSPierre Jolivet   PetscFunctionBegin;
146338cfc46eSPierre Jolivet   ierr = PetscObjectQuery((PetscObject)ovl,"_DM_Overlap_HPDDM_MATIS",(PetscObject*)&pJ);CHKERRQ(ierr);
146438cfc46eSPierre Jolivet   if (!pJ) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing overlapping Mat");CHKERRQ(ierr);
146538cfc46eSPierre Jolivet   ierr = PetscObjectQuery((PetscObject)ovl,"_DM_Original_HPDDM",(PetscObject*)&origdm);CHKERRQ(ierr);
146638cfc46eSPierre Jolivet   if (!origdm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing original DM");CHKERRQ(ierr);
146738cfc46eSPierre Jolivet   ierr = MatGetDM(pJ,&ovldm);CHKERRQ(ierr);
146838cfc46eSPierre Jolivet   ierr = DMSNESGetBoundaryLocal(origdm,&bfun,&bctx);CHKERRQ(ierr);
146938cfc46eSPierre Jolivet   ierr = DMSNESSetBoundaryLocal(ovldm,bfun,bctx);CHKERRQ(ierr);
147038cfc46eSPierre Jolivet   ierr = DMSNESGetJacobianLocal(origdm,&jfun,&jctx);CHKERRQ(ierr);
147138cfc46eSPierre Jolivet   ierr = DMSNESSetJacobianLocal(ovldm,jfun,jctx);CHKERRQ(ierr);
147238cfc46eSPierre Jolivet   ierr = PetscObjectQuery((PetscObject)ovl,"_DM_Overlap_HPDDM_SNES",(PetscObject*)&snes);CHKERRQ(ierr);
147338cfc46eSPierre Jolivet   if (!snes) {
147438cfc46eSPierre Jolivet     ierr = SNESCreate(PetscObjectComm((PetscObject)ovl),&snes);CHKERRQ(ierr);
147538cfc46eSPierre Jolivet     ierr = SNESSetDM(snes,ovldm);CHKERRQ(ierr);
147638cfc46eSPierre Jolivet     ierr = PetscObjectCompose((PetscObject)ovl,"_DM_Overlap_HPDDM_SNES",(PetscObject)snes);CHKERRQ(ierr);
147738cfc46eSPierre Jolivet     ierr = PetscObjectDereference((PetscObject)snes);CHKERRQ(ierr);
147838cfc46eSPierre Jolivet   }
147938cfc46eSPierre Jolivet   ierr = DMGetDMSNES(ovldm,&sdm);CHKERRQ(ierr);
148038cfc46eSPierre Jolivet   ierr = VecLockReadPush(X);CHKERRQ(ierr);
148138cfc46eSPierre Jolivet   PetscStackPush("SNES user Jacobian function");
148238cfc46eSPierre Jolivet   ierr = (*sdm->ops->computejacobian)(snes,X,pJ,pJ,sdm->jacobianctx);CHKERRQ(ierr);
148338cfc46eSPierre Jolivet   PetscStackPop;
148438cfc46eSPierre Jolivet   ierr = VecLockReadPop(X);CHKERRQ(ierr);
148538cfc46eSPierre Jolivet   /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */
148638cfc46eSPierre Jolivet   {
148738cfc46eSPierre Jolivet     Mat locpJ;
148838cfc46eSPierre Jolivet 
148938cfc46eSPierre Jolivet     ierr = MatISGetLocalMat(pJ,&locpJ);CHKERRQ(ierr);
149038cfc46eSPierre Jolivet     ierr = MatCopy(locpJ,J,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
149138cfc46eSPierre Jolivet   }
149238cfc46eSPierre Jolivet   PetscFunctionReturn(0);
149338cfc46eSPierre Jolivet }
149438cfc46eSPierre Jolivet 
1495a925c78cSMatthew G. Knepley /*@
14969f520fc2SToby Isaac   DMPlexSetSNESLocalFEM - Use DMPlex's internal FEM routines to compute SNES boundary values, residual, and Jacobian.
14979f520fc2SToby Isaac 
14989f520fc2SToby Isaac   Input Parameters:
14999f520fc2SToby Isaac + dm - The DM object
1500dff059c6SToby Isaac . boundaryctx - the user context that will be passed to pointwise evaluation of boundary values (see PetscDSAddBoundary())
15019f520fc2SToby Isaac . residualctx - the user context that will be passed to pointwise evaluation of finite element residual computations (see PetscDSSetResidual())
15029f520fc2SToby Isaac - jacobianctx - the user context that will be passed to pointwise evaluation of finite element Jacobian construction (see PetscDSSetJacobian())
15031a244344SSatish Balay 
15041a244344SSatish Balay   Level: developer
15059f520fc2SToby Isaac @*/
15069f520fc2SToby Isaac PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, void *boundaryctx, void *residualctx, void *jacobianctx)
15079f520fc2SToby Isaac {
15089f520fc2SToby Isaac   PetscErrorCode ierr;
15099f520fc2SToby Isaac 
15109f520fc2SToby Isaac   PetscFunctionBegin;
15119f520fc2SToby Isaac   ierr = DMSNESSetBoundaryLocal(dm,DMPlexSNESComputeBoundaryFEM,boundaryctx);CHKERRQ(ierr);
15129f520fc2SToby Isaac   ierr = DMSNESSetFunctionLocal(dm,DMPlexSNESComputeResidualFEM,residualctx);CHKERRQ(ierr);
15139f520fc2SToby Isaac   ierr = DMSNESSetJacobianLocal(dm,DMPlexSNESComputeJacobianFEM,jacobianctx);CHKERRQ(ierr);
151438cfc46eSPierre Jolivet   ierr = PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",MatComputeNeumannOverlap_Plex);CHKERRQ(ierr);
15159f520fc2SToby Isaac   PetscFunctionReturn(0);
15169f520fc2SToby Isaac }
15179f520fc2SToby Isaac 
1518f017bcb6SMatthew G. Knepley /*@C
1519f017bcb6SMatthew G. Knepley   DMSNESCheckDiscretization - Check the discretization error of the exact solution
1520f017bcb6SMatthew G. Knepley 
1521f017bcb6SMatthew G. Knepley   Input Parameters:
1522f017bcb6SMatthew G. Knepley + snes - the SNES object
1523f017bcb6SMatthew G. Knepley . dm   - the DM
1524f2cacb80SMatthew G. Knepley . t    - the time
1525f017bcb6SMatthew G. Knepley . u    - a DM vector
1526f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1527f017bcb6SMatthew G. Knepley 
1528f3c94560SMatthew G. Knepley   Output Parameters:
1529f3c94560SMatthew G. Knepley . error - An array which holds the discretization error in each field, or NULL
1530f3c94560SMatthew G. Knepley 
15317f96f943SMatthew G. Knepley   Note: The user must call PetscDSSetExactSolution() beforehand
15327f96f943SMatthew G. Knepley 
1533f017bcb6SMatthew G. Knepley   Level: developer
1534f017bcb6SMatthew G. Knepley 
15357f96f943SMatthew G. Knepley .seealso: DNSNESCheckFromOptions(), DMSNESCheckResidual(), DMSNESCheckJacobian(), PetscDSSetExactSolution()
1536f017bcb6SMatthew G. Knepley @*/
1537f2cacb80SMatthew G. Knepley PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[])
15381878804aSMatthew G. Knepley {
1539f017bcb6SMatthew G. Knepley   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
1540f017bcb6SMatthew G. Knepley   void            **ectxs;
1541f3c94560SMatthew G. Knepley   PetscReal        *err;
15427f96f943SMatthew G. Knepley   MPI_Comm          comm;
15437f96f943SMatthew G. Knepley   PetscInt          Nf, f;
15441878804aSMatthew G. Knepley   PetscErrorCode    ierr;
15451878804aSMatthew G. Knepley 
15461878804aSMatthew G. Knepley   PetscFunctionBegin;
1547f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1548f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1549f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1550534a8f05SLisandro Dalcin   if (error) PetscValidRealPointer(error, 6);
15517f96f943SMatthew G. Knepley 
1552f2cacb80SMatthew G. Knepley   ierr = DMComputeExactSolution(dm, t, u, NULL);CHKERRQ(ierr);
15537f96f943SMatthew G. Knepley   ierr = VecViewFromOptions(u, NULL, "-vec_view");CHKERRQ(ierr);
15547f96f943SMatthew G. Knepley 
1555f017bcb6SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) snes, &comm);CHKERRQ(ierr);
1556f017bcb6SMatthew G. Knepley   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
1557083401c6SMatthew G. Knepley   ierr = PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err);CHKERRQ(ierr);
15587f96f943SMatthew G. Knepley   {
15597f96f943SMatthew G. Knepley     PetscInt Nds, s;
15607f96f943SMatthew G. Knepley 
1561083401c6SMatthew G. Knepley     ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
1562083401c6SMatthew G. Knepley     for (s = 0; s < Nds; ++s) {
15637f96f943SMatthew G. Knepley       PetscDS         ds;
1564083401c6SMatthew G. Knepley       DMLabel         label;
1565083401c6SMatthew G. Knepley       IS              fieldIS;
15667f96f943SMatthew G. Knepley       const PetscInt *fields;
15677f96f943SMatthew G. Knepley       PetscInt        dsNf, f;
1568083401c6SMatthew G. Knepley 
1569083401c6SMatthew G. Knepley       ierr = DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);CHKERRQ(ierr);
1570083401c6SMatthew G. Knepley       ierr = PetscDSGetNumFields(ds, &dsNf);CHKERRQ(ierr);
1571083401c6SMatthew G. Knepley       ierr = ISGetIndices(fieldIS, &fields);CHKERRQ(ierr);
1572083401c6SMatthew G. Knepley       for (f = 0; f < dsNf; ++f) {
1573083401c6SMatthew G. Knepley         const PetscInt field = fields[f];
1574083401c6SMatthew G. Knepley         ierr = PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);CHKERRQ(ierr);
1575083401c6SMatthew G. Knepley       }
1576083401c6SMatthew G. Knepley       ierr = ISRestoreIndices(fieldIS, &fields);CHKERRQ(ierr);
1577083401c6SMatthew G. Knepley     }
1578083401c6SMatthew G. Knepley   }
1579f017bcb6SMatthew G. Knepley   if (Nf > 1) {
1580f2cacb80SMatthew G. Knepley     ierr = DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err);CHKERRQ(ierr);
1581f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
1582f017bcb6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
1583f3c94560SMatthew G. Knepley         if (err[f] > tol) SETERRQ3(comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g for field %D exceeds tolerance %g", (double) err[f], f, (double) tol);
15841878804aSMatthew G. Knepley       }
1585b878532fSMatthew G. Knepley     } else if (error) {
1586b878532fSMatthew G. Knepley       for (f = 0; f < Nf; ++f) error[f] = err[f];
15871878804aSMatthew G. Knepley     } else {
1588f017bcb6SMatthew G. Knepley       ierr = PetscPrintf(comm, "L_2 Error: [");CHKERRQ(ierr);
1589f017bcb6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
1590f017bcb6SMatthew G. Knepley         if (f) {ierr = PetscPrintf(comm, ", ");CHKERRQ(ierr);}
1591f3c94560SMatthew G. Knepley         ierr = PetscPrintf(comm, "%g", (double)err[f]);CHKERRQ(ierr);
15921878804aSMatthew G. Knepley       }
1593f017bcb6SMatthew G. Knepley       ierr = PetscPrintf(comm, "]\n");CHKERRQ(ierr);
1594f017bcb6SMatthew G. Knepley     }
1595f017bcb6SMatthew G. Knepley   } else {
1596f2cacb80SMatthew G. Knepley     ierr = DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0]);CHKERRQ(ierr);
1597f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
1598f3c94560SMatthew G. Knepley       if (err[0] > tol) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double) err[0], (double) tol);
1599b878532fSMatthew G. Knepley     } else if (error) {
1600b878532fSMatthew G. Knepley       error[0] = err[0];
1601f017bcb6SMatthew G. Knepley     } else {
1602f3c94560SMatthew G. Knepley       ierr = PetscPrintf(comm, "L_2 Error: %g\n", (double) err[0]);CHKERRQ(ierr);
1603f017bcb6SMatthew G. Knepley     }
1604f017bcb6SMatthew G. Knepley   }
1605f3c94560SMatthew G. Knepley   ierr = PetscFree3(exacts, ectxs, err);CHKERRQ(ierr);
1606f017bcb6SMatthew G. Knepley   PetscFunctionReturn(0);
1607f017bcb6SMatthew G. Knepley }
1608f017bcb6SMatthew G. Knepley 
1609f017bcb6SMatthew G. Knepley /*@C
1610f017bcb6SMatthew G. Knepley   DMSNESCheckResidual - Check the residual of the exact solution
1611f017bcb6SMatthew G. Knepley 
1612f017bcb6SMatthew G. Knepley   Input Parameters:
1613f017bcb6SMatthew G. Knepley + snes - the SNES object
1614f017bcb6SMatthew G. Knepley . dm   - the DM
1615f017bcb6SMatthew G. Knepley . u    - a DM vector
1616f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1617f017bcb6SMatthew G. Knepley 
1618f3c94560SMatthew G. Knepley   Output Parameters:
1619f3c94560SMatthew G. Knepley . residual - The residual norm of the exact solution, or NULL
1620f3c94560SMatthew G. Knepley 
1621f017bcb6SMatthew G. Knepley   Level: developer
1622f017bcb6SMatthew G. Knepley 
1623f017bcb6SMatthew G. Knepley .seealso: DNSNESCheckFromOptions(), DMSNESCheckDiscretization(), DMSNESCheckJacobian()
1624f017bcb6SMatthew G. Knepley @*/
1625f3c94560SMatthew G. Knepley PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual)
1626f017bcb6SMatthew G. Knepley {
1627f017bcb6SMatthew G. Knepley   MPI_Comm       comm;
1628f017bcb6SMatthew G. Knepley   Vec            r;
1629f017bcb6SMatthew G. Knepley   PetscReal      res;
1630f017bcb6SMatthew G. Knepley   PetscErrorCode ierr;
1631f017bcb6SMatthew G. Knepley 
1632f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1633f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1634f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1635f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1636534a8f05SLisandro Dalcin   if (residual) PetscValidRealPointer(residual, 5);
1637f017bcb6SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) snes, &comm);CHKERRQ(ierr);
1638f2cacb80SMatthew G. Knepley   ierr = DMComputeExactSolution(dm, 0.0, u, NULL);CHKERRQ(ierr);
1639f017bcb6SMatthew G. Knepley   ierr = VecDuplicate(u, &r);CHKERRQ(ierr);
16401878804aSMatthew G. Knepley   ierr = SNESComputeFunction(snes, u, r);CHKERRQ(ierr);
16411878804aSMatthew G. Knepley   ierr = VecNorm(r, NORM_2, &res);CHKERRQ(ierr);
1642f017bcb6SMatthew G. Knepley   if (tol >= 0.0) {
1643f017bcb6SMatthew G. Knepley     if (res > tol) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double) res, (double) tol);
1644b878532fSMatthew G. Knepley   } else if (residual) {
1645b878532fSMatthew G. Knepley     *residual = res;
1646f017bcb6SMatthew G. Knepley   } else {
1647f017bcb6SMatthew G. Knepley     ierr = PetscPrintf(comm, "L_2 Residual: %g\n", (double)res);CHKERRQ(ierr);
16481878804aSMatthew G. Knepley     ierr = VecChop(r, 1.0e-10);CHKERRQ(ierr);
16491878804aSMatthew G. Knepley     ierr = PetscObjectSetName((PetscObject) r, "Initial Residual");CHKERRQ(ierr);
1650685405a1SBarry Smith     ierr = PetscObjectSetOptionsPrefix((PetscObject)r,"res_");CHKERRQ(ierr);
1651685405a1SBarry Smith     ierr = VecViewFromOptions(r, NULL, "-vec_view");CHKERRQ(ierr);
1652f017bcb6SMatthew G. Knepley   }
1653f017bcb6SMatthew G. Knepley   ierr = VecDestroy(&r);CHKERRQ(ierr);
1654f017bcb6SMatthew G. Knepley   PetscFunctionReturn(0);
1655f017bcb6SMatthew G. Knepley }
1656f017bcb6SMatthew G. Knepley 
1657f017bcb6SMatthew G. Knepley /*@C
1658f3c94560SMatthew G. Knepley   DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test
1659f017bcb6SMatthew G. Knepley 
1660f017bcb6SMatthew G. Knepley   Input Parameters:
1661f017bcb6SMatthew G. Knepley + snes - the SNES object
1662f017bcb6SMatthew G. Knepley . dm   - the DM
1663f017bcb6SMatthew G. Knepley . u    - a DM vector
1664f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1665f017bcb6SMatthew G. Knepley 
1666f3c94560SMatthew G. Knepley   Output Parameters:
1667f3c94560SMatthew G. Knepley + isLinear - Flag indicaing that the function looks linear, or NULL
1668f3c94560SMatthew G. Knepley - convRate - The rate of convergence of the linear model, or NULL
1669f3c94560SMatthew G. Knepley 
1670f017bcb6SMatthew G. Knepley   Level: developer
1671f017bcb6SMatthew G. Knepley 
1672f017bcb6SMatthew G. Knepley .seealso: DNSNESCheckFromOptions(), DMSNESCheckDiscretization(), DMSNESCheckResidual()
1673f017bcb6SMatthew G. Knepley @*/
1674f3c94560SMatthew G. Knepley PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate)
1675f017bcb6SMatthew G. Knepley {
1676f017bcb6SMatthew G. Knepley   MPI_Comm       comm;
1677f017bcb6SMatthew G. Knepley   PetscDS        ds;
1678f017bcb6SMatthew G. Knepley   Mat            J, M;
1679f017bcb6SMatthew G. Knepley   MatNullSpace   nullspace;
1680f3c94560SMatthew G. Knepley   PetscReal      slope, intercept;
16817f96f943SMatthew G. Knepley   PetscBool      hasJac, hasPrec, isLin = PETSC_FALSE;
1682f017bcb6SMatthew G. Knepley   PetscErrorCode ierr;
1683f017bcb6SMatthew G. Knepley 
1684f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1685f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1686f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1687f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1688534a8f05SLisandro Dalcin   if (isLinear) PetscValidBoolPointer(isLinear, 5);
1689534a8f05SLisandro Dalcin   if (convRate) PetscValidRealPointer(convRate, 5);
1690f017bcb6SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) snes, &comm);CHKERRQ(ierr);
1691f2cacb80SMatthew G. Knepley   ierr = DMComputeExactSolution(dm, 0.0, u, NULL);CHKERRQ(ierr);
1692f017bcb6SMatthew G. Knepley   /* Create and view matrices */
1693f017bcb6SMatthew G. Knepley   ierr = DMCreateMatrix(dm, &J);CHKERRQ(ierr);
16947f96f943SMatthew G. Knepley   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
1695f017bcb6SMatthew G. Knepley   ierr = PetscDSHasJacobian(ds, &hasJac);CHKERRQ(ierr);
1696f017bcb6SMatthew G. Knepley   ierr = PetscDSHasJacobianPreconditioner(ds, &hasPrec);CHKERRQ(ierr);
1697282e7bb4SMatthew G. Knepley   if (hasJac && hasPrec) {
1698282e7bb4SMatthew G. Knepley     ierr = DMCreateMatrix(dm, &M);CHKERRQ(ierr);
1699282e7bb4SMatthew G. Knepley     ierr = SNESComputeJacobian(snes, u, J, M);CHKERRQ(ierr);
1700f017bcb6SMatthew G. Knepley     ierr = PetscObjectSetName((PetscObject) M, "Preconditioning Matrix");CHKERRQ(ierr);
1701282e7bb4SMatthew G. Knepley     ierr = PetscObjectSetOptionsPrefix((PetscObject) M, "jacpre_");CHKERRQ(ierr);
1702282e7bb4SMatthew G. Knepley     ierr = MatViewFromOptions(M, NULL, "-mat_view");CHKERRQ(ierr);
1703282e7bb4SMatthew G. Knepley     ierr = MatDestroy(&M);CHKERRQ(ierr);
1704282e7bb4SMatthew G. Knepley   } else {
1705282e7bb4SMatthew G. Knepley     ierr = SNESComputeJacobian(snes, u, J, J);CHKERRQ(ierr);
1706282e7bb4SMatthew G. Knepley   }
1707f017bcb6SMatthew G. Knepley   ierr = PetscObjectSetName((PetscObject) J, "Jacobian");CHKERRQ(ierr);
1708282e7bb4SMatthew G. Knepley   ierr = PetscObjectSetOptionsPrefix((PetscObject) J, "jac_");CHKERRQ(ierr);
1709282e7bb4SMatthew G. Knepley   ierr = MatViewFromOptions(J, NULL, "-mat_view");CHKERRQ(ierr);
1710f017bcb6SMatthew G. Knepley   /* Check nullspace */
1711f017bcb6SMatthew G. Knepley   ierr = MatGetNullSpace(J, &nullspace);CHKERRQ(ierr);
1712f017bcb6SMatthew G. Knepley   if (nullspace) {
17131878804aSMatthew G. Knepley     PetscBool isNull;
1714f017bcb6SMatthew G. Knepley     ierr = MatNullSpaceTest(nullspace, J, &isNull);CHKERRQ(ierr);
1715f017bcb6SMatthew G. Knepley     if (!isNull) SETERRQ(comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid.");
17161878804aSMatthew G. Knepley   }
1717f017bcb6SMatthew G. Knepley   /* Taylor test */
1718f017bcb6SMatthew G. Knepley   {
1719f017bcb6SMatthew G. Knepley     PetscRandom rand;
1720f017bcb6SMatthew G. Knepley     Vec         du, uhat, r, rhat, df;
1721f3c94560SMatthew G. Knepley     PetscReal   h;
1722f017bcb6SMatthew G. Knepley     PetscReal  *es, *hs, *errors;
1723f017bcb6SMatthew G. Knepley     PetscReal   hMax = 1.0, hMin = 1e-6, hMult = 0.1;
1724f017bcb6SMatthew G. Knepley     PetscInt    Nv, v;
1725f017bcb6SMatthew G. Knepley 
1726f017bcb6SMatthew G. Knepley     /* Choose a perturbation direction */
1727f017bcb6SMatthew G. Knepley     ierr = PetscRandomCreate(comm, &rand);CHKERRQ(ierr);
1728f017bcb6SMatthew G. Knepley     ierr = VecDuplicate(u, &du);CHKERRQ(ierr);
1729f017bcb6SMatthew G. Knepley     ierr = VecSetRandom(du, rand);CHKERRQ(ierr);
1730f017bcb6SMatthew G. Knepley     ierr = PetscRandomDestroy(&rand);CHKERRQ(ierr);
1731f017bcb6SMatthew G. Knepley     ierr = VecDuplicate(u, &df);CHKERRQ(ierr);
1732f017bcb6SMatthew G. Knepley     ierr = MatMult(J, du, df);CHKERRQ(ierr);
1733f017bcb6SMatthew G. Knepley     /* Evaluate residual at u, F(u), save in vector r */
1734f017bcb6SMatthew G. Knepley     ierr = VecDuplicate(u, &r);CHKERRQ(ierr);
1735f017bcb6SMatthew G. Knepley     ierr = SNESComputeFunction(snes, u, r);CHKERRQ(ierr);
1736f017bcb6SMatthew G. Knepley     /* Look at the convergence of our Taylor approximation as we approach u */
1737f017bcb6SMatthew G. Knepley     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv);
1738f017bcb6SMatthew G. Knepley     ierr = PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors);CHKERRQ(ierr);
1739f017bcb6SMatthew G. Knepley     ierr = VecDuplicate(u, &uhat);CHKERRQ(ierr);
1740f017bcb6SMatthew G. Knepley     ierr = VecDuplicate(u, &rhat);CHKERRQ(ierr);
1741f017bcb6SMatthew G. Knepley     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) {
1742f017bcb6SMatthew G. Knepley       ierr = VecWAXPY(uhat, h, du, u);CHKERRQ(ierr);
1743f017bcb6SMatthew G. Knepley       /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */
1744f017bcb6SMatthew G. Knepley       ierr = SNESComputeFunction(snes, uhat, rhat);CHKERRQ(ierr);
1745f017bcb6SMatthew G. Knepley       ierr = VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df);CHKERRQ(ierr);
1746f017bcb6SMatthew G. Knepley       ierr = VecNorm(rhat, NORM_2, &errors[Nv]);CHKERRQ(ierr);
1747f017bcb6SMatthew G. Knepley 
1748f017bcb6SMatthew G. Knepley       es[Nv] = PetscLog10Real(errors[Nv]);
1749f017bcb6SMatthew G. Knepley       hs[Nv] = PetscLog10Real(h);
1750f017bcb6SMatthew G. Knepley     }
1751f017bcb6SMatthew G. Knepley     ierr = VecDestroy(&uhat);CHKERRQ(ierr);
1752f017bcb6SMatthew G. Knepley     ierr = VecDestroy(&rhat);CHKERRQ(ierr);
1753f017bcb6SMatthew G. Knepley     ierr = VecDestroy(&df);CHKERRQ(ierr);
17541878804aSMatthew G. Knepley     ierr = VecDestroy(&r);CHKERRQ(ierr);
1755f017bcb6SMatthew G. Knepley     ierr = VecDestroy(&du);CHKERRQ(ierr);
1756f017bcb6SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1757f017bcb6SMatthew G. Knepley       if ((tol >= 0) && (errors[v] > tol)) break;
1758f017bcb6SMatthew G. Knepley       else if (errors[v] > PETSC_SMALL)    break;
1759f017bcb6SMatthew G. Knepley     }
1760f3c94560SMatthew G. Knepley     if (v == Nv) isLin = PETSC_TRUE;
1761f017bcb6SMatthew G. Knepley     ierr = PetscLinearRegression(Nv, hs, es, &slope, &intercept);CHKERRQ(ierr);
1762f017bcb6SMatthew G. Knepley     ierr = PetscFree3(es, hs, errors);CHKERRQ(ierr);
1763f017bcb6SMatthew G. Knepley     /* Slope should be about 2 */
1764f017bcb6SMatthew G. Knepley     if (tol >= 0) {
1765b878532fSMatthew G. Knepley       if (!isLin && PetscAbsReal(2 - slope) > tol) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double) slope);
1766b878532fSMatthew G. Knepley     } else if (isLinear || convRate) {
1767b878532fSMatthew G. Knepley       if (isLinear) *isLinear = isLin;
1768b878532fSMatthew G. Knepley       if (convRate) *convRate = slope;
1769f017bcb6SMatthew G. Knepley     } else {
1770f3c94560SMatthew G. Knepley       if (!isLin) {ierr = PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double) slope);CHKERRQ(ierr);}
1771f017bcb6SMatthew G. Knepley       else        {ierr = PetscPrintf(comm, "Function appears to be linear\n");CHKERRQ(ierr);}
1772f017bcb6SMatthew G. Knepley     }
1773f017bcb6SMatthew G. Knepley   }
17741878804aSMatthew G. Knepley   ierr = MatDestroy(&J);CHKERRQ(ierr);
17751878804aSMatthew G. Knepley   PetscFunctionReturn(0);
17761878804aSMatthew G. Knepley }
17771878804aSMatthew G. Knepley 
17787f96f943SMatthew G. Knepley PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u)
1779f017bcb6SMatthew G. Knepley {
1780f017bcb6SMatthew G. Knepley   PetscErrorCode ierr;
1781f017bcb6SMatthew G. Knepley 
1782f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1783f2cacb80SMatthew G. Knepley   ierr = DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL);CHKERRQ(ierr);
1784f3c94560SMatthew G. Knepley   ierr = DMSNESCheckResidual(snes, dm, u, -1.0, NULL);CHKERRQ(ierr);
1785f3c94560SMatthew G. Knepley   ierr = DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL);CHKERRQ(ierr);
1786f017bcb6SMatthew G. Knepley   PetscFunctionReturn(0);
1787f017bcb6SMatthew G. Knepley }
1788f017bcb6SMatthew G. Knepley 
1789bee9a294SMatthew G. Knepley /*@C
1790bee9a294SMatthew G. Knepley   DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information
1791bee9a294SMatthew G. Knepley 
1792bee9a294SMatthew G. Knepley   Input Parameters:
1793bee9a294SMatthew G. Knepley + snes - the SNES object
17947f96f943SMatthew G. Knepley - u    - representative SNES vector
17957f96f943SMatthew G. Knepley 
17967f96f943SMatthew G. Knepley   Note: The user must call PetscDSSetExactSolution() beforehand
1797bee9a294SMatthew G. Knepley 
1798bee9a294SMatthew G. Knepley   Level: developer
1799bee9a294SMatthew G. Knepley @*/
18007f96f943SMatthew G. Knepley PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u)
18011878804aSMatthew G. Knepley {
18021878804aSMatthew G. Knepley   DM             dm;
18031878804aSMatthew G. Knepley   Vec            sol;
18041878804aSMatthew G. Knepley   PetscBool      check;
18051878804aSMatthew G. Knepley   PetscErrorCode ierr;
18061878804aSMatthew G. Knepley 
18071878804aSMatthew G. Knepley   PetscFunctionBegin;
1808c5929fdfSBarry Smith   ierr = PetscOptionsHasName(((PetscObject)snes)->options,((PetscObject)snes)->prefix, "-dmsnes_check", &check);CHKERRQ(ierr);
18091878804aSMatthew G. Knepley   if (!check) PetscFunctionReturn(0);
18101878804aSMatthew G. Knepley   ierr = SNESGetDM(snes, &dm);CHKERRQ(ierr);
18111878804aSMatthew G. Knepley   ierr = VecDuplicate(u, &sol);CHKERRQ(ierr);
18121878804aSMatthew G. Knepley   ierr = SNESSetSolution(snes, sol);CHKERRQ(ierr);
18137f96f943SMatthew G. Knepley   ierr = DMSNESCheck_Internal(snes, dm, sol);CHKERRQ(ierr);
18141878804aSMatthew G. Knepley   ierr = VecDestroy(&sol);CHKERRQ(ierr);
1815552f7358SJed Brown   PetscFunctionReturn(0);
1816552f7358SJed Brown }
1817