xref: /petsc/src/snes/utils/dmplexsnes.c (revision e4094ef18e7e53fda86cf35f3a47fda48a8e77d8)
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 /*
1320f4b53cSBarry Smith   SNESCorrectDiscretePressure_Private - Add a vector in the nullspace to make the continuum integral of the pressure field equal to zero.
1420f4b53cSBarry 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 
282fe279fdSBarry Smith   Level: developer
292fe279fdSBarry Smith 
30649ef022SMatthew Knepley   Notes:
31649ef022SMatthew Knepley   If int(u) = a and int(n) = b, then int(u - a/b n) = a - a/b b = 0. We assume that the nullspace is a single vector given explicitly.
32649ef022SMatthew Knepley 
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
78*e4094ef1SJacob Faibussowitsch . gnorm - 2-norm of current step
79*e4094ef1SJacob Faibussowitsch . f     - 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 
8520f4b53cSBarry Smith   Options Database Key:
8620f4b53cSBarry Smith . -snes_convergence_test correct_pressure - see `SNESSetFromOptions()`
8720f4b53cSBarry Smith 
8820f4b53cSBarry Smith   Level: advanced
8920f4b53cSBarry 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 
96*e4094ef1SJacob Faibussowitsch .seealso: `SNES`, `DM`, `SNESConvergedDefault()`, `SNESSetConvergenceTest()`, `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 
19320f4b53cSBarry 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 
21420f4b53cSBarry 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 
23720f4b53cSBarry 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 
25820f4b53cSBarry 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 
268*e4094ef1SJacob Faibussowitsch .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 
28120f4b53cSBarry 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 
2882fe279fdSBarry Smith   Level: intermediate
2892fe279fdSBarry Smith 
290f6dfbefdSBarry Smith   Note:
291f6dfbefdSBarry Smith   The coordinate information is copied.
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 
320*e4094ef1SJacob Faibussowitsch .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 
44520f4b53cSBarry Smith   Level: intermediate
44620f4b53cSBarry 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 
4732fe279fdSBarry Smith   Level: intermediate
4742fe279fdSBarry Smith 
475f6dfbefdSBarry Smith   Note:
476f6dfbefdSBarry Smith   This vector should be returned using `DMInterpolationRestoreVector()`.
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 
10202fe279fdSBarry Smith   Output Parameter:
1021552f7358SJed Brown . v - The vector containing the interpolated values
10224267b1a3SMatthew G. Knepley 
10234267b1a3SMatthew G. Knepley   Level: beginner
10244267b1a3SMatthew G. Knepley 
10252fe279fdSBarry Smith   Note:
10262fe279fdSBarry Smith   A suitable `v` can be obtained using `DMInterpolationGetVector()`.
10272fe279fdSBarry Smith 
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 
11662fe279fdSBarry Smith   Level: intermediate
11672fe279fdSBarry Smith 
1168f6dfbefdSBarry Smith   Note:
1169cc0c4584SMatthew G. Knepley   This routine prints the residual norm at each iteration.
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 
12412fe279fdSBarry Smith   Level: developer
12422fe279fdSBarry Smith 
1243f6dfbefdSBarry Smith   Note:
1244f6dfbefdSBarry Smith   The residual is summed into F; the caller is responsible for using `VecZeroEntries()` or otherwise ensuring that any data in F is intentional.
12458db23a53SJed Brown 
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 
126307218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds, NULL));
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 
130107218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds, NULL));
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 
141107218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds, NULL));
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 /*@
14632fe279fdSBarry Smith   DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix `Jac` at the local solution `X` using pointwise functions specified by the user.
146424cdb843SMatthew G. Knepley 
146524cdb843SMatthew G. Knepley   Input Parameters:
14662fe279fdSBarry Smith + dm   - The `DM`
146724cdb843SMatthew G. Knepley . X    - Local input vector
146824cdb843SMatthew G. Knepley - user - The user context
146924cdb843SMatthew G. Knepley 
14702fe279fdSBarry Smith   Output Parameters:
14712fe279fdSBarry Smith + Jac  - Jacobian matrix
14722fe279fdSBarry Smith - JacP - approximate Jacobian from which the preconditioner will be built, often `Jac`
14732fe279fdSBarry Smith 
14742fe279fdSBarry Smith   Level: developer
147524cdb843SMatthew G. Knepley 
147624cdb843SMatthew G. Knepley   Note:
147724cdb843SMatthew G. Knepley   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
147824cdb843SMatthew G. Knepley   like a GPU, or vectorize on a multicore machine.
147924cdb843SMatthew G. Knepley 
1480f6dfbefdSBarry Smith .seealso: `DMPLEX`, `Mat`
148124cdb843SMatthew G. Knepley @*/
1482d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, void *user)
1483d71ae5a4SJacob Faibussowitsch {
14846da023fcSToby Isaac   DM        plex;
1485083401c6SMatthew G. Knepley   IS        allcellIS;
1486f04eb4edSMatthew G. Knepley   PetscBool hasJac, hasPrec;
14876528b96dSMatthew G. Knepley   PetscInt  Nds, s;
148824cdb843SMatthew G. Knepley 
148924cdb843SMatthew G. Knepley   PetscFunctionBegin;
14909566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
14919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
14929566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
1493083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1494083401c6SMatthew G. Knepley     PetscDS      ds;
1495083401c6SMatthew G. Knepley     IS           cellIS;
149606ad1575SMatthew G. Knepley     PetscFormKey key;
1497083401c6SMatthew G. Knepley 
149807218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds, NULL));
14996528b96dSMatthew G. Knepley     key.value = 0;
15006528b96dSMatthew G. Knepley     key.field = 0;
150106ad1575SMatthew G. Knepley     key.part  = 0;
15026528b96dSMatthew G. Knepley     if (!key.label) {
15039566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)allcellIS));
1504083401c6SMatthew G. Knepley       cellIS = allcellIS;
1505083401c6SMatthew G. Knepley     } else {
1506083401c6SMatthew G. Knepley       IS pointIS;
1507083401c6SMatthew G. Knepley 
15086528b96dSMatthew G. Knepley       key.value = 1;
15099566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
15109566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
15119566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
1512083401c6SMatthew G. Knepley     }
1513083401c6SMatthew G. Knepley     if (!s) {
15149566063dSJacob Faibussowitsch       PetscCall(PetscDSHasJacobian(ds, &hasJac));
15159566063dSJacob Faibussowitsch       PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
15169566063dSJacob Faibussowitsch       if (hasJac && hasPrec) PetscCall(MatZeroEntries(Jac));
15179566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(JacP));
1518083401c6SMatthew G. Knepley     }
15199566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeJacobian_Internal(plex, key, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, user));
15209566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
1521083401c6SMatthew G. Knepley   }
15229566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
15239566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
15243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
152524cdb843SMatthew G. Knepley }
15261878804aSMatthew G. Knepley 
15279371c9d4SSatish Balay struct _DMSNESJacobianMFCtx {
15288e3a2eefSMatthew G. Knepley   DM    dm;
15298e3a2eefSMatthew G. Knepley   Vec   X;
15308e3a2eefSMatthew G. Knepley   void *ctx;
15318e3a2eefSMatthew G. Knepley };
15328e3a2eefSMatthew G. Knepley 
1533d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Destroy_Private(Mat A)
1534d71ae5a4SJacob Faibussowitsch {
15358e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15368e3a2eefSMatthew G. Knepley 
15378e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15389566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
15399566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(A, NULL));
15409566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&ctx->dm));
15419566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ctx->X));
15429566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
15433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15448e3a2eefSMatthew G. Knepley }
15458e3a2eefSMatthew G. Knepley 
1546d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Mult_Private(Mat A, Vec Y, Vec Z)
1547d71ae5a4SJacob Faibussowitsch {
15488e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15498e3a2eefSMatthew G. Knepley 
15508e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15519566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
15529566063dSJacob Faibussowitsch   PetscCall(DMSNESComputeJacobianAction(ctx->dm, ctx->X, Y, Z, ctx->ctx));
15533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15548e3a2eefSMatthew G. Knepley }
15558e3a2eefSMatthew G. Knepley 
15568e3a2eefSMatthew G. Knepley /*@
1557f6dfbefdSBarry Smith   DMSNESCreateJacobianMF - Create a `Mat` which computes the action of the Jacobian matrix-free
15588e3a2eefSMatthew G. Knepley 
1559c3339decSBarry Smith   Collective
15608e3a2eefSMatthew G. Knepley 
15618e3a2eefSMatthew G. Knepley   Input Parameters:
1562f6dfbefdSBarry Smith + dm   - The `DM`
15638e3a2eefSMatthew G. Knepley . X    - The evaluation point for the Jacobian
15642fe279fdSBarry Smith - user - A user context, or `NULL`
15658e3a2eefSMatthew G. Knepley 
15668e3a2eefSMatthew G. Knepley   Output Parameter:
1567f6dfbefdSBarry Smith . J - The `Mat`
15688e3a2eefSMatthew G. Knepley 
15698e3a2eefSMatthew G. Knepley   Level: advanced
15708e3a2eefSMatthew G. Knepley 
1571f6dfbefdSBarry Smith   Note:
15722fe279fdSBarry Smith   Vec `X` is kept in `J`, so updating `X` then updates the evaluation point.
15738e3a2eefSMatthew G. Knepley 
1574f6dfbefdSBarry Smith .seealso: `DM`, `DMSNESComputeJacobianAction()`
15758e3a2eefSMatthew G. Knepley @*/
1576d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCreateJacobianMF(DM dm, Vec X, void *user, Mat *J)
1577d71ae5a4SJacob Faibussowitsch {
15788e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15798e3a2eefSMatthew G. Knepley   PetscInt                     n, N;
15808e3a2eefSMatthew G. Knepley 
15818e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15829566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
15839566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, MATSHELL));
15849566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(X, &n));
15859566063dSJacob Faibussowitsch   PetscCall(VecGetSize(X, &N));
15869566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, n, n, N, N));
15879566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)dm));
15889566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)X));
15899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &ctx));
15908e3a2eefSMatthew G. Knepley   ctx->dm  = dm;
15918e3a2eefSMatthew G. Knepley   ctx->X   = X;
15928e3a2eefSMatthew G. Knepley   ctx->ctx = user;
15939566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*J, ctx));
15949566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(*J, MATOP_DESTROY, (void (*)(void))DMSNESJacobianMF_Destroy_Private));
15959566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(*J, MATOP_MULT, (void (*)(void))DMSNESJacobianMF_Mult_Private));
15963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15978e3a2eefSMatthew G. Knepley }
15988e3a2eefSMatthew G. Knepley 
159938cfc46eSPierre Jolivet /*
160038cfc46eSPierre Jolivet      MatComputeNeumannOverlap - Computes an unassembled (Neumann) local overlapping Mat in nonlinear context.
160138cfc46eSPierre Jolivet 
160238cfc46eSPierre Jolivet    Input Parameters:
16032fe279fdSBarry Smith +     X - `SNES` linearization point
160438cfc46eSPierre Jolivet .     ovl - index set of overlapping subdomains
160538cfc46eSPierre Jolivet 
160638cfc46eSPierre Jolivet    Output Parameter:
160738cfc46eSPierre Jolivet .     J - unassembled (Neumann) local matrix
160838cfc46eSPierre Jolivet 
160938cfc46eSPierre Jolivet    Level: intermediate
161038cfc46eSPierre Jolivet 
1611db781477SPatrick Sanan .seealso: `DMCreateNeumannOverlap()`, `MATIS`, `PCHPDDMSetAuxiliaryMat()`
161238cfc46eSPierre Jolivet */
1613d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, void *ctx)
1614d71ae5a4SJacob Faibussowitsch {
161538cfc46eSPierre Jolivet   SNES   snes;
161638cfc46eSPierre Jolivet   Mat    pJ;
161738cfc46eSPierre Jolivet   DM     ovldm, origdm;
161838cfc46eSPierre Jolivet   DMSNES sdm;
161938cfc46eSPierre Jolivet   PetscErrorCode (*bfun)(DM, Vec, void *);
162038cfc46eSPierre Jolivet   PetscErrorCode (*jfun)(DM, Vec, Mat, Mat, void *);
162138cfc46eSPierre Jolivet   void *bctx, *jctx;
162238cfc46eSPierre Jolivet 
162338cfc46eSPierre Jolivet   PetscFunctionBegin;
16249566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_MATIS", (PetscObject *)&pJ));
162528b400f6SJacob Faibussowitsch   PetscCheck(pJ, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing overlapping Mat");
16269566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Original_HPDDM", (PetscObject *)&origdm));
162728b400f6SJacob Faibussowitsch   PetscCheck(origdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing original DM");
16289566063dSJacob Faibussowitsch   PetscCall(MatGetDM(pJ, &ovldm));
16299566063dSJacob Faibussowitsch   PetscCall(DMSNESGetBoundaryLocal(origdm, &bfun, &bctx));
16309566063dSJacob Faibussowitsch   PetscCall(DMSNESSetBoundaryLocal(ovldm, bfun, bctx));
16319566063dSJacob Faibussowitsch   PetscCall(DMSNESGetJacobianLocal(origdm, &jfun, &jctx));
16329566063dSJacob Faibussowitsch   PetscCall(DMSNESSetJacobianLocal(ovldm, jfun, jctx));
16339566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject *)&snes));
163438cfc46eSPierre Jolivet   if (!snes) {
16359566063dSJacob Faibussowitsch     PetscCall(SNESCreate(PetscObjectComm((PetscObject)ovl), &snes));
16369566063dSJacob Faibussowitsch     PetscCall(SNESSetDM(snes, ovldm));
16379566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject)snes));
16389566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)snes));
163938cfc46eSPierre Jolivet   }
16409566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(ovldm, &sdm));
16419566063dSJacob Faibussowitsch   PetscCall(VecLockReadPush(X));
1642800f99ffSJeremy L Thompson   {
1643800f99ffSJeremy L Thompson     void *ctx;
1644800f99ffSJeremy L Thompson     PetscErrorCode (*J)(SNES, Vec, Mat, Mat, void *);
1645800f99ffSJeremy L Thompson     PetscCall(DMSNESGetJacobian(ovldm, &J, &ctx));
1646800f99ffSJeremy L Thompson     PetscCallBack("SNES callback Jacobian", (*J)(snes, X, pJ, pJ, ctx));
1647800f99ffSJeremy L Thompson   }
16489566063dSJacob Faibussowitsch   PetscCall(VecLockReadPop(X));
164938cfc46eSPierre Jolivet   /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */
165038cfc46eSPierre Jolivet   {
165138cfc46eSPierre Jolivet     Mat locpJ;
165238cfc46eSPierre Jolivet 
16539566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pJ, &locpJ));
16549566063dSJacob Faibussowitsch     PetscCall(MatCopy(locpJ, J, SAME_NONZERO_PATTERN));
165538cfc46eSPierre Jolivet   }
16563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
165738cfc46eSPierre Jolivet }
165838cfc46eSPierre Jolivet 
1659a925c78cSMatthew G. Knepley /*@
1660f6dfbefdSBarry Smith   DMPlexSetSNESLocalFEM - Use `DMPLEX`'s internal FEM routines to compute `SNES` boundary values, residual, and Jacobian.
16619f520fc2SToby Isaac 
16629f520fc2SToby Isaac   Input Parameters:
1663f6dfbefdSBarry Smith + dm          - The `DM` object
1664f6dfbefdSBarry Smith . boundaryctx - the user context that will be passed to pointwise evaluation of boundary values (see `PetscDSAddBoundary()`)
1665f6dfbefdSBarry Smith . residualctx - the user context that will be passed to pointwise evaluation of finite element residual computations (see `PetscDSSetResidual()`)
1666f6dfbefdSBarry Smith - jacobianctx - the user context that will be passed to pointwise evaluation of finite element Jacobian construction (see `PetscDSSetJacobian()`)
16671a244344SSatish Balay 
16681a244344SSatish Balay   Level: developer
1669f6dfbefdSBarry Smith 
1670f6dfbefdSBarry Smith .seealso: `DMPLEX`, `SNES`
16719f520fc2SToby Isaac @*/
1672d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, void *boundaryctx, void *residualctx, void *jacobianctx)
1673d71ae5a4SJacob Faibussowitsch {
16749f520fc2SToby Isaac   PetscFunctionBegin;
16759566063dSJacob Faibussowitsch   PetscCall(DMSNESSetBoundaryLocal(dm, DMPlexSNESComputeBoundaryFEM, boundaryctx));
16769566063dSJacob Faibussowitsch   PetscCall(DMSNESSetFunctionLocal(dm, DMPlexSNESComputeResidualFEM, residualctx));
16779566063dSJacob Faibussowitsch   PetscCall(DMSNESSetJacobianLocal(dm, DMPlexSNESComputeJacobianFEM, jacobianctx));
16789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", MatComputeNeumannOverlap_Plex));
16793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16809f520fc2SToby Isaac }
16819f520fc2SToby Isaac 
1682f017bcb6SMatthew G. Knepley /*@C
1683f017bcb6SMatthew G. Knepley   DMSNESCheckDiscretization - Check the discretization error of the exact solution
1684f017bcb6SMatthew G. Knepley 
1685f017bcb6SMatthew G. Knepley   Input Parameters:
1686f6dfbefdSBarry Smith + snes - the `SNES` object
1687f6dfbefdSBarry Smith . dm   - the `DM`
1688f2cacb80SMatthew G. Knepley . t    - the time
1689f6dfbefdSBarry Smith . u    - a `DM` vector
1690f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1691f017bcb6SMatthew G. Knepley 
16922fe279fdSBarry Smith   Output Parameter:
16932fe279fdSBarry Smith . error - An array which holds the discretization error in each field, or `NULL`
16942fe279fdSBarry Smith 
16952fe279fdSBarry Smith   Level: developer
1696f3c94560SMatthew G. Knepley 
1697f6dfbefdSBarry Smith   Note:
1698f6dfbefdSBarry Smith   The user must call `PetscDSSetExactSolution()` beforehand
16997f96f943SMatthew G. Knepley 
1700*e4094ef1SJacob Faibussowitsch .seealso: `PetscDSSetExactSolution()`, `DNSNESCheckFromOptions()`, `DMSNESCheckResidual()`, `DMSNESCheckJacobian()`
1701f017bcb6SMatthew G. Knepley @*/
1702d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[])
1703d71ae5a4SJacob Faibussowitsch {
1704f017bcb6SMatthew G. Knepley   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
1705f017bcb6SMatthew G. Knepley   void     **ectxs;
1706f3c94560SMatthew G. Knepley   PetscReal *err;
17077f96f943SMatthew G. Knepley   MPI_Comm   comm;
17087f96f943SMatthew G. Knepley   PetscInt   Nf, f;
17091878804aSMatthew G. Knepley 
17101878804aSMatthew G. Knepley   PetscFunctionBegin;
1711f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1712f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1713064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(u, VEC_CLASSID, 4);
1714534a8f05SLisandro Dalcin   if (error) PetscValidRealPointer(error, 6);
17157f96f943SMatthew G. Knepley 
17169566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, t, u, NULL));
17179566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(u, NULL, "-vec_view"));
17187f96f943SMatthew G. Knepley 
17199566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
17209566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
17219566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err));
17227f96f943SMatthew G. Knepley   {
17237f96f943SMatthew G. Knepley     PetscInt Nds, s;
17247f96f943SMatthew G. Knepley 
17259566063dSJacob Faibussowitsch     PetscCall(DMGetNumDS(dm, &Nds));
1726083401c6SMatthew G. Knepley     for (s = 0; s < Nds; ++s) {
17277f96f943SMatthew G. Knepley       PetscDS         ds;
1728083401c6SMatthew G. Knepley       DMLabel         label;
1729083401c6SMatthew G. Knepley       IS              fieldIS;
17307f96f943SMatthew G. Knepley       const PetscInt *fields;
17317f96f943SMatthew G. Knepley       PetscInt        dsNf, f;
1732083401c6SMatthew G. Knepley 
173307218a29SMatthew G. Knepley       PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
17349566063dSJacob Faibussowitsch       PetscCall(PetscDSGetNumFields(ds, &dsNf));
17359566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(fieldIS, &fields));
1736083401c6SMatthew G. Knepley       for (f = 0; f < dsNf; ++f) {
1737083401c6SMatthew G. Knepley         const PetscInt field = fields[f];
17389566063dSJacob Faibussowitsch         PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]));
1739083401c6SMatthew G. Knepley       }
17409566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(fieldIS, &fields));
1741083401c6SMatthew G. Knepley     }
1742083401c6SMatthew G. Knepley   }
1743f017bcb6SMatthew G. Knepley   if (Nf > 1) {
17449566063dSJacob Faibussowitsch     PetscCall(DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err));
1745f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
1746ad540459SPierre 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);
1747b878532fSMatthew G. Knepley     } else if (error) {
1748b878532fSMatthew G. Knepley       for (f = 0; f < Nf; ++f) error[f] = err[f];
17491878804aSMatthew G. Knepley     } else {
17509566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "L_2 Error: ["));
1751f017bcb6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
17529566063dSJacob Faibussowitsch         if (f) PetscCall(PetscPrintf(comm, ", "));
17539566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(comm, "%g", (double)err[f]));
17541878804aSMatthew G. Knepley       }
17559566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "]\n"));
1756f017bcb6SMatthew G. Knepley     }
1757f017bcb6SMatthew G. Knepley   } else {
17589566063dSJacob Faibussowitsch     PetscCall(DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0]));
1759f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
176008401ef6SPierre Jolivet       PetscCheck(err[0] <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double)err[0], (double)tol);
1761b878532fSMatthew G. Knepley     } else if (error) {
1762b878532fSMatthew G. Knepley       error[0] = err[0];
1763f017bcb6SMatthew G. Knepley     } else {
17649566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "L_2 Error: %g\n", (double)err[0]));
1765f017bcb6SMatthew G. Knepley     }
1766f017bcb6SMatthew G. Knepley   }
17679566063dSJacob Faibussowitsch   PetscCall(PetscFree3(exacts, ectxs, err));
17683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1769f017bcb6SMatthew G. Knepley }
1770f017bcb6SMatthew G. Knepley 
1771f017bcb6SMatthew G. Knepley /*@C
1772f017bcb6SMatthew G. Knepley   DMSNESCheckResidual - Check the residual of the exact solution
1773f017bcb6SMatthew G. Knepley 
1774f017bcb6SMatthew G. Knepley   Input Parameters:
1775f6dfbefdSBarry Smith + snes - the `SNES` object
1776f6dfbefdSBarry Smith . dm   - the `DM`
1777f6dfbefdSBarry Smith . u    - a `DM` vector
1778f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1779f017bcb6SMatthew G. Knepley 
1780f6dfbefdSBarry Smith   Output Parameter:
17812fe279fdSBarry Smith . residual - The residual norm of the exact solution, or `NULL`
1782f3c94560SMatthew G. Knepley 
1783f017bcb6SMatthew G. Knepley   Level: developer
1784f017bcb6SMatthew G. Knepley 
1785db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckJacobian()`
1786f017bcb6SMatthew G. Knepley @*/
1787d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual)
1788d71ae5a4SJacob Faibussowitsch {
1789f017bcb6SMatthew G. Knepley   MPI_Comm  comm;
1790f017bcb6SMatthew G. Knepley   Vec       r;
1791f017bcb6SMatthew G. Knepley   PetscReal res;
1792f017bcb6SMatthew G. Knepley 
1793f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1794f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1795f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1796f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1797534a8f05SLisandro Dalcin   if (residual) PetscValidRealPointer(residual, 5);
17989566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
17999566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL));
18009566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(u, &r));
18019566063dSJacob Faibussowitsch   PetscCall(SNESComputeFunction(snes, u, r));
18029566063dSJacob Faibussowitsch   PetscCall(VecNorm(r, NORM_2, &res));
1803f017bcb6SMatthew G. Knepley   if (tol >= 0.0) {
180408401ef6SPierre Jolivet     PetscCheck(res <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double)res, (double)tol);
1805b878532fSMatthew G. Knepley   } else if (residual) {
1806b878532fSMatthew G. Knepley     *residual = res;
1807f017bcb6SMatthew G. Knepley   } else {
18089566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "L_2 Residual: %g\n", (double)res));
18099566063dSJacob Faibussowitsch     PetscCall(VecChop(r, 1.0e-10));
18109566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)r, "Initial Residual"));
18119566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)r, "res_"));
18129566063dSJacob Faibussowitsch     PetscCall(VecViewFromOptions(r, NULL, "-vec_view"));
1813f017bcb6SMatthew G. Knepley   }
18149566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
18153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1816f017bcb6SMatthew G. Knepley }
1817f017bcb6SMatthew G. Knepley 
1818f017bcb6SMatthew G. Knepley /*@C
1819f3c94560SMatthew G. Knepley   DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test
1820f017bcb6SMatthew G. Knepley 
1821f017bcb6SMatthew G. Knepley   Input Parameters:
1822f6dfbefdSBarry Smith + snes - the `SNES` object
1823f6dfbefdSBarry Smith . dm   - the `DM`
1824f6dfbefdSBarry Smith . u    - a `DM` vector
1825f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1826f017bcb6SMatthew G. Knepley 
1827f3c94560SMatthew G. Knepley   Output Parameters:
18282fe279fdSBarry Smith + isLinear - Flag indicaing that the function looks linear, or `NULL`
18292fe279fdSBarry Smith - convRate - The rate of convergence of the linear model, or `NULL`
1830f3c94560SMatthew G. Knepley 
1831f017bcb6SMatthew G. Knepley   Level: developer
1832f017bcb6SMatthew G. Knepley 
1833db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckResidual()`
1834f017bcb6SMatthew G. Knepley @*/
1835d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate)
1836d71ae5a4SJacob Faibussowitsch {
1837f017bcb6SMatthew G. Knepley   MPI_Comm     comm;
1838f017bcb6SMatthew G. Knepley   PetscDS      ds;
1839f017bcb6SMatthew G. Knepley   Mat          J, M;
1840f017bcb6SMatthew G. Knepley   MatNullSpace nullspace;
1841f3c94560SMatthew G. Knepley   PetscReal    slope, intercept;
18427f96f943SMatthew G. Knepley   PetscBool    hasJac, hasPrec, isLin = PETSC_FALSE;
1843f017bcb6SMatthew G. Knepley 
1844f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1845f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1846f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1847f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1848534a8f05SLisandro Dalcin   if (isLinear) PetscValidBoolPointer(isLinear, 5);
1849064a246eSJacob Faibussowitsch   if (convRate) PetscValidRealPointer(convRate, 6);
18509566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
18519566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL));
1852f017bcb6SMatthew G. Knepley   /* Create and view matrices */
18539566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(dm, &J));
18549566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
18559566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobian(ds, &hasJac));
18569566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
1857282e7bb4SMatthew G. Knepley   if (hasJac && hasPrec) {
18589566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dm, &M));
18599566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, u, J, M));
18609566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)M, "Preconditioning Matrix"));
18619566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)M, "jacpre_"));
18629566063dSJacob Faibussowitsch     PetscCall(MatViewFromOptions(M, NULL, "-mat_view"));
18639566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
1864282e7bb4SMatthew G. Knepley   } else {
18659566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, u, J, J));
1866282e7bb4SMatthew G. Knepley   }
18679566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)J, "Jacobian"));
18689566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)J, "jac_"));
18699566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(J, NULL, "-mat_view"));
1870f017bcb6SMatthew G. Knepley   /* Check nullspace */
18719566063dSJacob Faibussowitsch   PetscCall(MatGetNullSpace(J, &nullspace));
1872f017bcb6SMatthew G. Knepley   if (nullspace) {
18731878804aSMatthew G. Knepley     PetscBool isNull;
18749566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceTest(nullspace, J, &isNull));
187528b400f6SJacob Faibussowitsch     PetscCheck(isNull, comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid.");
18761878804aSMatthew G. Knepley   }
1877f017bcb6SMatthew G. Knepley   /* Taylor test */
1878f017bcb6SMatthew G. Knepley   {
1879f017bcb6SMatthew G. Knepley     PetscRandom rand;
1880f017bcb6SMatthew G. Knepley     Vec         du, uhat, r, rhat, df;
1881f3c94560SMatthew G. Knepley     PetscReal   h;
1882f017bcb6SMatthew G. Knepley     PetscReal  *es, *hs, *errors;
1883f017bcb6SMatthew G. Knepley     PetscReal   hMax = 1.0, hMin = 1e-6, hMult = 0.1;
1884f017bcb6SMatthew G. Knepley     PetscInt    Nv, v;
1885f017bcb6SMatthew G. Knepley 
1886f017bcb6SMatthew G. Knepley     /* Choose a perturbation direction */
18879566063dSJacob Faibussowitsch     PetscCall(PetscRandomCreate(comm, &rand));
18889566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &du));
18899566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(du, rand));
18909566063dSJacob Faibussowitsch     PetscCall(PetscRandomDestroy(&rand));
18919566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &df));
18929566063dSJacob Faibussowitsch     PetscCall(MatMult(J, du, df));
1893f017bcb6SMatthew G. Knepley     /* Evaluate residual at u, F(u), save in vector r */
18949566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &r));
18959566063dSJacob Faibussowitsch     PetscCall(SNESComputeFunction(snes, u, r));
1896f017bcb6SMatthew G. Knepley     /* Look at the convergence of our Taylor approximation as we approach u */
18979371c9d4SSatish Balay     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv)
18989371c9d4SSatish Balay       ;
18999566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors));
19009566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &uhat));
19019566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &rhat));
1902f017bcb6SMatthew G. Knepley     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) {
19039566063dSJacob Faibussowitsch       PetscCall(VecWAXPY(uhat, h, du, u));
1904f017bcb6SMatthew G. Knepley       /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */
19059566063dSJacob Faibussowitsch       PetscCall(SNESComputeFunction(snes, uhat, rhat));
19069566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df));
19079566063dSJacob Faibussowitsch       PetscCall(VecNorm(rhat, NORM_2, &errors[Nv]));
1908f017bcb6SMatthew G. Knepley 
190938d69901SMatthew G. Knepley       es[Nv] = errors[Nv] == 0 ? -16.0 : PetscLog10Real(errors[Nv]);
1910f017bcb6SMatthew G. Knepley       hs[Nv] = PetscLog10Real(h);
1911f017bcb6SMatthew G. Knepley     }
19129566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&uhat));
19139566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rhat));
19149566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&df));
19159566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&r));
19169566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&du));
1917f017bcb6SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1918f017bcb6SMatthew G. Knepley       if ((tol >= 0) && (errors[v] > tol)) break;
1919f017bcb6SMatthew G. Knepley       else if (errors[v] > PETSC_SMALL) break;
1920f017bcb6SMatthew G. Knepley     }
1921f3c94560SMatthew G. Knepley     if (v == Nv) isLin = PETSC_TRUE;
19229566063dSJacob Faibussowitsch     PetscCall(PetscLinearRegression(Nv, hs, es, &slope, &intercept));
19239566063dSJacob Faibussowitsch     PetscCall(PetscFree3(es, hs, errors));
1924f017bcb6SMatthew G. Knepley     /* Slope should be about 2 */
1925f017bcb6SMatthew G. Knepley     if (tol >= 0) {
19260b121fc5SBarry Smith       PetscCheck(isLin || PetscAbsReal(2 - slope) <= tol, comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double)slope);
1927b878532fSMatthew G. Knepley     } else if (isLinear || convRate) {
1928b878532fSMatthew G. Knepley       if (isLinear) *isLinear = isLin;
1929b878532fSMatthew G. Knepley       if (convRate) *convRate = slope;
1930f017bcb6SMatthew G. Knepley     } else {
19319566063dSJacob Faibussowitsch       if (!isLin) PetscCall(PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double)slope));
19329566063dSJacob Faibussowitsch       else PetscCall(PetscPrintf(comm, "Function appears to be linear\n"));
1933f017bcb6SMatthew G. Knepley     }
1934f017bcb6SMatthew G. Knepley   }
19359566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
19363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19371878804aSMatthew G. Knepley }
19381878804aSMatthew G. Knepley 
1939d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u)
1940d71ae5a4SJacob Faibussowitsch {
1941f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
19429566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL));
19439566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckResidual(snes, dm, u, -1.0, NULL));
19449566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL));
19453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1946f017bcb6SMatthew G. Knepley }
1947f017bcb6SMatthew G. Knepley 
1948bee9a294SMatthew G. Knepley /*@C
1949bee9a294SMatthew G. Knepley   DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information
1950bee9a294SMatthew G. Knepley 
1951bee9a294SMatthew G. Knepley   Input Parameters:
1952f6dfbefdSBarry Smith + snes - the `SNES` object
1953f6dfbefdSBarry Smith - u    - representative `SNES` vector
19547f96f943SMatthew G. Knepley 
19552fe279fdSBarry Smith   Level: developer
19562fe279fdSBarry Smith 
1957f6dfbefdSBarry Smith   Note:
1958f6dfbefdSBarry Smith   The user must call `PetscDSSetExactSolution()` beforehand
1959bee9a294SMatthew G. Knepley 
19602fe279fdSBarry Smith .seealso: `SNES`, `DM`
1961bee9a294SMatthew G. Knepley @*/
1962d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u)
1963d71ae5a4SJacob Faibussowitsch {
19641878804aSMatthew G. Knepley   DM        dm;
19651878804aSMatthew G. Knepley   Vec       sol;
19661878804aSMatthew G. Knepley   PetscBool check;
19671878804aSMatthew G. Knepley 
19681878804aSMatthew G. Knepley   PetscFunctionBegin;
19699566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-dmsnes_check", &check));
19703ba16761SJacob Faibussowitsch   if (!check) PetscFunctionReturn(PETSC_SUCCESS);
19719566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
19729566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(u, &sol));
19739566063dSJacob Faibussowitsch   PetscCall(SNESSetSolution(snes, sol));
19749566063dSJacob Faibussowitsch   PetscCall(DMSNESCheck_Internal(snes, dm, sol));
19759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sol));
19763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1977552f7358SJed Brown }
1978