xref: /petsc/src/snes/utils/dmplexsnes.c (revision ceaaa4989964adb3f5eb130cb04b8f49c83e49c9)
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
69*ceaaa498SBarry Smith   SNESConvergedCorrectPressure - The regular `SNES` convergence test that, up on convergence, adds a vector in the nullspace
70*ceaaa498SBarry Smith   to make the continuum integral of the pressure field equal to zero.
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
78e4094ef1SJacob Faibussowitsch . gnorm - 2-norm of current step
79e4094ef1SJacob 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*ceaaa498SBarry Smith   Developer Note:
97*ceaaa498SBarry Smith   This is a total misuse of the `SNES` convergence test handling system. It should be removed. Perhaps a `SNESSetPostSolve()` could
98*ceaaa498SBarry Smith   be constructed to handle this process.
99*ceaaa498SBarry Smith 
100e4094ef1SJacob Faibussowitsch .seealso: `SNES`, `DM`, `SNESConvergedDefault()`, `SNESSetConvergenceTest()`, `DMSetNullSpaceConstructor()`
101649ef022SMatthew Knepley @*/
102d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESConvergedCorrectPressure(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, void *ctx)
103d71ae5a4SJacob Faibussowitsch {
104649ef022SMatthew Knepley   PetscBool monitorIntegral = PETSC_FALSE;
105649ef022SMatthew Knepley 
106649ef022SMatthew Knepley   PetscFunctionBegin;
1079566063dSJacob Faibussowitsch   PetscCall(SNESConvergedDefault(snes, it, xnorm, gnorm, f, reason, ctx));
108649ef022SMatthew Knepley   if (monitorIntegral) {
109649ef022SMatthew Knepley     Mat          J;
110649ef022SMatthew Knepley     Vec          u;
111649ef022SMatthew Knepley     MatNullSpace nullspace;
112649ef022SMatthew Knepley     const Vec   *nullvecs;
113649ef022SMatthew Knepley     PetscScalar  pintd;
114649ef022SMatthew Knepley 
1159566063dSJacob Faibussowitsch     PetscCall(SNESGetSolution(snes, &u));
1169566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
1179566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(J, &nullspace));
1189566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceGetVecs(nullspace, NULL, NULL, &nullvecs));
1199566063dSJacob Faibussowitsch     PetscCall(VecDot(nullvecs[0], u, &pintd));
1209566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "SNES: Discrete integral of pressure: %g\n", (double)PetscRealPart(pintd)));
121649ef022SMatthew Knepley   }
122649ef022SMatthew Knepley   if (*reason > 0) {
123649ef022SMatthew Knepley     Mat          J;
124649ef022SMatthew Knepley     Vec          u;
125649ef022SMatthew Knepley     MatNullSpace nullspace;
126649ef022SMatthew Knepley     PetscInt     pfield = 1;
127649ef022SMatthew Knepley 
1289566063dSJacob Faibussowitsch     PetscCall(SNESGetSolution(snes, &u));
1299566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
1309566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(J, &nullspace));
1319566063dSJacob Faibussowitsch     PetscCall(SNESCorrectDiscretePressure_Private(snes, pfield, nullspace, u, ctx));
132649ef022SMatthew Knepley   }
1333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
134649ef022SMatthew Knepley }
135649ef022SMatthew Knepley 
13624cdb843SMatthew G. Knepley /************************** Interpolation *******************************/
13724cdb843SMatthew G. Knepley 
138d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESConvertPlex(DM dm, DM *plex, PetscBool copy)
139d71ae5a4SJacob Faibussowitsch {
1406da023fcSToby Isaac   PetscBool isPlex;
1416da023fcSToby Isaac 
1426da023fcSToby Isaac   PetscFunctionBegin;
1439566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
1446da023fcSToby Isaac   if (isPlex) {
1456da023fcSToby Isaac     *plex = dm;
1469566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
147f7148743SMatthew G. Knepley   } else {
1489566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex));
149f7148743SMatthew G. Knepley     if (!*plex) {
1509566063dSJacob Faibussowitsch       PetscCall(DMConvert(dm, DMPLEX, plex));
1519566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex));
1526da023fcSToby Isaac       if (copy) {
1539566063dSJacob Faibussowitsch         PetscCall(DMCopyDMSNES(dm, *plex));
1549566063dSJacob Faibussowitsch         PetscCall(DMCopyAuxiliaryVec(dm, *plex));
1556da023fcSToby Isaac       }
156f7148743SMatthew G. Knepley     } else {
1579566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)*plex));
158f7148743SMatthew G. Knepley     }
1596da023fcSToby Isaac   }
1603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1616da023fcSToby Isaac }
1626da023fcSToby Isaac 
1634267b1a3SMatthew G. Knepley /*@C
164f6dfbefdSBarry Smith   DMInterpolationCreate - Creates a `DMInterpolationInfo` context
1654267b1a3SMatthew G. Knepley 
166d083f849SBarry Smith   Collective
1674267b1a3SMatthew G. Knepley 
1684267b1a3SMatthew G. Knepley   Input Parameter:
1694267b1a3SMatthew G. Knepley . comm - the communicator
1704267b1a3SMatthew G. Knepley 
1714267b1a3SMatthew G. Knepley   Output Parameter:
1724267b1a3SMatthew G. Knepley . ctx - the context
1734267b1a3SMatthew G. Knepley 
1744267b1a3SMatthew G. Knepley   Level: beginner
1754267b1a3SMatthew G. Knepley 
176f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationDestroy()`
1774267b1a3SMatthew G. Knepley @*/
178d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationCreate(MPI_Comm comm, DMInterpolationInfo *ctx)
179d71ae5a4SJacob Faibussowitsch {
180552f7358SJed Brown   PetscFunctionBegin;
1814f572ea9SToby Isaac   PetscAssertPointer(ctx, 2);
1829566063dSJacob Faibussowitsch   PetscCall(PetscNew(ctx));
1831aa26658SKarl Rupp 
184552f7358SJed Brown   (*ctx)->comm   = comm;
185552f7358SJed Brown   (*ctx)->dim    = -1;
186552f7358SJed Brown   (*ctx)->nInput = 0;
1870298fd71SBarry Smith   (*ctx)->points = NULL;
1880298fd71SBarry Smith   (*ctx)->cells  = NULL;
189552f7358SJed Brown   (*ctx)->n      = -1;
1900298fd71SBarry Smith   (*ctx)->coords = NULL;
1913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
192552f7358SJed Brown }
193552f7358SJed Brown 
1944267b1a3SMatthew G. Knepley /*@C
1954267b1a3SMatthew G. Knepley   DMInterpolationSetDim - Sets the spatial dimension for the interpolation context
1964267b1a3SMatthew G. Knepley 
19720f4b53cSBarry Smith   Not Collective
1984267b1a3SMatthew G. Knepley 
1994267b1a3SMatthew G. Knepley   Input Parameters:
2004267b1a3SMatthew G. Knepley + ctx - the context
2014267b1a3SMatthew G. Knepley - dim - the spatial dimension
2024267b1a3SMatthew G. Knepley 
2034267b1a3SMatthew G. Knepley   Level: intermediate
2044267b1a3SMatthew G. Knepley 
205f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
2064267b1a3SMatthew G. Knepley @*/
207d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetDim(DMInterpolationInfo ctx, PetscInt dim)
208d71ae5a4SJacob Faibussowitsch {
209552f7358SJed Brown   PetscFunctionBegin;
21063a3b9bcSJacob Faibussowitsch   PetscCheck(!(dim < 1) && !(dim > 3), ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension for points: %" PetscInt_FMT, dim);
211552f7358SJed Brown   ctx->dim = dim;
2123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
213552f7358SJed Brown }
214552f7358SJed Brown 
2154267b1a3SMatthew G. Knepley /*@C
2164267b1a3SMatthew G. Knepley   DMInterpolationGetDim - Gets the spatial dimension for the interpolation context
2174267b1a3SMatthew G. Knepley 
21820f4b53cSBarry Smith   Not Collective
2194267b1a3SMatthew G. Knepley 
2204267b1a3SMatthew G. Knepley   Input Parameter:
2214267b1a3SMatthew G. Knepley . ctx - the context
2224267b1a3SMatthew G. Knepley 
2234267b1a3SMatthew G. Knepley   Output Parameter:
2244267b1a3SMatthew G. Knepley . dim - the spatial dimension
2254267b1a3SMatthew G. Knepley 
2264267b1a3SMatthew G. Knepley   Level: intermediate
2274267b1a3SMatthew G. Knepley 
228f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
2294267b1a3SMatthew G. Knepley @*/
230d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetDim(DMInterpolationInfo ctx, PetscInt *dim)
231d71ae5a4SJacob Faibussowitsch {
232552f7358SJed Brown   PetscFunctionBegin;
2334f572ea9SToby Isaac   PetscAssertPointer(dim, 2);
234552f7358SJed Brown   *dim = ctx->dim;
2353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
236552f7358SJed Brown }
237552f7358SJed Brown 
2384267b1a3SMatthew G. Knepley /*@C
2394267b1a3SMatthew G. Knepley   DMInterpolationSetDof - Sets the number of fields interpolated at a point for the interpolation context
2404267b1a3SMatthew G. Knepley 
24120f4b53cSBarry Smith   Not Collective
2424267b1a3SMatthew G. Knepley 
2434267b1a3SMatthew G. Knepley   Input Parameters:
2444267b1a3SMatthew G. Knepley + ctx - the context
2454267b1a3SMatthew G. Knepley - dof - the number of fields
2464267b1a3SMatthew G. Knepley 
2474267b1a3SMatthew G. Knepley   Level: intermediate
2484267b1a3SMatthew G. Knepley 
249f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
2504267b1a3SMatthew G. Knepley @*/
251d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetDof(DMInterpolationInfo ctx, PetscInt dof)
252d71ae5a4SJacob Faibussowitsch {
253552f7358SJed Brown   PetscFunctionBegin;
25463a3b9bcSJacob Faibussowitsch   PetscCheck(dof >= 1, ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of components: %" PetscInt_FMT, dof);
255552f7358SJed Brown   ctx->dof = dof;
2563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
257552f7358SJed Brown }
258552f7358SJed Brown 
2594267b1a3SMatthew G. Knepley /*@C
2604267b1a3SMatthew G. Knepley   DMInterpolationGetDof - Gets the number of fields interpolated at a point for the interpolation context
2614267b1a3SMatthew G. Knepley 
26220f4b53cSBarry Smith   Not Collective
2634267b1a3SMatthew G. Knepley 
2644267b1a3SMatthew G. Knepley   Input Parameter:
2654267b1a3SMatthew G. Knepley . ctx - the context
2664267b1a3SMatthew G. Knepley 
2674267b1a3SMatthew G. Knepley   Output Parameter:
2684267b1a3SMatthew G. Knepley . dof - the number of fields
2694267b1a3SMatthew G. Knepley 
2704267b1a3SMatthew G. Knepley   Level: intermediate
2714267b1a3SMatthew G. Knepley 
272e4094ef1SJacob Faibussowitsch .seealso: `DMInterpolationInfo`, `DMInterpolationSetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
2734267b1a3SMatthew G. Knepley @*/
274d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetDof(DMInterpolationInfo ctx, PetscInt *dof)
275d71ae5a4SJacob Faibussowitsch {
276552f7358SJed Brown   PetscFunctionBegin;
2774f572ea9SToby Isaac   PetscAssertPointer(dof, 2);
278552f7358SJed Brown   *dof = ctx->dof;
2793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
280552f7358SJed Brown }
281552f7358SJed Brown 
2824267b1a3SMatthew G. Knepley /*@C
2834267b1a3SMatthew G. Knepley   DMInterpolationAddPoints - Add points at which we will interpolate the fields
2844267b1a3SMatthew G. Knepley 
28520f4b53cSBarry Smith   Not Collective
2864267b1a3SMatthew G. Knepley 
2874267b1a3SMatthew G. Knepley   Input Parameters:
2884267b1a3SMatthew G. Knepley + ctx    - the context
2894267b1a3SMatthew G. Knepley . n      - the number of points
2904267b1a3SMatthew G. Knepley - points - the coordinates for each point, an array of size n * dim
2914267b1a3SMatthew G. Knepley 
2922fe279fdSBarry Smith   Level: intermediate
2932fe279fdSBarry Smith 
294f6dfbefdSBarry Smith   Note:
295f6dfbefdSBarry Smith   The coordinate information is copied.
2964267b1a3SMatthew G. Knepley 
297f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationCreate()`
2984267b1a3SMatthew G. Knepley @*/
299d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationAddPoints(DMInterpolationInfo ctx, PetscInt n, PetscReal points[])
300d71ae5a4SJacob Faibussowitsch {
301552f7358SJed Brown   PetscFunctionBegin;
30208401ef6SPierre Jolivet   PetscCheck(ctx->dim >= 0, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
30328b400f6SJacob Faibussowitsch   PetscCheck(!ctx->points, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot add points multiple times yet");
304552f7358SJed Brown   ctx->nInput = n;
3051aa26658SKarl Rupp 
3069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n * ctx->dim, &ctx->points));
3079566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(ctx->points, points, n * ctx->dim));
3083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
309552f7358SJed Brown }
310552f7358SJed Brown 
3114267b1a3SMatthew G. Knepley /*@C
31252aa1562SMatthew G. Knepley   DMInterpolationSetUp - Compute spatial indices for point location during interpolation
3134267b1a3SMatthew G. Knepley 
314c3339decSBarry Smith   Collective
3154267b1a3SMatthew G. Knepley 
3164267b1a3SMatthew G. Knepley   Input Parameters:
3174267b1a3SMatthew G. Knepley + ctx                 - the context
318f6dfbefdSBarry Smith . dm                  - the `DM` for the function space used for interpolation
319f6dfbefdSBarry Smith . redundantPoints     - If `PETSC_TRUE`, all processes are passing in the same array of points. Otherwise, points need to be communicated among processes.
320f6dfbefdSBarry Smith - ignoreOutsideDomain - If `PETSC_TRUE`, ignore points outside the domain, otherwise return an error
3214267b1a3SMatthew G. Knepley 
3224267b1a3SMatthew G. Knepley   Level: intermediate
3234267b1a3SMatthew G. Knepley 
324e4094ef1SJacob Faibussowitsch .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
3254267b1a3SMatthew G. Knepley @*/
326d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetUp(DMInterpolationInfo ctx, DM dm, PetscBool redundantPoints, PetscBool ignoreOutsideDomain)
327d71ae5a4SJacob Faibussowitsch {
328552f7358SJed Brown   MPI_Comm           comm = ctx->comm;
329552f7358SJed Brown   PetscScalar       *a;
330552f7358SJed Brown   PetscInt           p, q, i;
331552f7358SJed Brown   PetscMPIInt        rank, size;
332552f7358SJed Brown   Vec                pointVec;
3333a93e3b7SToby Isaac   PetscSF            cellSF;
334552f7358SJed Brown   PetscLayout        layout;
335552f7358SJed Brown   PetscReal         *globalPoints;
336cb313848SJed Brown   PetscScalar       *globalPointsScalar;
337552f7358SJed Brown   const PetscInt    *ranges;
338552f7358SJed Brown   PetscMPIInt       *counts, *displs;
3393a93e3b7SToby Isaac   const PetscSFNode *foundCells;
3403a93e3b7SToby Isaac   const PetscInt    *foundPoints;
341552f7358SJed Brown   PetscMPIInt       *foundProcs, *globalProcs;
3423a93e3b7SToby Isaac   PetscInt           n, N, numFound;
343552f7358SJed Brown 
34419436ca2SJed Brown   PetscFunctionBegin;
345064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
3469566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
3479566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
34808401ef6SPierre Jolivet   PetscCheck(ctx->dim >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
34919436ca2SJed Brown   /* Locate points */
35019436ca2SJed Brown   n = ctx->nInput;
351552f7358SJed Brown   if (!redundantPoints) {
3529566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCreate(comm, &layout));
3539566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetBlockSize(layout, 1));
3549566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetLocalSize(layout, n));
3559566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(layout));
3569566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, &N));
357552f7358SJed Brown     /* Communicate all points to all processes */
3589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(N * ctx->dim, &globalPoints, size, &counts, size, &displs));
3599566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRanges(layout, &ranges));
360552f7358SJed Brown     for (p = 0; p < size; ++p) {
361552f7358SJed Brown       counts[p] = (ranges[p + 1] - ranges[p]) * ctx->dim;
362552f7358SJed Brown       displs[p] = ranges[p] * ctx->dim;
363552f7358SJed Brown     }
3649566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgatherv(ctx->points, n * ctx->dim, MPIU_REAL, globalPoints, counts, displs, MPIU_REAL, comm));
365552f7358SJed Brown   } else {
366552f7358SJed Brown     N            = n;
367552f7358SJed Brown     globalPoints = ctx->points;
36838ea73c8SJed Brown     counts = displs = NULL;
36938ea73c8SJed Brown     layout          = NULL;
370552f7358SJed Brown   }
371552f7358SJed Brown #if 0
3729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(N,&foundCells,N,&foundProcs,N,&globalProcs));
37319436ca2SJed Brown   /* foundCells[p] = m->locatePoint(&globalPoints[p*ctx->dim]); */
374552f7358SJed Brown #else
375cb313848SJed Brown   #if defined(PETSC_USE_COMPLEX)
3769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(N * ctx->dim, &globalPointsScalar));
37746b3086cSToby Isaac   for (i = 0; i < N * ctx->dim; i++) globalPointsScalar[i] = globalPoints[i];
378cb313848SJed Brown   #else
379cb313848SJed Brown   globalPointsScalar = globalPoints;
380cb313848SJed Brown   #endif
3819566063dSJacob Faibussowitsch   PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, ctx->dim, N * ctx->dim, globalPointsScalar, &pointVec));
3829566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(N, &foundProcs, N, &globalProcs));
383ad540459SPierre Jolivet   for (p = 0; p < N; ++p) foundProcs[p] = size;
3843a93e3b7SToby Isaac   cellSF = NULL;
3859566063dSJacob Faibussowitsch   PetscCall(DMLocatePoints(dm, pointVec, DM_POINTLOCATION_REMOVE, &cellSF));
3869566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(cellSF, NULL, &numFound, &foundPoints, &foundCells));
387552f7358SJed Brown #endif
3883a93e3b7SToby Isaac   for (p = 0; p < numFound; ++p) {
3893a93e3b7SToby Isaac     if (foundCells[p].index >= 0) foundProcs[foundPoints ? foundPoints[p] : p] = rank;
390552f7358SJed Brown   }
391552f7358SJed Brown   /* Let the lowest rank process own each point */
3921c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(foundProcs, globalProcs, N, MPI_INT, MPI_MIN, comm));
393552f7358SJed Brown   ctx->n = 0;
394552f7358SJed Brown   for (p = 0; p < N; ++p) {
39552aa1562SMatthew G. Knepley     if (globalProcs[p] == size) {
3969371c9d4SSatish 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),
3979371c9d4SSatish Balay                  (double)(ctx->dim > 2 ? globalPoints[p * ctx->dim + 2] : 0.0));
398f7d195e4SLawrence Mitchell       if (rank == 0) ++ctx->n;
39952aa1562SMatthew G. Knepley     } else if (globalProcs[p] == rank) ++ctx->n;
400552f7358SJed Brown   }
401552f7358SJed Brown   /* Create coordinates vector and array of owned cells */
4029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ctx->n, &ctx->cells));
4039566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, &ctx->coords));
4049566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(ctx->coords, ctx->n * ctx->dim, PETSC_DECIDE));
4059566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(ctx->coords, ctx->dim));
4069566063dSJacob Faibussowitsch   PetscCall(VecSetType(ctx->coords, VECSTANDARD));
4079566063dSJacob Faibussowitsch   PetscCall(VecGetArray(ctx->coords, &a));
408552f7358SJed Brown   for (p = 0, q = 0, i = 0; p < N; ++p) {
409552f7358SJed Brown     if (globalProcs[p] == rank) {
410552f7358SJed Brown       PetscInt d;
411552f7358SJed Brown 
4121aa26658SKarl Rupp       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = globalPoints[p * ctx->dim + d];
413f317b747SMatthew G. Knepley       ctx->cells[q] = foundCells[q].index;
414f317b747SMatthew G. Knepley       ++q;
415552f7358SJed Brown     }
416dd400576SPatrick Sanan     if (globalProcs[p] == size && rank == 0) {
41752aa1562SMatthew G. Knepley       PetscInt d;
41852aa1562SMatthew G. Knepley 
41952aa1562SMatthew G. Knepley       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = 0.;
42052aa1562SMatthew G. Knepley       ctx->cells[q] = -1;
42152aa1562SMatthew G. Knepley       ++q;
42252aa1562SMatthew G. Knepley     }
423552f7358SJed Brown   }
4249566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(ctx->coords, &a));
425552f7358SJed Brown #if 0
4269566063dSJacob Faibussowitsch   PetscCall(PetscFree3(foundCells,foundProcs,globalProcs));
427552f7358SJed Brown #else
4289566063dSJacob Faibussowitsch   PetscCall(PetscFree2(foundProcs, globalProcs));
4299566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&cellSF));
4309566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pointVec));
431552f7358SJed Brown #endif
4329566063dSJacob Faibussowitsch   if ((void *)globalPointsScalar != (void *)globalPoints) PetscCall(PetscFree(globalPointsScalar));
4339566063dSJacob Faibussowitsch   if (!redundantPoints) PetscCall(PetscFree3(globalPoints, counts, displs));
4349566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&layout));
4353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
436552f7358SJed Brown }
437552f7358SJed Brown 
4384267b1a3SMatthew G. Knepley /*@C
439f6dfbefdSBarry Smith   DMInterpolationGetCoordinates - Gets a `Vec` with the coordinates of each interpolation point
4404267b1a3SMatthew G. Knepley 
441c3339decSBarry Smith   Collective
4424267b1a3SMatthew G. Knepley 
4434267b1a3SMatthew G. Knepley   Input Parameter:
4444267b1a3SMatthew G. Knepley . ctx - the context
4454267b1a3SMatthew G. Knepley 
4464267b1a3SMatthew G. Knepley   Output Parameter:
4474267b1a3SMatthew G. Knepley . coordinates - the coordinates of interpolation points
4484267b1a3SMatthew G. Knepley 
44920f4b53cSBarry Smith   Level: intermediate
45020f4b53cSBarry Smith 
451f6dfbefdSBarry Smith   Note:
452f6dfbefdSBarry Smith   The local vector entries correspond to interpolation points lying on this process, according to the associated `DM`.
453f6dfbefdSBarry Smith   This is a borrowed vector that the user should not destroy.
4544267b1a3SMatthew G. Knepley 
455f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
4564267b1a3SMatthew G. Knepley @*/
457d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetCoordinates(DMInterpolationInfo ctx, Vec *coordinates)
458d71ae5a4SJacob Faibussowitsch {
459552f7358SJed Brown   PetscFunctionBegin;
4604f572ea9SToby Isaac   PetscAssertPointer(coordinates, 2);
46128b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
462552f7358SJed Brown   *coordinates = ctx->coords;
4633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
464552f7358SJed Brown }
465552f7358SJed Brown 
4664267b1a3SMatthew G. Knepley /*@C
467f6dfbefdSBarry Smith   DMInterpolationGetVector - Gets a `Vec` which can hold all the interpolated field values
4684267b1a3SMatthew G. Knepley 
469c3339decSBarry Smith   Collective
4704267b1a3SMatthew G. Knepley 
4714267b1a3SMatthew G. Knepley   Input Parameter:
4724267b1a3SMatthew G. Knepley . ctx - the context
4734267b1a3SMatthew G. Knepley 
4744267b1a3SMatthew G. Knepley   Output Parameter:
4754267b1a3SMatthew G. Knepley . v - a vector capable of holding the interpolated field values
4764267b1a3SMatthew G. Knepley 
4772fe279fdSBarry Smith   Level: intermediate
4782fe279fdSBarry Smith 
479f6dfbefdSBarry Smith   Note:
480f6dfbefdSBarry Smith   This vector should be returned using `DMInterpolationRestoreVector()`.
4814267b1a3SMatthew G. Knepley 
482f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationRestoreVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
4834267b1a3SMatthew G. Knepley @*/
484d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetVector(DMInterpolationInfo ctx, Vec *v)
485d71ae5a4SJacob Faibussowitsch {
486552f7358SJed Brown   PetscFunctionBegin;
4874f572ea9SToby Isaac   PetscAssertPointer(v, 2);
48828b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
4899566063dSJacob Faibussowitsch   PetscCall(VecCreate(ctx->comm, v));
4909566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*v, ctx->n * ctx->dof, PETSC_DECIDE));
4919566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(*v, ctx->dof));
4929566063dSJacob Faibussowitsch   PetscCall(VecSetType(*v, VECSTANDARD));
4933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
494552f7358SJed Brown }
495552f7358SJed Brown 
4964267b1a3SMatthew G. Knepley /*@C
497f6dfbefdSBarry Smith   DMInterpolationRestoreVector - Returns a `Vec` which can hold all the interpolated field values
4984267b1a3SMatthew G. Knepley 
499c3339decSBarry Smith   Collective
5004267b1a3SMatthew G. Knepley 
5014267b1a3SMatthew G. Knepley   Input Parameters:
5024267b1a3SMatthew G. Knepley + ctx - the context
5034267b1a3SMatthew G. Knepley - v   - a vector capable of holding the interpolated field values
5044267b1a3SMatthew G. Knepley 
5054267b1a3SMatthew G. Knepley   Level: intermediate
5064267b1a3SMatthew G. Knepley 
507f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
5084267b1a3SMatthew G. Knepley @*/
509d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationRestoreVector(DMInterpolationInfo ctx, Vec *v)
510d71ae5a4SJacob Faibussowitsch {
511552f7358SJed Brown   PetscFunctionBegin;
5124f572ea9SToby Isaac   PetscAssertPointer(v, 2);
51328b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
5149566063dSJacob Faibussowitsch   PetscCall(VecDestroy(v));
5153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
516552f7358SJed Brown }
517552f7358SJed Brown 
518d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Segment_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
519d71ae5a4SJacob Faibussowitsch {
520cfe5744fSMatthew G. Knepley   PetscReal          v0, J, invJ, detJ;
521cfe5744fSMatthew G. Knepley   const PetscInt     dof = ctx->dof;
522cfe5744fSMatthew G. Knepley   const PetscScalar *coords;
523cfe5744fSMatthew G. Knepley   PetscScalar       *a;
524cfe5744fSMatthew G. Knepley   PetscInt           p;
525cfe5744fSMatthew G. Knepley 
526cfe5744fSMatthew G. Knepley   PetscFunctionBegin;
5279566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
5289566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
529cfe5744fSMatthew G. Knepley   for (p = 0; p < ctx->n; ++p) {
530cfe5744fSMatthew G. Knepley     PetscInt     c = ctx->cells[p];
531cfe5744fSMatthew G. Knepley     PetscScalar *x = NULL;
532cfe5744fSMatthew G. Knepley     PetscReal    xir[1];
533cfe5744fSMatthew G. Knepley     PetscInt     xSize, comp;
534cfe5744fSMatthew G. Knepley 
5359566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ));
536cfe5744fSMatthew G. Knepley     PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c);
537cfe5744fSMatthew G. Knepley     xir[0] = invJ * PetscRealPart(coords[p] - v0);
5389566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
539cfe5744fSMatthew G. Knepley     if (2 * dof == xSize) {
540cfe5744fSMatthew 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];
541cfe5744fSMatthew G. Knepley     } else if (dof == xSize) {
542cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp];
543cfe5744fSMatthew 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);
5449566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
545cfe5744fSMatthew G. Knepley   }
5469566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
5479566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
5483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
549cfe5744fSMatthew G. Knepley }
550cfe5744fSMatthew G. Knepley 
551d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Triangle_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
552d71ae5a4SJacob Faibussowitsch {
553552f7358SJed Brown   PetscReal         *v0, *J, *invJ, detJ;
55456044e6dSMatthew G. Knepley   const PetscScalar *coords;
55556044e6dSMatthew G. Knepley   PetscScalar       *a;
556552f7358SJed Brown   PetscInt           p;
557552f7358SJed Brown 
558552f7358SJed Brown   PetscFunctionBegin;
5599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ));
5609566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
5619566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
562552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
563552f7358SJed Brown     PetscInt     c = ctx->cells[p];
564a1e44745SMatthew G. Knepley     PetscScalar *x = NULL;
565552f7358SJed Brown     PetscReal    xi[4];
566552f7358SJed Brown     PetscInt     d, f, comp;
567552f7358SJed Brown 
5689566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
56963a3b9bcSJacob Faibussowitsch     PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c);
5709566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
5711aa26658SKarl Rupp     for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp];
5721aa26658SKarl Rupp 
573552f7358SJed Brown     for (d = 0; d < ctx->dim; ++d) {
574552f7358SJed Brown       xi[d] = 0.0;
5751aa26658SKarl 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]);
5761aa26658SKarl 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];
577552f7358SJed Brown     }
5789566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
579552f7358SJed Brown   }
5809566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
5819566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
5829566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
5833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
584552f7358SJed Brown }
585552f7358SJed Brown 
586d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Tetrahedron_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
587d71ae5a4SJacob Faibussowitsch {
5887a1931ceSMatthew G. Knepley   PetscReal         *v0, *J, *invJ, detJ;
58956044e6dSMatthew G. Knepley   const PetscScalar *coords;
59056044e6dSMatthew G. Knepley   PetscScalar       *a;
5917a1931ceSMatthew G. Knepley   PetscInt           p;
5927a1931ceSMatthew G. Knepley 
5937a1931ceSMatthew G. Knepley   PetscFunctionBegin;
5949566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ));
5959566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
5969566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
5977a1931ceSMatthew G. Knepley   for (p = 0; p < ctx->n; ++p) {
5987a1931ceSMatthew G. Knepley     PetscInt       c        = ctx->cells[p];
5997a1931ceSMatthew G. Knepley     const PetscInt order[3] = {2, 1, 3};
6002584bbe8SMatthew G. Knepley     PetscScalar   *x        = NULL;
6017a1931ceSMatthew G. Knepley     PetscReal      xi[4];
6027a1931ceSMatthew G. Knepley     PetscInt       d, f, comp;
6037a1931ceSMatthew G. Knepley 
6049566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
60563a3b9bcSJacob Faibussowitsch     PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c);
6069566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
6077a1931ceSMatthew G. Knepley     for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp];
6087a1931ceSMatthew G. Knepley 
6097a1931ceSMatthew G. Knepley     for (d = 0; d < ctx->dim; ++d) {
6107a1931ceSMatthew G. Knepley       xi[d] = 0.0;
6117a1931ceSMatthew 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]);
6127a1931ceSMatthew 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];
6137a1931ceSMatthew G. Knepley     }
6149566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
6157a1931ceSMatthew G. Knepley   }
6169566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
6179566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
6189566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
6193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6207a1931ceSMatthew G. Knepley }
6217a1931ceSMatthew G. Knepley 
622d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode QuadMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
623d71ae5a4SJacob Faibussowitsch {
624552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar *)ctx;
625552f7358SJed Brown   const PetscScalar  x0       = vertices[0];
626552f7358SJed Brown   const PetscScalar  y0       = vertices[1];
627552f7358SJed Brown   const PetscScalar  x1       = vertices[2];
628552f7358SJed Brown   const PetscScalar  y1       = vertices[3];
629552f7358SJed Brown   const PetscScalar  x2       = vertices[4];
630552f7358SJed Brown   const PetscScalar  y2       = vertices[5];
631552f7358SJed Brown   const PetscScalar  x3       = vertices[6];
632552f7358SJed Brown   const PetscScalar  y3       = vertices[7];
633552f7358SJed Brown   const PetscScalar  f_1      = x1 - x0;
634552f7358SJed Brown   const PetscScalar  g_1      = y1 - y0;
635552f7358SJed Brown   const PetscScalar  f_3      = x3 - x0;
636552f7358SJed Brown   const PetscScalar  g_3      = y3 - y0;
637552f7358SJed Brown   const PetscScalar  f_01     = x2 - x1 - x3 + x0;
638552f7358SJed Brown   const PetscScalar  g_01     = y2 - y1 - y3 + y0;
63956044e6dSMatthew G. Knepley   const PetscScalar *ref;
64056044e6dSMatthew G. Knepley   PetscScalar       *real;
641552f7358SJed Brown 
642552f7358SJed Brown   PetscFunctionBegin;
6439566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref, &ref));
6449566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Xreal, &real));
645552f7358SJed Brown   {
646552f7358SJed Brown     const PetscScalar p0 = ref[0];
647552f7358SJed Brown     const PetscScalar p1 = ref[1];
648552f7358SJed Brown 
649552f7358SJed Brown     real[0] = x0 + f_1 * p0 + f_3 * p1 + f_01 * p0 * p1;
650552f7358SJed Brown     real[1] = y0 + g_1 * p0 + g_3 * p1 + g_01 * p0 * p1;
651552f7358SJed Brown   }
6529566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(28));
6539566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref, &ref));
6549566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Xreal, &real));
6553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
656552f7358SJed Brown }
657552f7358SJed Brown 
658af0996ceSBarry Smith #include <petsc/private/dmimpl.h>
659d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode QuadJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
660d71ae5a4SJacob Faibussowitsch {
661552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar *)ctx;
662552f7358SJed Brown   const PetscScalar  x0       = vertices[0];
663552f7358SJed Brown   const PetscScalar  y0       = vertices[1];
664552f7358SJed Brown   const PetscScalar  x1       = vertices[2];
665552f7358SJed Brown   const PetscScalar  y1       = vertices[3];
666552f7358SJed Brown   const PetscScalar  x2       = vertices[4];
667552f7358SJed Brown   const PetscScalar  y2       = vertices[5];
668552f7358SJed Brown   const PetscScalar  x3       = vertices[6];
669552f7358SJed Brown   const PetscScalar  y3       = vertices[7];
670552f7358SJed Brown   const PetscScalar  f_01     = x2 - x1 - x3 + x0;
671552f7358SJed Brown   const PetscScalar  g_01     = y2 - y1 - y3 + y0;
67256044e6dSMatthew G. Knepley   const PetscScalar *ref;
673552f7358SJed Brown 
674552f7358SJed Brown   PetscFunctionBegin;
6759566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref, &ref));
676552f7358SJed Brown   {
677552f7358SJed Brown     const PetscScalar x       = ref[0];
678552f7358SJed Brown     const PetscScalar y       = ref[1];
679552f7358SJed Brown     const PetscInt    rows[2] = {0, 1};
680da80777bSKarl Rupp     PetscScalar       values[4];
681da80777bSKarl Rupp 
6829371c9d4SSatish Balay     values[0] = (x1 - x0 + f_01 * y) * 0.5;
6839371c9d4SSatish Balay     values[1] = (x3 - x0 + f_01 * x) * 0.5;
6849371c9d4SSatish Balay     values[2] = (y1 - y0 + g_01 * y) * 0.5;
6859371c9d4SSatish Balay     values[3] = (y3 - y0 + g_01 * x) * 0.5;
6869566063dSJacob Faibussowitsch     PetscCall(MatSetValues(J, 2, rows, 2, rows, values, INSERT_VALUES));
687552f7358SJed Brown   }
6889566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(30));
6899566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref, &ref));
6909566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
6919566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
6923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
693552f7358SJed Brown }
694552f7358SJed Brown 
695d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Quad_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
696d71ae5a4SJacob Faibussowitsch {
697fafc0619SMatthew G Knepley   DM                 dmCoord;
698de73a395SMatthew G. Knepley   PetscFE            fem = NULL;
699552f7358SJed Brown   SNES               snes;
700552f7358SJed Brown   KSP                ksp;
701552f7358SJed Brown   PC                 pc;
702552f7358SJed Brown   Vec                coordsLocal, r, ref, real;
703552f7358SJed Brown   Mat                J;
704716009bfSMatthew G. Knepley   PetscTabulation    T = NULL;
70556044e6dSMatthew G. Knepley   const PetscScalar *coords;
70656044e6dSMatthew G. Knepley   PetscScalar       *a;
707716009bfSMatthew G. Knepley   PetscReal          xir[2] = {0., 0.};
708de73a395SMatthew G. Knepley   PetscInt           Nf, p;
7095509d985SMatthew G. Knepley   const PetscInt     dof = ctx->dof;
710552f7358SJed Brown 
711552f7358SJed Brown   PetscFunctionBegin;
7129566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
713716009bfSMatthew G. Knepley   if (Nf) {
714cfe5744fSMatthew G. Knepley     PetscObject  obj;
715cfe5744fSMatthew G. Knepley     PetscClassId id;
716cfe5744fSMatthew G. Knepley 
7179566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, 0, NULL, &obj));
7189566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
7199371c9d4SSatish Balay     if (id == PETSCFE_CLASSID) {
7209371c9d4SSatish Balay       fem = (PetscFE)obj;
7219371c9d4SSatish Balay       PetscCall(PetscFECreateTabulation(fem, 1, 1, xir, 0, &T));
7229371c9d4SSatish Balay     }
723716009bfSMatthew G. Knepley   }
7249566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
7259566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &dmCoord));
7269566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
7279566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes, "quad_interp_"));
7289566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &r));
7299566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(r, 2, 2));
7309566063dSJacob Faibussowitsch   PetscCall(VecSetType(r, dm->vectype));
7319566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &ref));
7329566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &real));
7339566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &J));
7349566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(J, 2, 2, 2, 2));
7359566063dSJacob Faibussowitsch   PetscCall(MatSetType(J, MATSEQDENSE));
7369566063dSJacob Faibussowitsch   PetscCall(MatSetUp(J));
7379566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes, r, QuadMap_Private, NULL));
7389566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes, J, J, QuadJacobian_Private, NULL));
7399566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(snes, &ksp));
7409566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(ksp, &pc));
7419566063dSJacob Faibussowitsch   PetscCall(PCSetType(pc, PCLU));
7429566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
743552f7358SJed Brown 
7449566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
7459566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
746552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
747a1e44745SMatthew G. Knepley     PetscScalar *x = NULL, *vertices = NULL;
748552f7358SJed Brown     PetscScalar *xi;
749552f7358SJed Brown     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
750552f7358SJed Brown 
751552f7358SJed Brown     /* Can make this do all points at once */
7529566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
75363a3b9bcSJacob Faibussowitsch     PetscCheck(4 * 2 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %" PetscInt_FMT " should be %d", coordSize, 4 * 2);
7549566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
7559566063dSJacob Faibussowitsch     PetscCall(SNESSetFunction(snes, NULL, NULL, vertices));
7569566063dSJacob Faibussowitsch     PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
7579566063dSJacob Faibussowitsch     PetscCall(VecGetArray(real, &xi));
758552f7358SJed Brown     xi[0] = coords[p * ctx->dim + 0];
759552f7358SJed Brown     xi[1] = coords[p * ctx->dim + 1];
7609566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(real, &xi));
7619566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes, real, ref));
7629566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ref, &xi));
763cb313848SJed Brown     xir[0] = PetscRealPart(xi[0]);
764cb313848SJed Brown     xir[1] = PetscRealPart(xi[1]);
765cfe5744fSMatthew G. Knepley     if (4 * dof == xSize) {
7669371c9d4SSatish 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];
767cfe5744fSMatthew G. Knepley     } else if (dof == xSize) {
768cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp];
769cfe5744fSMatthew G. Knepley     } else {
7705509d985SMatthew G. Knepley       PetscInt d;
7711aa26658SKarl Rupp 
7722c71b3e2SJacob Faibussowitsch       PetscCheck(fem, ctx->comm, PETSC_ERR_ARG_WRONG, "Cannot have a higher order interpolant if the discretization is not PetscFE");
7739371c9d4SSatish Balay       xir[0] = 2.0 * xir[0] - 1.0;
7749371c9d4SSatish Balay       xir[1] = 2.0 * xir[1] - 1.0;
7759566063dSJacob Faibussowitsch       PetscCall(PetscFEComputeTabulation(fem, 1, xir, 0, T));
7765509d985SMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) {
7775509d985SMatthew G. Knepley         a[p * dof + comp] = 0.0;
778ad540459SPierre Jolivet         for (d = 0; d < xSize / dof; ++d) a[p * dof + comp] += x[d * dof + comp] * T->T[0][d * dof + comp];
7795509d985SMatthew G. Knepley       }
7805509d985SMatthew G. Knepley     }
7819566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ref, &xi));
7829566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
7839566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
784552f7358SJed Brown   }
7859566063dSJacob Faibussowitsch   PetscCall(PetscTabulationDestroy(&T));
7869566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
7879566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
788552f7358SJed Brown 
7899566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
7909566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
7919566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ref));
7929566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&real));
7939566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
7943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
795552f7358SJed Brown }
796552f7358SJed Brown 
797d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode HexMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
798d71ae5a4SJacob Faibussowitsch {
799552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar *)ctx;
800552f7358SJed Brown   const PetscScalar  x0       = vertices[0];
801552f7358SJed Brown   const PetscScalar  y0       = vertices[1];
802552f7358SJed Brown   const PetscScalar  z0       = vertices[2];
8037a1931ceSMatthew G. Knepley   const PetscScalar  x1       = vertices[9];
8047a1931ceSMatthew G. Knepley   const PetscScalar  y1       = vertices[10];
8057a1931ceSMatthew G. Knepley   const PetscScalar  z1       = vertices[11];
806552f7358SJed Brown   const PetscScalar  x2       = vertices[6];
807552f7358SJed Brown   const PetscScalar  y2       = vertices[7];
808552f7358SJed Brown   const PetscScalar  z2       = vertices[8];
8097a1931ceSMatthew G. Knepley   const PetscScalar  x3       = vertices[3];
8107a1931ceSMatthew G. Knepley   const PetscScalar  y3       = vertices[4];
8117a1931ceSMatthew G. Knepley   const PetscScalar  z3       = vertices[5];
812552f7358SJed Brown   const PetscScalar  x4       = vertices[12];
813552f7358SJed Brown   const PetscScalar  y4       = vertices[13];
814552f7358SJed Brown   const PetscScalar  z4       = vertices[14];
815552f7358SJed Brown   const PetscScalar  x5       = vertices[15];
816552f7358SJed Brown   const PetscScalar  y5       = vertices[16];
817552f7358SJed Brown   const PetscScalar  z5       = vertices[17];
818552f7358SJed Brown   const PetscScalar  x6       = vertices[18];
819552f7358SJed Brown   const PetscScalar  y6       = vertices[19];
820552f7358SJed Brown   const PetscScalar  z6       = vertices[20];
821552f7358SJed Brown   const PetscScalar  x7       = vertices[21];
822552f7358SJed Brown   const PetscScalar  y7       = vertices[22];
823552f7358SJed Brown   const PetscScalar  z7       = vertices[23];
824552f7358SJed Brown   const PetscScalar  f_1      = x1 - x0;
825552f7358SJed Brown   const PetscScalar  g_1      = y1 - y0;
826552f7358SJed Brown   const PetscScalar  h_1      = z1 - z0;
827552f7358SJed Brown   const PetscScalar  f_3      = x3 - x0;
828552f7358SJed Brown   const PetscScalar  g_3      = y3 - y0;
829552f7358SJed Brown   const PetscScalar  h_3      = z3 - z0;
830552f7358SJed Brown   const PetscScalar  f_4      = x4 - x0;
831552f7358SJed Brown   const PetscScalar  g_4      = y4 - y0;
832552f7358SJed Brown   const PetscScalar  h_4      = z4 - z0;
833552f7358SJed Brown   const PetscScalar  f_01     = x2 - x1 - x3 + x0;
834552f7358SJed Brown   const PetscScalar  g_01     = y2 - y1 - y3 + y0;
835552f7358SJed Brown   const PetscScalar  h_01     = z2 - z1 - z3 + z0;
836552f7358SJed Brown   const PetscScalar  f_12     = x7 - x3 - x4 + x0;
837552f7358SJed Brown   const PetscScalar  g_12     = y7 - y3 - y4 + y0;
838552f7358SJed Brown   const PetscScalar  h_12     = z7 - z3 - z4 + z0;
839552f7358SJed Brown   const PetscScalar  f_02     = x5 - x1 - x4 + x0;
840552f7358SJed Brown   const PetscScalar  g_02     = y5 - y1 - y4 + y0;
841552f7358SJed Brown   const PetscScalar  h_02     = z5 - z1 - z4 + z0;
842552f7358SJed Brown   const PetscScalar  f_012    = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
843552f7358SJed Brown   const PetscScalar  g_012    = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
844552f7358SJed Brown   const PetscScalar  h_012    = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
84556044e6dSMatthew G. Knepley   const PetscScalar *ref;
84656044e6dSMatthew G. Knepley   PetscScalar       *real;
847552f7358SJed Brown 
848552f7358SJed Brown   PetscFunctionBegin;
8499566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref, &ref));
8509566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Xreal, &real));
851552f7358SJed Brown   {
852552f7358SJed Brown     const PetscScalar p0 = ref[0];
853552f7358SJed Brown     const PetscScalar p1 = ref[1];
854552f7358SJed Brown     const PetscScalar p2 = ref[2];
855552f7358SJed Brown 
856552f7358SJed 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;
857552f7358SJed 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;
858552f7358SJed 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;
859552f7358SJed Brown   }
8609566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(114));
8619566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref, &ref));
8629566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Xreal, &real));
8633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
864552f7358SJed Brown }
865552f7358SJed Brown 
866d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode HexJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
867d71ae5a4SJacob Faibussowitsch {
868552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar *)ctx;
869552f7358SJed Brown   const PetscScalar  x0       = vertices[0];
870552f7358SJed Brown   const PetscScalar  y0       = vertices[1];
871552f7358SJed Brown   const PetscScalar  z0       = vertices[2];
8727a1931ceSMatthew G. Knepley   const PetscScalar  x1       = vertices[9];
8737a1931ceSMatthew G. Knepley   const PetscScalar  y1       = vertices[10];
8747a1931ceSMatthew G. Knepley   const PetscScalar  z1       = vertices[11];
875552f7358SJed Brown   const PetscScalar  x2       = vertices[6];
876552f7358SJed Brown   const PetscScalar  y2       = vertices[7];
877552f7358SJed Brown   const PetscScalar  z2       = vertices[8];
8787a1931ceSMatthew G. Knepley   const PetscScalar  x3       = vertices[3];
8797a1931ceSMatthew G. Knepley   const PetscScalar  y3       = vertices[4];
8807a1931ceSMatthew G. Knepley   const PetscScalar  z3       = vertices[5];
881552f7358SJed Brown   const PetscScalar  x4       = vertices[12];
882552f7358SJed Brown   const PetscScalar  y4       = vertices[13];
883552f7358SJed Brown   const PetscScalar  z4       = vertices[14];
884552f7358SJed Brown   const PetscScalar  x5       = vertices[15];
885552f7358SJed Brown   const PetscScalar  y5       = vertices[16];
886552f7358SJed Brown   const PetscScalar  z5       = vertices[17];
887552f7358SJed Brown   const PetscScalar  x6       = vertices[18];
888552f7358SJed Brown   const PetscScalar  y6       = vertices[19];
889552f7358SJed Brown   const PetscScalar  z6       = vertices[20];
890552f7358SJed Brown   const PetscScalar  x7       = vertices[21];
891552f7358SJed Brown   const PetscScalar  y7       = vertices[22];
892552f7358SJed Brown   const PetscScalar  z7       = vertices[23];
893552f7358SJed Brown   const PetscScalar  f_xy     = x2 - x1 - x3 + x0;
894552f7358SJed Brown   const PetscScalar  g_xy     = y2 - y1 - y3 + y0;
895552f7358SJed Brown   const PetscScalar  h_xy     = z2 - z1 - z3 + z0;
896552f7358SJed Brown   const PetscScalar  f_yz     = x7 - x3 - x4 + x0;
897552f7358SJed Brown   const PetscScalar  g_yz     = y7 - y3 - y4 + y0;
898552f7358SJed Brown   const PetscScalar  h_yz     = z7 - z3 - z4 + z0;
899552f7358SJed Brown   const PetscScalar  f_xz     = x5 - x1 - x4 + x0;
900552f7358SJed Brown   const PetscScalar  g_xz     = y5 - y1 - y4 + y0;
901552f7358SJed Brown   const PetscScalar  h_xz     = z5 - z1 - z4 + z0;
902552f7358SJed Brown   const PetscScalar  f_xyz    = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
903552f7358SJed Brown   const PetscScalar  g_xyz    = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
904552f7358SJed Brown   const PetscScalar  h_xyz    = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
90556044e6dSMatthew G. Knepley   const PetscScalar *ref;
906552f7358SJed Brown 
907552f7358SJed Brown   PetscFunctionBegin;
9089566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref, &ref));
909552f7358SJed Brown   {
910552f7358SJed Brown     const PetscScalar x       = ref[0];
911552f7358SJed Brown     const PetscScalar y       = ref[1];
912552f7358SJed Brown     const PetscScalar z       = ref[2];
913552f7358SJed Brown     const PetscInt    rows[3] = {0, 1, 2};
914da80777bSKarl Rupp     PetscScalar       values[9];
915da80777bSKarl Rupp 
916da80777bSKarl Rupp     values[0] = (x1 - x0 + f_xy * y + f_xz * z + f_xyz * y * z) / 2.0;
917da80777bSKarl Rupp     values[1] = (x3 - x0 + f_xy * x + f_yz * z + f_xyz * x * z) / 2.0;
918da80777bSKarl Rupp     values[2] = (x4 - x0 + f_yz * y + f_xz * x + f_xyz * x * y) / 2.0;
919da80777bSKarl Rupp     values[3] = (y1 - y0 + g_xy * y + g_xz * z + g_xyz * y * z) / 2.0;
920da80777bSKarl Rupp     values[4] = (y3 - y0 + g_xy * x + g_yz * z + g_xyz * x * z) / 2.0;
921da80777bSKarl Rupp     values[5] = (y4 - y0 + g_yz * y + g_xz * x + g_xyz * x * y) / 2.0;
922da80777bSKarl Rupp     values[6] = (z1 - z0 + h_xy * y + h_xz * z + h_xyz * y * z) / 2.0;
923da80777bSKarl Rupp     values[7] = (z3 - z0 + h_xy * x + h_yz * z + h_xyz * x * z) / 2.0;
924da80777bSKarl Rupp     values[8] = (z4 - z0 + h_yz * y + h_xz * x + h_xyz * x * y) / 2.0;
9251aa26658SKarl Rupp 
9269566063dSJacob Faibussowitsch     PetscCall(MatSetValues(J, 3, rows, 3, rows, values, INSERT_VALUES));
927552f7358SJed Brown   }
9289566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(152));
9299566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref, &ref));
9309566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
9319566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
9323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
933552f7358SJed Brown }
934552f7358SJed Brown 
935d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Hex_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
936d71ae5a4SJacob Faibussowitsch {
937fafc0619SMatthew G Knepley   DM                 dmCoord;
938552f7358SJed Brown   SNES               snes;
939552f7358SJed Brown   KSP                ksp;
940552f7358SJed Brown   PC                 pc;
941552f7358SJed Brown   Vec                coordsLocal, r, ref, real;
942552f7358SJed Brown   Mat                J;
94356044e6dSMatthew G. Knepley   const PetscScalar *coords;
94456044e6dSMatthew G. Knepley   PetscScalar       *a;
945552f7358SJed Brown   PetscInt           p;
946552f7358SJed Brown 
947552f7358SJed Brown   PetscFunctionBegin;
9489566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
9499566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &dmCoord));
9509566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
9519566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes, "hex_interp_"));
9529566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &r));
9539566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(r, 3, 3));
9549566063dSJacob Faibussowitsch   PetscCall(VecSetType(r, dm->vectype));
9559566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &ref));
9569566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &real));
9579566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &J));
9589566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(J, 3, 3, 3, 3));
9599566063dSJacob Faibussowitsch   PetscCall(MatSetType(J, MATSEQDENSE));
9609566063dSJacob Faibussowitsch   PetscCall(MatSetUp(J));
9619566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes, r, HexMap_Private, NULL));
9629566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes, J, J, HexJacobian_Private, NULL));
9639566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(snes, &ksp));
9649566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(ksp, &pc));
9659566063dSJacob Faibussowitsch   PetscCall(PCSetType(pc, PCLU));
9669566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
967552f7358SJed Brown 
9689566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
9699566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
970552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
971a1e44745SMatthew G. Knepley     PetscScalar *x = NULL, *vertices = NULL;
972552f7358SJed Brown     PetscScalar *xi;
973cb313848SJed Brown     PetscReal    xir[3];
974552f7358SJed Brown     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
975552f7358SJed Brown 
976552f7358SJed Brown     /* Can make this do all points at once */
9779566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
978cfe5744fSMatthew G. Knepley     PetscCheck(8 * 3 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid coordinate closure size %" PetscInt_FMT " should be %d", coordSize, 8 * 3);
9799566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
980cfe5744fSMatthew 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);
9819566063dSJacob Faibussowitsch     PetscCall(SNESSetFunction(snes, NULL, NULL, vertices));
9829566063dSJacob Faibussowitsch     PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
9839566063dSJacob Faibussowitsch     PetscCall(VecGetArray(real, &xi));
984552f7358SJed Brown     xi[0] = coords[p * ctx->dim + 0];
985552f7358SJed Brown     xi[1] = coords[p * ctx->dim + 1];
986552f7358SJed Brown     xi[2] = coords[p * ctx->dim + 2];
9879566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(real, &xi));
9889566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes, real, ref));
9899566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ref, &xi));
990cb313848SJed Brown     xir[0] = PetscRealPart(xi[0]);
991cb313848SJed Brown     xir[1] = PetscRealPart(xi[1]);
992cb313848SJed Brown     xir[2] = PetscRealPart(xi[2]);
993cfe5744fSMatthew G. Knepley     if (8 * ctx->dof == xSize) {
994552f7358SJed Brown       for (comp = 0; comp < ctx->dof; ++comp) {
9959371c9d4SSatish 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]) +
9969371c9d4SSatish 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];
997552f7358SJed Brown       }
998cfe5744fSMatthew G. Knepley     } else {
999cfe5744fSMatthew G. Knepley       for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp];
1000cfe5744fSMatthew G. Knepley     }
10019566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ref, &xi));
10029566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
10039566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
1004552f7358SJed Brown   }
10059566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
10069566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
1007552f7358SJed Brown 
10089566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
10099566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
10109566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ref));
10119566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&real));
10129566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
10133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1014552f7358SJed Brown }
1015552f7358SJed Brown 
10164267b1a3SMatthew G. Knepley /*@C
10174267b1a3SMatthew G. Knepley   DMInterpolationEvaluate - Using the input from dm and x, calculates interpolated field values at the interpolation points.
10184267b1a3SMatthew G. Knepley 
1019552f7358SJed Brown   Input Parameters:
1020f6dfbefdSBarry Smith + ctx - The `DMInterpolationInfo` context
1021f6dfbefdSBarry Smith . dm  - The `DM`
1022552f7358SJed Brown - x   - The local vector containing the field to be interpolated
1023552f7358SJed Brown 
10242fe279fdSBarry Smith   Output Parameter:
1025552f7358SJed Brown . v - The vector containing the interpolated values
10264267b1a3SMatthew G. Knepley 
10274267b1a3SMatthew G. Knepley   Level: beginner
10284267b1a3SMatthew G. Knepley 
10292fe279fdSBarry Smith   Note:
10302fe279fdSBarry Smith   A suitable `v` can be obtained using `DMInterpolationGetVector()`.
10312fe279fdSBarry Smith 
1032f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
10334267b1a3SMatthew G. Knepley @*/
1034d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationEvaluate(DMInterpolationInfo ctx, DM dm, Vec x, Vec v)
1035d71ae5a4SJacob Faibussowitsch {
103666a0a883SMatthew G. Knepley   PetscDS   ds;
103766a0a883SMatthew G. Knepley   PetscInt  n, p, Nf, field;
103866a0a883SMatthew G. Knepley   PetscBool useDS = PETSC_FALSE;
1039552f7358SJed Brown 
1040552f7358SJed Brown   PetscFunctionBegin;
1041552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1042552f7358SJed Brown   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
1043552f7358SJed Brown   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
10449566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
104563a3b9bcSJacob 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);
10463ba16761SJacob Faibussowitsch   if (!n) PetscFunctionReturn(PETSC_SUCCESS);
10479566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
1048680d18d5SMatthew G. Knepley   if (ds) {
104966a0a883SMatthew G. Knepley     useDS = PETSC_TRUE;
10509566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(ds, &Nf));
1051680d18d5SMatthew G. Knepley     for (field = 0; field < Nf; ++field) {
105266a0a883SMatthew G. Knepley       PetscObject  obj;
1053680d18d5SMatthew G. Knepley       PetscClassId id;
1054680d18d5SMatthew G. Knepley 
10559566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, field, &obj));
10569566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
10579371c9d4SSatish Balay       if (id != PETSCFE_CLASSID) {
10589371c9d4SSatish Balay         useDS = PETSC_FALSE;
10599371c9d4SSatish Balay         break;
10609371c9d4SSatish Balay       }
106166a0a883SMatthew G. Knepley     }
106266a0a883SMatthew G. Knepley   }
106366a0a883SMatthew G. Knepley   if (useDS) {
106466a0a883SMatthew G. Knepley     const PetscScalar *coords;
106566a0a883SMatthew G. Knepley     PetscScalar       *interpolant;
106666a0a883SMatthew G. Knepley     PetscInt           cdim, d;
106766a0a883SMatthew G. Knepley 
10689566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &cdim));
10699566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ctx->coords, &coords));
10709566063dSJacob Faibussowitsch     PetscCall(VecGetArrayWrite(v, &interpolant));
1071680d18d5SMatthew G. Knepley     for (p = 0; p < ctx->n; ++p) {
107266a0a883SMatthew G. Knepley       PetscReal    pcoords[3], xi[3];
1073680d18d5SMatthew G. Knepley       PetscScalar *xa   = NULL;
107466a0a883SMatthew G. Knepley       PetscInt     coff = 0, foff = 0, clSize;
1075680d18d5SMatthew G. Knepley 
107652aa1562SMatthew G. Knepley       if (ctx->cells[p] < 0) continue;
1077680d18d5SMatthew G. Knepley       for (d = 0; d < cdim; ++d) pcoords[d] = PetscRealPart(coords[p * cdim + d]);
10789566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference(dm, ctx->cells[p], 1, pcoords, xi));
10799566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
108066a0a883SMatthew G. Knepley       for (field = 0; field < Nf; ++field) {
108166a0a883SMatthew G. Knepley         PetscTabulation T;
108266a0a883SMatthew G. Knepley         PetscFE         fe;
108366a0a883SMatthew G. Knepley 
10849566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
10859566063dSJacob Faibussowitsch         PetscCall(PetscFECreateTabulation(fe, 1, 1, xi, 0, &T));
1086680d18d5SMatthew G. Knepley         {
1087680d18d5SMatthew G. Knepley           const PetscReal *basis = T->T[0];
1088680d18d5SMatthew G. Knepley           const PetscInt   Nb    = T->Nb;
1089680d18d5SMatthew G. Knepley           const PetscInt   Nc    = T->Nc;
109066a0a883SMatthew G. Knepley           PetscInt         f, fc;
109166a0a883SMatthew G. Knepley 
1092680d18d5SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
109366a0a883SMatthew G. Knepley             interpolant[p * ctx->dof + coff + fc] = 0.0;
1094ad540459SPierre Jolivet             for (f = 0; f < Nb; ++f) interpolant[p * ctx->dof + coff + fc] += xa[foff + f] * basis[(0 * Nb + f) * Nc + fc];
1095680d18d5SMatthew G. Knepley           }
109666a0a883SMatthew G. Knepley           coff += Nc;
109766a0a883SMatthew G. Knepley           foff += Nb;
1098680d18d5SMatthew G. Knepley         }
10999566063dSJacob Faibussowitsch         PetscCall(PetscTabulationDestroy(&T));
1100680d18d5SMatthew G. Knepley       }
11019566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
110263a3b9bcSJacob Faibussowitsch       PetscCheck(coff == ctx->dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total components %" PetscInt_FMT " != %" PetscInt_FMT " dof specified for interpolation", coff, ctx->dof);
110363a3b9bcSJacob Faibussowitsch       PetscCheck(foff == clSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total FE space size %" PetscInt_FMT " != %" PetscInt_FMT " closure size", foff, clSize);
110466a0a883SMatthew G. Knepley     }
11059566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
11069566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayWrite(v, &interpolant));
110766a0a883SMatthew G. Knepley   } else {
110866a0a883SMatthew G. Knepley     DMPolytopeType ct;
110966a0a883SMatthew G. Knepley 
1110680d18d5SMatthew G. Knepley     /* TODO Check each cell individually */
11119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, ctx->cells[0], &ct));
1112680d18d5SMatthew G. Knepley     switch (ct) {
1113d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_SEGMENT:
1114d71ae5a4SJacob Faibussowitsch       PetscCall(DMInterpolate_Segment_Private(ctx, dm, x, v));
1115d71ae5a4SJacob Faibussowitsch       break;
1116d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_TRIANGLE:
1117d71ae5a4SJacob Faibussowitsch       PetscCall(DMInterpolate_Triangle_Private(ctx, dm, x, v));
1118d71ae5a4SJacob Faibussowitsch       break;
1119d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_QUADRILATERAL:
1120d71ae5a4SJacob Faibussowitsch       PetscCall(DMInterpolate_Quad_Private(ctx, dm, x, v));
1121d71ae5a4SJacob Faibussowitsch       break;
1122d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_TETRAHEDRON:
1123d71ae5a4SJacob Faibussowitsch       PetscCall(DMInterpolate_Tetrahedron_Private(ctx, dm, x, v));
1124d71ae5a4SJacob Faibussowitsch       break;
1125d71ae5a4SJacob Faibussowitsch     case DM_POLYTOPE_HEXAHEDRON:
1126d71ae5a4SJacob Faibussowitsch       PetscCall(DMInterpolate_Hex_Private(ctx, dm, x, v));
1127d71ae5a4SJacob Faibussowitsch       break;
1128d71ae5a4SJacob Faibussowitsch     default:
1129d71ae5a4SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for cell type %s", DMPolytopeTypes[PetscMax(0, PetscMin(ct, DM_NUM_POLYTOPES))]);
1130680d18d5SMatthew G. Knepley     }
1131552f7358SJed Brown   }
11323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1133552f7358SJed Brown }
1134552f7358SJed Brown 
11354267b1a3SMatthew G. Knepley /*@C
1136f6dfbefdSBarry Smith   DMInterpolationDestroy - Destroys a `DMInterpolationInfo` context
11374267b1a3SMatthew G. Knepley 
1138c3339decSBarry Smith   Collective
11394267b1a3SMatthew G. Knepley 
11404267b1a3SMatthew G. Knepley   Input Parameter:
11414267b1a3SMatthew G. Knepley . ctx - the context
11424267b1a3SMatthew G. Knepley 
11434267b1a3SMatthew G. Knepley   Level: beginner
11444267b1a3SMatthew G. Knepley 
1145f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
11464267b1a3SMatthew G. Knepley @*/
1147d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationDestroy(DMInterpolationInfo *ctx)
1148d71ae5a4SJacob Faibussowitsch {
1149552f7358SJed Brown   PetscFunctionBegin;
11504f572ea9SToby Isaac   PetscAssertPointer(ctx, 1);
11519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(*ctx)->coords));
11529566063dSJacob Faibussowitsch   PetscCall(PetscFree((*ctx)->points));
11539566063dSJacob Faibussowitsch   PetscCall(PetscFree((*ctx)->cells));
11549566063dSJacob Faibussowitsch   PetscCall(PetscFree(*ctx));
11550298fd71SBarry Smith   *ctx = NULL;
11563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1157552f7358SJed Brown }
1158cc0c4584SMatthew G. Knepley 
1159cc0c4584SMatthew G. Knepley /*@C
1160cc0c4584SMatthew G. Knepley   SNESMonitorFields - Monitors the residual for each field separately
1161cc0c4584SMatthew G. Knepley 
1162c3339decSBarry Smith   Collective
1163cc0c4584SMatthew G. Knepley 
1164cc0c4584SMatthew G. Knepley   Input Parameters:
1165f6dfbefdSBarry Smith + snes   - the `SNES` context
1166cc0c4584SMatthew G. Knepley . its    - iteration number
1167cc0c4584SMatthew G. Knepley . fgnorm - 2-norm of residual
1168f6dfbefdSBarry Smith - vf     - `PetscViewerAndFormat` of `PetscViewerType` `PETSCVIEWERASCII`
1169cc0c4584SMatthew G. Knepley 
11702fe279fdSBarry Smith   Level: intermediate
11712fe279fdSBarry Smith 
1172f6dfbefdSBarry Smith   Note:
1173cc0c4584SMatthew G. Knepley   This routine prints the residual norm at each iteration.
1174cc0c4584SMatthew G. Knepley 
1175f6dfbefdSBarry Smith .seealso: `SNES`, `SNESMonitorSet()`, `SNESMonitorDefault()`
1176cc0c4584SMatthew G. Knepley @*/
1177d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
1178d71ae5a4SJacob Faibussowitsch {
1179d43b4f6eSBarry Smith   PetscViewer        viewer = vf->viewer;
1180cc0c4584SMatthew G. Knepley   Vec                res;
1181cc0c4584SMatthew G. Knepley   DM                 dm;
1182cc0c4584SMatthew G. Knepley   PetscSection       s;
1183cc0c4584SMatthew G. Knepley   const PetscScalar *r;
1184cc0c4584SMatthew G. Knepley   PetscReal         *lnorms, *norms;
1185cc0c4584SMatthew G. Knepley   PetscInt           numFields, f, pStart, pEnd, p;
1186cc0c4584SMatthew G. Knepley 
1187cc0c4584SMatthew G. Knepley   PetscFunctionBegin;
11884d4332d5SBarry Smith   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
11899566063dSJacob Faibussowitsch   PetscCall(SNESGetFunction(snes, &res, NULL, NULL));
11909566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
11919566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
11929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &numFields));
11939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
11949566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &lnorms, numFields, &norms));
11959566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(res, &r));
1196cc0c4584SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
1197cc0c4584SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
1198cc0c4584SMatthew G. Knepley       PetscInt fdof, foff, d;
1199cc0c4584SMatthew G. Knepley 
12009566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof));
12019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff));
1202cc0c4584SMatthew G. Knepley       for (d = 0; d < fdof; ++d) lnorms[f] += PetscRealPart(PetscSqr(r[foff + d]));
1203cc0c4584SMatthew G. Knepley     }
1204cc0c4584SMatthew G. Knepley   }
12059566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(res, &r));
12061c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(lnorms, norms, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
12079566063dSJacob Faibussowitsch   PetscCall(PetscViewerPushFormat(viewer, vf->format));
12089566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
120963a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e [", its, (double)fgnorm));
1210cc0c4584SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
12119566063dSJacob Faibussowitsch     if (f > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
12129566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "%14.12e", (double)PetscSqrtReal(norms[f])));
1213cc0c4584SMatthew G. Knepley   }
12149566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "]\n"));
12159566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
12169566063dSJacob Faibussowitsch   PetscCall(PetscViewerPopFormat(viewer));
12179566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lnorms, norms));
12183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1219cc0c4584SMatthew G. Knepley }
122024cdb843SMatthew G. Knepley 
122124cdb843SMatthew G. Knepley /********************* Residual Computation **************************/
122224cdb843SMatthew G. Knepley 
1223d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
1224d71ae5a4SJacob Faibussowitsch {
12256528b96dSMatthew G. Knepley   PetscInt depth;
12266528b96dSMatthew G. Knepley 
12276528b96dSMatthew G. Knepley   PetscFunctionBegin;
12289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(plex, &depth));
12299566063dSJacob Faibussowitsch   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
12309566063dSJacob Faibussowitsch   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
12313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12326528b96dSMatthew G. Knepley }
12336528b96dSMatthew G. Knepley 
123424cdb843SMatthew G. Knepley /*@
12358db23a53SJed Brown   DMPlexSNESComputeResidualFEM - Sums the local residual into vector F from the local input X using pointwise functions specified by the user
123624cdb843SMatthew G. Knepley 
123724cdb843SMatthew G. Knepley   Input Parameters:
123824cdb843SMatthew G. Knepley + dm   - The mesh
123924cdb843SMatthew G. Knepley . X    - Local solution
124024cdb843SMatthew G. Knepley - user - The user context
124124cdb843SMatthew G. Knepley 
124224cdb843SMatthew G. Knepley   Output Parameter:
124324cdb843SMatthew G. Knepley . F - Local output vector
124424cdb843SMatthew G. Knepley 
12452fe279fdSBarry Smith   Level: developer
12462fe279fdSBarry Smith 
1247f6dfbefdSBarry Smith   Note:
1248f6dfbefdSBarry Smith   The residual is summed into F; the caller is responsible for using `VecZeroEntries()` or otherwise ensuring that any data in F is intentional.
12498db23a53SJed Brown 
1250f6dfbefdSBarry Smith .seealso: `DM`, `DMPlexComputeJacobianAction()`
125124cdb843SMatthew G. Knepley @*/
1252d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
1253d71ae5a4SJacob Faibussowitsch {
12546da023fcSToby Isaac   DM       plex;
1255083401c6SMatthew G. Knepley   IS       allcellIS;
12566528b96dSMatthew G. Knepley   PetscInt Nds, s;
125724cdb843SMatthew G. Knepley 
125824cdb843SMatthew G. Knepley   PetscFunctionBegin;
12599566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
12609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
12619566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
12626528b96dSMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
12636528b96dSMatthew G. Knepley     PetscDS      ds;
12646528b96dSMatthew G. Knepley     IS           cellIS;
126506ad1575SMatthew G. Knepley     PetscFormKey key;
12666528b96dSMatthew G. Knepley 
126707218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds, NULL));
12686528b96dSMatthew G. Knepley     key.value = 0;
12696528b96dSMatthew G. Knepley     key.field = 0;
127006ad1575SMatthew G. Knepley     key.part  = 0;
12716528b96dSMatthew G. Knepley     if (!key.label) {
12729566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)allcellIS));
12736528b96dSMatthew G. Knepley       cellIS = allcellIS;
12746528b96dSMatthew G. Knepley     } else {
12756528b96dSMatthew G. Knepley       IS pointIS;
12766528b96dSMatthew G. Knepley 
12776528b96dSMatthew G. Knepley       key.value = 1;
12789566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
12799566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
12809566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
12816528b96dSMatthew G. Knepley     }
12829566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeResidual_Internal(plex, key, cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user));
12839566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
12846528b96dSMatthew G. Knepley   }
12859566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
12869566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
12873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12886528b96dSMatthew G. Knepley }
12896528b96dSMatthew G. Knepley 
1290d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESComputeResidual(DM dm, Vec X, Vec F, void *user)
1291d71ae5a4SJacob Faibussowitsch {
12926528b96dSMatthew G. Knepley   DM       plex;
12936528b96dSMatthew G. Knepley   IS       allcellIS;
12946528b96dSMatthew G. Knepley   PetscInt Nds, s;
12956528b96dSMatthew G. Knepley 
12966528b96dSMatthew G. Knepley   PetscFunctionBegin;
12979566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
12989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
12999566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
1300083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1301083401c6SMatthew G. Knepley     PetscDS ds;
1302083401c6SMatthew G. Knepley     DMLabel label;
1303083401c6SMatthew G. Knepley     IS      cellIS;
1304083401c6SMatthew G. Knepley 
130507218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds, NULL));
13066528b96dSMatthew G. Knepley     {
130706ad1575SMatthew G. Knepley       PetscWeakFormKind resmap[2] = {PETSC_WF_F0, PETSC_WF_F1};
13086528b96dSMatthew G. Knepley       PetscWeakForm     wf;
13096528b96dSMatthew G. Knepley       PetscInt          Nm = 2, m, Nk = 0, k, kp, off = 0;
131006ad1575SMatthew G. Knepley       PetscFormKey     *reskeys;
13116528b96dSMatthew G. Knepley 
13126528b96dSMatthew G. Knepley       /* Get unique residual keys */
13136528b96dSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
13146528b96dSMatthew G. Knepley         PetscInt Nkm;
13159566063dSJacob Faibussowitsch         PetscCall(PetscHMapFormGetSize(ds->wf->form[resmap[m]], &Nkm));
13166528b96dSMatthew G. Knepley         Nk += Nkm;
13176528b96dSMatthew G. Knepley       }
13189566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nk, &reskeys));
131948a46eb9SPierre Jolivet       for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[resmap[m]], &off, reskeys));
132063a3b9bcSJacob Faibussowitsch       PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk);
13219566063dSJacob Faibussowitsch       PetscCall(PetscFormKeySort(Nk, reskeys));
13226528b96dSMatthew G. Knepley       for (k = 0, kp = 1; kp < Nk; ++kp) {
13236528b96dSMatthew G. Knepley         if ((reskeys[k].label != reskeys[kp].label) || (reskeys[k].value != reskeys[kp].value)) {
13246528b96dSMatthew G. Knepley           ++k;
13256528b96dSMatthew G. Knepley           if (kp != k) reskeys[k] = reskeys[kp];
13266528b96dSMatthew G. Knepley         }
13276528b96dSMatthew G. Knepley       }
13286528b96dSMatthew G. Knepley       Nk = k;
13296528b96dSMatthew G. Knepley 
13309566063dSJacob Faibussowitsch       PetscCall(PetscDSGetWeakForm(ds, &wf));
13316528b96dSMatthew G. Knepley       for (k = 0; k < Nk; ++k) {
13326528b96dSMatthew G. Knepley         DMLabel  label = reskeys[k].label;
13336528b96dSMatthew G. Knepley         PetscInt val   = reskeys[k].value;
13346528b96dSMatthew G. Knepley 
1335083401c6SMatthew G. Knepley         if (!label) {
13369566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)allcellIS));
1337083401c6SMatthew G. Knepley           cellIS = allcellIS;
1338083401c6SMatthew G. Knepley         } else {
1339083401c6SMatthew G. Knepley           IS pointIS;
1340083401c6SMatthew G. Knepley 
13419566063dSJacob Faibussowitsch           PetscCall(DMLabelGetStratumIS(label, val, &pointIS));
13429566063dSJacob Faibussowitsch           PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
13439566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&pointIS));
13444a3e9fdbSToby Isaac         }
13459566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeResidual_Internal(plex, reskeys[k], cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user));
13469566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&cellIS));
1347083401c6SMatthew G. Knepley       }
13489566063dSJacob Faibussowitsch       PetscCall(PetscFree(reskeys));
13496528b96dSMatthew G. Knepley     }
13506528b96dSMatthew G. Knepley   }
13519566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
13529566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
13533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
135424cdb843SMatthew G. Knepley }
135524cdb843SMatthew G. Knepley 
1356bdd6f66aSToby Isaac /*@
1357bdd6f66aSToby Isaac   DMPlexSNESComputeBoundaryFEM - Form the boundary values for the local input X
1358bdd6f66aSToby Isaac 
1359bdd6f66aSToby Isaac   Input Parameters:
1360bdd6f66aSToby Isaac + dm   - The mesh
1361bdd6f66aSToby Isaac - user - The user context
1362bdd6f66aSToby Isaac 
1363bdd6f66aSToby Isaac   Output Parameter:
1364bdd6f66aSToby Isaac . X - Local solution
1365bdd6f66aSToby Isaac 
1366bdd6f66aSToby Isaac   Level: developer
1367bdd6f66aSToby Isaac 
1368f6dfbefdSBarry Smith .seealso: `DMPLEX`, `DMPlexComputeJacobianAction()`
1369bdd6f66aSToby Isaac @*/
1370d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeBoundaryFEM(DM dm, Vec X, void *user)
1371d71ae5a4SJacob Faibussowitsch {
1372bdd6f66aSToby Isaac   DM plex;
1373bdd6f66aSToby Isaac 
1374bdd6f66aSToby Isaac   PetscFunctionBegin;
13759566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
13769566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, X, PETSC_MIN_REAL, NULL, NULL, NULL));
13779566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
13783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1379bdd6f66aSToby Isaac }
1380bdd6f66aSToby Isaac 
13817a73cf09SMatthew G. Knepley /*@
13828e3a2eefSMatthew G. Knepley   DMSNESComputeJacobianAction - Compute the action of the Jacobian J(X) on Y
13837a73cf09SMatthew G. Knepley 
13847a73cf09SMatthew G. Knepley   Input Parameters:
1385f6dfbefdSBarry Smith + dm   - The `DM`
13867a73cf09SMatthew G. Knepley . X    - Local solution vector
13877a73cf09SMatthew G. Knepley . Y    - Local input vector
13887a73cf09SMatthew G. Knepley - user - The user context
13897a73cf09SMatthew G. Knepley 
13907a73cf09SMatthew G. Knepley   Output Parameter:
139169d47153SPierre Jolivet . F - local output vector
13927a73cf09SMatthew G. Knepley 
13937a73cf09SMatthew G. Knepley   Level: developer
13947a73cf09SMatthew G. Knepley 
13958e3a2eefSMatthew G. Knepley   Notes:
1396f6dfbefdSBarry Smith   Users will typically use `DMSNESCreateJacobianMF()` followed by `MatMult()` instead of calling this routine directly.
13978e3a2eefSMatthew G. Knepley 
1398f6dfbefdSBarry Smith .seealso: `DM`, ``DMSNESCreateJacobianMF()`, `DMPlexSNESComputeResidualFEM()`
13997a73cf09SMatthew G. Knepley @*/
1400d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESComputeJacobianAction(DM dm, Vec X, Vec Y, Vec F, void *user)
1401d71ae5a4SJacob Faibussowitsch {
14028e3a2eefSMatthew G. Knepley   DM       plex;
14038e3a2eefSMatthew G. Knepley   IS       allcellIS;
14048e3a2eefSMatthew G. Knepley   PetscInt Nds, s;
1405a925c78cSMatthew G. Knepley 
1406a925c78cSMatthew G. Knepley   PetscFunctionBegin;
14079566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
14089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
14099566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
14108e3a2eefSMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
14118e3a2eefSMatthew G. Knepley     PetscDS ds;
14128e3a2eefSMatthew G. Knepley     DMLabel label;
14138e3a2eefSMatthew G. Knepley     IS      cellIS;
14147a73cf09SMatthew G. Knepley 
141507218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds, NULL));
14168e3a2eefSMatthew G. Knepley     {
141706ad1575SMatthew G. Knepley       PetscWeakFormKind jacmap[4] = {PETSC_WF_G0, PETSC_WF_G1, PETSC_WF_G2, PETSC_WF_G3};
14188e3a2eefSMatthew G. Knepley       PetscWeakForm     wf;
14198e3a2eefSMatthew G. Knepley       PetscInt          Nm = 4, m, Nk = 0, k, kp, off = 0;
142006ad1575SMatthew G. Knepley       PetscFormKey     *jackeys;
14218e3a2eefSMatthew G. Knepley 
14228e3a2eefSMatthew G. Knepley       /* Get unique Jacobian keys */
14238e3a2eefSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
14248e3a2eefSMatthew G. Knepley         PetscInt Nkm;
14259566063dSJacob Faibussowitsch         PetscCall(PetscHMapFormGetSize(ds->wf->form[jacmap[m]], &Nkm));
14268e3a2eefSMatthew G. Knepley         Nk += Nkm;
14278e3a2eefSMatthew G. Knepley       }
14289566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nk, &jackeys));
142948a46eb9SPierre Jolivet       for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[jacmap[m]], &off, jackeys));
143063a3b9bcSJacob Faibussowitsch       PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk);
14319566063dSJacob Faibussowitsch       PetscCall(PetscFormKeySort(Nk, jackeys));
14328e3a2eefSMatthew G. Knepley       for (k = 0, kp = 1; kp < Nk; ++kp) {
14338e3a2eefSMatthew G. Knepley         if ((jackeys[k].label != jackeys[kp].label) || (jackeys[k].value != jackeys[kp].value)) {
14348e3a2eefSMatthew G. Knepley           ++k;
14358e3a2eefSMatthew G. Knepley           if (kp != k) jackeys[k] = jackeys[kp];
14368e3a2eefSMatthew G. Knepley         }
14378e3a2eefSMatthew G. Knepley       }
14388e3a2eefSMatthew G. Knepley       Nk = k;
14398e3a2eefSMatthew G. Knepley 
14409566063dSJacob Faibussowitsch       PetscCall(PetscDSGetWeakForm(ds, &wf));
14418e3a2eefSMatthew G. Knepley       for (k = 0; k < Nk; ++k) {
14428e3a2eefSMatthew G. Knepley         DMLabel  label = jackeys[k].label;
14438e3a2eefSMatthew G. Knepley         PetscInt val   = jackeys[k].value;
14448e3a2eefSMatthew G. Knepley 
14458e3a2eefSMatthew G. Knepley         if (!label) {
14469566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)allcellIS));
14478e3a2eefSMatthew G. Knepley           cellIS = allcellIS;
14487a73cf09SMatthew G. Knepley         } else {
14498e3a2eefSMatthew G. Knepley           IS pointIS;
1450a925c78cSMatthew G. Knepley 
14519566063dSJacob Faibussowitsch           PetscCall(DMLabelGetStratumIS(label, val, &pointIS));
14529566063dSJacob Faibussowitsch           PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
14539566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&pointIS));
1454a925c78cSMatthew G. Knepley         }
14559566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeJacobian_Action_Internal(plex, jackeys[k], cellIS, 0.0, 0.0, X, NULL, Y, F, user));
14569566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&cellIS));
14578e3a2eefSMatthew G. Knepley       }
14589566063dSJacob Faibussowitsch       PetscCall(PetscFree(jackeys));
14598e3a2eefSMatthew G. Knepley     }
14608e3a2eefSMatthew G. Knepley   }
14619566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
14629566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
14633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1464a925c78cSMatthew G. Knepley }
1465a925c78cSMatthew G. Knepley 
146624cdb843SMatthew G. Knepley /*@
14672fe279fdSBarry Smith   DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix `Jac` at the local solution `X` using pointwise functions specified by the user.
146824cdb843SMatthew G. Knepley 
146924cdb843SMatthew G. Knepley   Input Parameters:
14702fe279fdSBarry Smith + dm   - The `DM`
147124cdb843SMatthew G. Knepley . X    - Local input vector
147224cdb843SMatthew G. Knepley - user - The user context
147324cdb843SMatthew G. Knepley 
14742fe279fdSBarry Smith   Output Parameters:
14752fe279fdSBarry Smith + Jac  - Jacobian matrix
14762fe279fdSBarry Smith - JacP - approximate Jacobian from which the preconditioner will be built, often `Jac`
14772fe279fdSBarry Smith 
14782fe279fdSBarry Smith   Level: developer
147924cdb843SMatthew G. Knepley 
148024cdb843SMatthew G. Knepley   Note:
148124cdb843SMatthew G. Knepley   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
148224cdb843SMatthew G. Knepley   like a GPU, or vectorize on a multicore machine.
148324cdb843SMatthew G. Knepley 
1484f6dfbefdSBarry Smith .seealso: `DMPLEX`, `Mat`
148524cdb843SMatthew G. Knepley @*/
1486d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, void *user)
1487d71ae5a4SJacob Faibussowitsch {
14886da023fcSToby Isaac   DM        plex;
1489083401c6SMatthew G. Knepley   IS        allcellIS;
1490f04eb4edSMatthew G. Knepley   PetscBool hasJac, hasPrec;
14916528b96dSMatthew G. Knepley   PetscInt  Nds, s;
149224cdb843SMatthew G. Knepley 
149324cdb843SMatthew G. Knepley   PetscFunctionBegin;
14949566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
14959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
14969566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
1497083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1498083401c6SMatthew G. Knepley     PetscDS      ds;
1499083401c6SMatthew G. Knepley     IS           cellIS;
150006ad1575SMatthew G. Knepley     PetscFormKey key;
1501083401c6SMatthew G. Knepley 
150207218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds, NULL));
15036528b96dSMatthew G. Knepley     key.value = 0;
15046528b96dSMatthew G. Knepley     key.field = 0;
150506ad1575SMatthew G. Knepley     key.part  = 0;
15066528b96dSMatthew G. Knepley     if (!key.label) {
15079566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)allcellIS));
1508083401c6SMatthew G. Knepley       cellIS = allcellIS;
1509083401c6SMatthew G. Knepley     } else {
1510083401c6SMatthew G. Knepley       IS pointIS;
1511083401c6SMatthew G. Knepley 
15126528b96dSMatthew G. Knepley       key.value = 1;
15139566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
15149566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
15159566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
1516083401c6SMatthew G. Knepley     }
1517083401c6SMatthew G. Knepley     if (!s) {
15189566063dSJacob Faibussowitsch       PetscCall(PetscDSHasJacobian(ds, &hasJac));
15199566063dSJacob Faibussowitsch       PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
15209566063dSJacob Faibussowitsch       if (hasJac && hasPrec) PetscCall(MatZeroEntries(Jac));
15219566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(JacP));
1522083401c6SMatthew G. Knepley     }
15239566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeJacobian_Internal(plex, key, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, user));
15249566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
1525083401c6SMatthew G. Knepley   }
15269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
15279566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
15283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
152924cdb843SMatthew G. Knepley }
15301878804aSMatthew G. Knepley 
15319371c9d4SSatish Balay struct _DMSNESJacobianMFCtx {
15328e3a2eefSMatthew G. Knepley   DM    dm;
15338e3a2eefSMatthew G. Knepley   Vec   X;
15348e3a2eefSMatthew G. Knepley   void *ctx;
15358e3a2eefSMatthew G. Knepley };
15368e3a2eefSMatthew G. Knepley 
1537d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Destroy_Private(Mat A)
1538d71ae5a4SJacob Faibussowitsch {
15398e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15408e3a2eefSMatthew G. Knepley 
15418e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15429566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
15439566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(A, NULL));
15449566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&ctx->dm));
15459566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ctx->X));
15469566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
15473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15488e3a2eefSMatthew G. Knepley }
15498e3a2eefSMatthew G. Knepley 
1550d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Mult_Private(Mat A, Vec Y, Vec Z)
1551d71ae5a4SJacob Faibussowitsch {
15528e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15538e3a2eefSMatthew G. Knepley 
15548e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15559566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
15569566063dSJacob Faibussowitsch   PetscCall(DMSNESComputeJacobianAction(ctx->dm, ctx->X, Y, Z, ctx->ctx));
15573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15588e3a2eefSMatthew G. Knepley }
15598e3a2eefSMatthew G. Knepley 
15608e3a2eefSMatthew G. Knepley /*@
1561f6dfbefdSBarry Smith   DMSNESCreateJacobianMF - Create a `Mat` which computes the action of the Jacobian matrix-free
15628e3a2eefSMatthew G. Knepley 
1563c3339decSBarry Smith   Collective
15648e3a2eefSMatthew G. Knepley 
15658e3a2eefSMatthew G. Knepley   Input Parameters:
1566f6dfbefdSBarry Smith + dm   - The `DM`
15678e3a2eefSMatthew G. Knepley . X    - The evaluation point for the Jacobian
15682fe279fdSBarry Smith - user - A user context, or `NULL`
15698e3a2eefSMatthew G. Knepley 
15708e3a2eefSMatthew G. Knepley   Output Parameter:
1571f6dfbefdSBarry Smith . J - The `Mat`
15728e3a2eefSMatthew G. Knepley 
15738e3a2eefSMatthew G. Knepley   Level: advanced
15748e3a2eefSMatthew G. Knepley 
1575f6dfbefdSBarry Smith   Note:
15762fe279fdSBarry Smith   Vec `X` is kept in `J`, so updating `X` then updates the evaluation point.
15778e3a2eefSMatthew G. Knepley 
1578f6dfbefdSBarry Smith .seealso: `DM`, `DMSNESComputeJacobianAction()`
15798e3a2eefSMatthew G. Knepley @*/
1580d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCreateJacobianMF(DM dm, Vec X, void *user, Mat *J)
1581d71ae5a4SJacob Faibussowitsch {
15828e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15838e3a2eefSMatthew G. Knepley   PetscInt                     n, N;
15848e3a2eefSMatthew G. Knepley 
15858e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15869566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
15879566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, MATSHELL));
15889566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(X, &n));
15899566063dSJacob Faibussowitsch   PetscCall(VecGetSize(X, &N));
15909566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, n, n, N, N));
15919566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)dm));
15929566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)X));
15939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &ctx));
15948e3a2eefSMatthew G. Knepley   ctx->dm  = dm;
15958e3a2eefSMatthew G. Knepley   ctx->X   = X;
15968e3a2eefSMatthew G. Knepley   ctx->ctx = user;
15979566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*J, ctx));
15989566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(*J, MATOP_DESTROY, (void (*)(void))DMSNESJacobianMF_Destroy_Private));
15999566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(*J, MATOP_MULT, (void (*)(void))DMSNESJacobianMF_Mult_Private));
16003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16018e3a2eefSMatthew G. Knepley }
16028e3a2eefSMatthew G. Knepley 
160338cfc46eSPierre Jolivet /*
160438cfc46eSPierre Jolivet      MatComputeNeumannOverlap - Computes an unassembled (Neumann) local overlapping Mat in nonlinear context.
160538cfc46eSPierre Jolivet 
160638cfc46eSPierre Jolivet    Input Parameters:
16072fe279fdSBarry Smith +     X - `SNES` linearization point
160838cfc46eSPierre Jolivet .     ovl - index set of overlapping subdomains
160938cfc46eSPierre Jolivet 
161038cfc46eSPierre Jolivet    Output Parameter:
161138cfc46eSPierre Jolivet .     J - unassembled (Neumann) local matrix
161238cfc46eSPierre Jolivet 
161338cfc46eSPierre Jolivet    Level: intermediate
161438cfc46eSPierre Jolivet 
1615db781477SPatrick Sanan .seealso: `DMCreateNeumannOverlap()`, `MATIS`, `PCHPDDMSetAuxiliaryMat()`
161638cfc46eSPierre Jolivet */
1617d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, void *ctx)
1618d71ae5a4SJacob Faibussowitsch {
161938cfc46eSPierre Jolivet   SNES   snes;
162038cfc46eSPierre Jolivet   Mat    pJ;
162138cfc46eSPierre Jolivet   DM     ovldm, origdm;
162238cfc46eSPierre Jolivet   DMSNES sdm;
162338cfc46eSPierre Jolivet   PetscErrorCode (*bfun)(DM, Vec, void *);
162438cfc46eSPierre Jolivet   PetscErrorCode (*jfun)(DM, Vec, Mat, Mat, void *);
162538cfc46eSPierre Jolivet   void *bctx, *jctx;
162638cfc46eSPierre Jolivet 
162738cfc46eSPierre Jolivet   PetscFunctionBegin;
16289566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_MATIS", (PetscObject *)&pJ));
162928b400f6SJacob Faibussowitsch   PetscCheck(pJ, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing overlapping Mat");
16309566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Original_HPDDM", (PetscObject *)&origdm));
163128b400f6SJacob Faibussowitsch   PetscCheck(origdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing original DM");
16329566063dSJacob Faibussowitsch   PetscCall(MatGetDM(pJ, &ovldm));
16339566063dSJacob Faibussowitsch   PetscCall(DMSNESGetBoundaryLocal(origdm, &bfun, &bctx));
16349566063dSJacob Faibussowitsch   PetscCall(DMSNESSetBoundaryLocal(ovldm, bfun, bctx));
16359566063dSJacob Faibussowitsch   PetscCall(DMSNESGetJacobianLocal(origdm, &jfun, &jctx));
16369566063dSJacob Faibussowitsch   PetscCall(DMSNESSetJacobianLocal(ovldm, jfun, jctx));
16379566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject *)&snes));
163838cfc46eSPierre Jolivet   if (!snes) {
16399566063dSJacob Faibussowitsch     PetscCall(SNESCreate(PetscObjectComm((PetscObject)ovl), &snes));
16409566063dSJacob Faibussowitsch     PetscCall(SNESSetDM(snes, ovldm));
16419566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject)snes));
16429566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)snes));
164338cfc46eSPierre Jolivet   }
16449566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(ovldm, &sdm));
16459566063dSJacob Faibussowitsch   PetscCall(VecLockReadPush(X));
1646800f99ffSJeremy L Thompson   {
1647800f99ffSJeremy L Thompson     void *ctx;
1648800f99ffSJeremy L Thompson     PetscErrorCode (*J)(SNES, Vec, Mat, Mat, void *);
1649800f99ffSJeremy L Thompson     PetscCall(DMSNESGetJacobian(ovldm, &J, &ctx));
1650800f99ffSJeremy L Thompson     PetscCallBack("SNES callback Jacobian", (*J)(snes, X, pJ, pJ, ctx));
1651800f99ffSJeremy L Thompson   }
16529566063dSJacob Faibussowitsch   PetscCall(VecLockReadPop(X));
165338cfc46eSPierre Jolivet   /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */
165438cfc46eSPierre Jolivet   {
165538cfc46eSPierre Jolivet     Mat locpJ;
165638cfc46eSPierre Jolivet 
16579566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pJ, &locpJ));
16589566063dSJacob Faibussowitsch     PetscCall(MatCopy(locpJ, J, SAME_NONZERO_PATTERN));
165938cfc46eSPierre Jolivet   }
16603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
166138cfc46eSPierre Jolivet }
166238cfc46eSPierre Jolivet 
1663a925c78cSMatthew G. Knepley /*@
1664f6dfbefdSBarry Smith   DMPlexSetSNESLocalFEM - Use `DMPLEX`'s internal FEM routines to compute `SNES` boundary values, residual, and Jacobian.
16659f520fc2SToby Isaac 
16669f520fc2SToby Isaac   Input Parameters:
1667f6dfbefdSBarry Smith + dm          - The `DM` object
1668f6dfbefdSBarry Smith . boundaryctx - the user context that will be passed to pointwise evaluation of boundary values (see `PetscDSAddBoundary()`)
1669f6dfbefdSBarry Smith . residualctx - the user context that will be passed to pointwise evaluation of finite element residual computations (see `PetscDSSetResidual()`)
1670f6dfbefdSBarry Smith - jacobianctx - the user context that will be passed to pointwise evaluation of finite element Jacobian construction (see `PetscDSSetJacobian()`)
16711a244344SSatish Balay 
16721a244344SSatish Balay   Level: developer
1673f6dfbefdSBarry Smith 
1674f6dfbefdSBarry Smith .seealso: `DMPLEX`, `SNES`
16759f520fc2SToby Isaac @*/
1676d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, void *boundaryctx, void *residualctx, void *jacobianctx)
1677d71ae5a4SJacob Faibussowitsch {
16789f520fc2SToby Isaac   PetscFunctionBegin;
16799566063dSJacob Faibussowitsch   PetscCall(DMSNESSetBoundaryLocal(dm, DMPlexSNESComputeBoundaryFEM, boundaryctx));
16809566063dSJacob Faibussowitsch   PetscCall(DMSNESSetFunctionLocal(dm, DMPlexSNESComputeResidualFEM, residualctx));
16819566063dSJacob Faibussowitsch   PetscCall(DMSNESSetJacobianLocal(dm, DMPlexSNESComputeJacobianFEM, jacobianctx));
16829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", MatComputeNeumannOverlap_Plex));
16833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16849f520fc2SToby Isaac }
16859f520fc2SToby Isaac 
1686f017bcb6SMatthew G. Knepley /*@C
1687f017bcb6SMatthew G. Knepley   DMSNESCheckDiscretization - Check the discretization error of the exact solution
1688f017bcb6SMatthew G. Knepley 
1689f017bcb6SMatthew G. Knepley   Input Parameters:
1690f6dfbefdSBarry Smith + snes - the `SNES` object
1691f6dfbefdSBarry Smith . dm   - the `DM`
1692f2cacb80SMatthew G. Knepley . t    - the time
1693f6dfbefdSBarry Smith . u    - a `DM` vector
1694f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1695f017bcb6SMatthew G. Knepley 
16962fe279fdSBarry Smith   Output Parameter:
16972fe279fdSBarry Smith . error - An array which holds the discretization error in each field, or `NULL`
16982fe279fdSBarry Smith 
16992fe279fdSBarry Smith   Level: developer
1700f3c94560SMatthew G. Knepley 
1701f6dfbefdSBarry Smith   Note:
1702f6dfbefdSBarry Smith   The user must call `PetscDSSetExactSolution()` beforehand
17037f96f943SMatthew G. Knepley 
1704e4094ef1SJacob Faibussowitsch .seealso: `PetscDSSetExactSolution()`, `DNSNESCheckFromOptions()`, `DMSNESCheckResidual()`, `DMSNESCheckJacobian()`
1705f017bcb6SMatthew G. Knepley @*/
1706d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[])
1707d71ae5a4SJacob Faibussowitsch {
1708f017bcb6SMatthew G. Knepley   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
1709f017bcb6SMatthew G. Knepley   void     **ectxs;
1710f3c94560SMatthew G. Knepley   PetscReal *err;
17117f96f943SMatthew G. Knepley   MPI_Comm   comm;
17127f96f943SMatthew G. Knepley   PetscInt   Nf, f;
17131878804aSMatthew G. Knepley 
17141878804aSMatthew G. Knepley   PetscFunctionBegin;
1715f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1716f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1717064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(u, VEC_CLASSID, 4);
17184f572ea9SToby Isaac   if (error) PetscAssertPointer(error, 6);
17197f96f943SMatthew G. Knepley 
17209566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, t, u, NULL));
17219566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(u, NULL, "-vec_view"));
17227f96f943SMatthew G. Knepley 
17239566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
17249566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
17259566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err));
17267f96f943SMatthew G. Knepley   {
17277f96f943SMatthew G. Knepley     PetscInt Nds, s;
17287f96f943SMatthew G. Knepley 
17299566063dSJacob Faibussowitsch     PetscCall(DMGetNumDS(dm, &Nds));
1730083401c6SMatthew G. Knepley     for (s = 0; s < Nds; ++s) {
17317f96f943SMatthew G. Knepley       PetscDS         ds;
1732083401c6SMatthew G. Knepley       DMLabel         label;
1733083401c6SMatthew G. Knepley       IS              fieldIS;
17347f96f943SMatthew G. Knepley       const PetscInt *fields;
17357f96f943SMatthew G. Knepley       PetscInt        dsNf, f;
1736083401c6SMatthew G. Knepley 
173707218a29SMatthew G. Knepley       PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
17389566063dSJacob Faibussowitsch       PetscCall(PetscDSGetNumFields(ds, &dsNf));
17399566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(fieldIS, &fields));
1740083401c6SMatthew G. Knepley       for (f = 0; f < dsNf; ++f) {
1741083401c6SMatthew G. Knepley         const PetscInt field = fields[f];
17429566063dSJacob Faibussowitsch         PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]));
1743083401c6SMatthew G. Knepley       }
17449566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(fieldIS, &fields));
1745083401c6SMatthew G. Knepley     }
1746083401c6SMatthew G. Knepley   }
1747f017bcb6SMatthew G. Knepley   if (Nf > 1) {
17489566063dSJacob Faibussowitsch     PetscCall(DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err));
1749f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
1750ad540459SPierre 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);
1751b878532fSMatthew G. Knepley     } else if (error) {
1752b878532fSMatthew G. Knepley       for (f = 0; f < Nf; ++f) error[f] = err[f];
17531878804aSMatthew G. Knepley     } else {
17549566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "L_2 Error: ["));
1755f017bcb6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
17569566063dSJacob Faibussowitsch         if (f) PetscCall(PetscPrintf(comm, ", "));
17579566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(comm, "%g", (double)err[f]));
17581878804aSMatthew G. Knepley       }
17599566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "]\n"));
1760f017bcb6SMatthew G. Knepley     }
1761f017bcb6SMatthew G. Knepley   } else {
17629566063dSJacob Faibussowitsch     PetscCall(DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0]));
1763f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
176408401ef6SPierre Jolivet       PetscCheck(err[0] <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double)err[0], (double)tol);
1765b878532fSMatthew G. Knepley     } else if (error) {
1766b878532fSMatthew G. Knepley       error[0] = err[0];
1767f017bcb6SMatthew G. Knepley     } else {
17689566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "L_2 Error: %g\n", (double)err[0]));
1769f017bcb6SMatthew G. Knepley     }
1770f017bcb6SMatthew G. Knepley   }
17719566063dSJacob Faibussowitsch   PetscCall(PetscFree3(exacts, ectxs, err));
17723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1773f017bcb6SMatthew G. Knepley }
1774f017bcb6SMatthew G. Knepley 
1775f017bcb6SMatthew G. Knepley /*@C
1776f017bcb6SMatthew G. Knepley   DMSNESCheckResidual - Check the residual of the exact solution
1777f017bcb6SMatthew G. Knepley 
1778f017bcb6SMatthew G. Knepley   Input Parameters:
1779f6dfbefdSBarry Smith + snes - the `SNES` object
1780f6dfbefdSBarry Smith . dm   - the `DM`
1781f6dfbefdSBarry Smith . u    - a `DM` vector
1782f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1783f017bcb6SMatthew G. Knepley 
1784f6dfbefdSBarry Smith   Output Parameter:
17852fe279fdSBarry Smith . residual - The residual norm of the exact solution, or `NULL`
1786f3c94560SMatthew G. Knepley 
1787f017bcb6SMatthew G. Knepley   Level: developer
1788f017bcb6SMatthew G. Knepley 
1789db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckJacobian()`
1790f017bcb6SMatthew G. Knepley @*/
1791d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual)
1792d71ae5a4SJacob Faibussowitsch {
1793f017bcb6SMatthew G. Knepley   MPI_Comm  comm;
1794f017bcb6SMatthew G. Knepley   Vec       r;
1795f017bcb6SMatthew G. Knepley   PetscReal res;
1796f017bcb6SMatthew G. Knepley 
1797f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1798f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1799f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1800f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
18014f572ea9SToby Isaac   if (residual) PetscAssertPointer(residual, 5);
18029566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
18039566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL));
18049566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(u, &r));
18059566063dSJacob Faibussowitsch   PetscCall(SNESComputeFunction(snes, u, r));
18069566063dSJacob Faibussowitsch   PetscCall(VecNorm(r, NORM_2, &res));
1807f017bcb6SMatthew G. Knepley   if (tol >= 0.0) {
180808401ef6SPierre Jolivet     PetscCheck(res <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double)res, (double)tol);
1809b878532fSMatthew G. Knepley   } else if (residual) {
1810b878532fSMatthew G. Knepley     *residual = res;
1811f017bcb6SMatthew G. Knepley   } else {
18129566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "L_2 Residual: %g\n", (double)res));
181393ec0da9SPierre Jolivet     PetscCall(VecFilter(r, 1.0e-10));
18149566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)r, "Initial Residual"));
18159566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)r, "res_"));
18169566063dSJacob Faibussowitsch     PetscCall(VecViewFromOptions(r, NULL, "-vec_view"));
1817f017bcb6SMatthew G. Knepley   }
18189566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
18193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1820f017bcb6SMatthew G. Knepley }
1821f017bcb6SMatthew G. Knepley 
1822f017bcb6SMatthew G. Knepley /*@C
1823f3c94560SMatthew G. Knepley   DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test
1824f017bcb6SMatthew G. Knepley 
1825f017bcb6SMatthew G. Knepley   Input Parameters:
1826f6dfbefdSBarry Smith + snes - the `SNES` object
1827f6dfbefdSBarry Smith . dm   - the `DM`
1828f6dfbefdSBarry Smith . u    - a `DM` vector
1829f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1830f017bcb6SMatthew G. Knepley 
1831f3c94560SMatthew G. Knepley   Output Parameters:
18322fe279fdSBarry Smith + isLinear - Flag indicaing that the function looks linear, or `NULL`
18332fe279fdSBarry Smith - convRate - The rate of convergence of the linear model, or `NULL`
1834f3c94560SMatthew G. Knepley 
1835f017bcb6SMatthew G. Knepley   Level: developer
1836f017bcb6SMatthew G. Knepley 
1837db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckResidual()`
1838f017bcb6SMatthew G. Knepley @*/
1839d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate)
1840d71ae5a4SJacob Faibussowitsch {
1841f017bcb6SMatthew G. Knepley   MPI_Comm     comm;
1842f017bcb6SMatthew G. Knepley   PetscDS      ds;
1843f017bcb6SMatthew G. Knepley   Mat          J, M;
1844f017bcb6SMatthew G. Knepley   MatNullSpace nullspace;
1845f3c94560SMatthew G. Knepley   PetscReal    slope, intercept;
18467f96f943SMatthew G. Knepley   PetscBool    hasJac, hasPrec, isLin = PETSC_FALSE;
1847f017bcb6SMatthew G. Knepley 
1848f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1849f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1850f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1851f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
18524f572ea9SToby Isaac   if (isLinear) PetscAssertPointer(isLinear, 5);
18534f572ea9SToby Isaac   if (convRate) PetscAssertPointer(convRate, 6);
18549566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
18559566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL));
1856f017bcb6SMatthew G. Knepley   /* Create and view matrices */
18579566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(dm, &J));
18589566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
18599566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobian(ds, &hasJac));
18609566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
1861282e7bb4SMatthew G. Knepley   if (hasJac && hasPrec) {
18629566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dm, &M));
18639566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, u, J, M));
18649566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)M, "Preconditioning Matrix"));
18659566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)M, "jacpre_"));
18669566063dSJacob Faibussowitsch     PetscCall(MatViewFromOptions(M, NULL, "-mat_view"));
18679566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
1868282e7bb4SMatthew G. Knepley   } else {
18699566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, u, J, J));
1870282e7bb4SMatthew G. Knepley   }
18719566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)J, "Jacobian"));
18729566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)J, "jac_"));
18739566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(J, NULL, "-mat_view"));
1874f017bcb6SMatthew G. Knepley   /* Check nullspace */
18759566063dSJacob Faibussowitsch   PetscCall(MatGetNullSpace(J, &nullspace));
1876f017bcb6SMatthew G. Knepley   if (nullspace) {
18771878804aSMatthew G. Knepley     PetscBool isNull;
18789566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceTest(nullspace, J, &isNull));
187928b400f6SJacob Faibussowitsch     PetscCheck(isNull, comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid.");
18801878804aSMatthew G. Knepley   }
1881f017bcb6SMatthew G. Knepley   /* Taylor test */
1882f017bcb6SMatthew G. Knepley   {
1883f017bcb6SMatthew G. Knepley     PetscRandom rand;
1884f017bcb6SMatthew G. Knepley     Vec         du, uhat, r, rhat, df;
1885f3c94560SMatthew G. Knepley     PetscReal   h;
1886f017bcb6SMatthew G. Knepley     PetscReal  *es, *hs, *errors;
1887f017bcb6SMatthew G. Knepley     PetscReal   hMax = 1.0, hMin = 1e-6, hMult = 0.1;
1888f017bcb6SMatthew G. Knepley     PetscInt    Nv, v;
1889f017bcb6SMatthew G. Knepley 
1890f017bcb6SMatthew G. Knepley     /* Choose a perturbation direction */
18919566063dSJacob Faibussowitsch     PetscCall(PetscRandomCreate(comm, &rand));
18929566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &du));
18939566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(du, rand));
18949566063dSJacob Faibussowitsch     PetscCall(PetscRandomDestroy(&rand));
18959566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &df));
18969566063dSJacob Faibussowitsch     PetscCall(MatMult(J, du, df));
1897f017bcb6SMatthew G. Knepley     /* Evaluate residual at u, F(u), save in vector r */
18989566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &r));
18999566063dSJacob Faibussowitsch     PetscCall(SNESComputeFunction(snes, u, r));
1900f017bcb6SMatthew G. Knepley     /* Look at the convergence of our Taylor approximation as we approach u */
19019371c9d4SSatish Balay     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv)
19029371c9d4SSatish Balay       ;
19039566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors));
19049566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &uhat));
19059566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &rhat));
1906f017bcb6SMatthew G. Knepley     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) {
19079566063dSJacob Faibussowitsch       PetscCall(VecWAXPY(uhat, h, du, u));
1908f017bcb6SMatthew G. Knepley       /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */
19099566063dSJacob Faibussowitsch       PetscCall(SNESComputeFunction(snes, uhat, rhat));
19109566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df));
19119566063dSJacob Faibussowitsch       PetscCall(VecNorm(rhat, NORM_2, &errors[Nv]));
1912f017bcb6SMatthew G. Knepley 
191338d69901SMatthew G. Knepley       es[Nv] = errors[Nv] == 0 ? -16.0 : PetscLog10Real(errors[Nv]);
1914f017bcb6SMatthew G. Knepley       hs[Nv] = PetscLog10Real(h);
1915f017bcb6SMatthew G. Knepley     }
19169566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&uhat));
19179566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rhat));
19189566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&df));
19199566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&r));
19209566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&du));
1921f017bcb6SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1922f017bcb6SMatthew G. Knepley       if ((tol >= 0) && (errors[v] > tol)) break;
1923f017bcb6SMatthew G. Knepley       else if (errors[v] > PETSC_SMALL) break;
1924f017bcb6SMatthew G. Knepley     }
1925f3c94560SMatthew G. Knepley     if (v == Nv) isLin = PETSC_TRUE;
19269566063dSJacob Faibussowitsch     PetscCall(PetscLinearRegression(Nv, hs, es, &slope, &intercept));
19279566063dSJacob Faibussowitsch     PetscCall(PetscFree3(es, hs, errors));
1928f017bcb6SMatthew G. Knepley     /* Slope should be about 2 */
1929f017bcb6SMatthew G. Knepley     if (tol >= 0) {
19300b121fc5SBarry Smith       PetscCheck(isLin || PetscAbsReal(2 - slope) <= tol, comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double)slope);
1931b878532fSMatthew G. Knepley     } else if (isLinear || convRate) {
1932b878532fSMatthew G. Knepley       if (isLinear) *isLinear = isLin;
1933b878532fSMatthew G. Knepley       if (convRate) *convRate = slope;
1934f017bcb6SMatthew G. Knepley     } else {
19359566063dSJacob Faibussowitsch       if (!isLin) PetscCall(PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double)slope));
19369566063dSJacob Faibussowitsch       else PetscCall(PetscPrintf(comm, "Function appears to be linear\n"));
1937f017bcb6SMatthew G. Knepley     }
1938f017bcb6SMatthew G. Knepley   }
19399566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
19403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19411878804aSMatthew G. Knepley }
19421878804aSMatthew G. Knepley 
1943d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u)
1944d71ae5a4SJacob Faibussowitsch {
1945f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
19469566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL));
19479566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckResidual(snes, dm, u, -1.0, NULL));
19489566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL));
19493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1950f017bcb6SMatthew G. Knepley }
1951f017bcb6SMatthew G. Knepley 
1952bee9a294SMatthew G. Knepley /*@C
1953bee9a294SMatthew G. Knepley   DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information
1954bee9a294SMatthew G. Knepley 
1955bee9a294SMatthew G. Knepley   Input Parameters:
1956f6dfbefdSBarry Smith + snes - the `SNES` object
1957f6dfbefdSBarry Smith - u    - representative `SNES` vector
19587f96f943SMatthew G. Knepley 
19592fe279fdSBarry Smith   Level: developer
19602fe279fdSBarry Smith 
1961f6dfbefdSBarry Smith   Note:
1962f6dfbefdSBarry Smith   The user must call `PetscDSSetExactSolution()` beforehand
1963bee9a294SMatthew G. Knepley 
19642fe279fdSBarry Smith .seealso: `SNES`, `DM`
1965bee9a294SMatthew G. Knepley @*/
1966d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u)
1967d71ae5a4SJacob Faibussowitsch {
19681878804aSMatthew G. Knepley   DM        dm;
19691878804aSMatthew G. Knepley   Vec       sol;
19701878804aSMatthew G. Knepley   PetscBool check;
19711878804aSMatthew G. Knepley 
19721878804aSMatthew G. Knepley   PetscFunctionBegin;
19739566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-dmsnes_check", &check));
19743ba16761SJacob Faibussowitsch   if (!check) PetscFunctionReturn(PETSC_SUCCESS);
19759566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
19769566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(u, &sol));
19779566063dSJacob Faibussowitsch   PetscCall(SNESSetSolution(snes, sol));
19789566063dSJacob Faibussowitsch   PetscCall(DMSNESCheck_Internal(snes, dm, sol));
19799566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sol));
19803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1981552f7358SJed Brown }
1982