xref: /petsc/src/snes/utils/dmplexsnes.c (revision 20f4b53cbb5e9bd9ef12b76a8697d60d197cda17)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/
2af0996ceSBarry Smith #include <petsc/private/snesimpl.h>   /*I "petscsnes.h"   I*/
324cdb843SMatthew G. Knepley #include <petscds.h>
4af0996ceSBarry Smith #include <petsc/private/petscimpl.h>
5af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
6552f7358SJed Brown 
7d71ae5a4SJacob Faibussowitsch static void pressure_Private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar p[])
8d71ae5a4SJacob Faibussowitsch {
9649ef022SMatthew Knepley   p[0] = u[uOff[1]];
10649ef022SMatthew Knepley }
11649ef022SMatthew Knepley 
12649ef022SMatthew Knepley /*
13*20f4b53cSBarry Smith   SNESCorrectDiscretePressure_Private - Add a vector in the nullspace to make the continuum integral of the pressure field equal to zero.
14*20f4b53cSBarry Smith   This is normally used only to evaluate convergence rates for the pressure accurately.
15649ef022SMatthew Knepley 
16c3339decSBarry Smith   Collective
17649ef022SMatthew Knepley 
18649ef022SMatthew Knepley   Input Parameters:
19649ef022SMatthew Knepley + snes      - The SNES
20649ef022SMatthew Knepley . pfield    - The field number for pressure
21649ef022SMatthew Knepley . nullspace - The pressure nullspace
22649ef022SMatthew Knepley . u         - The solution vector
23649ef022SMatthew Knepley - ctx       - An optional user context
24649ef022SMatthew Knepley 
25649ef022SMatthew Knepley   Output Parameter:
26649ef022SMatthew Knepley . u         - The solution with a continuum pressure integral of zero
27649ef022SMatthew Knepley 
28649ef022SMatthew Knepley   Notes:
29649ef022SMatthew 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.
30649ef022SMatthew Knepley 
31649ef022SMatthew Knepley   Level: developer
32649ef022SMatthew Knepley 
33db781477SPatrick Sanan .seealso: `SNESConvergedCorrectPressure()`
34649ef022SMatthew Knepley */
35d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESCorrectDiscretePressure_Private(SNES snes, PetscInt pfield, MatNullSpace nullspace, Vec u, void *ctx)
36d71ae5a4SJacob Faibussowitsch {
37649ef022SMatthew Knepley   DM          dm;
38649ef022SMatthew Knepley   PetscDS     ds;
39649ef022SMatthew Knepley   const Vec  *nullvecs;
40649ef022SMatthew Knepley   PetscScalar pintd, *intc, *intn;
41649ef022SMatthew Knepley   MPI_Comm    comm;
42649ef022SMatthew Knepley   PetscInt    Nf, Nv;
43649ef022SMatthew Knepley 
44649ef022SMatthew Knepley   PetscFunctionBegin;
459566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
469566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
4728b400f6SJacob Faibussowitsch   PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a SNES DM");
4828b400f6SJacob Faibussowitsch   PetscCheck(nullspace, comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a Jacobian nullspace");
499566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
509566063dSJacob Faibussowitsch   PetscCall(PetscDSSetObjective(ds, pfield, pressure_Private));
519566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceGetVecs(nullspace, NULL, &Nv, &nullvecs));
5263a3b9bcSJacob Faibussowitsch   PetscCheck(Nv == 1, comm, PETSC_ERR_ARG_OUTOFRANGE, "Can only handle a single null vector for pressure, not %" PetscInt_FMT, Nv);
539566063dSJacob Faibussowitsch   PetscCall(VecDot(nullvecs[0], u, &pintd));
5408401ef6SPierre Jolivet   PetscCheck(PetscAbsScalar(pintd) <= PETSC_SMALL, comm, PETSC_ERR_ARG_WRONG, "Discrete integral of pressure: %g", (double)PetscRealPart(pintd));
559566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(Nf, &intc, Nf, &intn));
579566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegralFEM(dm, nullvecs[0], intn, ctx));
589566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegralFEM(dm, u, intc, ctx));
599566063dSJacob Faibussowitsch   PetscCall(VecAXPY(u, -intc[pfield] / intn[pfield], nullvecs[0]));
60649ef022SMatthew Knepley #if defined(PETSC_USE_DEBUG)
619566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegralFEM(dm, u, intc, ctx));
6208401ef6SPierre Jolivet   PetscCheck(PetscAbsScalar(intc[pfield]) <= PETSC_SMALL, comm, PETSC_ERR_ARG_WRONG, "Continuum integral of pressure after correction: %g", (double)PetscRealPart(intc[pfield]));
63649ef022SMatthew Knepley #endif
649566063dSJacob Faibussowitsch   PetscCall(PetscFree2(intc, intn));
653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
66649ef022SMatthew Knepley }
67649ef022SMatthew Knepley 
68649ef022SMatthew Knepley /*@C
69f6dfbefdSBarry Smith    SNESConvergedCorrectPressure - Convergence test that adds a vector in the nullspace to make the continuum integral of the pressure field equal to zero.
70f6dfbefdSBarry Smith    This is normally used only to evaluate convergence rates for the pressure accurately. The convergence test itself just mimics `SNESConvergedDefault()`.
71649ef022SMatthew Knepley 
72c3339decSBarry Smith    Logically Collective
73649ef022SMatthew Knepley 
74649ef022SMatthew Knepley    Input Parameters:
75f6dfbefdSBarry Smith +  snes - the `SNES` context
76649ef022SMatthew Knepley .  it - the iteration (0 indicates before any Newton steps)
77649ef022SMatthew Knepley .  xnorm - 2-norm of current iterate
78649ef022SMatthew Knepley .  snorm - 2-norm of current step
79649ef022SMatthew Knepley .  fnorm - 2-norm of function at current iterate
80649ef022SMatthew Knepley -  ctx   - Optional user context
81649ef022SMatthew Knepley 
82649ef022SMatthew Knepley    Output Parameter:
83f6dfbefdSBarry Smith .  reason  - `SNES_CONVERGED_ITERATING`, `SNES_CONVERGED_ITS`, or `SNES_DIVERGED_FNORM_NAN`
84649ef022SMatthew Knepley 
85*20f4b53cSBarry Smith    Options Database Key:
86*20f4b53cSBarry Smith .  -snes_convergence_test correct_pressure - see `SNESSetFromOptions()`
87*20f4b53cSBarry Smith 
88*20f4b53cSBarry Smith    Level: advanced
89*20f4b53cSBarry Smith 
90649ef022SMatthew Knepley    Notes:
91f6dfbefdSBarry Smith    In order to use this convergence test, you must set up several PETSc structures. First fields must be added to the `DM`, and a `PetscDS`
92f6dfbefdSBarry Smith    must be created with discretizations of those fields. We currently assume that the pressure field has index 1.
93f6dfbefdSBarry Smith    The pressure field must have a nullspace, likely created using the `DMSetNullSpaceConstructor()` interface.
94f6dfbefdSBarry Smith    Last we must be able to integrate the pressure over the domain, so the `DM` attached to the SNES `must` be a `DMPLEX` at this time.
95f362779dSJed Brown 
96f6dfbefdSBarry Smith .seealso: `SNES`, `DM`, `SNESConvergedDefault()`, `SNESSetConvergenceTest()`, `DMSetNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`
97649ef022SMatthew Knepley @*/
98d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESConvergedCorrectPressure(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, void *ctx)
99d71ae5a4SJacob Faibussowitsch {
100649ef022SMatthew Knepley   PetscBool monitorIntegral = PETSC_FALSE;
101649ef022SMatthew Knepley 
102649ef022SMatthew Knepley   PetscFunctionBegin;
1039566063dSJacob Faibussowitsch   PetscCall(SNESConvergedDefault(snes, it, xnorm, gnorm, f, reason, ctx));
104649ef022SMatthew Knepley   if (monitorIntegral) {
105649ef022SMatthew Knepley     Mat          J;
106649ef022SMatthew Knepley     Vec          u;
107649ef022SMatthew Knepley     MatNullSpace nullspace;
108649ef022SMatthew Knepley     const Vec   *nullvecs;
109649ef022SMatthew Knepley     PetscScalar  pintd;
110649ef022SMatthew Knepley 
1119566063dSJacob Faibussowitsch     PetscCall(SNESGetSolution(snes, &u));
1129566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
1139566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(J, &nullspace));
1149566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceGetVecs(nullspace, NULL, NULL, &nullvecs));
1159566063dSJacob Faibussowitsch     PetscCall(VecDot(nullvecs[0], u, &pintd));
1169566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "SNES: Discrete integral of pressure: %g\n", (double)PetscRealPart(pintd)));
117649ef022SMatthew Knepley   }
118649ef022SMatthew Knepley   if (*reason > 0) {
119649ef022SMatthew Knepley     Mat          J;
120649ef022SMatthew Knepley     Vec          u;
121649ef022SMatthew Knepley     MatNullSpace nullspace;
122649ef022SMatthew Knepley     PetscInt     pfield = 1;
123649ef022SMatthew Knepley 
1249566063dSJacob Faibussowitsch     PetscCall(SNESGetSolution(snes, &u));
1259566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
1269566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(J, &nullspace));
1279566063dSJacob Faibussowitsch     PetscCall(SNESCorrectDiscretePressure_Private(snes, pfield, nullspace, u, ctx));
128649ef022SMatthew Knepley   }
1293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
130649ef022SMatthew Knepley }
131649ef022SMatthew Knepley 
13224cdb843SMatthew G. Knepley /************************** Interpolation *******************************/
13324cdb843SMatthew G. Knepley 
134d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESConvertPlex(DM dm, DM *plex, PetscBool copy)
135d71ae5a4SJacob Faibussowitsch {
1366da023fcSToby Isaac   PetscBool isPlex;
1376da023fcSToby Isaac 
1386da023fcSToby Isaac   PetscFunctionBegin;
1399566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
1406da023fcSToby Isaac   if (isPlex) {
1416da023fcSToby Isaac     *plex = dm;
1429566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
143f7148743SMatthew G. Knepley   } else {
1449566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex));
145f7148743SMatthew G. Knepley     if (!*plex) {
1469566063dSJacob Faibussowitsch       PetscCall(DMConvert(dm, DMPLEX, plex));
1479566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex));
1486da023fcSToby Isaac       if (copy) {
1499566063dSJacob Faibussowitsch         PetscCall(DMCopyDMSNES(dm, *plex));
1509566063dSJacob Faibussowitsch         PetscCall(DMCopyAuxiliaryVec(dm, *plex));
1516da023fcSToby Isaac       }
152f7148743SMatthew G. Knepley     } else {
1539566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)*plex));
154f7148743SMatthew G. Knepley     }
1556da023fcSToby Isaac   }
1563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1576da023fcSToby Isaac }
1586da023fcSToby Isaac 
1594267b1a3SMatthew G. Knepley /*@C
160f6dfbefdSBarry Smith   DMInterpolationCreate - Creates a `DMInterpolationInfo` context
1614267b1a3SMatthew G. Knepley 
162d083f849SBarry Smith   Collective
1634267b1a3SMatthew G. Knepley 
1644267b1a3SMatthew G. Knepley   Input Parameter:
1654267b1a3SMatthew G. Knepley . comm - the communicator
1664267b1a3SMatthew G. Knepley 
1674267b1a3SMatthew G. Knepley   Output Parameter:
1684267b1a3SMatthew G. Knepley . ctx - the context
1694267b1a3SMatthew G. Knepley 
1704267b1a3SMatthew G. Knepley   Level: beginner
1714267b1a3SMatthew G. Knepley 
172f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationDestroy()`
1734267b1a3SMatthew G. Knepley @*/
174d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationCreate(MPI_Comm comm, DMInterpolationInfo *ctx)
175d71ae5a4SJacob Faibussowitsch {
176552f7358SJed Brown   PetscFunctionBegin;
177552f7358SJed Brown   PetscValidPointer(ctx, 2);
1789566063dSJacob Faibussowitsch   PetscCall(PetscNew(ctx));
1791aa26658SKarl Rupp 
180552f7358SJed Brown   (*ctx)->comm   = comm;
181552f7358SJed Brown   (*ctx)->dim    = -1;
182552f7358SJed Brown   (*ctx)->nInput = 0;
1830298fd71SBarry Smith   (*ctx)->points = NULL;
1840298fd71SBarry Smith   (*ctx)->cells  = NULL;
185552f7358SJed Brown   (*ctx)->n      = -1;
1860298fd71SBarry Smith   (*ctx)->coords = NULL;
1873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
188552f7358SJed Brown }
189552f7358SJed Brown 
1904267b1a3SMatthew G. Knepley /*@C
1914267b1a3SMatthew G. Knepley   DMInterpolationSetDim - Sets the spatial dimension for the interpolation context
1924267b1a3SMatthew G. Knepley 
193*20f4b53cSBarry Smith   Not Collective
1944267b1a3SMatthew G. Knepley 
1954267b1a3SMatthew G. Knepley   Input Parameters:
1964267b1a3SMatthew G. Knepley + ctx - the context
1974267b1a3SMatthew G. Knepley - dim - the spatial dimension
1984267b1a3SMatthew G. Knepley 
1994267b1a3SMatthew G. Knepley   Level: intermediate
2004267b1a3SMatthew G. Knepley 
201f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
2024267b1a3SMatthew G. Knepley @*/
203d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetDim(DMInterpolationInfo ctx, PetscInt dim)
204d71ae5a4SJacob Faibussowitsch {
205552f7358SJed Brown   PetscFunctionBegin;
20663a3b9bcSJacob Faibussowitsch   PetscCheck(!(dim < 1) && !(dim > 3), ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension for points: %" PetscInt_FMT, dim);
207552f7358SJed Brown   ctx->dim = dim;
2083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
209552f7358SJed Brown }
210552f7358SJed Brown 
2114267b1a3SMatthew G. Knepley /*@C
2124267b1a3SMatthew G. Knepley   DMInterpolationGetDim - Gets the spatial dimension for the interpolation context
2134267b1a3SMatthew G. Knepley 
214*20f4b53cSBarry Smith   Not Collective
2154267b1a3SMatthew G. Knepley 
2164267b1a3SMatthew G. Knepley   Input Parameter:
2174267b1a3SMatthew G. Knepley . ctx - the context
2184267b1a3SMatthew G. Knepley 
2194267b1a3SMatthew G. Knepley   Output Parameter:
2204267b1a3SMatthew G. Knepley . dim - the spatial dimension
2214267b1a3SMatthew G. Knepley 
2224267b1a3SMatthew G. Knepley   Level: intermediate
2234267b1a3SMatthew G. Knepley 
224f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
2254267b1a3SMatthew G. Knepley @*/
226d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetDim(DMInterpolationInfo ctx, PetscInt *dim)
227d71ae5a4SJacob Faibussowitsch {
228552f7358SJed Brown   PetscFunctionBegin;
229552f7358SJed Brown   PetscValidIntPointer(dim, 2);
230552f7358SJed Brown   *dim = ctx->dim;
2313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
232552f7358SJed Brown }
233552f7358SJed Brown 
2344267b1a3SMatthew G. Knepley /*@C
2354267b1a3SMatthew G. Knepley   DMInterpolationSetDof - Sets the number of fields interpolated at a point for the interpolation context
2364267b1a3SMatthew G. Knepley 
237*20f4b53cSBarry Smith   Not Collective
2384267b1a3SMatthew G. Knepley 
2394267b1a3SMatthew G. Knepley   Input Parameters:
2404267b1a3SMatthew G. Knepley + ctx - the context
2414267b1a3SMatthew G. Knepley - dof - the number of fields
2424267b1a3SMatthew G. Knepley 
2434267b1a3SMatthew G. Knepley   Level: intermediate
2444267b1a3SMatthew G. Knepley 
245f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
2464267b1a3SMatthew G. Knepley @*/
247d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetDof(DMInterpolationInfo ctx, PetscInt dof)
248d71ae5a4SJacob Faibussowitsch {
249552f7358SJed Brown   PetscFunctionBegin;
25063a3b9bcSJacob Faibussowitsch   PetscCheck(dof >= 1, ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of components: %" PetscInt_FMT, dof);
251552f7358SJed Brown   ctx->dof = dof;
2523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
253552f7358SJed Brown }
254552f7358SJed Brown 
2554267b1a3SMatthew G. Knepley /*@C
2564267b1a3SMatthew G. Knepley   DMInterpolationGetDof - Gets the number of fields interpolated at a point for the interpolation context
2574267b1a3SMatthew G. Knepley 
258*20f4b53cSBarry Smith   Not Collective
2594267b1a3SMatthew G. Knepley 
2604267b1a3SMatthew G. Knepley   Input Parameter:
2614267b1a3SMatthew G. Knepley . ctx - the context
2624267b1a3SMatthew G. Knepley 
2634267b1a3SMatthew G. Knepley   Output Parameter:
2644267b1a3SMatthew G. Knepley . dof - the number of fields
2654267b1a3SMatthew G. Knepley 
2664267b1a3SMatthew G. Knepley   Level: intermediate
2674267b1a3SMatthew G. Knepley 
268f6dfbefdSBarry Smith .seealso: DMInterpolationInfo, `DMInterpolationSetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
2694267b1a3SMatthew G. Knepley @*/
270d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetDof(DMInterpolationInfo ctx, PetscInt *dof)
271d71ae5a4SJacob Faibussowitsch {
272552f7358SJed Brown   PetscFunctionBegin;
273552f7358SJed Brown   PetscValidIntPointer(dof, 2);
274552f7358SJed Brown   *dof = ctx->dof;
2753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
276552f7358SJed Brown }
277552f7358SJed Brown 
2784267b1a3SMatthew G. Knepley /*@C
2794267b1a3SMatthew G. Knepley   DMInterpolationAddPoints - Add points at which we will interpolate the fields
2804267b1a3SMatthew G. Knepley 
281*20f4b53cSBarry Smith   Not Collective
2824267b1a3SMatthew G. Knepley 
2834267b1a3SMatthew G. Knepley   Input Parameters:
2844267b1a3SMatthew G. Knepley + ctx    - the context
2854267b1a3SMatthew G. Knepley . n      - the number of points
2864267b1a3SMatthew G. Knepley - points - the coordinates for each point, an array of size n * dim
2874267b1a3SMatthew G. Knepley 
288f6dfbefdSBarry Smith   Note:
289f6dfbefdSBarry Smith   The coordinate information is copied.
2904267b1a3SMatthew G. Knepley 
2914267b1a3SMatthew G. Knepley   Level: intermediate
2924267b1a3SMatthew G. Knepley 
293f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationCreate()`
2944267b1a3SMatthew G. Knepley @*/
295d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationAddPoints(DMInterpolationInfo ctx, PetscInt n, PetscReal points[])
296d71ae5a4SJacob Faibussowitsch {
297552f7358SJed Brown   PetscFunctionBegin;
29808401ef6SPierre Jolivet   PetscCheck(ctx->dim >= 0, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
29928b400f6SJacob Faibussowitsch   PetscCheck(!ctx->points, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot add points multiple times yet");
300552f7358SJed Brown   ctx->nInput = n;
3011aa26658SKarl Rupp 
3029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n * ctx->dim, &ctx->points));
3039566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(ctx->points, points, n * ctx->dim));
3043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
305552f7358SJed Brown }
306552f7358SJed Brown 
3074267b1a3SMatthew G. Knepley /*@C
30852aa1562SMatthew G. Knepley   DMInterpolationSetUp - Compute spatial indices for point location during interpolation
3094267b1a3SMatthew G. Knepley 
310c3339decSBarry Smith   Collective
3114267b1a3SMatthew G. Knepley 
3124267b1a3SMatthew G. Knepley   Input Parameters:
3134267b1a3SMatthew G. Knepley + ctx - the context
314f6dfbefdSBarry Smith . dm  - the `DM` for the function space used for interpolation
315f6dfbefdSBarry Smith . redundantPoints - If `PETSC_TRUE`, all processes are passing in the same array of points. Otherwise, points need to be communicated among processes.
316f6dfbefdSBarry Smith - ignoreOutsideDomain - If `PETSC_TRUE`, ignore points outside the domain, otherwise return an error
3174267b1a3SMatthew G. Knepley 
3184267b1a3SMatthew G. Knepley   Level: intermediate
3194267b1a3SMatthew G. Knepley 
320f6dfbefdSBarry Smith .seealso: DMInterpolationInfo, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
3214267b1a3SMatthew G. Knepley @*/
322d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetUp(DMInterpolationInfo ctx, DM dm, PetscBool redundantPoints, PetscBool ignoreOutsideDomain)
323d71ae5a4SJacob Faibussowitsch {
324552f7358SJed Brown   MPI_Comm           comm = ctx->comm;
325552f7358SJed Brown   PetscScalar       *a;
326552f7358SJed Brown   PetscInt           p, q, i;
327552f7358SJed Brown   PetscMPIInt        rank, size;
328552f7358SJed Brown   Vec                pointVec;
3293a93e3b7SToby Isaac   PetscSF            cellSF;
330552f7358SJed Brown   PetscLayout        layout;
331552f7358SJed Brown   PetscReal         *globalPoints;
332cb313848SJed Brown   PetscScalar       *globalPointsScalar;
333552f7358SJed Brown   const PetscInt    *ranges;
334552f7358SJed Brown   PetscMPIInt       *counts, *displs;
3353a93e3b7SToby Isaac   const PetscSFNode *foundCells;
3363a93e3b7SToby Isaac   const PetscInt    *foundPoints;
337552f7358SJed Brown   PetscMPIInt       *foundProcs, *globalProcs;
3383a93e3b7SToby Isaac   PetscInt           n, N, numFound;
339552f7358SJed Brown 
34019436ca2SJed Brown   PetscFunctionBegin;
341064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
3429566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
3439566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
34408401ef6SPierre Jolivet   PetscCheck(ctx->dim >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
34519436ca2SJed Brown   /* Locate points */
34619436ca2SJed Brown   n = ctx->nInput;
347552f7358SJed Brown   if (!redundantPoints) {
3489566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCreate(comm, &layout));
3499566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetBlockSize(layout, 1));
3509566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetLocalSize(layout, n));
3519566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(layout));
3529566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, &N));
353552f7358SJed Brown     /* Communicate all points to all processes */
3549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(N * ctx->dim, &globalPoints, size, &counts, size, &displs));
3559566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRanges(layout, &ranges));
356552f7358SJed Brown     for (p = 0; p < size; ++p) {
357552f7358SJed Brown       counts[p] = (ranges[p + 1] - ranges[p]) * ctx->dim;
358552f7358SJed Brown       displs[p] = ranges[p] * ctx->dim;
359552f7358SJed Brown     }
3609566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgatherv(ctx->points, n * ctx->dim, MPIU_REAL, globalPoints, counts, displs, MPIU_REAL, comm));
361552f7358SJed Brown   } else {
362552f7358SJed Brown     N            = n;
363552f7358SJed Brown     globalPoints = ctx->points;
36438ea73c8SJed Brown     counts = displs = NULL;
36538ea73c8SJed Brown     layout          = NULL;
366552f7358SJed Brown   }
367552f7358SJed Brown #if 0
3689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(N,&foundCells,N,&foundProcs,N,&globalProcs));
36919436ca2SJed Brown   /* foundCells[p] = m->locatePoint(&globalPoints[p*ctx->dim]); */
370552f7358SJed Brown #else
371cb313848SJed Brown   #if defined(PETSC_USE_COMPLEX)
3729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(N * ctx->dim, &globalPointsScalar));
37346b3086cSToby Isaac   for (i = 0; i < N * ctx->dim; i++) globalPointsScalar[i] = globalPoints[i];
374cb313848SJed Brown   #else
375cb313848SJed Brown   globalPointsScalar = globalPoints;
376cb313848SJed Brown   #endif
3779566063dSJacob Faibussowitsch   PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, ctx->dim, N * ctx->dim, globalPointsScalar, &pointVec));
3789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(N, &foundProcs, N, &globalProcs));
379ad540459SPierre Jolivet   for (p = 0; p < N; ++p) foundProcs[p] = size;
3803a93e3b7SToby Isaac   cellSF = NULL;
3819566063dSJacob Faibussowitsch   PetscCall(DMLocatePoints(dm, pointVec, DM_POINTLOCATION_REMOVE, &cellSF));
3829566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(cellSF, NULL, &numFound, &foundPoints, &foundCells));
383552f7358SJed Brown #endif
3843a93e3b7SToby Isaac   for (p = 0; p < numFound; ++p) {
3853a93e3b7SToby Isaac     if (foundCells[p].index >= 0) foundProcs[foundPoints ? foundPoints[p] : p] = rank;
386552f7358SJed Brown   }
387552f7358SJed Brown   /* Let the lowest rank process own each point */
3881c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(foundProcs, globalProcs, N, MPI_INT, MPI_MIN, comm));
389552f7358SJed Brown   ctx->n = 0;
390552f7358SJed Brown   for (p = 0; p < N; ++p) {
39152aa1562SMatthew G. Knepley     if (globalProcs[p] == size) {
3929371c9d4SSatish Balay       PetscCheck(ignoreOutsideDomain, comm, PETSC_ERR_PLIB, "Point %" PetscInt_FMT ": %g %g %g not located in mesh", p, (double)globalPoints[p * ctx->dim + 0], (double)(ctx->dim > 1 ? globalPoints[p * ctx->dim + 1] : 0.0),
3939371c9d4SSatish Balay                  (double)(ctx->dim > 2 ? globalPoints[p * ctx->dim + 2] : 0.0));
394f7d195e4SLawrence Mitchell       if (rank == 0) ++ctx->n;
39552aa1562SMatthew G. Knepley     } else if (globalProcs[p] == rank) ++ctx->n;
396552f7358SJed Brown   }
397552f7358SJed Brown   /* Create coordinates vector and array of owned cells */
3989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ctx->n, &ctx->cells));
3999566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, &ctx->coords));
4009566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(ctx->coords, ctx->n * ctx->dim, PETSC_DECIDE));
4019566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(ctx->coords, ctx->dim));
4029566063dSJacob Faibussowitsch   PetscCall(VecSetType(ctx->coords, VECSTANDARD));
4039566063dSJacob Faibussowitsch   PetscCall(VecGetArray(ctx->coords, &a));
404552f7358SJed Brown   for (p = 0, q = 0, i = 0; p < N; ++p) {
405552f7358SJed Brown     if (globalProcs[p] == rank) {
406552f7358SJed Brown       PetscInt d;
407552f7358SJed Brown 
4081aa26658SKarl Rupp       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = globalPoints[p * ctx->dim + d];
409f317b747SMatthew G. Knepley       ctx->cells[q] = foundCells[q].index;
410f317b747SMatthew G. Knepley       ++q;
411552f7358SJed Brown     }
412dd400576SPatrick Sanan     if (globalProcs[p] == size && rank == 0) {
41352aa1562SMatthew G. Knepley       PetscInt d;
41452aa1562SMatthew G. Knepley 
41552aa1562SMatthew G. Knepley       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = 0.;
41652aa1562SMatthew G. Knepley       ctx->cells[q] = -1;
41752aa1562SMatthew G. Knepley       ++q;
41852aa1562SMatthew G. Knepley     }
419552f7358SJed Brown   }
4209566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(ctx->coords, &a));
421552f7358SJed Brown #if 0
4229566063dSJacob Faibussowitsch   PetscCall(PetscFree3(foundCells,foundProcs,globalProcs));
423552f7358SJed Brown #else
4249566063dSJacob Faibussowitsch   PetscCall(PetscFree2(foundProcs, globalProcs));
4259566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&cellSF));
4269566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pointVec));
427552f7358SJed Brown #endif
4289566063dSJacob Faibussowitsch   if ((void *)globalPointsScalar != (void *)globalPoints) PetscCall(PetscFree(globalPointsScalar));
4299566063dSJacob Faibussowitsch   if (!redundantPoints) PetscCall(PetscFree3(globalPoints, counts, displs));
4309566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&layout));
4313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
432552f7358SJed Brown }
433552f7358SJed Brown 
4344267b1a3SMatthew G. Knepley /*@C
435f6dfbefdSBarry Smith   DMInterpolationGetCoordinates - Gets a `Vec` with the coordinates of each interpolation point
4364267b1a3SMatthew G. Knepley 
437c3339decSBarry Smith   Collective
4384267b1a3SMatthew G. Knepley 
4394267b1a3SMatthew G. Knepley   Input Parameter:
4404267b1a3SMatthew G. Knepley . ctx - the context
4414267b1a3SMatthew G. Knepley 
4424267b1a3SMatthew G. Knepley   Output Parameter:
4434267b1a3SMatthew G. Knepley . coordinates  - the coordinates of interpolation points
4444267b1a3SMatthew G. Knepley 
445*20f4b53cSBarry Smith   Level: intermediate
446*20f4b53cSBarry Smith 
447f6dfbefdSBarry Smith   Note:
448f6dfbefdSBarry Smith   The local vector entries correspond to interpolation points lying on this process, according to the associated `DM`.
449f6dfbefdSBarry Smith   This is a borrowed vector that the user should not destroy.
4504267b1a3SMatthew G. Knepley 
451f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
4524267b1a3SMatthew G. Knepley @*/
453d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetCoordinates(DMInterpolationInfo ctx, Vec *coordinates)
454d71ae5a4SJacob Faibussowitsch {
455552f7358SJed Brown   PetscFunctionBegin;
456552f7358SJed Brown   PetscValidPointer(coordinates, 2);
45728b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
458552f7358SJed Brown   *coordinates = ctx->coords;
4593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
460552f7358SJed Brown }
461552f7358SJed Brown 
4624267b1a3SMatthew G. Knepley /*@C
463f6dfbefdSBarry Smith   DMInterpolationGetVector - Gets a `Vec` which can hold all the interpolated field values
4644267b1a3SMatthew G. Knepley 
465c3339decSBarry Smith   Collective
4664267b1a3SMatthew G. Knepley 
4674267b1a3SMatthew G. Knepley   Input Parameter:
4684267b1a3SMatthew G. Knepley . ctx - the context
4694267b1a3SMatthew G. Knepley 
4704267b1a3SMatthew G. Knepley   Output Parameter:
4714267b1a3SMatthew G. Knepley . v  - a vector capable of holding the interpolated field values
4724267b1a3SMatthew G. Knepley 
473f6dfbefdSBarry Smith   Note:
474f6dfbefdSBarry Smith   This vector should be returned using `DMInterpolationRestoreVector()`.
4754267b1a3SMatthew G. Knepley 
4764267b1a3SMatthew G. Knepley   Level: intermediate
4774267b1a3SMatthew G. Knepley 
478f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationRestoreVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
4794267b1a3SMatthew G. Knepley @*/
480d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetVector(DMInterpolationInfo ctx, Vec *v)
481d71ae5a4SJacob Faibussowitsch {
482552f7358SJed Brown   PetscFunctionBegin;
483552f7358SJed Brown   PetscValidPointer(v, 2);
48428b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
4859566063dSJacob Faibussowitsch   PetscCall(VecCreate(ctx->comm, v));
4869566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*v, ctx->n * ctx->dof, PETSC_DECIDE));
4879566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(*v, ctx->dof));
4889566063dSJacob Faibussowitsch   PetscCall(VecSetType(*v, VECSTANDARD));
4893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
490552f7358SJed Brown }
491552f7358SJed Brown 
4924267b1a3SMatthew G. Knepley /*@C
493f6dfbefdSBarry Smith   DMInterpolationRestoreVector - Returns a `Vec` which can hold all the interpolated field values
4944267b1a3SMatthew G. Knepley 
495c3339decSBarry Smith   Collective
4964267b1a3SMatthew G. Knepley 
4974267b1a3SMatthew G. Knepley   Input Parameters:
4984267b1a3SMatthew G. Knepley + ctx - the context
4994267b1a3SMatthew G. Knepley - v  - a vector capable of holding the interpolated field values
5004267b1a3SMatthew G. Knepley 
5014267b1a3SMatthew G. Knepley   Level: intermediate
5024267b1a3SMatthew G. Knepley 
503f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
5044267b1a3SMatthew G. Knepley @*/
505d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationRestoreVector(DMInterpolationInfo ctx, Vec *v)
506d71ae5a4SJacob Faibussowitsch {
507552f7358SJed Brown   PetscFunctionBegin;
508552f7358SJed Brown   PetscValidPointer(v, 2);
50928b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
5109566063dSJacob Faibussowitsch   PetscCall(VecDestroy(v));
5113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
512552f7358SJed Brown }
513552f7358SJed Brown 
514d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Segment_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
515d71ae5a4SJacob Faibussowitsch {
516cfe5744fSMatthew G. Knepley   PetscReal          v0, J, invJ, detJ;
517cfe5744fSMatthew G. Knepley   const PetscInt     dof = ctx->dof;
518cfe5744fSMatthew G. Knepley   const PetscScalar *coords;
519cfe5744fSMatthew G. Knepley   PetscScalar       *a;
520cfe5744fSMatthew G. Knepley   PetscInt           p;
521cfe5744fSMatthew G. Knepley 
522cfe5744fSMatthew G. Knepley   PetscFunctionBegin;
5239566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
5249566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
525cfe5744fSMatthew G. Knepley   for (p = 0; p < ctx->n; ++p) {
526cfe5744fSMatthew G. Knepley     PetscInt     c = ctx->cells[p];
527cfe5744fSMatthew G. Knepley     PetscScalar *x = NULL;
528cfe5744fSMatthew G. Knepley     PetscReal    xir[1];
529cfe5744fSMatthew G. Knepley     PetscInt     xSize, comp;
530cfe5744fSMatthew G. Knepley 
5319566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ));
532cfe5744fSMatthew G. Knepley     PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c);
533cfe5744fSMatthew G. Knepley     xir[0] = invJ * PetscRealPart(coords[p] - v0);
5349566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
535cfe5744fSMatthew G. Knepley     if (2 * dof == xSize) {
536cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp] * (1 - xir[0]) + x[1 * dof + comp] * xir[0];
537cfe5744fSMatthew G. Knepley     } else if (dof == xSize) {
538cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp];
539cfe5744fSMatthew G. Knepley     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input closure size %" PetscInt_FMT " must be either %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 2 * dof, dof);
5409566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
541cfe5744fSMatthew G. Knepley   }
5429566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
5439566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
5443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
545cfe5744fSMatthew G. Knepley }
546cfe5744fSMatthew G. Knepley 
547d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Triangle_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
548d71ae5a4SJacob Faibussowitsch {
549552f7358SJed Brown   PetscReal         *v0, *J, *invJ, detJ;
55056044e6dSMatthew G. Knepley   const PetscScalar *coords;
55156044e6dSMatthew G. Knepley   PetscScalar       *a;
552552f7358SJed Brown   PetscInt           p;
553552f7358SJed Brown 
554552f7358SJed Brown   PetscFunctionBegin;
5559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ));
5569566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
5579566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
558552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
559552f7358SJed Brown     PetscInt     c = ctx->cells[p];
560a1e44745SMatthew G. Knepley     PetscScalar *x = NULL;
561552f7358SJed Brown     PetscReal    xi[4];
562552f7358SJed Brown     PetscInt     d, f, comp;
563552f7358SJed Brown 
5649566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
56563a3b9bcSJacob Faibussowitsch     PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c);
5669566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
5671aa26658SKarl Rupp     for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp];
5681aa26658SKarl Rupp 
569552f7358SJed Brown     for (d = 0; d < ctx->dim; ++d) {
570552f7358SJed Brown       xi[d] = 0.0;
5711aa26658SKarl 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]);
5721aa26658SKarl 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];
573552f7358SJed Brown     }
5749566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
575552f7358SJed Brown   }
5769566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
5779566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
5789566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
5793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
580552f7358SJed Brown }
581552f7358SJed Brown 
582d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Tetrahedron_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
583d71ae5a4SJacob Faibussowitsch {
5847a1931ceSMatthew G. Knepley   PetscReal         *v0, *J, *invJ, detJ;
58556044e6dSMatthew G. Knepley   const PetscScalar *coords;
58656044e6dSMatthew G. Knepley   PetscScalar       *a;
5877a1931ceSMatthew G. Knepley   PetscInt           p;
5887a1931ceSMatthew G. Knepley 
5897a1931ceSMatthew G. Knepley   PetscFunctionBegin;
5909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ));
5919566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
5929566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
5937a1931ceSMatthew G. Knepley   for (p = 0; p < ctx->n; ++p) {
5947a1931ceSMatthew G. Knepley     PetscInt       c        = ctx->cells[p];
5957a1931ceSMatthew G. Knepley     const PetscInt order[3] = {2, 1, 3};
5962584bbe8SMatthew G. Knepley     PetscScalar   *x        = NULL;
5977a1931ceSMatthew G. Knepley     PetscReal      xi[4];
5987a1931ceSMatthew G. Knepley     PetscInt       d, f, comp;
5997a1931ceSMatthew G. Knepley 
6009566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
60163a3b9bcSJacob Faibussowitsch     PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c);
6029566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
6037a1931ceSMatthew G. Knepley     for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp];
6047a1931ceSMatthew G. Knepley 
6057a1931ceSMatthew G. Knepley     for (d = 0; d < ctx->dim; ++d) {
6067a1931ceSMatthew G. Knepley       xi[d] = 0.0;
6077a1931ceSMatthew 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]);
6087a1931ceSMatthew 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];
6097a1931ceSMatthew G. Knepley     }
6109566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
6117a1931ceSMatthew G. Knepley   }
6129566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
6139566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
6149566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
6153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6167a1931ceSMatthew G. Knepley }
6177a1931ceSMatthew G. Knepley 
618d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode QuadMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
619d71ae5a4SJacob Faibussowitsch {
620552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar *)ctx;
621552f7358SJed Brown   const PetscScalar  x0       = vertices[0];
622552f7358SJed Brown   const PetscScalar  y0       = vertices[1];
623552f7358SJed Brown   const PetscScalar  x1       = vertices[2];
624552f7358SJed Brown   const PetscScalar  y1       = vertices[3];
625552f7358SJed Brown   const PetscScalar  x2       = vertices[4];
626552f7358SJed Brown   const PetscScalar  y2       = vertices[5];
627552f7358SJed Brown   const PetscScalar  x3       = vertices[6];
628552f7358SJed Brown   const PetscScalar  y3       = vertices[7];
629552f7358SJed Brown   const PetscScalar  f_1      = x1 - x0;
630552f7358SJed Brown   const PetscScalar  g_1      = y1 - y0;
631552f7358SJed Brown   const PetscScalar  f_3      = x3 - x0;
632552f7358SJed Brown   const PetscScalar  g_3      = y3 - y0;
633552f7358SJed Brown   const PetscScalar  f_01     = x2 - x1 - x3 + x0;
634552f7358SJed Brown   const PetscScalar  g_01     = y2 - y1 - y3 + y0;
63556044e6dSMatthew G. Knepley   const PetscScalar *ref;
63656044e6dSMatthew G. Knepley   PetscScalar       *real;
637552f7358SJed Brown 
638552f7358SJed Brown   PetscFunctionBegin;
6399566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref, &ref));
6409566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Xreal, &real));
641552f7358SJed Brown   {
642552f7358SJed Brown     const PetscScalar p0 = ref[0];
643552f7358SJed Brown     const PetscScalar p1 = ref[1];
644552f7358SJed Brown 
645552f7358SJed Brown     real[0] = x0 + f_1 * p0 + f_3 * p1 + f_01 * p0 * p1;
646552f7358SJed Brown     real[1] = y0 + g_1 * p0 + g_3 * p1 + g_01 * p0 * p1;
647552f7358SJed Brown   }
6489566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(28));
6499566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref, &ref));
6509566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Xreal, &real));
6513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
652552f7358SJed Brown }
653552f7358SJed Brown 
654af0996ceSBarry Smith #include <petsc/private/dmimpl.h>
655d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode QuadJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
656d71ae5a4SJacob Faibussowitsch {
657552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar *)ctx;
658552f7358SJed Brown   const PetscScalar  x0       = vertices[0];
659552f7358SJed Brown   const PetscScalar  y0       = vertices[1];
660552f7358SJed Brown   const PetscScalar  x1       = vertices[2];
661552f7358SJed Brown   const PetscScalar  y1       = vertices[3];
662552f7358SJed Brown   const PetscScalar  x2       = vertices[4];
663552f7358SJed Brown   const PetscScalar  y2       = vertices[5];
664552f7358SJed Brown   const PetscScalar  x3       = vertices[6];
665552f7358SJed Brown   const PetscScalar  y3       = vertices[7];
666552f7358SJed Brown   const PetscScalar  f_01     = x2 - x1 - x3 + x0;
667552f7358SJed Brown   const PetscScalar  g_01     = y2 - y1 - y3 + y0;
66856044e6dSMatthew G. Knepley   const PetscScalar *ref;
669552f7358SJed Brown 
670552f7358SJed Brown   PetscFunctionBegin;
6719566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref, &ref));
672552f7358SJed Brown   {
673552f7358SJed Brown     const PetscScalar x       = ref[0];
674552f7358SJed Brown     const PetscScalar y       = ref[1];
675552f7358SJed Brown     const PetscInt    rows[2] = {0, 1};
676da80777bSKarl Rupp     PetscScalar       values[4];
677da80777bSKarl Rupp 
6789371c9d4SSatish Balay     values[0] = (x1 - x0 + f_01 * y) * 0.5;
6799371c9d4SSatish Balay     values[1] = (x3 - x0 + f_01 * x) * 0.5;
6809371c9d4SSatish Balay     values[2] = (y1 - y0 + g_01 * y) * 0.5;
6819371c9d4SSatish Balay     values[3] = (y3 - y0 + g_01 * x) * 0.5;
6829566063dSJacob Faibussowitsch     PetscCall(MatSetValues(J, 2, rows, 2, rows, values, INSERT_VALUES));
683552f7358SJed Brown   }
6849566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(30));
6859566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref, &ref));
6869566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
6879566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
6883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
689552f7358SJed Brown }
690552f7358SJed Brown 
691d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Quad_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
692d71ae5a4SJacob Faibussowitsch {
693fafc0619SMatthew G Knepley   DM                 dmCoord;
694de73a395SMatthew G. Knepley   PetscFE            fem = NULL;
695552f7358SJed Brown   SNES               snes;
696552f7358SJed Brown   KSP                ksp;
697552f7358SJed Brown   PC                 pc;
698552f7358SJed Brown   Vec                coordsLocal, r, ref, real;
699552f7358SJed Brown   Mat                J;
700716009bfSMatthew G. Knepley   PetscTabulation    T = NULL;
70156044e6dSMatthew G. Knepley   const PetscScalar *coords;
70256044e6dSMatthew G. Knepley   PetscScalar       *a;
703716009bfSMatthew G. Knepley   PetscReal          xir[2] = {0., 0.};
704de73a395SMatthew G. Knepley   PetscInt           Nf, p;
7055509d985SMatthew G. Knepley   const PetscInt     dof = ctx->dof;
706552f7358SJed Brown 
707552f7358SJed Brown   PetscFunctionBegin;
7089566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
709716009bfSMatthew G. Knepley   if (Nf) {
710cfe5744fSMatthew G. Knepley     PetscObject  obj;
711cfe5744fSMatthew G. Knepley     PetscClassId id;
712cfe5744fSMatthew G. Knepley 
7139566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, 0, NULL, &obj));
7149566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
7159371c9d4SSatish Balay     if (id == PETSCFE_CLASSID) {
7169371c9d4SSatish Balay       fem = (PetscFE)obj;
7179371c9d4SSatish Balay       PetscCall(PetscFECreateTabulation(fem, 1, 1, xir, 0, &T));
7189371c9d4SSatish Balay     }
719716009bfSMatthew G. Knepley   }
7209566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
7219566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &dmCoord));
7229566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
7239566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes, "quad_interp_"));
7249566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &r));
7259566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(r, 2, 2));
7269566063dSJacob Faibussowitsch   PetscCall(VecSetType(r, dm->vectype));
7279566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &ref));
7289566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &real));
7299566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &J));
7309566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(J, 2, 2, 2, 2));
7319566063dSJacob Faibussowitsch   PetscCall(MatSetType(J, MATSEQDENSE));
7329566063dSJacob Faibussowitsch   PetscCall(MatSetUp(J));
7339566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes, r, QuadMap_Private, NULL));
7349566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes, J, J, QuadJacobian_Private, NULL));
7359566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(snes, &ksp));
7369566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(ksp, &pc));
7379566063dSJacob Faibussowitsch   PetscCall(PCSetType(pc, PCLU));
7389566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
739552f7358SJed Brown 
7409566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
7419566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
742552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
743a1e44745SMatthew G. Knepley     PetscScalar *x = NULL, *vertices = NULL;
744552f7358SJed Brown     PetscScalar *xi;
745552f7358SJed Brown     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
746552f7358SJed Brown 
747552f7358SJed Brown     /* Can make this do all points at once */
7489566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
74963a3b9bcSJacob Faibussowitsch     PetscCheck(4 * 2 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %" PetscInt_FMT " should be %d", coordSize, 4 * 2);
7509566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
7519566063dSJacob Faibussowitsch     PetscCall(SNESSetFunction(snes, NULL, NULL, vertices));
7529566063dSJacob Faibussowitsch     PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
7539566063dSJacob Faibussowitsch     PetscCall(VecGetArray(real, &xi));
754552f7358SJed Brown     xi[0] = coords[p * ctx->dim + 0];
755552f7358SJed Brown     xi[1] = coords[p * ctx->dim + 1];
7569566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(real, &xi));
7579566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes, real, ref));
7589566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ref, &xi));
759cb313848SJed Brown     xir[0] = PetscRealPart(xi[0]);
760cb313848SJed Brown     xir[1] = PetscRealPart(xi[1]);
761cfe5744fSMatthew G. Knepley     if (4 * dof == xSize) {
7629371c9d4SSatish Balay       for (comp = 0; comp < dof; ++comp) 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];
763cfe5744fSMatthew G. Knepley     } else if (dof == xSize) {
764cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp];
765cfe5744fSMatthew G. Knepley     } else {
7665509d985SMatthew G. Knepley       PetscInt d;
7671aa26658SKarl Rupp 
7682c71b3e2SJacob Faibussowitsch       PetscCheck(fem, ctx->comm, PETSC_ERR_ARG_WRONG, "Cannot have a higher order interpolant if the discretization is not PetscFE");
7699371c9d4SSatish Balay       xir[0] = 2.0 * xir[0] - 1.0;
7709371c9d4SSatish Balay       xir[1] = 2.0 * xir[1] - 1.0;
7719566063dSJacob Faibussowitsch       PetscCall(PetscFEComputeTabulation(fem, 1, xir, 0, T));
7725509d985SMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) {
7735509d985SMatthew G. Knepley         a[p * dof + comp] = 0.0;
774ad540459SPierre Jolivet         for (d = 0; d < xSize / dof; ++d) a[p * dof + comp] += x[d * dof + comp] * T->T[0][d * dof + comp];
7755509d985SMatthew G. Knepley       }
7765509d985SMatthew G. Knepley     }
7779566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ref, &xi));
7789566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
7799566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
780552f7358SJed Brown   }
7819566063dSJacob Faibussowitsch   PetscCall(PetscTabulationDestroy(&T));
7829566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
7839566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
784552f7358SJed Brown 
7859566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
7869566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
7879566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ref));
7889566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&real));
7899566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
7903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
791552f7358SJed Brown }
792552f7358SJed Brown 
793d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode HexMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
794d71ae5a4SJacob Faibussowitsch {
795552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar *)ctx;
796552f7358SJed Brown   const PetscScalar  x0       = vertices[0];
797552f7358SJed Brown   const PetscScalar  y0       = vertices[1];
798552f7358SJed Brown   const PetscScalar  z0       = vertices[2];
7997a1931ceSMatthew G. Knepley   const PetscScalar  x1       = vertices[9];
8007a1931ceSMatthew G. Knepley   const PetscScalar  y1       = vertices[10];
8017a1931ceSMatthew G. Knepley   const PetscScalar  z1       = vertices[11];
802552f7358SJed Brown   const PetscScalar  x2       = vertices[6];
803552f7358SJed Brown   const PetscScalar  y2       = vertices[7];
804552f7358SJed Brown   const PetscScalar  z2       = vertices[8];
8057a1931ceSMatthew G. Knepley   const PetscScalar  x3       = vertices[3];
8067a1931ceSMatthew G. Knepley   const PetscScalar  y3       = vertices[4];
8077a1931ceSMatthew G. Knepley   const PetscScalar  z3       = vertices[5];
808552f7358SJed Brown   const PetscScalar  x4       = vertices[12];
809552f7358SJed Brown   const PetscScalar  y4       = vertices[13];
810552f7358SJed Brown   const PetscScalar  z4       = vertices[14];
811552f7358SJed Brown   const PetscScalar  x5       = vertices[15];
812552f7358SJed Brown   const PetscScalar  y5       = vertices[16];
813552f7358SJed Brown   const PetscScalar  z5       = vertices[17];
814552f7358SJed Brown   const PetscScalar  x6       = vertices[18];
815552f7358SJed Brown   const PetscScalar  y6       = vertices[19];
816552f7358SJed Brown   const PetscScalar  z6       = vertices[20];
817552f7358SJed Brown   const PetscScalar  x7       = vertices[21];
818552f7358SJed Brown   const PetscScalar  y7       = vertices[22];
819552f7358SJed Brown   const PetscScalar  z7       = vertices[23];
820552f7358SJed Brown   const PetscScalar  f_1      = x1 - x0;
821552f7358SJed Brown   const PetscScalar  g_1      = y1 - y0;
822552f7358SJed Brown   const PetscScalar  h_1      = z1 - z0;
823552f7358SJed Brown   const PetscScalar  f_3      = x3 - x0;
824552f7358SJed Brown   const PetscScalar  g_3      = y3 - y0;
825552f7358SJed Brown   const PetscScalar  h_3      = z3 - z0;
826552f7358SJed Brown   const PetscScalar  f_4      = x4 - x0;
827552f7358SJed Brown   const PetscScalar  g_4      = y4 - y0;
828552f7358SJed Brown   const PetscScalar  h_4      = z4 - z0;
829552f7358SJed Brown   const PetscScalar  f_01     = x2 - x1 - x3 + x0;
830552f7358SJed Brown   const PetscScalar  g_01     = y2 - y1 - y3 + y0;
831552f7358SJed Brown   const PetscScalar  h_01     = z2 - z1 - z3 + z0;
832552f7358SJed Brown   const PetscScalar  f_12     = x7 - x3 - x4 + x0;
833552f7358SJed Brown   const PetscScalar  g_12     = y7 - y3 - y4 + y0;
834552f7358SJed Brown   const PetscScalar  h_12     = z7 - z3 - z4 + z0;
835552f7358SJed Brown   const PetscScalar  f_02     = x5 - x1 - x4 + x0;
836552f7358SJed Brown   const PetscScalar  g_02     = y5 - y1 - y4 + y0;
837552f7358SJed Brown   const PetscScalar  h_02     = z5 - z1 - z4 + z0;
838552f7358SJed Brown   const PetscScalar  f_012    = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
839552f7358SJed Brown   const PetscScalar  g_012    = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
840552f7358SJed Brown   const PetscScalar  h_012    = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
84156044e6dSMatthew G. Knepley   const PetscScalar *ref;
84256044e6dSMatthew G. Knepley   PetscScalar       *real;
843552f7358SJed Brown 
844552f7358SJed Brown   PetscFunctionBegin;
8459566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref, &ref));
8469566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Xreal, &real));
847552f7358SJed Brown   {
848552f7358SJed Brown     const PetscScalar p0 = ref[0];
849552f7358SJed Brown     const PetscScalar p1 = ref[1];
850552f7358SJed Brown     const PetscScalar p2 = ref[2];
851552f7358SJed Brown 
852552f7358SJed 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;
853552f7358SJed 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;
854552f7358SJed 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;
855552f7358SJed Brown   }
8569566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(114));
8579566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref, &ref));
8589566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Xreal, &real));
8593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
860552f7358SJed Brown }
861552f7358SJed Brown 
862d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode HexJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
863d71ae5a4SJacob Faibussowitsch {
864552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar *)ctx;
865552f7358SJed Brown   const PetscScalar  x0       = vertices[0];
866552f7358SJed Brown   const PetscScalar  y0       = vertices[1];
867552f7358SJed Brown   const PetscScalar  z0       = vertices[2];
8687a1931ceSMatthew G. Knepley   const PetscScalar  x1       = vertices[9];
8697a1931ceSMatthew G. Knepley   const PetscScalar  y1       = vertices[10];
8707a1931ceSMatthew G. Knepley   const PetscScalar  z1       = vertices[11];
871552f7358SJed Brown   const PetscScalar  x2       = vertices[6];
872552f7358SJed Brown   const PetscScalar  y2       = vertices[7];
873552f7358SJed Brown   const PetscScalar  z2       = vertices[8];
8747a1931ceSMatthew G. Knepley   const PetscScalar  x3       = vertices[3];
8757a1931ceSMatthew G. Knepley   const PetscScalar  y3       = vertices[4];
8767a1931ceSMatthew G. Knepley   const PetscScalar  z3       = vertices[5];
877552f7358SJed Brown   const PetscScalar  x4       = vertices[12];
878552f7358SJed Brown   const PetscScalar  y4       = vertices[13];
879552f7358SJed Brown   const PetscScalar  z4       = vertices[14];
880552f7358SJed Brown   const PetscScalar  x5       = vertices[15];
881552f7358SJed Brown   const PetscScalar  y5       = vertices[16];
882552f7358SJed Brown   const PetscScalar  z5       = vertices[17];
883552f7358SJed Brown   const PetscScalar  x6       = vertices[18];
884552f7358SJed Brown   const PetscScalar  y6       = vertices[19];
885552f7358SJed Brown   const PetscScalar  z6       = vertices[20];
886552f7358SJed Brown   const PetscScalar  x7       = vertices[21];
887552f7358SJed Brown   const PetscScalar  y7       = vertices[22];
888552f7358SJed Brown   const PetscScalar  z7       = vertices[23];
889552f7358SJed Brown   const PetscScalar  f_xy     = x2 - x1 - x3 + x0;
890552f7358SJed Brown   const PetscScalar  g_xy     = y2 - y1 - y3 + y0;
891552f7358SJed Brown   const PetscScalar  h_xy     = z2 - z1 - z3 + z0;
892552f7358SJed Brown   const PetscScalar  f_yz     = x7 - x3 - x4 + x0;
893552f7358SJed Brown   const PetscScalar  g_yz     = y7 - y3 - y4 + y0;
894552f7358SJed Brown   const PetscScalar  h_yz     = z7 - z3 - z4 + z0;
895552f7358SJed Brown   const PetscScalar  f_xz     = x5 - x1 - x4 + x0;
896552f7358SJed Brown   const PetscScalar  g_xz     = y5 - y1 - y4 + y0;
897552f7358SJed Brown   const PetscScalar  h_xz     = z5 - z1 - z4 + z0;
898552f7358SJed Brown   const PetscScalar  f_xyz    = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
899552f7358SJed Brown   const PetscScalar  g_xyz    = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
900552f7358SJed Brown   const PetscScalar  h_xyz    = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
90156044e6dSMatthew G. Knepley   const PetscScalar *ref;
902552f7358SJed Brown 
903552f7358SJed Brown   PetscFunctionBegin;
9049566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref, &ref));
905552f7358SJed Brown   {
906552f7358SJed Brown     const PetscScalar x       = ref[0];
907552f7358SJed Brown     const PetscScalar y       = ref[1];
908552f7358SJed Brown     const PetscScalar z       = ref[2];
909552f7358SJed Brown     const PetscInt    rows[3] = {0, 1, 2};
910da80777bSKarl Rupp     PetscScalar       values[9];
911da80777bSKarl Rupp 
912da80777bSKarl Rupp     values[0] = (x1 - x0 + f_xy * y + f_xz * z + f_xyz * y * z) / 2.0;
913da80777bSKarl Rupp     values[1] = (x3 - x0 + f_xy * x + f_yz * z + f_xyz * x * z) / 2.0;
914da80777bSKarl Rupp     values[2] = (x4 - x0 + f_yz * y + f_xz * x + f_xyz * x * y) / 2.0;
915da80777bSKarl Rupp     values[3] = (y1 - y0 + g_xy * y + g_xz * z + g_xyz * y * z) / 2.0;
916da80777bSKarl Rupp     values[4] = (y3 - y0 + g_xy * x + g_yz * z + g_xyz * x * z) / 2.0;
917da80777bSKarl Rupp     values[5] = (y4 - y0 + g_yz * y + g_xz * x + g_xyz * x * y) / 2.0;
918da80777bSKarl Rupp     values[6] = (z1 - z0 + h_xy * y + h_xz * z + h_xyz * y * z) / 2.0;
919da80777bSKarl Rupp     values[7] = (z3 - z0 + h_xy * x + h_yz * z + h_xyz * x * z) / 2.0;
920da80777bSKarl Rupp     values[8] = (z4 - z0 + h_yz * y + h_xz * x + h_xyz * x * y) / 2.0;
9211aa26658SKarl Rupp 
9229566063dSJacob Faibussowitsch     PetscCall(MatSetValues(J, 3, rows, 3, rows, values, INSERT_VALUES));
923552f7358SJed Brown   }
9249566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(152));
9259566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref, &ref));
9269566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
9279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
9283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
929552f7358SJed Brown }
930552f7358SJed Brown 
931d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Hex_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
932d71ae5a4SJacob Faibussowitsch {
933fafc0619SMatthew G Knepley   DM                 dmCoord;
934552f7358SJed Brown   SNES               snes;
935552f7358SJed Brown   KSP                ksp;
936552f7358SJed Brown   PC                 pc;
937552f7358SJed Brown   Vec                coordsLocal, r, ref, real;
938552f7358SJed Brown   Mat                J;
93956044e6dSMatthew G. Knepley   const PetscScalar *coords;
94056044e6dSMatthew G. Knepley   PetscScalar       *a;
941552f7358SJed Brown   PetscInt           p;
942552f7358SJed Brown 
943552f7358SJed Brown   PetscFunctionBegin;
9449566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
9459566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &dmCoord));
9469566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
9479566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes, "hex_interp_"));
9489566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &r));
9499566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(r, 3, 3));
9509566063dSJacob Faibussowitsch   PetscCall(VecSetType(r, dm->vectype));
9519566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &ref));
9529566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &real));
9539566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &J));
9549566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(J, 3, 3, 3, 3));
9559566063dSJacob Faibussowitsch   PetscCall(MatSetType(J, MATSEQDENSE));
9569566063dSJacob Faibussowitsch   PetscCall(MatSetUp(J));
9579566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes, r, HexMap_Private, NULL));
9589566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes, J, J, HexJacobian_Private, NULL));
9599566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(snes, &ksp));
9609566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(ksp, &pc));
9619566063dSJacob Faibussowitsch   PetscCall(PCSetType(pc, PCLU));
9629566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
963552f7358SJed Brown 
9649566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
9659566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
966552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
967a1e44745SMatthew G. Knepley     PetscScalar *x = NULL, *vertices = NULL;
968552f7358SJed Brown     PetscScalar *xi;
969cb313848SJed Brown     PetscReal    xir[3];
970552f7358SJed Brown     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
971552f7358SJed Brown 
972552f7358SJed Brown     /* Can make this do all points at once */
9739566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
974cfe5744fSMatthew G. Knepley     PetscCheck(8 * 3 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid coordinate closure size %" PetscInt_FMT " should be %d", coordSize, 8 * 3);
9759566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
976cfe5744fSMatthew G. Knepley     PetscCheck((8 * ctx->dof == xSize) || (ctx->dof == xSize), ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input closure size %" PetscInt_FMT " should be %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 8 * ctx->dof, ctx->dof);
9779566063dSJacob Faibussowitsch     PetscCall(SNESSetFunction(snes, NULL, NULL, vertices));
9789566063dSJacob Faibussowitsch     PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
9799566063dSJacob Faibussowitsch     PetscCall(VecGetArray(real, &xi));
980552f7358SJed Brown     xi[0] = coords[p * ctx->dim + 0];
981552f7358SJed Brown     xi[1] = coords[p * ctx->dim + 1];
982552f7358SJed Brown     xi[2] = coords[p * ctx->dim + 2];
9839566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(real, &xi));
9849566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes, real, ref));
9859566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ref, &xi));
986cb313848SJed Brown     xir[0] = PetscRealPart(xi[0]);
987cb313848SJed Brown     xir[1] = PetscRealPart(xi[1]);
988cb313848SJed Brown     xir[2] = PetscRealPart(xi[2]);
989cfe5744fSMatthew G. Knepley     if (8 * ctx->dof == xSize) {
990552f7358SJed Brown       for (comp = 0; comp < ctx->dof; ++comp) {
9919371c9d4SSatish Balay         a[p * ctx->dof + comp] = x[0 * ctx->dof + comp] * (1 - xir[0]) * (1 - xir[1]) * (1 - xir[2]) + x[3 * ctx->dof + comp] * xir[0] * (1 - xir[1]) * (1 - xir[2]) + x[2 * ctx->dof + comp] * xir[0] * xir[1] * (1 - xir[2]) + x[1 * ctx->dof + comp] * (1 - xir[0]) * xir[1] * (1 - xir[2]) +
9929371c9d4SSatish Balay                                  x[4 * ctx->dof + comp] * (1 - xir[0]) * (1 - xir[1]) * xir[2] + x[5 * ctx->dof + comp] * xir[0] * (1 - xir[1]) * xir[2] + x[6 * ctx->dof + comp] * xir[0] * xir[1] * xir[2] + x[7 * ctx->dof + comp] * (1 - xir[0]) * xir[1] * xir[2];
993552f7358SJed Brown       }
994cfe5744fSMatthew G. Knepley     } else {
995cfe5744fSMatthew G. Knepley       for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp];
996cfe5744fSMatthew G. Knepley     }
9979566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ref, &xi));
9989566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
9999566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
1000552f7358SJed Brown   }
10019566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
10029566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
1003552f7358SJed Brown 
10049566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
10059566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
10069566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ref));
10079566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&real));
10089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
10093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1010552f7358SJed Brown }
1011552f7358SJed Brown 
10124267b1a3SMatthew G. Knepley /*@C
10134267b1a3SMatthew G. Knepley   DMInterpolationEvaluate - Using the input from dm and x, calculates interpolated field values at the interpolation points.
10144267b1a3SMatthew G. Knepley 
1015552f7358SJed Brown   Input Parameters:
1016f6dfbefdSBarry Smith + ctx - The `DMInterpolationInfo` context
1017f6dfbefdSBarry Smith . dm  - The `DM`
1018552f7358SJed Brown - x   - The local vector containing the field to be interpolated
1019552f7358SJed Brown 
1020552f7358SJed Brown   Output Parameters:
1021552f7358SJed Brown . v   - The vector containing the interpolated values
10224267b1a3SMatthew G. Knepley 
1023f6dfbefdSBarry Smith   Note:
1024f6dfbefdSBarry Smith   A suitable v can be obtained using `DMInterpolationGetVector()`.
10254267b1a3SMatthew G. Knepley 
10264267b1a3SMatthew G. Knepley   Level: beginner
10274267b1a3SMatthew G. Knepley 
1028f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
10294267b1a3SMatthew G. Knepley @*/
1030d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationEvaluate(DMInterpolationInfo ctx, DM dm, Vec x, Vec v)
1031d71ae5a4SJacob Faibussowitsch {
103266a0a883SMatthew G. Knepley   PetscDS   ds;
103366a0a883SMatthew G. Knepley   PetscInt  n, p, Nf, field;
103466a0a883SMatthew G. Knepley   PetscBool useDS = PETSC_FALSE;
1035552f7358SJed Brown 
1036552f7358SJed Brown   PetscFunctionBegin;
1037552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1038552f7358SJed Brown   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
1039552f7358SJed Brown   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
10409566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
104163a3b9bcSJacob Faibussowitsch   PetscCheck(n == ctx->n * ctx->dof, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input vector size %" PetscInt_FMT " should be %" PetscInt_FMT, n, ctx->n * ctx->dof);
10423ba16761SJacob Faibussowitsch   if (!n) PetscFunctionReturn(PETSC_SUCCESS);
10439566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
1044680d18d5SMatthew G. Knepley   if (ds) {
104566a0a883SMatthew G. Knepley     useDS = PETSC_TRUE;
10469566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(ds, &Nf));
1047680d18d5SMatthew G. Knepley     for (field = 0; field < Nf; ++field) {
104866a0a883SMatthew G. Knepley       PetscObject  obj;
1049680d18d5SMatthew G. Knepley       PetscClassId id;
1050680d18d5SMatthew G. Knepley 
10519566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, field, &obj));
10529566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
10539371c9d4SSatish Balay       if (id != PETSCFE_CLASSID) {
10549371c9d4SSatish Balay         useDS = PETSC_FALSE;
10559371c9d4SSatish Balay         break;
10569371c9d4SSatish Balay       }
105766a0a883SMatthew G. Knepley     }
105866a0a883SMatthew G. Knepley   }
105966a0a883SMatthew G. Knepley   if (useDS) {
106066a0a883SMatthew G. Knepley     const PetscScalar *coords;
106166a0a883SMatthew G. Knepley     PetscScalar       *interpolant;
106266a0a883SMatthew G. Knepley     PetscInt           cdim, d;
106366a0a883SMatthew G. Knepley 
10649566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &cdim));
10659566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ctx->coords, &coords));
10669566063dSJacob Faibussowitsch     PetscCall(VecGetArrayWrite(v, &interpolant));
1067680d18d5SMatthew G. Knepley     for (p = 0; p < ctx->n; ++p) {
106866a0a883SMatthew G. Knepley       PetscReal    pcoords[3], xi[3];
1069680d18d5SMatthew G. Knepley       PetscScalar *xa   = NULL;
107066a0a883SMatthew G. Knepley       PetscInt     coff = 0, foff = 0, clSize;
1071680d18d5SMatthew G. Knepley 
107252aa1562SMatthew G. Knepley       if (ctx->cells[p] < 0) continue;
1073680d18d5SMatthew G. Knepley       for (d = 0; d < cdim; ++d) pcoords[d] = PetscRealPart(coords[p * cdim + d]);
10749566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference(dm, ctx->cells[p], 1, pcoords, xi));
10759566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
107666a0a883SMatthew G. Knepley       for (field = 0; field < Nf; ++field) {
107766a0a883SMatthew G. Knepley         PetscTabulation T;
107866a0a883SMatthew G. Knepley         PetscFE         fe;
107966a0a883SMatthew G. Knepley 
10809566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
10819566063dSJacob Faibussowitsch         PetscCall(PetscFECreateTabulation(fe, 1, 1, xi, 0, &T));
1082680d18d5SMatthew G. Knepley         {
1083680d18d5SMatthew G. Knepley           const PetscReal *basis = T->T[0];
1084680d18d5SMatthew G. Knepley           const PetscInt   Nb    = T->Nb;
1085680d18d5SMatthew G. Knepley           const PetscInt   Nc    = T->Nc;
108666a0a883SMatthew G. Knepley           PetscInt         f, fc;
108766a0a883SMatthew G. Knepley 
1088680d18d5SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
108966a0a883SMatthew G. Knepley             interpolant[p * ctx->dof + coff + fc] = 0.0;
1090ad540459SPierre Jolivet             for (f = 0; f < Nb; ++f) interpolant[p * ctx->dof + coff + fc] += xa[foff + f] * basis[(0 * Nb + f) * Nc + fc];
1091680d18d5SMatthew G. Knepley           }
109266a0a883SMatthew G. Knepley           coff += Nc;
109366a0a883SMatthew G. Knepley           foff += Nb;
1094680d18d5SMatthew G. Knepley         }
10959566063dSJacob Faibussowitsch         PetscCall(PetscTabulationDestroy(&T));
1096680d18d5SMatthew G. Knepley       }
10979566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
109863a3b9bcSJacob Faibussowitsch       PetscCheck(coff == ctx->dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total components %" PetscInt_FMT " != %" PetscInt_FMT " dof specified for interpolation", coff, ctx->dof);
109963a3b9bcSJacob Faibussowitsch       PetscCheck(foff == clSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total FE space size %" PetscInt_FMT " != %" PetscInt_FMT " closure size", foff, clSize);
110066a0a883SMatthew G. Knepley     }
11019566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
11029566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayWrite(v, &interpolant));
110366a0a883SMatthew G. Knepley   } else {
110466a0a883SMatthew G. Knepley     DMPolytopeType ct;
110566a0a883SMatthew G. Knepley 
1106680d18d5SMatthew G. Knepley     /* TODO Check each cell individually */
11079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, ctx->cells[0], &ct));
1108680d18d5SMatthew G. Knepley     switch (ct) {
1109d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_SEGMENT:
1110d71ae5a4SJacob Faibussowitsch       PetscCall(DMInterpolate_Segment_Private(ctx, dm, x, v));
1111d71ae5a4SJacob Faibussowitsch       break;
1112d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_TRIANGLE:
1113d71ae5a4SJacob Faibussowitsch       PetscCall(DMInterpolate_Triangle_Private(ctx, dm, x, v));
1114d71ae5a4SJacob Faibussowitsch       break;
1115d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_QUADRILATERAL:
1116d71ae5a4SJacob Faibussowitsch       PetscCall(DMInterpolate_Quad_Private(ctx, dm, x, v));
1117d71ae5a4SJacob Faibussowitsch       break;
1118d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_TETRAHEDRON:
1119d71ae5a4SJacob Faibussowitsch       PetscCall(DMInterpolate_Tetrahedron_Private(ctx, dm, x, v));
1120d71ae5a4SJacob Faibussowitsch       break;
1121d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_HEXAHEDRON:
1122d71ae5a4SJacob Faibussowitsch       PetscCall(DMInterpolate_Hex_Private(ctx, dm, x, v));
1123d71ae5a4SJacob Faibussowitsch       break;
1124d71ae5a4SJacob Faibussowitsch     default:
1125d71ae5a4SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for cell type %s", DMPolytopeTypes[PetscMax(0, PetscMin(ct, DM_NUM_POLYTOPES))]);
1126680d18d5SMatthew G. Knepley     }
1127552f7358SJed Brown   }
11283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1129552f7358SJed Brown }
1130552f7358SJed Brown 
11314267b1a3SMatthew G. Knepley /*@C
1132f6dfbefdSBarry Smith   DMInterpolationDestroy - Destroys a `DMInterpolationInfo` context
11334267b1a3SMatthew G. Knepley 
1134c3339decSBarry Smith   Collective
11354267b1a3SMatthew G. Knepley 
11364267b1a3SMatthew G. Knepley   Input Parameter:
11374267b1a3SMatthew G. Knepley . ctx - the context
11384267b1a3SMatthew G. Knepley 
11394267b1a3SMatthew G. Knepley   Level: beginner
11404267b1a3SMatthew G. Knepley 
1141f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
11424267b1a3SMatthew G. Knepley @*/
1143d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationDestroy(DMInterpolationInfo *ctx)
1144d71ae5a4SJacob Faibussowitsch {
1145552f7358SJed Brown   PetscFunctionBegin;
1146064a246eSJacob Faibussowitsch   PetscValidPointer(ctx, 1);
11479566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(*ctx)->coords));
11489566063dSJacob Faibussowitsch   PetscCall(PetscFree((*ctx)->points));
11499566063dSJacob Faibussowitsch   PetscCall(PetscFree((*ctx)->cells));
11509566063dSJacob Faibussowitsch   PetscCall(PetscFree(*ctx));
11510298fd71SBarry Smith   *ctx = NULL;
11523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1153552f7358SJed Brown }
1154cc0c4584SMatthew G. Knepley 
1155cc0c4584SMatthew G. Knepley /*@C
1156cc0c4584SMatthew G. Knepley   SNESMonitorFields - Monitors the residual for each field separately
1157cc0c4584SMatthew G. Knepley 
1158c3339decSBarry Smith   Collective
1159cc0c4584SMatthew G. Knepley 
1160cc0c4584SMatthew G. Knepley   Input Parameters:
1161f6dfbefdSBarry Smith + snes   - the `SNES` context
1162cc0c4584SMatthew G. Knepley . its    - iteration number
1163cc0c4584SMatthew G. Knepley . fgnorm - 2-norm of residual
1164f6dfbefdSBarry Smith - vf  - `PetscViewerAndFormat` of `PetscViewerType` `PETSCVIEWERASCII`
1165cc0c4584SMatthew G. Knepley 
1166f6dfbefdSBarry Smith   Note:
1167cc0c4584SMatthew G. Knepley   This routine prints the residual norm at each iteration.
1168cc0c4584SMatthew G. Knepley 
1169cc0c4584SMatthew G. Knepley   Level: intermediate
1170cc0c4584SMatthew G. Knepley 
1171f6dfbefdSBarry Smith .seealso: `SNES`, `SNESMonitorSet()`, `SNESMonitorDefault()`
1172cc0c4584SMatthew G. Knepley @*/
1173d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
1174d71ae5a4SJacob Faibussowitsch {
1175d43b4f6eSBarry Smith   PetscViewer        viewer = vf->viewer;
1176cc0c4584SMatthew G. Knepley   Vec                res;
1177cc0c4584SMatthew G. Knepley   DM                 dm;
1178cc0c4584SMatthew G. Knepley   PetscSection       s;
1179cc0c4584SMatthew G. Knepley   const PetscScalar *r;
1180cc0c4584SMatthew G. Knepley   PetscReal         *lnorms, *norms;
1181cc0c4584SMatthew G. Knepley   PetscInt           numFields, f, pStart, pEnd, p;
1182cc0c4584SMatthew G. Knepley 
1183cc0c4584SMatthew G. Knepley   PetscFunctionBegin;
11844d4332d5SBarry Smith   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
11859566063dSJacob Faibussowitsch   PetscCall(SNESGetFunction(snes, &res, NULL, NULL));
11869566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
11879566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
11889566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &numFields));
11899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
11909566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &lnorms, numFields, &norms));
11919566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(res, &r));
1192cc0c4584SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
1193cc0c4584SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
1194cc0c4584SMatthew G. Knepley       PetscInt fdof, foff, d;
1195cc0c4584SMatthew G. Knepley 
11969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof));
11979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff));
1198cc0c4584SMatthew G. Knepley       for (d = 0; d < fdof; ++d) lnorms[f] += PetscRealPart(PetscSqr(r[foff + d]));
1199cc0c4584SMatthew G. Knepley     }
1200cc0c4584SMatthew G. Knepley   }
12019566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(res, &r));
12021c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(lnorms, norms, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
12039566063dSJacob Faibussowitsch   PetscCall(PetscViewerPushFormat(viewer, vf->format));
12049566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
120563a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e [", its, (double)fgnorm));
1206cc0c4584SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
12079566063dSJacob Faibussowitsch     if (f > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
12089566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "%14.12e", (double)PetscSqrtReal(norms[f])));
1209cc0c4584SMatthew G. Knepley   }
12109566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "]\n"));
12119566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
12129566063dSJacob Faibussowitsch   PetscCall(PetscViewerPopFormat(viewer));
12139566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lnorms, norms));
12143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1215cc0c4584SMatthew G. Knepley }
121624cdb843SMatthew G. Knepley 
121724cdb843SMatthew G. Knepley /********************* Residual Computation **************************/
121824cdb843SMatthew G. Knepley 
1219d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
1220d71ae5a4SJacob Faibussowitsch {
12216528b96dSMatthew G. Knepley   PetscInt depth;
12226528b96dSMatthew G. Knepley 
12236528b96dSMatthew G. Knepley   PetscFunctionBegin;
12249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(plex, &depth));
12259566063dSJacob Faibussowitsch   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
12269566063dSJacob Faibussowitsch   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
12273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12286528b96dSMatthew G. Knepley }
12296528b96dSMatthew G. Knepley 
123024cdb843SMatthew G. Knepley /*@
12318db23a53SJed Brown   DMPlexSNESComputeResidualFEM - Sums the local residual into vector F from the local input X using pointwise functions specified by the user
123224cdb843SMatthew G. Knepley 
123324cdb843SMatthew G. Knepley   Input Parameters:
123424cdb843SMatthew G. Knepley + dm - The mesh
123524cdb843SMatthew G. Knepley . X  - Local solution
123624cdb843SMatthew G. Knepley - user - The user context
123724cdb843SMatthew G. Knepley 
123824cdb843SMatthew G. Knepley   Output Parameter:
123924cdb843SMatthew G. Knepley . F  - Local output vector
124024cdb843SMatthew G. Knepley 
1241f6dfbefdSBarry Smith   Note:
1242f6dfbefdSBarry Smith   The residual is summed into F; the caller is responsible for using `VecZeroEntries()` or otherwise ensuring that any data in F is intentional.
12438db23a53SJed Brown 
124424cdb843SMatthew G. Knepley   Level: developer
124524cdb843SMatthew G. Knepley 
1246f6dfbefdSBarry Smith .seealso: `DM`, `DMPlexComputeJacobianAction()`
124724cdb843SMatthew G. Knepley @*/
1248d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
1249d71ae5a4SJacob Faibussowitsch {
12506da023fcSToby Isaac   DM       plex;
1251083401c6SMatthew G. Knepley   IS       allcellIS;
12526528b96dSMatthew G. Knepley   PetscInt Nds, s;
125324cdb843SMatthew G. Knepley 
125424cdb843SMatthew G. Knepley   PetscFunctionBegin;
12559566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
12569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
12579566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
12586528b96dSMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
12596528b96dSMatthew G. Knepley     PetscDS      ds;
12606528b96dSMatthew G. Knepley     IS           cellIS;
126106ad1575SMatthew G. Knepley     PetscFormKey key;
12626528b96dSMatthew G. Knepley 
12639566063dSJacob Faibussowitsch     PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds));
12646528b96dSMatthew G. Knepley     key.value = 0;
12656528b96dSMatthew G. Knepley     key.field = 0;
126606ad1575SMatthew G. Knepley     key.part  = 0;
12676528b96dSMatthew G. Knepley     if (!key.label) {
12689566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)allcellIS));
12696528b96dSMatthew G. Knepley       cellIS = allcellIS;
12706528b96dSMatthew G. Knepley     } else {
12716528b96dSMatthew G. Knepley       IS pointIS;
12726528b96dSMatthew G. Knepley 
12736528b96dSMatthew G. Knepley       key.value = 1;
12749566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
12759566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
12769566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
12776528b96dSMatthew G. Knepley     }
12789566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeResidual_Internal(plex, key, cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user));
12799566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
12806528b96dSMatthew G. Knepley   }
12819566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
12829566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
12833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12846528b96dSMatthew G. Knepley }
12856528b96dSMatthew G. Knepley 
1286d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESComputeResidual(DM dm, Vec X, Vec F, void *user)
1287d71ae5a4SJacob Faibussowitsch {
12886528b96dSMatthew G. Knepley   DM       plex;
12896528b96dSMatthew G. Knepley   IS       allcellIS;
12906528b96dSMatthew G. Knepley   PetscInt Nds, s;
12916528b96dSMatthew G. Knepley 
12926528b96dSMatthew G. Knepley   PetscFunctionBegin;
12939566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
12949566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
12959566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
1296083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1297083401c6SMatthew G. Knepley     PetscDS ds;
1298083401c6SMatthew G. Knepley     DMLabel label;
1299083401c6SMatthew G. Knepley     IS      cellIS;
1300083401c6SMatthew G. Knepley 
13019566063dSJacob Faibussowitsch     PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds));
13026528b96dSMatthew G. Knepley     {
130306ad1575SMatthew G. Knepley       PetscWeakFormKind resmap[2] = {PETSC_WF_F0, PETSC_WF_F1};
13046528b96dSMatthew G. Knepley       PetscWeakForm     wf;
13056528b96dSMatthew G. Knepley       PetscInt          Nm = 2, m, Nk = 0, k, kp, off = 0;
130606ad1575SMatthew G. Knepley       PetscFormKey     *reskeys;
13076528b96dSMatthew G. Knepley 
13086528b96dSMatthew G. Knepley       /* Get unique residual keys */
13096528b96dSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
13106528b96dSMatthew G. Knepley         PetscInt Nkm;
13119566063dSJacob Faibussowitsch         PetscCall(PetscHMapFormGetSize(ds->wf->form[resmap[m]], &Nkm));
13126528b96dSMatthew G. Knepley         Nk += Nkm;
13136528b96dSMatthew G. Knepley       }
13149566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nk, &reskeys));
131548a46eb9SPierre Jolivet       for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[resmap[m]], &off, reskeys));
131663a3b9bcSJacob Faibussowitsch       PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk);
13179566063dSJacob Faibussowitsch       PetscCall(PetscFormKeySort(Nk, reskeys));
13186528b96dSMatthew G. Knepley       for (k = 0, kp = 1; kp < Nk; ++kp) {
13196528b96dSMatthew G. Knepley         if ((reskeys[k].label != reskeys[kp].label) || (reskeys[k].value != reskeys[kp].value)) {
13206528b96dSMatthew G. Knepley           ++k;
13216528b96dSMatthew G. Knepley           if (kp != k) reskeys[k] = reskeys[kp];
13226528b96dSMatthew G. Knepley         }
13236528b96dSMatthew G. Knepley       }
13246528b96dSMatthew G. Knepley       Nk = k;
13256528b96dSMatthew G. Knepley 
13269566063dSJacob Faibussowitsch       PetscCall(PetscDSGetWeakForm(ds, &wf));
13276528b96dSMatthew G. Knepley       for (k = 0; k < Nk; ++k) {
13286528b96dSMatthew G. Knepley         DMLabel  label = reskeys[k].label;
13296528b96dSMatthew G. Knepley         PetscInt val   = reskeys[k].value;
13306528b96dSMatthew G. Knepley 
1331083401c6SMatthew G. Knepley         if (!label) {
13329566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)allcellIS));
1333083401c6SMatthew G. Knepley           cellIS = allcellIS;
1334083401c6SMatthew G. Knepley         } else {
1335083401c6SMatthew G. Knepley           IS pointIS;
1336083401c6SMatthew G. Knepley 
13379566063dSJacob Faibussowitsch           PetscCall(DMLabelGetStratumIS(label, val, &pointIS));
13389566063dSJacob Faibussowitsch           PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
13399566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&pointIS));
13404a3e9fdbSToby Isaac         }
13419566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeResidual_Internal(plex, reskeys[k], cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user));
13429566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&cellIS));
1343083401c6SMatthew G. Knepley       }
13449566063dSJacob Faibussowitsch       PetscCall(PetscFree(reskeys));
13456528b96dSMatthew G. Knepley     }
13466528b96dSMatthew G. Knepley   }
13479566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
13489566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
13493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
135024cdb843SMatthew G. Knepley }
135124cdb843SMatthew G. Knepley 
1352bdd6f66aSToby Isaac /*@
1353bdd6f66aSToby Isaac   DMPlexSNESComputeBoundaryFEM - Form the boundary values for the local input X
1354bdd6f66aSToby Isaac 
1355bdd6f66aSToby Isaac   Input Parameters:
1356bdd6f66aSToby Isaac + dm - The mesh
1357bdd6f66aSToby Isaac - user - The user context
1358bdd6f66aSToby Isaac 
1359bdd6f66aSToby Isaac   Output Parameter:
1360bdd6f66aSToby Isaac . X  - Local solution
1361bdd6f66aSToby Isaac 
1362bdd6f66aSToby Isaac   Level: developer
1363bdd6f66aSToby Isaac 
1364f6dfbefdSBarry Smith .seealso: `DMPLEX`, `DMPlexComputeJacobianAction()`
1365bdd6f66aSToby Isaac @*/
1366d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeBoundaryFEM(DM dm, Vec X, void *user)
1367d71ae5a4SJacob Faibussowitsch {
1368bdd6f66aSToby Isaac   DM plex;
1369bdd6f66aSToby Isaac 
1370bdd6f66aSToby Isaac   PetscFunctionBegin;
13719566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
13729566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, X, PETSC_MIN_REAL, NULL, NULL, NULL));
13739566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
13743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1375bdd6f66aSToby Isaac }
1376bdd6f66aSToby Isaac 
13777a73cf09SMatthew G. Knepley /*@
13788e3a2eefSMatthew G. Knepley   DMSNESComputeJacobianAction - Compute the action of the Jacobian J(X) on Y
13797a73cf09SMatthew G. Knepley 
13807a73cf09SMatthew G. Knepley   Input Parameters:
1381f6dfbefdSBarry Smith + dm   - The `DM`
13827a73cf09SMatthew G. Knepley . X    - Local solution vector
13837a73cf09SMatthew G. Knepley . Y    - Local input vector
13847a73cf09SMatthew G. Knepley - user - The user context
13857a73cf09SMatthew G. Knepley 
13867a73cf09SMatthew G. Knepley   Output Parameter:
138769d47153SPierre Jolivet . F    - local output vector
13887a73cf09SMatthew G. Knepley 
13897a73cf09SMatthew G. Knepley   Level: developer
13907a73cf09SMatthew G. Knepley 
13918e3a2eefSMatthew G. Knepley   Notes:
1392f6dfbefdSBarry Smith   Users will typically use `DMSNESCreateJacobianMF()` followed by `MatMult()` instead of calling this routine directly.
13938e3a2eefSMatthew G. Knepley 
1394f6dfbefdSBarry Smith .seealso: `DM`, ``DMSNESCreateJacobianMF()`, `DMPlexSNESComputeResidualFEM()`
13957a73cf09SMatthew G. Knepley @*/
1396d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESComputeJacobianAction(DM dm, Vec X, Vec Y, Vec F, void *user)
1397d71ae5a4SJacob Faibussowitsch {
13988e3a2eefSMatthew G. Knepley   DM       plex;
13998e3a2eefSMatthew G. Knepley   IS       allcellIS;
14008e3a2eefSMatthew G. Knepley   PetscInt Nds, s;
1401a925c78cSMatthew G. Knepley 
1402a925c78cSMatthew G. Knepley   PetscFunctionBegin;
14039566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
14049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
14059566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
14068e3a2eefSMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
14078e3a2eefSMatthew G. Knepley     PetscDS ds;
14088e3a2eefSMatthew G. Knepley     DMLabel label;
14098e3a2eefSMatthew G. Knepley     IS      cellIS;
14107a73cf09SMatthew G. Knepley 
14119566063dSJacob Faibussowitsch     PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds));
14128e3a2eefSMatthew G. Knepley     {
141306ad1575SMatthew G. Knepley       PetscWeakFormKind jacmap[4] = {PETSC_WF_G0, PETSC_WF_G1, PETSC_WF_G2, PETSC_WF_G3};
14148e3a2eefSMatthew G. Knepley       PetscWeakForm     wf;
14158e3a2eefSMatthew G. Knepley       PetscInt          Nm = 4, m, Nk = 0, k, kp, off = 0;
141606ad1575SMatthew G. Knepley       PetscFormKey     *jackeys;
14178e3a2eefSMatthew G. Knepley 
14188e3a2eefSMatthew G. Knepley       /* Get unique Jacobian keys */
14198e3a2eefSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
14208e3a2eefSMatthew G. Knepley         PetscInt Nkm;
14219566063dSJacob Faibussowitsch         PetscCall(PetscHMapFormGetSize(ds->wf->form[jacmap[m]], &Nkm));
14228e3a2eefSMatthew G. Knepley         Nk += Nkm;
14238e3a2eefSMatthew G. Knepley       }
14249566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nk, &jackeys));
142548a46eb9SPierre Jolivet       for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[jacmap[m]], &off, jackeys));
142663a3b9bcSJacob Faibussowitsch       PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk);
14279566063dSJacob Faibussowitsch       PetscCall(PetscFormKeySort(Nk, jackeys));
14288e3a2eefSMatthew G. Knepley       for (k = 0, kp = 1; kp < Nk; ++kp) {
14298e3a2eefSMatthew G. Knepley         if ((jackeys[k].label != jackeys[kp].label) || (jackeys[k].value != jackeys[kp].value)) {
14308e3a2eefSMatthew G. Knepley           ++k;
14318e3a2eefSMatthew G. Knepley           if (kp != k) jackeys[k] = jackeys[kp];
14328e3a2eefSMatthew G. Knepley         }
14338e3a2eefSMatthew G. Knepley       }
14348e3a2eefSMatthew G. Knepley       Nk = k;
14358e3a2eefSMatthew G. Knepley 
14369566063dSJacob Faibussowitsch       PetscCall(PetscDSGetWeakForm(ds, &wf));
14378e3a2eefSMatthew G. Knepley       for (k = 0; k < Nk; ++k) {
14388e3a2eefSMatthew G. Knepley         DMLabel  label = jackeys[k].label;
14398e3a2eefSMatthew G. Knepley         PetscInt val   = jackeys[k].value;
14408e3a2eefSMatthew G. Knepley 
14418e3a2eefSMatthew G. Knepley         if (!label) {
14429566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)allcellIS));
14438e3a2eefSMatthew G. Knepley           cellIS = allcellIS;
14447a73cf09SMatthew G. Knepley         } else {
14458e3a2eefSMatthew G. Knepley           IS pointIS;
1446a925c78cSMatthew G. Knepley 
14479566063dSJacob Faibussowitsch           PetscCall(DMLabelGetStratumIS(label, val, &pointIS));
14489566063dSJacob Faibussowitsch           PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
14499566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&pointIS));
1450a925c78cSMatthew G. Knepley         }
14519566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeJacobian_Action_Internal(plex, jackeys[k], cellIS, 0.0, 0.0, X, NULL, Y, F, user));
14529566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&cellIS));
14538e3a2eefSMatthew G. Knepley       }
14549566063dSJacob Faibussowitsch       PetscCall(PetscFree(jackeys));
14558e3a2eefSMatthew G. Knepley     }
14568e3a2eefSMatthew G. Knepley   }
14579566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
14589566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
14593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1460a925c78cSMatthew G. Knepley }
1461a925c78cSMatthew G. Knepley 
146224cdb843SMatthew G. Knepley /*@
146324cdb843SMatthew G. Knepley   DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
146424cdb843SMatthew G. Knepley 
146524cdb843SMatthew G. Knepley   Input Parameters:
146624cdb843SMatthew G. Knepley + dm - The mesh
146724cdb843SMatthew G. Knepley . X  - Local input vector
146824cdb843SMatthew G. Knepley - user - The user context
146924cdb843SMatthew G. Knepley 
147024cdb843SMatthew G. Knepley   Output Parameter:
147124cdb843SMatthew G. Knepley . Jac  - Jacobian matrix
147224cdb843SMatthew G. Knepley 
147324cdb843SMatthew G. Knepley   Note:
147424cdb843SMatthew G. Knepley   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
147524cdb843SMatthew G. Knepley   like a GPU, or vectorize on a multicore machine.
147624cdb843SMatthew G. Knepley 
147724cdb843SMatthew G. Knepley   Level: developer
147824cdb843SMatthew G. Knepley 
1479f6dfbefdSBarry Smith .seealso: `DMPLEX`, `Mat`
148024cdb843SMatthew G. Knepley @*/
1481d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, void *user)
1482d71ae5a4SJacob Faibussowitsch {
14836da023fcSToby Isaac   DM        plex;
1484083401c6SMatthew G. Knepley   IS        allcellIS;
1485f04eb4edSMatthew G. Knepley   PetscBool hasJac, hasPrec;
14866528b96dSMatthew G. Knepley   PetscInt  Nds, s;
148724cdb843SMatthew G. Knepley 
148824cdb843SMatthew G. Knepley   PetscFunctionBegin;
14899566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
14909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
14919566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
1492083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1493083401c6SMatthew G. Knepley     PetscDS      ds;
1494083401c6SMatthew G. Knepley     IS           cellIS;
149506ad1575SMatthew G. Knepley     PetscFormKey key;
1496083401c6SMatthew G. Knepley 
14979566063dSJacob Faibussowitsch     PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds));
14986528b96dSMatthew G. Knepley     key.value = 0;
14996528b96dSMatthew G. Knepley     key.field = 0;
150006ad1575SMatthew G. Knepley     key.part  = 0;
15016528b96dSMatthew G. Knepley     if (!key.label) {
15029566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)allcellIS));
1503083401c6SMatthew G. Knepley       cellIS = allcellIS;
1504083401c6SMatthew G. Knepley     } else {
1505083401c6SMatthew G. Knepley       IS pointIS;
1506083401c6SMatthew G. Knepley 
15076528b96dSMatthew G. Knepley       key.value = 1;
15089566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
15099566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
15109566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
1511083401c6SMatthew G. Knepley     }
1512083401c6SMatthew G. Knepley     if (!s) {
15139566063dSJacob Faibussowitsch       PetscCall(PetscDSHasJacobian(ds, &hasJac));
15149566063dSJacob Faibussowitsch       PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
15159566063dSJacob Faibussowitsch       if (hasJac && hasPrec) PetscCall(MatZeroEntries(Jac));
15169566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(JacP));
1517083401c6SMatthew G. Knepley     }
15189566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeJacobian_Internal(plex, key, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, user));
15199566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
1520083401c6SMatthew G. Knepley   }
15219566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
15229566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
15233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
152424cdb843SMatthew G. Knepley }
15251878804aSMatthew G. Knepley 
15269371c9d4SSatish Balay struct _DMSNESJacobianMFCtx {
15278e3a2eefSMatthew G. Knepley   DM    dm;
15288e3a2eefSMatthew G. Knepley   Vec   X;
15298e3a2eefSMatthew G. Knepley   void *ctx;
15308e3a2eefSMatthew G. Knepley };
15318e3a2eefSMatthew G. Knepley 
1532d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Destroy_Private(Mat A)
1533d71ae5a4SJacob Faibussowitsch {
15348e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15358e3a2eefSMatthew G. Knepley 
15368e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15379566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
15389566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(A, NULL));
15399566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&ctx->dm));
15409566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ctx->X));
15419566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
15423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15438e3a2eefSMatthew G. Knepley }
15448e3a2eefSMatthew G. Knepley 
1545d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Mult_Private(Mat A, Vec Y, Vec Z)
1546d71ae5a4SJacob Faibussowitsch {
15478e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15488e3a2eefSMatthew G. Knepley 
15498e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15509566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
15519566063dSJacob Faibussowitsch   PetscCall(DMSNESComputeJacobianAction(ctx->dm, ctx->X, Y, Z, ctx->ctx));
15523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15538e3a2eefSMatthew G. Knepley }
15548e3a2eefSMatthew G. Knepley 
15558e3a2eefSMatthew G. Knepley /*@
1556f6dfbefdSBarry Smith   DMSNESCreateJacobianMF - Create a `Mat` which computes the action of the Jacobian matrix-free
15578e3a2eefSMatthew G. Knepley 
1558c3339decSBarry Smith   Collective
15598e3a2eefSMatthew G. Knepley 
15608e3a2eefSMatthew G. Knepley   Input Parameters:
1561f6dfbefdSBarry Smith + dm   - The `DM`
15628e3a2eefSMatthew G. Knepley . X    - The evaluation point for the Jacobian
15638e3a2eefSMatthew G. Knepley - user - A user context, or NULL
15648e3a2eefSMatthew G. Knepley 
15658e3a2eefSMatthew G. Knepley   Output Parameter:
1566f6dfbefdSBarry Smith . J    - The `Mat`
15678e3a2eefSMatthew G. Knepley 
15688e3a2eefSMatthew G. Knepley   Level: advanced
15698e3a2eefSMatthew G. Knepley 
1570f6dfbefdSBarry Smith   Note:
1571f6dfbefdSBarry Smith   Vec X is kept in `Mat` J, so updating X then updates the evaluation point.
15728e3a2eefSMatthew G. Knepley 
1573f6dfbefdSBarry Smith .seealso: `DM`, `DMSNESComputeJacobianAction()`
15748e3a2eefSMatthew G. Knepley @*/
1575d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCreateJacobianMF(DM dm, Vec X, void *user, Mat *J)
1576d71ae5a4SJacob Faibussowitsch {
15778e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15788e3a2eefSMatthew G. Knepley   PetscInt                     n, N;
15798e3a2eefSMatthew G. Knepley 
15808e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15819566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
15829566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, MATSHELL));
15839566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(X, &n));
15849566063dSJacob Faibussowitsch   PetscCall(VecGetSize(X, &N));
15859566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, n, n, N, N));
15869566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)dm));
15879566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)X));
15889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &ctx));
15898e3a2eefSMatthew G. Knepley   ctx->dm  = dm;
15908e3a2eefSMatthew G. Knepley   ctx->X   = X;
15918e3a2eefSMatthew G. Knepley   ctx->ctx = user;
15929566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*J, ctx));
15939566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(*J, MATOP_DESTROY, (void (*)(void))DMSNESJacobianMF_Destroy_Private));
15949566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(*J, MATOP_MULT, (void (*)(void))DMSNESJacobianMF_Mult_Private));
15953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15968e3a2eefSMatthew G. Knepley }
15978e3a2eefSMatthew G. Knepley 
159838cfc46eSPierre Jolivet /*
159938cfc46eSPierre Jolivet      MatComputeNeumannOverlap - Computes an unassembled (Neumann) local overlapping Mat in nonlinear context.
160038cfc46eSPierre Jolivet 
160138cfc46eSPierre Jolivet    Input Parameters:
160238cfc46eSPierre Jolivet +     X - SNES linearization point
160338cfc46eSPierre Jolivet .     ovl - index set of overlapping subdomains
160438cfc46eSPierre Jolivet 
160538cfc46eSPierre Jolivet    Output Parameter:
160638cfc46eSPierre Jolivet .     J - unassembled (Neumann) local matrix
160738cfc46eSPierre Jolivet 
160838cfc46eSPierre Jolivet    Level: intermediate
160938cfc46eSPierre Jolivet 
1610db781477SPatrick Sanan .seealso: `DMCreateNeumannOverlap()`, `MATIS`, `PCHPDDMSetAuxiliaryMat()`
161138cfc46eSPierre Jolivet */
1612d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, void *ctx)
1613d71ae5a4SJacob Faibussowitsch {
161438cfc46eSPierre Jolivet   SNES   snes;
161538cfc46eSPierre Jolivet   Mat    pJ;
161638cfc46eSPierre Jolivet   DM     ovldm, origdm;
161738cfc46eSPierre Jolivet   DMSNES sdm;
161838cfc46eSPierre Jolivet   PetscErrorCode (*bfun)(DM, Vec, void *);
161938cfc46eSPierre Jolivet   PetscErrorCode (*jfun)(DM, Vec, Mat, Mat, void *);
162038cfc46eSPierre Jolivet   void *bctx, *jctx;
162138cfc46eSPierre Jolivet 
162238cfc46eSPierre Jolivet   PetscFunctionBegin;
16239566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_MATIS", (PetscObject *)&pJ));
162428b400f6SJacob Faibussowitsch   PetscCheck(pJ, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing overlapping Mat");
16259566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Original_HPDDM", (PetscObject *)&origdm));
162628b400f6SJacob Faibussowitsch   PetscCheck(origdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing original DM");
16279566063dSJacob Faibussowitsch   PetscCall(MatGetDM(pJ, &ovldm));
16289566063dSJacob Faibussowitsch   PetscCall(DMSNESGetBoundaryLocal(origdm, &bfun, &bctx));
16299566063dSJacob Faibussowitsch   PetscCall(DMSNESSetBoundaryLocal(ovldm, bfun, bctx));
16309566063dSJacob Faibussowitsch   PetscCall(DMSNESGetJacobianLocal(origdm, &jfun, &jctx));
16319566063dSJacob Faibussowitsch   PetscCall(DMSNESSetJacobianLocal(ovldm, jfun, jctx));
16329566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject *)&snes));
163338cfc46eSPierre Jolivet   if (!snes) {
16349566063dSJacob Faibussowitsch     PetscCall(SNESCreate(PetscObjectComm((PetscObject)ovl), &snes));
16359566063dSJacob Faibussowitsch     PetscCall(SNESSetDM(snes, ovldm));
16369566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject)snes));
16379566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)snes));
163838cfc46eSPierre Jolivet   }
16399566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(ovldm, &sdm));
16409566063dSJacob Faibussowitsch   PetscCall(VecLockReadPush(X));
1641800f99ffSJeremy L Thompson   {
1642800f99ffSJeremy L Thompson     void *ctx;
1643800f99ffSJeremy L Thompson     PetscErrorCode (*J)(SNES, Vec, Mat, Mat, void *);
1644800f99ffSJeremy L Thompson     PetscCall(DMSNESGetJacobian(ovldm, &J, &ctx));
1645800f99ffSJeremy L Thompson     PetscCallBack("SNES callback Jacobian", (*J)(snes, X, pJ, pJ, ctx));
1646800f99ffSJeremy L Thompson   }
16479566063dSJacob Faibussowitsch   PetscCall(VecLockReadPop(X));
164838cfc46eSPierre Jolivet   /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */
164938cfc46eSPierre Jolivet   {
165038cfc46eSPierre Jolivet     Mat locpJ;
165138cfc46eSPierre Jolivet 
16529566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pJ, &locpJ));
16539566063dSJacob Faibussowitsch     PetscCall(MatCopy(locpJ, J, SAME_NONZERO_PATTERN));
165438cfc46eSPierre Jolivet   }
16553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
165638cfc46eSPierre Jolivet }
165738cfc46eSPierre Jolivet 
1658a925c78cSMatthew G. Knepley /*@
1659f6dfbefdSBarry Smith   DMPlexSetSNESLocalFEM - Use `DMPLEX`'s internal FEM routines to compute `SNES` boundary values, residual, and Jacobian.
16609f520fc2SToby Isaac 
16619f520fc2SToby Isaac   Input Parameters:
1662f6dfbefdSBarry Smith + dm - The `DM` object
1663f6dfbefdSBarry Smith . boundaryctx - the user context that will be passed to pointwise evaluation of boundary values (see `PetscDSAddBoundary()`)
1664f6dfbefdSBarry Smith . residualctx - the user context that will be passed to pointwise evaluation of finite element residual computations (see `PetscDSSetResidual()`)
1665f6dfbefdSBarry Smith - jacobianctx - the user context that will be passed to pointwise evaluation of finite element Jacobian construction (see `PetscDSSetJacobian()`)
16661a244344SSatish Balay 
16671a244344SSatish Balay   Level: developer
1668f6dfbefdSBarry Smith 
1669f6dfbefdSBarry Smith .seealso: `DMPLEX`, `SNES`
16709f520fc2SToby Isaac @*/
1671d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, void *boundaryctx, void *residualctx, void *jacobianctx)
1672d71ae5a4SJacob Faibussowitsch {
16739f520fc2SToby Isaac   PetscFunctionBegin;
16749566063dSJacob Faibussowitsch   PetscCall(DMSNESSetBoundaryLocal(dm, DMPlexSNESComputeBoundaryFEM, boundaryctx));
16759566063dSJacob Faibussowitsch   PetscCall(DMSNESSetFunctionLocal(dm, DMPlexSNESComputeResidualFEM, residualctx));
16769566063dSJacob Faibussowitsch   PetscCall(DMSNESSetJacobianLocal(dm, DMPlexSNESComputeJacobianFEM, jacobianctx));
16779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", MatComputeNeumannOverlap_Plex));
16783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16799f520fc2SToby Isaac }
16809f520fc2SToby Isaac 
1681f017bcb6SMatthew G. Knepley /*@C
1682f017bcb6SMatthew G. Knepley   DMSNESCheckDiscretization - Check the discretization error of the exact solution
1683f017bcb6SMatthew G. Knepley 
1684f017bcb6SMatthew G. Knepley   Input Parameters:
1685f6dfbefdSBarry Smith + snes - the `SNES` object
1686f6dfbefdSBarry Smith . dm   - the `DM`
1687f2cacb80SMatthew G. Knepley . t    - the time
1688f6dfbefdSBarry Smith . u    - a `DM` vector
1689f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1690f017bcb6SMatthew G. Knepley 
1691f3c94560SMatthew G. Knepley   Output Parameters:
1692f3c94560SMatthew G. Knepley . error - An array which holds the discretization error in each field, or NULL
1693f3c94560SMatthew G. Knepley 
1694f6dfbefdSBarry Smith   Note:
1695f6dfbefdSBarry Smith   The user must call `PetscDSSetExactSolution()` beforehand
16967f96f943SMatthew G. Knepley 
1697f017bcb6SMatthew G. Knepley   Level: developer
1698f017bcb6SMatthew G. Knepley 
1699f6dfbefdSBarry Smith .seealso: `PetscDSSetExactSolution()`, `DNSNESCheckFromOptions()`, `DMSNESCheckResidual()`, `DMSNESCheckJacobian()`, `PetscDSSetExactSolution()`
1700f017bcb6SMatthew G. Knepley @*/
1701d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[])
1702d71ae5a4SJacob Faibussowitsch {
1703f017bcb6SMatthew G. Knepley   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
1704f017bcb6SMatthew G. Knepley   void     **ectxs;
1705f3c94560SMatthew G. Knepley   PetscReal *err;
17067f96f943SMatthew G. Knepley   MPI_Comm   comm;
17077f96f943SMatthew G. Knepley   PetscInt   Nf, f;
17081878804aSMatthew G. Knepley 
17091878804aSMatthew G. Knepley   PetscFunctionBegin;
1710f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1711f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1712064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(u, VEC_CLASSID, 4);
1713534a8f05SLisandro Dalcin   if (error) PetscValidRealPointer(error, 6);
17147f96f943SMatthew G. Knepley 
17159566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, t, u, NULL));
17169566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(u, NULL, "-vec_view"));
17177f96f943SMatthew G. Knepley 
17189566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
17199566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
17209566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err));
17217f96f943SMatthew G. Knepley   {
17227f96f943SMatthew G. Knepley     PetscInt Nds, s;
17237f96f943SMatthew G. Knepley 
17249566063dSJacob Faibussowitsch     PetscCall(DMGetNumDS(dm, &Nds));
1725083401c6SMatthew G. Knepley     for (s = 0; s < Nds; ++s) {
17267f96f943SMatthew G. Knepley       PetscDS         ds;
1727083401c6SMatthew G. Knepley       DMLabel         label;
1728083401c6SMatthew G. Knepley       IS              fieldIS;
17297f96f943SMatthew G. Knepley       const PetscInt *fields;
17307f96f943SMatthew G. Knepley       PetscInt        dsNf, f;
1731083401c6SMatthew G. Knepley 
17329566063dSJacob Faibussowitsch       PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
17339566063dSJacob Faibussowitsch       PetscCall(PetscDSGetNumFields(ds, &dsNf));
17349566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(fieldIS, &fields));
1735083401c6SMatthew G. Knepley       for (f = 0; f < dsNf; ++f) {
1736083401c6SMatthew G. Knepley         const PetscInt field = fields[f];
17379566063dSJacob Faibussowitsch         PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]));
1738083401c6SMatthew G. Knepley       }
17399566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(fieldIS, &fields));
1740083401c6SMatthew G. Knepley     }
1741083401c6SMatthew G. Knepley   }
1742f017bcb6SMatthew G. Knepley   if (Nf > 1) {
17439566063dSJacob Faibussowitsch     PetscCall(DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err));
1744f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
1745ad540459SPierre Jolivet       for (f = 0; f < Nf; ++f) PetscCheck(err[f] <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g for field %" PetscInt_FMT " exceeds tolerance %g", (double)err[f], f, (double)tol);
1746b878532fSMatthew G. Knepley     } else if (error) {
1747b878532fSMatthew G. Knepley       for (f = 0; f < Nf; ++f) error[f] = err[f];
17481878804aSMatthew G. Knepley     } else {
17499566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "L_2 Error: ["));
1750f017bcb6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
17519566063dSJacob Faibussowitsch         if (f) PetscCall(PetscPrintf(comm, ", "));
17529566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(comm, "%g", (double)err[f]));
17531878804aSMatthew G. Knepley       }
17549566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "]\n"));
1755f017bcb6SMatthew G. Knepley     }
1756f017bcb6SMatthew G. Knepley   } else {
17579566063dSJacob Faibussowitsch     PetscCall(DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0]));
1758f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
175908401ef6SPierre Jolivet       PetscCheck(err[0] <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double)err[0], (double)tol);
1760b878532fSMatthew G. Knepley     } else if (error) {
1761b878532fSMatthew G. Knepley       error[0] = err[0];
1762f017bcb6SMatthew G. Knepley     } else {
17639566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "L_2 Error: %g\n", (double)err[0]));
1764f017bcb6SMatthew G. Knepley     }
1765f017bcb6SMatthew G. Knepley   }
17669566063dSJacob Faibussowitsch   PetscCall(PetscFree3(exacts, ectxs, err));
17673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1768f017bcb6SMatthew G. Knepley }
1769f017bcb6SMatthew G. Knepley 
1770f017bcb6SMatthew G. Knepley /*@C
1771f017bcb6SMatthew G. Knepley   DMSNESCheckResidual - Check the residual of the exact solution
1772f017bcb6SMatthew G. Knepley 
1773f017bcb6SMatthew G. Knepley   Input Parameters:
1774f6dfbefdSBarry Smith + snes - the `SNES` object
1775f6dfbefdSBarry Smith . dm   - the `DM`
1776f6dfbefdSBarry Smith . u    - a `DM` vector
1777f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1778f017bcb6SMatthew G. Knepley 
1779f6dfbefdSBarry Smith   Output Parameter:
1780f3c94560SMatthew G. Knepley . residual - The residual norm of the exact solution, or NULL
1781f3c94560SMatthew G. Knepley 
1782f017bcb6SMatthew G. Knepley   Level: developer
1783f017bcb6SMatthew G. Knepley 
1784db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckJacobian()`
1785f017bcb6SMatthew G. Knepley @*/
1786d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual)
1787d71ae5a4SJacob Faibussowitsch {
1788f017bcb6SMatthew G. Knepley   MPI_Comm  comm;
1789f017bcb6SMatthew G. Knepley   Vec       r;
1790f017bcb6SMatthew G. Knepley   PetscReal res;
1791f017bcb6SMatthew G. Knepley 
1792f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1793f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1794f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1795f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1796534a8f05SLisandro Dalcin   if (residual) PetscValidRealPointer(residual, 5);
17979566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
17989566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL));
17999566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(u, &r));
18009566063dSJacob Faibussowitsch   PetscCall(SNESComputeFunction(snes, u, r));
18019566063dSJacob Faibussowitsch   PetscCall(VecNorm(r, NORM_2, &res));
1802f017bcb6SMatthew G. Knepley   if (tol >= 0.0) {
180308401ef6SPierre Jolivet     PetscCheck(res <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double)res, (double)tol);
1804b878532fSMatthew G. Knepley   } else if (residual) {
1805b878532fSMatthew G. Knepley     *residual = res;
1806f017bcb6SMatthew G. Knepley   } else {
18079566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "L_2 Residual: %g\n", (double)res));
18089566063dSJacob Faibussowitsch     PetscCall(VecChop(r, 1.0e-10));
18099566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)r, "Initial Residual"));
18109566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)r, "res_"));
18119566063dSJacob Faibussowitsch     PetscCall(VecViewFromOptions(r, NULL, "-vec_view"));
1812f017bcb6SMatthew G. Knepley   }
18139566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
18143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1815f017bcb6SMatthew G. Knepley }
1816f017bcb6SMatthew G. Knepley 
1817f017bcb6SMatthew G. Knepley /*@C
1818f3c94560SMatthew G. Knepley   DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test
1819f017bcb6SMatthew G. Knepley 
1820f017bcb6SMatthew G. Knepley   Input Parameters:
1821f6dfbefdSBarry Smith + snes - the `SNES` object
1822f6dfbefdSBarry Smith . dm   - the `DM`
1823f6dfbefdSBarry Smith . u    - a `DM` vector
1824f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1825f017bcb6SMatthew G. Knepley 
1826f3c94560SMatthew G. Knepley   Output Parameters:
1827f3c94560SMatthew G. Knepley + isLinear - Flag indicaing that the function looks linear, or NULL
1828f3c94560SMatthew G. Knepley - convRate - The rate of convergence of the linear model, or NULL
1829f3c94560SMatthew G. Knepley 
1830f017bcb6SMatthew G. Knepley   Level: developer
1831f017bcb6SMatthew G. Knepley 
1832db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckResidual()`
1833f017bcb6SMatthew G. Knepley @*/
1834d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate)
1835d71ae5a4SJacob Faibussowitsch {
1836f017bcb6SMatthew G. Knepley   MPI_Comm     comm;
1837f017bcb6SMatthew G. Knepley   PetscDS      ds;
1838f017bcb6SMatthew G. Knepley   Mat          J, M;
1839f017bcb6SMatthew G. Knepley   MatNullSpace nullspace;
1840f3c94560SMatthew G. Knepley   PetscReal    slope, intercept;
18417f96f943SMatthew G. Knepley   PetscBool    hasJac, hasPrec, isLin = PETSC_FALSE;
1842f017bcb6SMatthew G. Knepley 
1843f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1844f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1845f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1846f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1847534a8f05SLisandro Dalcin   if (isLinear) PetscValidBoolPointer(isLinear, 5);
1848064a246eSJacob Faibussowitsch   if (convRate) PetscValidRealPointer(convRate, 6);
18499566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
18509566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL));
1851f017bcb6SMatthew G. Knepley   /* Create and view matrices */
18529566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(dm, &J));
18539566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
18549566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobian(ds, &hasJac));
18559566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
1856282e7bb4SMatthew G. Knepley   if (hasJac && hasPrec) {
18579566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dm, &M));
18589566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, u, J, M));
18599566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)M, "Preconditioning Matrix"));
18609566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)M, "jacpre_"));
18619566063dSJacob Faibussowitsch     PetscCall(MatViewFromOptions(M, NULL, "-mat_view"));
18629566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
1863282e7bb4SMatthew G. Knepley   } else {
18649566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, u, J, J));
1865282e7bb4SMatthew G. Knepley   }
18669566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)J, "Jacobian"));
18679566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)J, "jac_"));
18689566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(J, NULL, "-mat_view"));
1869f017bcb6SMatthew G. Knepley   /* Check nullspace */
18709566063dSJacob Faibussowitsch   PetscCall(MatGetNullSpace(J, &nullspace));
1871f017bcb6SMatthew G. Knepley   if (nullspace) {
18721878804aSMatthew G. Knepley     PetscBool isNull;
18739566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceTest(nullspace, J, &isNull));
187428b400f6SJacob Faibussowitsch     PetscCheck(isNull, comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid.");
18751878804aSMatthew G. Knepley   }
1876f017bcb6SMatthew G. Knepley   /* Taylor test */
1877f017bcb6SMatthew G. Knepley   {
1878f017bcb6SMatthew G. Knepley     PetscRandom rand;
1879f017bcb6SMatthew G. Knepley     Vec         du, uhat, r, rhat, df;
1880f3c94560SMatthew G. Knepley     PetscReal   h;
1881f017bcb6SMatthew G. Knepley     PetscReal  *es, *hs, *errors;
1882f017bcb6SMatthew G. Knepley     PetscReal   hMax = 1.0, hMin = 1e-6, hMult = 0.1;
1883f017bcb6SMatthew G. Knepley     PetscInt    Nv, v;
1884f017bcb6SMatthew G. Knepley 
1885f017bcb6SMatthew G. Knepley     /* Choose a perturbation direction */
18869566063dSJacob Faibussowitsch     PetscCall(PetscRandomCreate(comm, &rand));
18879566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &du));
18889566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(du, rand));
18899566063dSJacob Faibussowitsch     PetscCall(PetscRandomDestroy(&rand));
18909566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &df));
18919566063dSJacob Faibussowitsch     PetscCall(MatMult(J, du, df));
1892f017bcb6SMatthew G. Knepley     /* Evaluate residual at u, F(u), save in vector r */
18939566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &r));
18949566063dSJacob Faibussowitsch     PetscCall(SNESComputeFunction(snes, u, r));
1895f017bcb6SMatthew G. Knepley     /* Look at the convergence of our Taylor approximation as we approach u */
18969371c9d4SSatish Balay     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv)
18979371c9d4SSatish Balay       ;
18989566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors));
18999566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &uhat));
19009566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &rhat));
1901f017bcb6SMatthew G. Knepley     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) {
19029566063dSJacob Faibussowitsch       PetscCall(VecWAXPY(uhat, h, du, u));
1903f017bcb6SMatthew G. Knepley       /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */
19049566063dSJacob Faibussowitsch       PetscCall(SNESComputeFunction(snes, uhat, rhat));
19059566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df));
19069566063dSJacob Faibussowitsch       PetscCall(VecNorm(rhat, NORM_2, &errors[Nv]));
1907f017bcb6SMatthew G. Knepley 
1908f017bcb6SMatthew G. Knepley       es[Nv] = PetscLog10Real(errors[Nv]);
1909f017bcb6SMatthew G. Knepley       hs[Nv] = PetscLog10Real(h);
1910f017bcb6SMatthew G. Knepley     }
19119566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&uhat));
19129566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rhat));
19139566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&df));
19149566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&r));
19159566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&du));
1916f017bcb6SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1917f017bcb6SMatthew G. Knepley       if ((tol >= 0) && (errors[v] > tol)) break;
1918f017bcb6SMatthew G. Knepley       else if (errors[v] > PETSC_SMALL) break;
1919f017bcb6SMatthew G. Knepley     }
1920f3c94560SMatthew G. Knepley     if (v == Nv) isLin = PETSC_TRUE;
19219566063dSJacob Faibussowitsch     PetscCall(PetscLinearRegression(Nv, hs, es, &slope, &intercept));
19229566063dSJacob Faibussowitsch     PetscCall(PetscFree3(es, hs, errors));
1923f017bcb6SMatthew G. Knepley     /* Slope should be about 2 */
1924f017bcb6SMatthew G. Knepley     if (tol >= 0) {
19250b121fc5SBarry Smith       PetscCheck(isLin || PetscAbsReal(2 - slope) <= tol, comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double)slope);
1926b878532fSMatthew G. Knepley     } else if (isLinear || convRate) {
1927b878532fSMatthew G. Knepley       if (isLinear) *isLinear = isLin;
1928b878532fSMatthew G. Knepley       if (convRate) *convRate = slope;
1929f017bcb6SMatthew G. Knepley     } else {
19309566063dSJacob Faibussowitsch       if (!isLin) PetscCall(PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double)slope));
19319566063dSJacob Faibussowitsch       else PetscCall(PetscPrintf(comm, "Function appears to be linear\n"));
1932f017bcb6SMatthew G. Knepley     }
1933f017bcb6SMatthew G. Knepley   }
19349566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
19353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19361878804aSMatthew G. Knepley }
19371878804aSMatthew G. Knepley 
1938d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u)
1939d71ae5a4SJacob Faibussowitsch {
1940f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
19419566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL));
19429566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckResidual(snes, dm, u, -1.0, NULL));
19439566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL));
19443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1945f017bcb6SMatthew G. Knepley }
1946f017bcb6SMatthew G. Knepley 
1947bee9a294SMatthew G. Knepley /*@C
1948bee9a294SMatthew G. Knepley   DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information
1949bee9a294SMatthew G. Knepley 
1950bee9a294SMatthew G. Knepley   Input Parameters:
1951f6dfbefdSBarry Smith + snes - the `SNES` object
1952f6dfbefdSBarry Smith - u    - representative `SNES` vector
19537f96f943SMatthew G. Knepley 
1954f6dfbefdSBarry Smith   Note:
1955f6dfbefdSBarry Smith   The user must call `PetscDSSetExactSolution()` beforehand
1956bee9a294SMatthew G. Knepley 
1957bee9a294SMatthew G. Knepley   Level: developer
1958bee9a294SMatthew G. Knepley @*/
1959d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u)
1960d71ae5a4SJacob Faibussowitsch {
19611878804aSMatthew G. Knepley   DM        dm;
19621878804aSMatthew G. Knepley   Vec       sol;
19631878804aSMatthew G. Knepley   PetscBool check;
19641878804aSMatthew G. Knepley 
19651878804aSMatthew G. Knepley   PetscFunctionBegin;
19669566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-dmsnes_check", &check));
19673ba16761SJacob Faibussowitsch   if (!check) PetscFunctionReturn(PETSC_SUCCESS);
19689566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
19699566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(u, &sol));
19709566063dSJacob Faibussowitsch   PetscCall(SNESSetSolution(snes, sol));
19719566063dSJacob Faibussowitsch   PetscCall(DMSNESCheck_Internal(snes, dm, sol));
19729566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sol));
19733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1974552f7358SJed Brown }
1975