xref: /petsc/src/snes/utils/dmplexsnes.c (revision 08401ef684002a709c6d3db98a0c9f54a8bcf1ec)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I "petscdmplex.h" I*/
2af0996ceSBarry Smith #include <petsc/private/snesimpl.h>     /*I "petscsnes.h"   I*/
324cdb843SMatthew G. Knepley #include <petscds.h>
4af0996ceSBarry Smith #include <petsc/private/petscimpl.h>
5af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
6552f7358SJed Brown 
7649ef022SMatthew Knepley static void pressure_Private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8649ef022SMatthew Knepley                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9649ef022SMatthew Knepley                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
10649ef022SMatthew Knepley                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar p[])
11649ef022SMatthew Knepley {
12649ef022SMatthew Knepley   p[0] = u[uOff[1]];
13649ef022SMatthew Knepley }
14649ef022SMatthew Knepley 
15649ef022SMatthew Knepley /*
16649ef022SMatthew Knepley   SNESCorrectDiscretePressure_Private - Add a vector in the nullspace to make the continuum integral of the pressure field equal to zero. This is normally used only to evaluate convergence rates for the pressure accurately.
17649ef022SMatthew Knepley 
18649ef022SMatthew Knepley   Collective on SNES
19649ef022SMatthew Knepley 
20649ef022SMatthew Knepley   Input Parameters:
21649ef022SMatthew Knepley + snes      - The SNES
22649ef022SMatthew Knepley . pfield    - The field number for pressure
23649ef022SMatthew Knepley . nullspace - The pressure nullspace
24649ef022SMatthew Knepley . u         - The solution vector
25649ef022SMatthew Knepley - ctx       - An optional user context
26649ef022SMatthew Knepley 
27649ef022SMatthew Knepley   Output Parameter:
28649ef022SMatthew Knepley . u         - The solution with a continuum pressure integral of zero
29649ef022SMatthew Knepley 
30649ef022SMatthew Knepley   Notes:
31649ef022SMatthew Knepley   If int(u) = a and int(n) = b, then int(u - a/b n) = a - a/b b = 0. We assume that the nullspace is a single vector given explicitly.
32649ef022SMatthew Knepley 
33649ef022SMatthew Knepley   Level: developer
34649ef022SMatthew Knepley 
35649ef022SMatthew Knepley .seealso: SNESConvergedCorrectPressure()
36649ef022SMatthew Knepley */
37649ef022SMatthew Knepley static PetscErrorCode SNESCorrectDiscretePressure_Private(SNES snes, PetscInt pfield, MatNullSpace nullspace, Vec u, void *ctx)
38649ef022SMatthew Knepley {
39649ef022SMatthew Knepley   DM             dm;
40649ef022SMatthew Knepley   PetscDS        ds;
41649ef022SMatthew Knepley   const Vec     *nullvecs;
42649ef022SMatthew Knepley   PetscScalar    pintd, *intc, *intn;
43649ef022SMatthew Knepley   MPI_Comm       comm;
44649ef022SMatthew Knepley   PetscInt       Nf, Nv;
45649ef022SMatthew Knepley 
46649ef022SMatthew Knepley   PetscFunctionBegin;
479566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) snes, &comm));
489566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
4928b400f6SJacob Faibussowitsch   PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a SNES DM");
5028b400f6SJacob Faibussowitsch   PetscCheck(nullspace,comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a Jacobian nullspace");
519566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
529566063dSJacob Faibussowitsch   PetscCall(PetscDSSetObjective(ds, pfield, pressure_Private));
539566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceGetVecs(nullspace, NULL, &Nv, &nullvecs));
54*08401ef6SPierre Jolivet   PetscCheck(Nv == 1,comm, PETSC_ERR_ARG_OUTOFRANGE, "Can only handle a single null vector for pressure, not %D", Nv);
559566063dSJacob Faibussowitsch   PetscCall(VecDot(nullvecs[0], u, &pintd));
56*08401ef6SPierre Jolivet   PetscCheck(PetscAbsScalar(pintd) <= PETSC_SMALL,comm, PETSC_ERR_ARG_WRONG, "Discrete integral of pressure: %g", (double) PetscRealPart(pintd));
579566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(Nf, &intc, Nf, &intn));
599566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegralFEM(dm, nullvecs[0], intn, ctx));
609566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegralFEM(dm, u, intc, ctx));
619566063dSJacob Faibussowitsch   PetscCall(VecAXPY(u, -intc[pfield]/intn[pfield], nullvecs[0]));
62649ef022SMatthew Knepley #if defined (PETSC_USE_DEBUG)
639566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegralFEM(dm, u, intc, ctx));
64*08401ef6SPierre Jolivet   PetscCheck(PetscAbsScalar(intc[pfield]) <= PETSC_SMALL,comm, PETSC_ERR_ARG_WRONG, "Continuum integral of pressure after correction: %g", (double) PetscRealPart(intc[pfield]));
65649ef022SMatthew Knepley #endif
669566063dSJacob Faibussowitsch   PetscCall(PetscFree2(intc, intn));
67649ef022SMatthew Knepley   PetscFunctionReturn(0);
68649ef022SMatthew Knepley }
69649ef022SMatthew Knepley 
70649ef022SMatthew Knepley /*@C
71649ef022SMatthew Knepley    SNESConvergedCorrectPressure - Convergence test that adds a vector in the nullspace to make the continuum integral of the pressure field equal to zero. This is normally used only to evaluate convergence rates for the pressure accurately. The convergence test itself just mimics SNESConvergedDefault().
72649ef022SMatthew Knepley 
73649ef022SMatthew Knepley    Logically Collective on SNES
74649ef022SMatthew Knepley 
75649ef022SMatthew Knepley    Input Parameters:
76649ef022SMatthew Knepley +  snes - the SNES context
77649ef022SMatthew Knepley .  it - the iteration (0 indicates before any Newton steps)
78649ef022SMatthew Knepley .  xnorm - 2-norm of current iterate
79649ef022SMatthew Knepley .  snorm - 2-norm of current step
80649ef022SMatthew Knepley .  fnorm - 2-norm of function at current iterate
81649ef022SMatthew Knepley -  ctx   - Optional user context
82649ef022SMatthew Knepley 
83649ef022SMatthew Knepley    Output Parameter:
84649ef022SMatthew Knepley .  reason  - SNES_CONVERGED_ITERATING, SNES_CONVERGED_ITS, or SNES_DIVERGED_FNORM_NAN
85649ef022SMatthew Knepley 
86649ef022SMatthew Knepley    Notes:
87649ef022SMatthew Knepley    In order to use this monitor, you must setup several PETSc structures. First fields must be added to the DM, and a PetscDS must be created with discretizations of those fields. We currently assume that the pressure field has index 1. The pressure field must have a nullspace, likely created using the DMSetNullSpaceConstructor() interface. Last we must be able to integrate the pressure over the domain, so the DM attached to the SNES must be a Plex at this time.
88649ef022SMatthew Knepley 
89649ef022SMatthew Knepley    Level: advanced
90649ef022SMatthew Knepley 
91649ef022SMatthew Knepley .seealso: SNESConvergedDefault(), SNESSetConvergenceTest(), DMSetNullSpaceConstructor()
92649ef022SMatthew Knepley @*/
93649ef022SMatthew Knepley PetscErrorCode SNESConvergedCorrectPressure(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, void *ctx)
94649ef022SMatthew Knepley {
95649ef022SMatthew Knepley   PetscBool      monitorIntegral = PETSC_FALSE;
96649ef022SMatthew Knepley 
97649ef022SMatthew Knepley   PetscFunctionBegin;
989566063dSJacob Faibussowitsch   PetscCall(SNESConvergedDefault(snes, it, xnorm, gnorm, f, reason, ctx));
99649ef022SMatthew Knepley   if (monitorIntegral) {
100649ef022SMatthew Knepley     Mat          J;
101649ef022SMatthew Knepley     Vec          u;
102649ef022SMatthew Knepley     MatNullSpace nullspace;
103649ef022SMatthew Knepley     const Vec   *nullvecs;
104649ef022SMatthew Knepley     PetscScalar  pintd;
105649ef022SMatthew Knepley 
1069566063dSJacob Faibussowitsch     PetscCall(SNESGetSolution(snes, &u));
1079566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
1089566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(J, &nullspace));
1099566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceGetVecs(nullspace, NULL, NULL, &nullvecs));
1109566063dSJacob Faibussowitsch     PetscCall(VecDot(nullvecs[0], u, &pintd));
1119566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "SNES: Discrete integral of pressure: %g\n", (double) PetscRealPart(pintd)));
112649ef022SMatthew Knepley   }
113649ef022SMatthew Knepley   if (*reason > 0) {
114649ef022SMatthew Knepley     Mat          J;
115649ef022SMatthew Knepley     Vec          u;
116649ef022SMatthew Knepley     MatNullSpace nullspace;
117649ef022SMatthew Knepley     PetscInt     pfield = 1;
118649ef022SMatthew Knepley 
1199566063dSJacob Faibussowitsch     PetscCall(SNESGetSolution(snes, &u));
1209566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
1219566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(J, &nullspace));
1229566063dSJacob Faibussowitsch     PetscCall(SNESCorrectDiscretePressure_Private(snes, pfield, nullspace, u, ctx));
123649ef022SMatthew Knepley   }
124649ef022SMatthew Knepley   PetscFunctionReturn(0);
125649ef022SMatthew Knepley }
126649ef022SMatthew Knepley 
12724cdb843SMatthew G. Knepley /************************** Interpolation *******************************/
12824cdb843SMatthew G. Knepley 
1296da023fcSToby Isaac static PetscErrorCode DMSNESConvertPlex(DM dm, DM *plex, PetscBool copy)
1306da023fcSToby Isaac {
1316da023fcSToby Isaac   PetscBool      isPlex;
1326da023fcSToby Isaac 
1336da023fcSToby Isaac   PetscFunctionBegin;
1349566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex));
1356da023fcSToby Isaac   if (isPlex) {
1366da023fcSToby Isaac     *plex = dm;
1379566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject) dm));
138f7148743SMatthew G. Knepley   } else {
1399566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex));
140f7148743SMatthew G. Knepley     if (!*plex) {
1419566063dSJacob Faibussowitsch       PetscCall(DMConvert(dm,DMPLEX,plex));
1429566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex));
1436da023fcSToby Isaac       if (copy) {
1449566063dSJacob Faibussowitsch         PetscCall(DMCopyDMSNES(dm, *plex));
1459566063dSJacob Faibussowitsch         PetscCall(DMCopyAuxiliaryVec(dm, *plex));
1466da023fcSToby Isaac       }
147f7148743SMatthew G. Knepley     } else {
1489566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject) *plex));
149f7148743SMatthew G. Knepley     }
1506da023fcSToby Isaac   }
1516da023fcSToby Isaac   PetscFunctionReturn(0);
1526da023fcSToby Isaac }
1536da023fcSToby Isaac 
1544267b1a3SMatthew G. Knepley /*@C
1554267b1a3SMatthew G. Knepley   DMInterpolationCreate - Creates a DMInterpolationInfo context
1564267b1a3SMatthew G. Knepley 
157d083f849SBarry Smith   Collective
1584267b1a3SMatthew G. Knepley 
1594267b1a3SMatthew G. Knepley   Input Parameter:
1604267b1a3SMatthew G. Knepley . comm - the communicator
1614267b1a3SMatthew G. Knepley 
1624267b1a3SMatthew G. Knepley   Output Parameter:
1634267b1a3SMatthew G. Knepley . ctx - the context
1644267b1a3SMatthew G. Knepley 
1654267b1a3SMatthew G. Knepley   Level: beginner
1664267b1a3SMatthew G. Knepley 
1674267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationDestroy()
1684267b1a3SMatthew G. Knepley @*/
1690adebc6cSBarry Smith PetscErrorCode DMInterpolationCreate(MPI_Comm comm, DMInterpolationInfo *ctx)
1700adebc6cSBarry Smith {
171552f7358SJed Brown   PetscFunctionBegin;
172552f7358SJed Brown   PetscValidPointer(ctx, 2);
1739566063dSJacob Faibussowitsch   PetscCall(PetscNew(ctx));
1741aa26658SKarl Rupp 
175552f7358SJed Brown   (*ctx)->comm   = comm;
176552f7358SJed Brown   (*ctx)->dim    = -1;
177552f7358SJed Brown   (*ctx)->nInput = 0;
1780298fd71SBarry Smith   (*ctx)->points = NULL;
1790298fd71SBarry Smith   (*ctx)->cells  = NULL;
180552f7358SJed Brown   (*ctx)->n      = -1;
1810298fd71SBarry Smith   (*ctx)->coords = NULL;
182552f7358SJed Brown   PetscFunctionReturn(0);
183552f7358SJed Brown }
184552f7358SJed Brown 
1854267b1a3SMatthew G. Knepley /*@C
1864267b1a3SMatthew G. Knepley   DMInterpolationSetDim - Sets the spatial dimension for the interpolation context
1874267b1a3SMatthew G. Knepley 
1884267b1a3SMatthew G. Knepley   Not collective
1894267b1a3SMatthew G. Knepley 
1904267b1a3SMatthew G. Knepley   Input Parameters:
1914267b1a3SMatthew G. Knepley + ctx - the context
1924267b1a3SMatthew G. Knepley - dim - the spatial dimension
1934267b1a3SMatthew G. Knepley 
1944267b1a3SMatthew G. Knepley   Level: intermediate
1954267b1a3SMatthew G. Knepley 
1964267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetDim(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
1974267b1a3SMatthew G. Knepley @*/
1980adebc6cSBarry Smith PetscErrorCode DMInterpolationSetDim(DMInterpolationInfo ctx, PetscInt dim)
1990adebc6cSBarry Smith {
200552f7358SJed Brown   PetscFunctionBegin;
201*08401ef6SPierre Jolivet   PetscCheck(!(dim < 1) && !(dim > 3),ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension for points: %D", dim);
202552f7358SJed Brown   ctx->dim = dim;
203552f7358SJed Brown   PetscFunctionReturn(0);
204552f7358SJed Brown }
205552f7358SJed Brown 
2064267b1a3SMatthew G. Knepley /*@C
2074267b1a3SMatthew G. Knepley   DMInterpolationGetDim - Gets the spatial dimension for the interpolation context
2084267b1a3SMatthew G. Knepley 
2094267b1a3SMatthew G. Knepley   Not collective
2104267b1a3SMatthew G. Knepley 
2114267b1a3SMatthew G. Knepley   Input Parameter:
2124267b1a3SMatthew G. Knepley . ctx - the context
2134267b1a3SMatthew G. Knepley 
2144267b1a3SMatthew G. Knepley   Output Parameter:
2154267b1a3SMatthew G. Knepley . dim - the spatial dimension
2164267b1a3SMatthew G. Knepley 
2174267b1a3SMatthew G. Knepley   Level: intermediate
2184267b1a3SMatthew G. Knepley 
2194267b1a3SMatthew G. Knepley .seealso: DMInterpolationSetDim(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
2204267b1a3SMatthew G. Knepley @*/
2210adebc6cSBarry Smith PetscErrorCode DMInterpolationGetDim(DMInterpolationInfo ctx, PetscInt *dim)
2220adebc6cSBarry Smith {
223552f7358SJed Brown   PetscFunctionBegin;
224552f7358SJed Brown   PetscValidIntPointer(dim, 2);
225552f7358SJed Brown   *dim = ctx->dim;
226552f7358SJed Brown   PetscFunctionReturn(0);
227552f7358SJed Brown }
228552f7358SJed Brown 
2294267b1a3SMatthew G. Knepley /*@C
2304267b1a3SMatthew G. Knepley   DMInterpolationSetDof - Sets the number of fields interpolated at a point for the interpolation context
2314267b1a3SMatthew G. Knepley 
2324267b1a3SMatthew G. Knepley   Not collective
2334267b1a3SMatthew G. Knepley 
2344267b1a3SMatthew G. Knepley   Input Parameters:
2354267b1a3SMatthew G. Knepley + ctx - the context
2364267b1a3SMatthew G. Knepley - dof - the number of fields
2374267b1a3SMatthew G. Knepley 
2384267b1a3SMatthew G. Knepley   Level: intermediate
2394267b1a3SMatthew G. Knepley 
2404267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetDof(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
2414267b1a3SMatthew G. Knepley @*/
2420adebc6cSBarry Smith PetscErrorCode DMInterpolationSetDof(DMInterpolationInfo ctx, PetscInt dof)
2430adebc6cSBarry Smith {
244552f7358SJed Brown   PetscFunctionBegin;
245*08401ef6SPierre Jolivet   PetscCheck(dof >= 1,ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of components: %D", dof);
246552f7358SJed Brown   ctx->dof = dof;
247552f7358SJed Brown   PetscFunctionReturn(0);
248552f7358SJed Brown }
249552f7358SJed Brown 
2504267b1a3SMatthew G. Knepley /*@C
2514267b1a3SMatthew G. Knepley   DMInterpolationGetDof - Gets the number of fields interpolated at a point for the interpolation context
2524267b1a3SMatthew G. Knepley 
2534267b1a3SMatthew G. Knepley   Not collective
2544267b1a3SMatthew G. Knepley 
2554267b1a3SMatthew G. Knepley   Input Parameter:
2564267b1a3SMatthew G. Knepley . ctx - the context
2574267b1a3SMatthew G. Knepley 
2584267b1a3SMatthew G. Knepley   Output Parameter:
2594267b1a3SMatthew G. Knepley . dof - the number of fields
2604267b1a3SMatthew G. Knepley 
2614267b1a3SMatthew G. Knepley   Level: intermediate
2624267b1a3SMatthew G. Knepley 
2634267b1a3SMatthew G. Knepley .seealso: DMInterpolationSetDof(), DMInterpolationEvaluate(), DMInterpolationAddPoints()
2644267b1a3SMatthew G. Knepley @*/
2650adebc6cSBarry Smith PetscErrorCode DMInterpolationGetDof(DMInterpolationInfo ctx, PetscInt *dof)
2660adebc6cSBarry Smith {
267552f7358SJed Brown   PetscFunctionBegin;
268552f7358SJed Brown   PetscValidIntPointer(dof, 2);
269552f7358SJed Brown   *dof = ctx->dof;
270552f7358SJed Brown   PetscFunctionReturn(0);
271552f7358SJed Brown }
272552f7358SJed Brown 
2734267b1a3SMatthew G. Knepley /*@C
2744267b1a3SMatthew G. Knepley   DMInterpolationAddPoints - Add points at which we will interpolate the fields
2754267b1a3SMatthew G. Knepley 
2764267b1a3SMatthew G. Knepley   Not collective
2774267b1a3SMatthew G. Knepley 
2784267b1a3SMatthew G. Knepley   Input Parameters:
2794267b1a3SMatthew G. Knepley + ctx    - the context
2804267b1a3SMatthew G. Knepley . n      - the number of points
2814267b1a3SMatthew G. Knepley - points - the coordinates for each point, an array of size n * dim
2824267b1a3SMatthew G. Knepley 
2834267b1a3SMatthew G. Knepley   Note: The coordinate information is copied.
2844267b1a3SMatthew G. Knepley 
2854267b1a3SMatthew G. Knepley   Level: intermediate
2864267b1a3SMatthew G. Knepley 
2874267b1a3SMatthew G. Knepley .seealso: DMInterpolationSetDim(), DMInterpolationEvaluate(), DMInterpolationCreate()
2884267b1a3SMatthew G. Knepley @*/
2890adebc6cSBarry Smith PetscErrorCode DMInterpolationAddPoints(DMInterpolationInfo ctx, PetscInt n, PetscReal points[])
2900adebc6cSBarry Smith {
291552f7358SJed Brown   PetscFunctionBegin;
292*08401ef6SPierre Jolivet   PetscCheck(ctx->dim >= 0,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
29328b400f6SJacob Faibussowitsch   PetscCheck(!ctx->points,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot add points multiple times yet");
294552f7358SJed Brown   ctx->nInput = n;
2951aa26658SKarl Rupp 
2969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n*ctx->dim, &ctx->points));
2979566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(ctx->points, points, n*ctx->dim));
298552f7358SJed Brown   PetscFunctionReturn(0);
299552f7358SJed Brown }
300552f7358SJed Brown 
3014267b1a3SMatthew G. Knepley /*@C
30252aa1562SMatthew G. Knepley   DMInterpolationSetUp - Compute spatial indices for point location during interpolation
3034267b1a3SMatthew G. Knepley 
3044267b1a3SMatthew G. Knepley   Collective on ctx
3054267b1a3SMatthew G. Knepley 
3064267b1a3SMatthew G. Knepley   Input Parameters:
3074267b1a3SMatthew G. Knepley + ctx - the context
3084267b1a3SMatthew G. Knepley . dm  - the DM for the function space used for interpolation
30952aa1562SMatthew G. Knepley . redundantPoints - If PETSC_TRUE, all processes are passing in the same array of points. Otherwise, points need to be communicated among processes.
3107deeda50SSatish Balay - ignoreOutsideDomain - If PETSC_TRUE, ignore points outside the domain, otherwise return an error
3114267b1a3SMatthew G. Knepley 
3124267b1a3SMatthew G. Knepley   Level: intermediate
3134267b1a3SMatthew G. Knepley 
3144267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
3154267b1a3SMatthew G. Knepley @*/
31652aa1562SMatthew G. Knepley PetscErrorCode DMInterpolationSetUp(DMInterpolationInfo ctx, DM dm, PetscBool redundantPoints, PetscBool ignoreOutsideDomain)
3170adebc6cSBarry Smith {
318552f7358SJed Brown   MPI_Comm          comm = ctx->comm;
319552f7358SJed Brown   PetscScalar       *a;
320552f7358SJed Brown   PetscInt          p, q, i;
321552f7358SJed Brown   PetscMPIInt       rank, size;
322552f7358SJed Brown   Vec               pointVec;
3233a93e3b7SToby Isaac   PetscSF           cellSF;
324552f7358SJed Brown   PetscLayout       layout;
325552f7358SJed Brown   PetscReal         *globalPoints;
326cb313848SJed Brown   PetscScalar       *globalPointsScalar;
327552f7358SJed Brown   const PetscInt    *ranges;
328552f7358SJed Brown   PetscMPIInt       *counts, *displs;
3293a93e3b7SToby Isaac   const PetscSFNode *foundCells;
3303a93e3b7SToby Isaac   const PetscInt    *foundPoints;
331552f7358SJed Brown   PetscMPIInt       *foundProcs, *globalProcs;
3323a93e3b7SToby Isaac   PetscInt          n, N, numFound;
333552f7358SJed Brown 
33419436ca2SJed Brown   PetscFunctionBegin;
335064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
3369566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
3379566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
338*08401ef6SPierre Jolivet   PetscCheck(ctx->dim >= 0,comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
33919436ca2SJed Brown   /* Locate points */
34019436ca2SJed Brown   n = ctx->nInput;
341552f7358SJed Brown   if (!redundantPoints) {
3429566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCreate(comm, &layout));
3439566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetBlockSize(layout, 1));
3449566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetLocalSize(layout, n));
3459566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(layout));
3469566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(layout, &N));
347552f7358SJed Brown     /* Communicate all points to all processes */
3489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(N*ctx->dim,&globalPoints,size,&counts,size,&displs));
3499566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRanges(layout, &ranges));
350552f7358SJed Brown     for (p = 0; p < size; ++p) {
351552f7358SJed Brown       counts[p] = (ranges[p+1] - ranges[p])*ctx->dim;
352552f7358SJed Brown       displs[p] = ranges[p]*ctx->dim;
353552f7358SJed Brown     }
3549566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgatherv(ctx->points, n*ctx->dim, MPIU_REAL, globalPoints, counts, displs, MPIU_REAL, comm));
355552f7358SJed Brown   } else {
356552f7358SJed Brown     N = n;
357552f7358SJed Brown     globalPoints = ctx->points;
35838ea73c8SJed Brown     counts = displs = NULL;
35938ea73c8SJed Brown     layout = NULL;
360552f7358SJed Brown   }
361552f7358SJed Brown #if 0
3629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(N,&foundCells,N,&foundProcs,N,&globalProcs));
36319436ca2SJed Brown   /* foundCells[p] = m->locatePoint(&globalPoints[p*ctx->dim]); */
364552f7358SJed Brown #else
365cb313848SJed Brown #if defined(PETSC_USE_COMPLEX)
3669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(N*ctx->dim,&globalPointsScalar));
36746b3086cSToby Isaac   for (i=0; i<N*ctx->dim; i++) globalPointsScalar[i] = globalPoints[i];
368cb313848SJed Brown #else
369cb313848SJed Brown   globalPointsScalar = globalPoints;
370cb313848SJed Brown #endif
3719566063dSJacob Faibussowitsch   PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, ctx->dim, N*ctx->dim, globalPointsScalar, &pointVec));
3729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(N,&foundProcs,N,&globalProcs));
3737b5f2079SMatthew G. Knepley   for (p = 0; p < N; ++p) {foundProcs[p] = size;}
3743a93e3b7SToby Isaac   cellSF = NULL;
3759566063dSJacob Faibussowitsch   PetscCall(DMLocatePoints(dm, pointVec, DM_POINTLOCATION_REMOVE, &cellSF));
3769566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(cellSF,NULL,&numFound,&foundPoints,&foundCells));
377552f7358SJed Brown #endif
3783a93e3b7SToby Isaac   for (p = 0; p < numFound; ++p) {
3793a93e3b7SToby Isaac     if (foundCells[p].index >= 0) foundProcs[foundPoints ? foundPoints[p] : p] = rank;
380552f7358SJed Brown   }
381552f7358SJed Brown   /* Let the lowest rank process own each point */
3821c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(foundProcs, globalProcs, N, MPI_INT, MPI_MIN, comm));
383552f7358SJed Brown   ctx->n = 0;
384552f7358SJed Brown   for (p = 0; p < N; ++p) {
38552aa1562SMatthew G. Knepley     if (globalProcs[p] == size) {
38628b400f6SJacob Faibussowitsch       PetscCheck(ignoreOutsideDomain,comm, PETSC_ERR_PLIB, "Point %d: %g %g %g not located in mesh", p, (double)globalPoints[p*ctx->dim+0], (double)(ctx->dim > 1 ? globalPoints[p*ctx->dim+1] : 0.0), (double)(ctx->dim > 2 ? globalPoints[p*ctx->dim+2] : 0.0));
387dd400576SPatrick Sanan       else if (rank == 0) ++ctx->n;
38852aa1562SMatthew G. Knepley     } else if (globalProcs[p] == rank) ++ctx->n;
389552f7358SJed Brown   }
390552f7358SJed Brown   /* Create coordinates vector and array of owned cells */
3919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ctx->n, &ctx->cells));
3929566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, &ctx->coords));
3939566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(ctx->coords, ctx->n*ctx->dim, PETSC_DECIDE));
3949566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(ctx->coords, ctx->dim));
3959566063dSJacob Faibussowitsch   PetscCall(VecSetType(ctx->coords,VECSTANDARD));
3969566063dSJacob Faibussowitsch   PetscCall(VecGetArray(ctx->coords, &a));
397552f7358SJed Brown   for (p = 0, q = 0, i = 0; p < N; ++p) {
398552f7358SJed Brown     if (globalProcs[p] == rank) {
399552f7358SJed Brown       PetscInt d;
400552f7358SJed Brown 
4011aa26658SKarl Rupp       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = globalPoints[p*ctx->dim+d];
402f317b747SMatthew G. Knepley       ctx->cells[q] = foundCells[q].index;
403f317b747SMatthew G. Knepley       ++q;
404552f7358SJed Brown     }
405dd400576SPatrick Sanan     if (globalProcs[p] == size && rank == 0) {
40652aa1562SMatthew G. Knepley       PetscInt d;
40752aa1562SMatthew G. Knepley 
40852aa1562SMatthew G. Knepley       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = 0.;
40952aa1562SMatthew G. Knepley       ctx->cells[q] = -1;
41052aa1562SMatthew G. Knepley       ++q;
41152aa1562SMatthew G. Knepley     }
412552f7358SJed Brown   }
4139566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(ctx->coords, &a));
414552f7358SJed Brown #if 0
4159566063dSJacob Faibussowitsch   PetscCall(PetscFree3(foundCells,foundProcs,globalProcs));
416552f7358SJed Brown #else
4179566063dSJacob Faibussowitsch   PetscCall(PetscFree2(foundProcs,globalProcs));
4189566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&cellSF));
4199566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pointVec));
420552f7358SJed Brown #endif
4219566063dSJacob Faibussowitsch   if ((void*)globalPointsScalar != (void*)globalPoints) PetscCall(PetscFree(globalPointsScalar));
4229566063dSJacob Faibussowitsch   if (!redundantPoints) PetscCall(PetscFree3(globalPoints,counts,displs));
4239566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&layout));
424552f7358SJed Brown   PetscFunctionReturn(0);
425552f7358SJed Brown }
426552f7358SJed Brown 
4274267b1a3SMatthew G. Knepley /*@C
4284267b1a3SMatthew G. Knepley   DMInterpolationGetCoordinates - Gets a Vec with the coordinates of each interpolation point
4294267b1a3SMatthew G. Knepley 
4304267b1a3SMatthew G. Knepley   Collective on ctx
4314267b1a3SMatthew G. Knepley 
4324267b1a3SMatthew G. Knepley   Input Parameter:
4334267b1a3SMatthew G. Knepley . ctx - the context
4344267b1a3SMatthew G. Knepley 
4354267b1a3SMatthew G. Knepley   Output Parameter:
4364267b1a3SMatthew G. Knepley . coordinates  - the coordinates of interpolation points
4374267b1a3SMatthew G. Knepley 
4384267b1a3SMatthew G. Knepley   Note: The local vector entries correspond to interpolation points lying on this process, according to the associated DM. This is a borrowed vector that the user should not destroy.
4394267b1a3SMatthew G. Knepley 
4404267b1a3SMatthew G. Knepley   Level: intermediate
4414267b1a3SMatthew G. Knepley 
4424267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
4434267b1a3SMatthew G. Knepley @*/
4440adebc6cSBarry Smith PetscErrorCode DMInterpolationGetCoordinates(DMInterpolationInfo ctx, Vec *coordinates)
4450adebc6cSBarry Smith {
446552f7358SJed Brown   PetscFunctionBegin;
447552f7358SJed Brown   PetscValidPointer(coordinates, 2);
44828b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
449552f7358SJed Brown   *coordinates = ctx->coords;
450552f7358SJed Brown   PetscFunctionReturn(0);
451552f7358SJed Brown }
452552f7358SJed Brown 
4534267b1a3SMatthew G. Knepley /*@C
4544267b1a3SMatthew G. Knepley   DMInterpolationGetVector - Gets a Vec which can hold all the interpolated field values
4554267b1a3SMatthew G. Knepley 
4564267b1a3SMatthew G. Knepley   Collective on ctx
4574267b1a3SMatthew G. Knepley 
4584267b1a3SMatthew G. Knepley   Input Parameter:
4594267b1a3SMatthew G. Knepley . ctx - the context
4604267b1a3SMatthew G. Knepley 
4614267b1a3SMatthew G. Knepley   Output Parameter:
4624267b1a3SMatthew G. Knepley . v  - a vector capable of holding the interpolated field values
4634267b1a3SMatthew G. Knepley 
4644267b1a3SMatthew G. Knepley   Note: This vector should be returned using DMInterpolationRestoreVector().
4654267b1a3SMatthew G. Knepley 
4664267b1a3SMatthew G. Knepley   Level: intermediate
4674267b1a3SMatthew G. Knepley 
4684267b1a3SMatthew G. Knepley .seealso: DMInterpolationRestoreVector(), DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
4694267b1a3SMatthew G. Knepley @*/
4700adebc6cSBarry Smith PetscErrorCode DMInterpolationGetVector(DMInterpolationInfo ctx, Vec *v)
4710adebc6cSBarry Smith {
472552f7358SJed Brown   PetscFunctionBegin;
473552f7358SJed Brown   PetscValidPointer(v, 2);
47428b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
4759566063dSJacob Faibussowitsch   PetscCall(VecCreate(ctx->comm, v));
4769566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*v, ctx->n*ctx->dof, PETSC_DECIDE));
4779566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(*v, ctx->dof));
4789566063dSJacob Faibussowitsch   PetscCall(VecSetType(*v,VECSTANDARD));
479552f7358SJed Brown   PetscFunctionReturn(0);
480552f7358SJed Brown }
481552f7358SJed Brown 
4824267b1a3SMatthew G. Knepley /*@C
4834267b1a3SMatthew G. Knepley   DMInterpolationRestoreVector - Returns a Vec which can hold all the interpolated field values
4844267b1a3SMatthew G. Knepley 
4854267b1a3SMatthew G. Knepley   Collective on ctx
4864267b1a3SMatthew G. Knepley 
4874267b1a3SMatthew G. Knepley   Input Parameters:
4884267b1a3SMatthew G. Knepley + ctx - the context
4894267b1a3SMatthew G. Knepley - v  - a vector capable of holding the interpolated field values
4904267b1a3SMatthew G. Knepley 
4914267b1a3SMatthew G. Knepley   Level: intermediate
4924267b1a3SMatthew G. Knepley 
4934267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetVector(), DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
4944267b1a3SMatthew G. Knepley @*/
4950adebc6cSBarry Smith PetscErrorCode DMInterpolationRestoreVector(DMInterpolationInfo ctx, Vec *v)
4960adebc6cSBarry Smith {
497552f7358SJed Brown   PetscFunctionBegin;
498552f7358SJed Brown   PetscValidPointer(v, 2);
49928b400f6SJacob Faibussowitsch   PetscCheck(ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
5009566063dSJacob Faibussowitsch   PetscCall(VecDestroy(v));
501552f7358SJed Brown   PetscFunctionReturn(0);
502552f7358SJed Brown }
503552f7358SJed Brown 
504cfe5744fSMatthew G. Knepley static inline PetscErrorCode DMInterpolate_Segment_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
505cfe5744fSMatthew G. Knepley {
506cfe5744fSMatthew G. Knepley   PetscReal          v0, J, invJ, detJ;
507cfe5744fSMatthew G. Knepley   const PetscInt     dof = ctx->dof;
508cfe5744fSMatthew G. Knepley   const PetscScalar *coords;
509cfe5744fSMatthew G. Knepley   PetscScalar       *a;
510cfe5744fSMatthew G. Knepley   PetscInt           p;
511cfe5744fSMatthew G. Knepley 
512cfe5744fSMatthew G. Knepley   PetscFunctionBegin;
5139566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
5149566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
515cfe5744fSMatthew G. Knepley   for (p = 0; p < ctx->n; ++p) {
516cfe5744fSMatthew G. Knepley     PetscInt     c = ctx->cells[p];
517cfe5744fSMatthew G. Knepley     PetscScalar *x = NULL;
518cfe5744fSMatthew G. Knepley     PetscReal    xir[1];
519cfe5744fSMatthew G. Knepley     PetscInt     xSize, comp;
520cfe5744fSMatthew G. Knepley 
5219566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ));
522cfe5744fSMatthew G. Knepley     PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double) detJ, c);
523cfe5744fSMatthew G. Knepley     xir[0] = invJ*PetscRealPart(coords[p] - v0);
5249566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
525cfe5744fSMatthew G. Knepley     if (2*dof == xSize) {
526cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp]*(1 - xir[0]) + x[1*dof+comp]*xir[0];
527cfe5744fSMatthew G. Knepley     } else if (dof == xSize) {
528cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp];
529cfe5744fSMatthew G. Knepley     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input closure size %" PetscInt_FMT " must be either %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 2*dof, dof);
5309566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
531cfe5744fSMatthew G. Knepley   }
5329566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
5339566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
534cfe5744fSMatthew G. Knepley   PetscFunctionReturn(0);
535cfe5744fSMatthew G. Knepley }
536cfe5744fSMatthew G. Knepley 
5379fbee547SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Triangle_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
538a6dfd86eSKarl Rupp {
539552f7358SJed Brown   PetscReal      *v0, *J, *invJ, detJ;
54056044e6dSMatthew G. Knepley   const PetscScalar *coords;
54156044e6dSMatthew G. Knepley   PetscScalar    *a;
542552f7358SJed Brown   PetscInt       p;
543552f7358SJed Brown 
544552f7358SJed Brown   PetscFunctionBegin;
5459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(ctx->dim,&v0,ctx->dim*ctx->dim,&J,ctx->dim*ctx->dim,&invJ));
5469566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
5479566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
548552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
549552f7358SJed Brown     PetscInt     c = ctx->cells[p];
550a1e44745SMatthew G. Knepley     PetscScalar *x = NULL;
551552f7358SJed Brown     PetscReal    xi[4];
552552f7358SJed Brown     PetscInt     d, f, comp;
553552f7358SJed Brown 
5549566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
555*08401ef6SPierre Jolivet     PetscCheck(detJ > 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D", (double)detJ, c);
5569566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
5571aa26658SKarl Rupp     for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp];
5581aa26658SKarl Rupp 
559552f7358SJed Brown     for (d = 0; d < ctx->dim; ++d) {
560552f7358SJed Brown       xi[d] = 0.0;
5611aa26658SKarl Rupp       for (f = 0; f < ctx->dim; ++f) xi[d] += invJ[d*ctx->dim+f]*0.5*PetscRealPart(coords[p*ctx->dim+f] - v0[f]);
5621aa26658SKarl Rupp       for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] += PetscRealPart(x[(d+1)*ctx->dof+comp] - x[0*ctx->dof+comp])*xi[d];
563552f7358SJed Brown     }
5649566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
565552f7358SJed Brown   }
5669566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
5679566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
5689566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
569552f7358SJed Brown   PetscFunctionReturn(0);
570552f7358SJed Brown }
571552f7358SJed Brown 
5729fbee547SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Tetrahedron_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
5737a1931ceSMatthew G. Knepley {
5747a1931ceSMatthew G. Knepley   PetscReal      *v0, *J, *invJ, detJ;
57556044e6dSMatthew G. Knepley   const PetscScalar *coords;
57656044e6dSMatthew G. Knepley   PetscScalar    *a;
5777a1931ceSMatthew G. Knepley   PetscInt       p;
5787a1931ceSMatthew G. Knepley 
5797a1931ceSMatthew G. Knepley   PetscFunctionBegin;
5809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(ctx->dim,&v0,ctx->dim*ctx->dim,&J,ctx->dim*ctx->dim,&invJ));
5819566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
5829566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
5837a1931ceSMatthew G. Knepley   for (p = 0; p < ctx->n; ++p) {
5847a1931ceSMatthew G. Knepley     PetscInt       c = ctx->cells[p];
5857a1931ceSMatthew G. Knepley     const PetscInt order[3] = {2, 1, 3};
5862584bbe8SMatthew G. Knepley     PetscScalar   *x = NULL;
5877a1931ceSMatthew G. Knepley     PetscReal      xi[4];
5887a1931ceSMatthew G. Knepley     PetscInt       d, f, comp;
5897a1931ceSMatthew G. Knepley 
5909566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
591*08401ef6SPierre Jolivet     PetscCheck(detJ > 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D", (double)detJ, c);
5929566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
5937a1931ceSMatthew G. Knepley     for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp];
5947a1931ceSMatthew G. Knepley 
5957a1931ceSMatthew G. Knepley     for (d = 0; d < ctx->dim; ++d) {
5967a1931ceSMatthew G. Knepley       xi[d] = 0.0;
5977a1931ceSMatthew G. Knepley       for (f = 0; f < ctx->dim; ++f) xi[d] += invJ[d*ctx->dim+f]*0.5*PetscRealPart(coords[p*ctx->dim+f] - v0[f]);
5987a1931ceSMatthew G. Knepley       for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] += PetscRealPart(x[order[d]*ctx->dof+comp] - x[0*ctx->dof+comp])*xi[d];
5997a1931ceSMatthew G. Knepley     }
6009566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
6017a1931ceSMatthew G. Knepley   }
6029566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
6039566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
6049566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
6057a1931ceSMatthew G. Knepley   PetscFunctionReturn(0);
6067a1931ceSMatthew G. Knepley }
6077a1931ceSMatthew G. Knepley 
6089fbee547SJacob Faibussowitsch static inline PetscErrorCode QuadMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
609552f7358SJed Brown {
610552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
611552f7358SJed Brown   const PetscScalar x0        = vertices[0];
612552f7358SJed Brown   const PetscScalar y0        = vertices[1];
613552f7358SJed Brown   const PetscScalar x1        = vertices[2];
614552f7358SJed Brown   const PetscScalar y1        = vertices[3];
615552f7358SJed Brown   const PetscScalar x2        = vertices[4];
616552f7358SJed Brown   const PetscScalar y2        = vertices[5];
617552f7358SJed Brown   const PetscScalar x3        = vertices[6];
618552f7358SJed Brown   const PetscScalar y3        = vertices[7];
619552f7358SJed Brown   const PetscScalar f_1       = x1 - x0;
620552f7358SJed Brown   const PetscScalar g_1       = y1 - y0;
621552f7358SJed Brown   const PetscScalar f_3       = x3 - x0;
622552f7358SJed Brown   const PetscScalar g_3       = y3 - y0;
623552f7358SJed Brown   const PetscScalar f_01      = x2 - x1 - x3 + x0;
624552f7358SJed Brown   const PetscScalar g_01      = y2 - y1 - y3 + y0;
62556044e6dSMatthew G. Knepley   const PetscScalar *ref;
62656044e6dSMatthew G. Knepley   PetscScalar       *real;
627552f7358SJed Brown 
628552f7358SJed Brown   PetscFunctionBegin;
6299566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref,  &ref));
6309566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Xreal, &real));
631552f7358SJed Brown   {
632552f7358SJed Brown     const PetscScalar p0 = ref[0];
633552f7358SJed Brown     const PetscScalar p1 = ref[1];
634552f7358SJed Brown 
635552f7358SJed Brown     real[0] = x0 + f_1 * p0 + f_3 * p1 + f_01 * p0 * p1;
636552f7358SJed Brown     real[1] = y0 + g_1 * p0 + g_3 * p1 + g_01 * p0 * p1;
637552f7358SJed Brown   }
6389566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(28));
6399566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref,  &ref));
6409566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Xreal, &real));
641552f7358SJed Brown   PetscFunctionReturn(0);
642552f7358SJed Brown }
643552f7358SJed Brown 
644af0996ceSBarry Smith #include <petsc/private/dmimpl.h>
6459fbee547SJacob Faibussowitsch static inline PetscErrorCode QuadJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
646552f7358SJed Brown {
647552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
648552f7358SJed Brown   const PetscScalar x0        = vertices[0];
649552f7358SJed Brown   const PetscScalar y0        = vertices[1];
650552f7358SJed Brown   const PetscScalar x1        = vertices[2];
651552f7358SJed Brown   const PetscScalar y1        = vertices[3];
652552f7358SJed Brown   const PetscScalar x2        = vertices[4];
653552f7358SJed Brown   const PetscScalar y2        = vertices[5];
654552f7358SJed Brown   const PetscScalar x3        = vertices[6];
655552f7358SJed Brown   const PetscScalar y3        = vertices[7];
656552f7358SJed Brown   const PetscScalar f_01      = x2 - x1 - x3 + x0;
657552f7358SJed Brown   const PetscScalar g_01      = y2 - y1 - y3 + y0;
65856044e6dSMatthew G. Knepley   const PetscScalar *ref;
659552f7358SJed Brown 
660552f7358SJed Brown   PetscFunctionBegin;
6619566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref,  &ref));
662552f7358SJed Brown   {
663552f7358SJed Brown     const PetscScalar x       = ref[0];
664552f7358SJed Brown     const PetscScalar y       = ref[1];
665552f7358SJed Brown     const PetscInt    rows[2] = {0, 1};
666da80777bSKarl Rupp     PetscScalar       values[4];
667da80777bSKarl Rupp 
668da80777bSKarl Rupp     values[0] = (x1 - x0 + f_01*y) * 0.5; values[1] = (x3 - x0 + f_01*x) * 0.5;
669da80777bSKarl Rupp     values[2] = (y1 - y0 + g_01*y) * 0.5; values[3] = (y3 - y0 + g_01*x) * 0.5;
6709566063dSJacob Faibussowitsch     PetscCall(MatSetValues(J, 2, rows, 2, rows, values, INSERT_VALUES));
671552f7358SJed Brown   }
6729566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(30));
6739566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref,  &ref));
6749566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
6759566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
676552f7358SJed Brown   PetscFunctionReturn(0);
677552f7358SJed Brown }
678552f7358SJed Brown 
6799fbee547SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Quad_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
680a6dfd86eSKarl Rupp {
681fafc0619SMatthew G Knepley   DM                 dmCoord;
682de73a395SMatthew G. Knepley   PetscFE            fem = NULL;
683552f7358SJed Brown   SNES               snes;
684552f7358SJed Brown   KSP                ksp;
685552f7358SJed Brown   PC                 pc;
686552f7358SJed Brown   Vec                coordsLocal, r, ref, real;
687552f7358SJed Brown   Mat                J;
688716009bfSMatthew G. Knepley   PetscTabulation    T = NULL;
68956044e6dSMatthew G. Knepley   const PetscScalar *coords;
69056044e6dSMatthew G. Knepley   PetscScalar        *a;
691716009bfSMatthew G. Knepley   PetscReal          xir[2] = {0., 0.};
692de73a395SMatthew G. Knepley   PetscInt           Nf, p;
6935509d985SMatthew G. Knepley   const PetscInt     dof = ctx->dof;
694552f7358SJed Brown 
695552f7358SJed Brown   PetscFunctionBegin;
6969566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
697716009bfSMatthew G. Knepley   if (Nf) {
698cfe5744fSMatthew G. Knepley     PetscObject  obj;
699cfe5744fSMatthew G. Knepley     PetscClassId id;
700cfe5744fSMatthew G. Knepley 
7019566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, 0, NULL, &obj));
7029566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
7039566063dSJacob Faibussowitsch     if (id == PETSCFE_CLASSID) {fem = (PetscFE) obj; PetscCall(PetscFECreateTabulation(fem, 1, 1, xir, 0, &T));}
704716009bfSMatthew G. Knepley   }
7059566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
7069566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &dmCoord));
7079566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
7089566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes, "quad_interp_"));
7099566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &r));
7109566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(r, 2, 2));
7119566063dSJacob Faibussowitsch   PetscCall(VecSetType(r,dm->vectype));
7129566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &ref));
7139566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &real));
7149566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &J));
7159566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(J, 2, 2, 2, 2));
7169566063dSJacob Faibussowitsch   PetscCall(MatSetType(J, MATSEQDENSE));
7179566063dSJacob Faibussowitsch   PetscCall(MatSetUp(J));
7189566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes, r, QuadMap_Private, NULL));
7199566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes, J, J, QuadJacobian_Private, NULL));
7209566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(snes, &ksp));
7219566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(ksp, &pc));
7229566063dSJacob Faibussowitsch   PetscCall(PCSetType(pc, PCLU));
7239566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
724552f7358SJed Brown 
7259566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
7269566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
727552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
728a1e44745SMatthew G. Knepley     PetscScalar *x = NULL, *vertices = NULL;
729552f7358SJed Brown     PetscScalar *xi;
730552f7358SJed Brown     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
731552f7358SJed Brown 
732552f7358SJed Brown     /* Can make this do all points at once */
7339566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
734*08401ef6SPierre Jolivet     PetscCheck(4*2 == coordSize,ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %D should be %d", coordSize, 4*2);
7359566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
7369566063dSJacob Faibussowitsch     PetscCall(SNESSetFunction(snes, NULL, NULL, vertices));
7379566063dSJacob Faibussowitsch     PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
7389566063dSJacob Faibussowitsch     PetscCall(VecGetArray(real, &xi));
739552f7358SJed Brown     xi[0]  = coords[p*ctx->dim+0];
740552f7358SJed Brown     xi[1]  = coords[p*ctx->dim+1];
7419566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(real, &xi));
7429566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes, real, ref));
7439566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ref, &xi));
744cb313848SJed Brown     xir[0] = PetscRealPart(xi[0]);
745cb313848SJed Brown     xir[1] = PetscRealPart(xi[1]);
746cfe5744fSMatthew G. Knepley     if (4*dof == xSize) {
747cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp)
748cfe5744fSMatthew G. Knepley         a[p*dof+comp] = x[0*dof+comp]*(1 - xir[0])*(1 - xir[1]) + x[1*dof+comp]*xir[0]*(1 - xir[1]) + x[2*dof+comp]*xir[0]*xir[1] + x[3*dof+comp]*(1 - xir[0])*xir[1];
749cfe5744fSMatthew G. Knepley     } else if (dof == xSize) {
750cfe5744fSMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp];
751cfe5744fSMatthew G. Knepley     } else {
7525509d985SMatthew G. Knepley       PetscInt d;
7531aa26658SKarl Rupp 
7542c71b3e2SJacob Faibussowitsch       PetscCheck(fem, ctx->comm, PETSC_ERR_ARG_WRONG, "Cannot have a higher order interpolant if the discretization is not PetscFE");
7555509d985SMatthew G. Knepley       xir[0] = 2.0*xir[0] - 1.0; xir[1] = 2.0*xir[1] - 1.0;
7569566063dSJacob Faibussowitsch       PetscCall(PetscFEComputeTabulation(fem, 1, xir, 0, T));
7575509d985SMatthew G. Knepley       for (comp = 0; comp < dof; ++comp) {
7585509d985SMatthew G. Knepley         a[p*dof+comp] = 0.0;
7595509d985SMatthew G. Knepley         for (d = 0; d < xSize/dof; ++d) {
760ef0bb6c7SMatthew G. Knepley           a[p*dof+comp] += x[d*dof+comp]*T->T[0][d*dof+comp];
7615509d985SMatthew G. Knepley         }
7625509d985SMatthew G. Knepley       }
7635509d985SMatthew G. Knepley     }
7649566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ref, &xi));
7659566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
7669566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
767552f7358SJed Brown   }
7689566063dSJacob Faibussowitsch   PetscCall(PetscTabulationDestroy(&T));
7699566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
7709566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
771552f7358SJed Brown 
7729566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
7739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
7749566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ref));
7759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&real));
7769566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
777552f7358SJed Brown   PetscFunctionReturn(0);
778552f7358SJed Brown }
779552f7358SJed Brown 
7809fbee547SJacob Faibussowitsch static inline PetscErrorCode HexMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
781552f7358SJed Brown {
782552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
783552f7358SJed Brown   const PetscScalar x0        = vertices[0];
784552f7358SJed Brown   const PetscScalar y0        = vertices[1];
785552f7358SJed Brown   const PetscScalar z0        = vertices[2];
7867a1931ceSMatthew G. Knepley   const PetscScalar x1        = vertices[9];
7877a1931ceSMatthew G. Knepley   const PetscScalar y1        = vertices[10];
7887a1931ceSMatthew G. Knepley   const PetscScalar z1        = vertices[11];
789552f7358SJed Brown   const PetscScalar x2        = vertices[6];
790552f7358SJed Brown   const PetscScalar y2        = vertices[7];
791552f7358SJed Brown   const PetscScalar z2        = vertices[8];
7927a1931ceSMatthew G. Knepley   const PetscScalar x3        = vertices[3];
7937a1931ceSMatthew G. Knepley   const PetscScalar y3        = vertices[4];
7947a1931ceSMatthew G. Knepley   const PetscScalar z3        = vertices[5];
795552f7358SJed Brown   const PetscScalar x4        = vertices[12];
796552f7358SJed Brown   const PetscScalar y4        = vertices[13];
797552f7358SJed Brown   const PetscScalar z4        = vertices[14];
798552f7358SJed Brown   const PetscScalar x5        = vertices[15];
799552f7358SJed Brown   const PetscScalar y5        = vertices[16];
800552f7358SJed Brown   const PetscScalar z5        = vertices[17];
801552f7358SJed Brown   const PetscScalar x6        = vertices[18];
802552f7358SJed Brown   const PetscScalar y6        = vertices[19];
803552f7358SJed Brown   const PetscScalar z6        = vertices[20];
804552f7358SJed Brown   const PetscScalar x7        = vertices[21];
805552f7358SJed Brown   const PetscScalar y7        = vertices[22];
806552f7358SJed Brown   const PetscScalar z7        = vertices[23];
807552f7358SJed Brown   const PetscScalar f_1       = x1 - x0;
808552f7358SJed Brown   const PetscScalar g_1       = y1 - y0;
809552f7358SJed Brown   const PetscScalar h_1       = z1 - z0;
810552f7358SJed Brown   const PetscScalar f_3       = x3 - x0;
811552f7358SJed Brown   const PetscScalar g_3       = y3 - y0;
812552f7358SJed Brown   const PetscScalar h_3       = z3 - z0;
813552f7358SJed Brown   const PetscScalar f_4       = x4 - x0;
814552f7358SJed Brown   const PetscScalar g_4       = y4 - y0;
815552f7358SJed Brown   const PetscScalar h_4       = z4 - z0;
816552f7358SJed Brown   const PetscScalar f_01      = x2 - x1 - x3 + x0;
817552f7358SJed Brown   const PetscScalar g_01      = y2 - y1 - y3 + y0;
818552f7358SJed Brown   const PetscScalar h_01      = z2 - z1 - z3 + z0;
819552f7358SJed Brown   const PetscScalar f_12      = x7 - x3 - x4 + x0;
820552f7358SJed Brown   const PetscScalar g_12      = y7 - y3 - y4 + y0;
821552f7358SJed Brown   const PetscScalar h_12      = z7 - z3 - z4 + z0;
822552f7358SJed Brown   const PetscScalar f_02      = x5 - x1 - x4 + x0;
823552f7358SJed Brown   const PetscScalar g_02      = y5 - y1 - y4 + y0;
824552f7358SJed Brown   const PetscScalar h_02      = z5 - z1 - z4 + z0;
825552f7358SJed Brown   const PetscScalar f_012     = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
826552f7358SJed Brown   const PetscScalar g_012     = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
827552f7358SJed Brown   const PetscScalar h_012     = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
82856044e6dSMatthew G. Knepley   const PetscScalar *ref;
82956044e6dSMatthew G. Knepley   PetscScalar       *real;
830552f7358SJed Brown 
831552f7358SJed Brown   PetscFunctionBegin;
8329566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref,  &ref));
8339566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Xreal, &real));
834552f7358SJed Brown   {
835552f7358SJed Brown     const PetscScalar p0 = ref[0];
836552f7358SJed Brown     const PetscScalar p1 = ref[1];
837552f7358SJed Brown     const PetscScalar p2 = ref[2];
838552f7358SJed Brown 
839552f7358SJed Brown     real[0] = x0 + f_1*p0 + f_3*p1 + f_4*p2 + f_01*p0*p1 + f_12*p1*p2 + f_02*p0*p2 + f_012*p0*p1*p2;
840552f7358SJed Brown     real[1] = y0 + g_1*p0 + g_3*p1 + g_4*p2 + g_01*p0*p1 + g_01*p0*p1 + g_12*p1*p2 + g_02*p0*p2 + g_012*p0*p1*p2;
841552f7358SJed Brown     real[2] = z0 + h_1*p0 + h_3*p1 + h_4*p2 + h_01*p0*p1 + h_01*p0*p1 + h_12*p1*p2 + h_02*p0*p2 + h_012*p0*p1*p2;
842552f7358SJed Brown   }
8439566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(114));
8449566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref,  &ref));
8459566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Xreal, &real));
846552f7358SJed Brown   PetscFunctionReturn(0);
847552f7358SJed Brown }
848552f7358SJed Brown 
8499fbee547SJacob Faibussowitsch static inline PetscErrorCode HexJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
850552f7358SJed Brown {
851552f7358SJed Brown   const PetscScalar *vertices = (const PetscScalar*) ctx;
852552f7358SJed Brown   const PetscScalar x0        = vertices[0];
853552f7358SJed Brown   const PetscScalar y0        = vertices[1];
854552f7358SJed Brown   const PetscScalar z0        = vertices[2];
8557a1931ceSMatthew G. Knepley   const PetscScalar x1        = vertices[9];
8567a1931ceSMatthew G. Knepley   const PetscScalar y1        = vertices[10];
8577a1931ceSMatthew G. Knepley   const PetscScalar z1        = vertices[11];
858552f7358SJed Brown   const PetscScalar x2        = vertices[6];
859552f7358SJed Brown   const PetscScalar y2        = vertices[7];
860552f7358SJed Brown   const PetscScalar z2        = vertices[8];
8617a1931ceSMatthew G. Knepley   const PetscScalar x3        = vertices[3];
8627a1931ceSMatthew G. Knepley   const PetscScalar y3        = vertices[4];
8637a1931ceSMatthew G. Knepley   const PetscScalar z3        = vertices[5];
864552f7358SJed Brown   const PetscScalar x4        = vertices[12];
865552f7358SJed Brown   const PetscScalar y4        = vertices[13];
866552f7358SJed Brown   const PetscScalar z4        = vertices[14];
867552f7358SJed Brown   const PetscScalar x5        = vertices[15];
868552f7358SJed Brown   const PetscScalar y5        = vertices[16];
869552f7358SJed Brown   const PetscScalar z5        = vertices[17];
870552f7358SJed Brown   const PetscScalar x6        = vertices[18];
871552f7358SJed Brown   const PetscScalar y6        = vertices[19];
872552f7358SJed Brown   const PetscScalar z6        = vertices[20];
873552f7358SJed Brown   const PetscScalar x7        = vertices[21];
874552f7358SJed Brown   const PetscScalar y7        = vertices[22];
875552f7358SJed Brown   const PetscScalar z7        = vertices[23];
876552f7358SJed Brown   const PetscScalar f_xy      = x2 - x1 - x3 + x0;
877552f7358SJed Brown   const PetscScalar g_xy      = y2 - y1 - y3 + y0;
878552f7358SJed Brown   const PetscScalar h_xy      = z2 - z1 - z3 + z0;
879552f7358SJed Brown   const PetscScalar f_yz      = x7 - x3 - x4 + x0;
880552f7358SJed Brown   const PetscScalar g_yz      = y7 - y3 - y4 + y0;
881552f7358SJed Brown   const PetscScalar h_yz      = z7 - z3 - z4 + z0;
882552f7358SJed Brown   const PetscScalar f_xz      = x5 - x1 - x4 + x0;
883552f7358SJed Brown   const PetscScalar g_xz      = y5 - y1 - y4 + y0;
884552f7358SJed Brown   const PetscScalar h_xz      = z5 - z1 - z4 + z0;
885552f7358SJed Brown   const PetscScalar f_xyz     = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
886552f7358SJed Brown   const PetscScalar g_xyz     = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
887552f7358SJed Brown   const PetscScalar h_xyz     = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
88856044e6dSMatthew G. Knepley   const PetscScalar *ref;
889552f7358SJed Brown 
890552f7358SJed Brown   PetscFunctionBegin;
8919566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Xref,  &ref));
892552f7358SJed Brown   {
893552f7358SJed Brown     const PetscScalar x       = ref[0];
894552f7358SJed Brown     const PetscScalar y       = ref[1];
895552f7358SJed Brown     const PetscScalar z       = ref[2];
896552f7358SJed Brown     const PetscInt    rows[3] = {0, 1, 2};
897da80777bSKarl Rupp     PetscScalar       values[9];
898da80777bSKarl Rupp 
899da80777bSKarl Rupp     values[0] = (x1 - x0 + f_xy*y + f_xz*z + f_xyz*y*z) / 2.0;
900da80777bSKarl Rupp     values[1] = (x3 - x0 + f_xy*x + f_yz*z + f_xyz*x*z) / 2.0;
901da80777bSKarl Rupp     values[2] = (x4 - x0 + f_yz*y + f_xz*x + f_xyz*x*y) / 2.0;
902da80777bSKarl Rupp     values[3] = (y1 - y0 + g_xy*y + g_xz*z + g_xyz*y*z) / 2.0;
903da80777bSKarl Rupp     values[4] = (y3 - y0 + g_xy*x + g_yz*z + g_xyz*x*z) / 2.0;
904da80777bSKarl Rupp     values[5] = (y4 - y0 + g_yz*y + g_xz*x + g_xyz*x*y) / 2.0;
905da80777bSKarl Rupp     values[6] = (z1 - z0 + h_xy*y + h_xz*z + h_xyz*y*z) / 2.0;
906da80777bSKarl Rupp     values[7] = (z3 - z0 + h_xy*x + h_yz*z + h_xyz*x*z) / 2.0;
907da80777bSKarl Rupp     values[8] = (z4 - z0 + h_yz*y + h_xz*x + h_xyz*x*y) / 2.0;
9081aa26658SKarl Rupp 
9099566063dSJacob Faibussowitsch     PetscCall(MatSetValues(J, 3, rows, 3, rows, values, INSERT_VALUES));
910552f7358SJed Brown   }
9119566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(152));
9129566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Xref,  &ref));
9139566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
9149566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
915552f7358SJed Brown   PetscFunctionReturn(0);
916552f7358SJed Brown }
917552f7358SJed Brown 
9189fbee547SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Hex_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v)
919a6dfd86eSKarl Rupp {
920fafc0619SMatthew G Knepley   DM             dmCoord;
921552f7358SJed Brown   SNES           snes;
922552f7358SJed Brown   KSP            ksp;
923552f7358SJed Brown   PC             pc;
924552f7358SJed Brown   Vec            coordsLocal, r, ref, real;
925552f7358SJed Brown   Mat            J;
92656044e6dSMatthew G. Knepley   const PetscScalar *coords;
92756044e6dSMatthew G. Knepley   PetscScalar    *a;
928552f7358SJed Brown   PetscInt       p;
929552f7358SJed Brown 
930552f7358SJed Brown   PetscFunctionBegin;
9319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
9329566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &dmCoord));
9339566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
9349566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes, "hex_interp_"));
9359566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &r));
9369566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(r, 3, 3));
9379566063dSJacob Faibussowitsch   PetscCall(VecSetType(r,dm->vectype));
9389566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &ref));
9399566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(r, &real));
9409566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &J));
9419566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(J, 3, 3, 3, 3));
9429566063dSJacob Faibussowitsch   PetscCall(MatSetType(J, MATSEQDENSE));
9439566063dSJacob Faibussowitsch   PetscCall(MatSetUp(J));
9449566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes, r, HexMap_Private, NULL));
9459566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes, J, J, HexJacobian_Private, NULL));
9469566063dSJacob Faibussowitsch   PetscCall(SNESGetKSP(snes, &ksp));
9479566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(ksp, &pc));
9489566063dSJacob Faibussowitsch   PetscCall(PCSetType(pc, PCLU));
9499566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
950552f7358SJed Brown 
9519566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(ctx->coords, &coords));
9529566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
953552f7358SJed Brown   for (p = 0; p < ctx->n; ++p) {
954a1e44745SMatthew G. Knepley     PetscScalar *x = NULL, *vertices = NULL;
955552f7358SJed Brown     PetscScalar *xi;
956cb313848SJed Brown     PetscReal    xir[3];
957552f7358SJed Brown     PetscInt     c = ctx->cells[p], comp, coordSize, xSize;
958552f7358SJed Brown 
959552f7358SJed Brown     /* Can make this do all points at once */
9609566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
961cfe5744fSMatthew G. Knepley     PetscCheck(8*3 == coordSize,ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid coordinate closure size %" PetscInt_FMT " should be %d", coordSize, 8*3);
9629566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
963cfe5744fSMatthew G. Knepley     PetscCheck((8*ctx->dof == xSize) || (ctx->dof == xSize),ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input closure size %" PetscInt_FMT " should be %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 8*ctx->dof, ctx->dof);
9649566063dSJacob Faibussowitsch     PetscCall(SNESSetFunction(snes, NULL, NULL, vertices));
9659566063dSJacob Faibussowitsch     PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
9669566063dSJacob Faibussowitsch     PetscCall(VecGetArray(real, &xi));
967552f7358SJed Brown     xi[0]  = coords[p*ctx->dim+0];
968552f7358SJed Brown     xi[1]  = coords[p*ctx->dim+1];
969552f7358SJed Brown     xi[2]  = coords[p*ctx->dim+2];
9709566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(real, &xi));
9719566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes, real, ref));
9729566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ref, &xi));
973cb313848SJed Brown     xir[0] = PetscRealPart(xi[0]);
974cb313848SJed Brown     xir[1] = PetscRealPart(xi[1]);
975cb313848SJed Brown     xir[2] = PetscRealPart(xi[2]);
976cfe5744fSMatthew G. Knepley     if (8*ctx->dof == xSize) {
977552f7358SJed Brown       for (comp = 0; comp < ctx->dof; ++comp) {
978552f7358SJed Brown         a[p*ctx->dof+comp] =
979cb313848SJed Brown           x[0*ctx->dof+comp]*(1-xir[0])*(1-xir[1])*(1-xir[2]) +
9807a1931ceSMatthew G. Knepley           x[3*ctx->dof+comp]*    xir[0]*(1-xir[1])*(1-xir[2]) +
981cb313848SJed Brown           x[2*ctx->dof+comp]*    xir[0]*    xir[1]*(1-xir[2]) +
9827a1931ceSMatthew G. Knepley           x[1*ctx->dof+comp]*(1-xir[0])*    xir[1]*(1-xir[2]) +
983cb313848SJed Brown           x[4*ctx->dof+comp]*(1-xir[0])*(1-xir[1])*   xir[2] +
984cb313848SJed Brown           x[5*ctx->dof+comp]*    xir[0]*(1-xir[1])*   xir[2] +
985cb313848SJed Brown           x[6*ctx->dof+comp]*    xir[0]*    xir[1]*   xir[2] +
986cb313848SJed Brown           x[7*ctx->dof+comp]*(1-xir[0])*    xir[1]*   xir[2];
987552f7358SJed Brown       }
988cfe5744fSMatthew G. Knepley     } else {
989cfe5744fSMatthew G. Knepley       for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp];
990cfe5744fSMatthew G. Knepley     }
9919566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ref, &xi));
9929566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
9939566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
994552f7358SJed Brown   }
9959566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
9969566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
997552f7358SJed Brown 
9989566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
9999566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
10009566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ref));
10019566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&real));
10029566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
1003552f7358SJed Brown   PetscFunctionReturn(0);
1004552f7358SJed Brown }
1005552f7358SJed Brown 
10064267b1a3SMatthew G. Knepley /*@C
10074267b1a3SMatthew G. Knepley   DMInterpolationEvaluate - Using the input from dm and x, calculates interpolated field values at the interpolation points.
10084267b1a3SMatthew G. Knepley 
1009552f7358SJed Brown   Input Parameters:
1010552f7358SJed Brown + ctx - The DMInterpolationInfo context
1011552f7358SJed Brown . dm  - The DM
1012552f7358SJed Brown - x   - The local vector containing the field to be interpolated
1013552f7358SJed Brown 
1014552f7358SJed Brown   Output Parameters:
1015552f7358SJed Brown . v   - The vector containing the interpolated values
10164267b1a3SMatthew G. Knepley 
10174267b1a3SMatthew G. Knepley   Note: A suitable v can be obtained using DMInterpolationGetVector().
10184267b1a3SMatthew G. Knepley 
10194267b1a3SMatthew G. Knepley   Level: beginner
10204267b1a3SMatthew G. Knepley 
10214267b1a3SMatthew G. Knepley .seealso: DMInterpolationGetVector(), DMInterpolationAddPoints(), DMInterpolationCreate()
10224267b1a3SMatthew G. Knepley @*/
10230adebc6cSBarry Smith PetscErrorCode DMInterpolationEvaluate(DMInterpolationInfo ctx, DM dm, Vec x, Vec v)
10240adebc6cSBarry Smith {
102566a0a883SMatthew G. Knepley   PetscDS        ds;
102666a0a883SMatthew G. Knepley   PetscInt       n, p, Nf, field;
102766a0a883SMatthew G. Knepley   PetscBool      useDS = PETSC_FALSE;
1028552f7358SJed Brown 
1029552f7358SJed Brown   PetscFunctionBegin;
1030552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1031552f7358SJed Brown   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
1032552f7358SJed Brown   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
10339566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
1034*08401ef6SPierre Jolivet   PetscCheck(n == ctx->n*ctx->dof,ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input vector size %D should be %D", n, ctx->n*ctx->dof);
103566a0a883SMatthew G. Knepley   if (!n) PetscFunctionReturn(0);
10369566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
1037680d18d5SMatthew G. Knepley   if (ds) {
103866a0a883SMatthew G. Knepley     useDS = PETSC_TRUE;
10399566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(ds, &Nf));
1040680d18d5SMatthew G. Knepley     for (field = 0; field < Nf; ++field) {
104166a0a883SMatthew G. Knepley       PetscObject  obj;
1042680d18d5SMatthew G. Knepley       PetscClassId id;
1043680d18d5SMatthew G. Knepley 
10449566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, field, &obj));
10459566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
104666a0a883SMatthew G. Knepley       if (id != PETSCFE_CLASSID) {useDS = PETSC_FALSE; break;}
104766a0a883SMatthew G. Knepley     }
104866a0a883SMatthew G. Knepley   }
104966a0a883SMatthew G. Knepley   if (useDS) {
105066a0a883SMatthew G. Knepley     const PetscScalar *coords;
105166a0a883SMatthew G. Knepley     PetscScalar       *interpolant;
105266a0a883SMatthew G. Knepley     PetscInt           cdim, d;
105366a0a883SMatthew G. Knepley 
10549566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &cdim));
10559566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ctx->coords, &coords));
10569566063dSJacob Faibussowitsch     PetscCall(VecGetArrayWrite(v, &interpolant));
1057680d18d5SMatthew G. Knepley     for (p = 0; p < ctx->n; ++p) {
105866a0a883SMatthew G. Knepley       PetscReal    pcoords[3], xi[3];
1059680d18d5SMatthew G. Knepley       PetscScalar *xa   = NULL;
106066a0a883SMatthew G. Knepley       PetscInt     coff = 0, foff = 0, clSize;
1061680d18d5SMatthew G. Knepley 
106252aa1562SMatthew G. Knepley       if (ctx->cells[p] < 0) continue;
1063680d18d5SMatthew G. Knepley       for (d = 0; d < cdim; ++d) pcoords[d] = PetscRealPart(coords[p*cdim+d]);
10649566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference(dm, ctx->cells[p], 1, pcoords, xi));
10659566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
106666a0a883SMatthew G. Knepley       for (field = 0; field < Nf; ++field) {
106766a0a883SMatthew G. Knepley         PetscTabulation T;
106866a0a883SMatthew G. Knepley         PetscFE         fe;
106966a0a883SMatthew G. Knepley 
10709566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *) &fe));
10719566063dSJacob Faibussowitsch         PetscCall(PetscFECreateTabulation(fe, 1, 1, xi, 0, &T));
1072680d18d5SMatthew G. Knepley         {
1073680d18d5SMatthew G. Knepley           const PetscReal *basis = T->T[0];
1074680d18d5SMatthew G. Knepley           const PetscInt   Nb    = T->Nb;
1075680d18d5SMatthew G. Knepley           const PetscInt   Nc    = T->Nc;
107666a0a883SMatthew G. Knepley           PetscInt         f, fc;
107766a0a883SMatthew G. Knepley 
1078680d18d5SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
107966a0a883SMatthew G. Knepley             interpolant[p*ctx->dof+coff+fc] = 0.0;
1080680d18d5SMatthew G. Knepley             for (f = 0; f < Nb; ++f) {
108166a0a883SMatthew G. Knepley               interpolant[p*ctx->dof+coff+fc] += xa[foff+f]*basis[(0*Nb + f)*Nc + fc];
1082552f7358SJed Brown             }
1083680d18d5SMatthew G. Knepley           }
108466a0a883SMatthew G. Knepley           coff += Nc;
108566a0a883SMatthew G. Knepley           foff += Nb;
1086680d18d5SMatthew G. Knepley         }
10879566063dSJacob Faibussowitsch         PetscCall(PetscTabulationDestroy(&T));
1088680d18d5SMatthew G. Knepley       }
10899566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
1090*08401ef6SPierre Jolivet       PetscCheck(coff == ctx->dof,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total components %D != %D dof specified for interpolation", coff, ctx->dof);
1091*08401ef6SPierre Jolivet       PetscCheck(foff == clSize,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total FE space size %D != %D closure size", foff, clSize);
109266a0a883SMatthew G. Knepley     }
10939566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
10949566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayWrite(v, &interpolant));
109566a0a883SMatthew G. Knepley   } else {
109666a0a883SMatthew G. Knepley     DMPolytopeType ct;
109766a0a883SMatthew G. Knepley 
1098680d18d5SMatthew G. Knepley     /* TODO Check each cell individually */
10999566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(dm, ctx->cells[0], &ct));
1100680d18d5SMatthew G. Knepley     switch (ct) {
11019566063dSJacob Faibussowitsch       case DM_POLYTOPE_SEGMENT:       PetscCall(DMInterpolate_Segment_Private(ctx, dm, x, v));break;
11029566063dSJacob Faibussowitsch       case DM_POLYTOPE_TRIANGLE:      PetscCall(DMInterpolate_Triangle_Private(ctx, dm, x, v));break;
11039566063dSJacob Faibussowitsch       case DM_POLYTOPE_QUADRILATERAL: PetscCall(DMInterpolate_Quad_Private(ctx, dm, x, v));break;
11049566063dSJacob Faibussowitsch       case DM_POLYTOPE_TETRAHEDRON:   PetscCall(DMInterpolate_Tetrahedron_Private(ctx, dm, x, v));break;
11059566063dSJacob Faibussowitsch       case DM_POLYTOPE_HEXAHEDRON:    PetscCall(DMInterpolate_Hex_Private(ctx, dm, x, v));break;
1106cfe5744fSMatthew G. Knepley       default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for cell type %s", DMPolytopeTypes[PetscMax(0, PetscMin(ct, DM_NUM_POLYTOPES))]);
1107680d18d5SMatthew G. Knepley     }
1108552f7358SJed Brown   }
1109552f7358SJed Brown   PetscFunctionReturn(0);
1110552f7358SJed Brown }
1111552f7358SJed Brown 
11124267b1a3SMatthew G. Knepley /*@C
11134267b1a3SMatthew G. Knepley   DMInterpolationDestroy - Destroys a DMInterpolationInfo context
11144267b1a3SMatthew G. Knepley 
11154267b1a3SMatthew G. Knepley   Collective on ctx
11164267b1a3SMatthew G. Knepley 
11174267b1a3SMatthew G. Knepley   Input Parameter:
11184267b1a3SMatthew G. Knepley . ctx - the context
11194267b1a3SMatthew G. Knepley 
11204267b1a3SMatthew G. Knepley   Level: beginner
11214267b1a3SMatthew G. Knepley 
11224267b1a3SMatthew G. Knepley .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate()
11234267b1a3SMatthew G. Knepley @*/
11240adebc6cSBarry Smith PetscErrorCode DMInterpolationDestroy(DMInterpolationInfo *ctx)
11250adebc6cSBarry Smith {
1126552f7358SJed Brown   PetscFunctionBegin;
1127064a246eSJacob Faibussowitsch   PetscValidPointer(ctx, 1);
11289566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(*ctx)->coords));
11299566063dSJacob Faibussowitsch   PetscCall(PetscFree((*ctx)->points));
11309566063dSJacob Faibussowitsch   PetscCall(PetscFree((*ctx)->cells));
11319566063dSJacob Faibussowitsch   PetscCall(PetscFree(*ctx));
11320298fd71SBarry Smith   *ctx = NULL;
1133552f7358SJed Brown   PetscFunctionReturn(0);
1134552f7358SJed Brown }
1135cc0c4584SMatthew G. Knepley 
1136cc0c4584SMatthew G. Knepley /*@C
1137cc0c4584SMatthew G. Knepley   SNESMonitorFields - Monitors the residual for each field separately
1138cc0c4584SMatthew G. Knepley 
1139cc0c4584SMatthew G. Knepley   Collective on SNES
1140cc0c4584SMatthew G. Knepley 
1141cc0c4584SMatthew G. Knepley   Input Parameters:
1142cc0c4584SMatthew G. Knepley + snes   - the SNES context
1143cc0c4584SMatthew G. Knepley . its    - iteration number
1144cc0c4584SMatthew G. Knepley . fgnorm - 2-norm of residual
1145d43b4f6eSBarry Smith - vf  - PetscViewerAndFormat of type ASCII
1146cc0c4584SMatthew G. Knepley 
1147cc0c4584SMatthew G. Knepley   Notes:
1148cc0c4584SMatthew G. Knepley   This routine prints the residual norm at each iteration.
1149cc0c4584SMatthew G. Knepley 
1150cc0c4584SMatthew G. Knepley   Level: intermediate
1151cc0c4584SMatthew G. Knepley 
1152cc0c4584SMatthew G. Knepley .seealso: SNESMonitorSet(), SNESMonitorDefault()
1153cc0c4584SMatthew G. Knepley @*/
1154d43b4f6eSBarry Smith PetscErrorCode SNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
1155cc0c4584SMatthew G. Knepley {
1156d43b4f6eSBarry Smith   PetscViewer        viewer = vf->viewer;
1157cc0c4584SMatthew G. Knepley   Vec                res;
1158cc0c4584SMatthew G. Knepley   DM                 dm;
1159cc0c4584SMatthew G. Knepley   PetscSection       s;
1160cc0c4584SMatthew G. Knepley   const PetscScalar *r;
1161cc0c4584SMatthew G. Knepley   PetscReal         *lnorms, *norms;
1162cc0c4584SMatthew G. Knepley   PetscInt           numFields, f, pStart, pEnd, p;
1163cc0c4584SMatthew G. Knepley 
1164cc0c4584SMatthew G. Knepley   PetscFunctionBegin;
11654d4332d5SBarry Smith   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4);
11669566063dSJacob Faibussowitsch   PetscCall(SNESGetFunction(snes, &res, NULL, NULL));
11679566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
11689566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
11699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &numFields));
11709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
11719566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &lnorms, numFields, &norms));
11729566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(res, &r));
1173cc0c4584SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
1174cc0c4584SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
1175cc0c4584SMatthew G. Knepley       PetscInt fdof, foff, d;
1176cc0c4584SMatthew G. Knepley 
11779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof));
11789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff));
1179cc0c4584SMatthew G. Knepley       for (d = 0; d < fdof; ++d) lnorms[f] += PetscRealPart(PetscSqr(r[foff+d]));
1180cc0c4584SMatthew G. Knepley     }
1181cc0c4584SMatthew G. Knepley   }
11829566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(res, &r));
11831c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(lnorms, norms, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject) dm)));
11849566063dSJacob Faibussowitsch   PetscCall(PetscViewerPushFormat(viewer,vf->format));
11859566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject) snes)->tablevel));
11869566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "%3D SNES Function norm %14.12e [", its, (double) fgnorm));
1187cc0c4584SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
11889566063dSJacob Faibussowitsch     if (f > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
11899566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "%14.12e", (double) PetscSqrtReal(norms[f])));
1190cc0c4584SMatthew G. Knepley   }
11919566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "]\n"));
11929566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject) snes)->tablevel));
11939566063dSJacob Faibussowitsch   PetscCall(PetscViewerPopFormat(viewer));
11949566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lnorms, norms));
1195cc0c4584SMatthew G. Knepley   PetscFunctionReturn(0);
1196cc0c4584SMatthew G. Knepley }
119724cdb843SMatthew G. Knepley 
119824cdb843SMatthew G. Knepley /********************* Residual Computation **************************/
119924cdb843SMatthew G. Knepley 
12006528b96dSMatthew G. Knepley PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
12016528b96dSMatthew G. Knepley {
12026528b96dSMatthew G. Knepley   PetscInt       depth;
12036528b96dSMatthew G. Knepley 
12046528b96dSMatthew G. Knepley   PetscFunctionBegin;
12059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(plex, &depth));
12069566063dSJacob Faibussowitsch   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
12079566063dSJacob Faibussowitsch   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
12086528b96dSMatthew G. Knepley   PetscFunctionReturn(0);
12096528b96dSMatthew G. Knepley }
12106528b96dSMatthew G. Knepley 
121124cdb843SMatthew G. Knepley /*@
12128db23a53SJed Brown   DMPlexSNESComputeResidualFEM - Sums the local residual into vector F from the local input X using pointwise functions specified by the user
121324cdb843SMatthew G. Knepley 
121424cdb843SMatthew G. Knepley   Input Parameters:
121524cdb843SMatthew G. Knepley + dm - The mesh
121624cdb843SMatthew G. Knepley . X  - Local solution
121724cdb843SMatthew G. Knepley - user - The user context
121824cdb843SMatthew G. Knepley 
121924cdb843SMatthew G. Knepley   Output Parameter:
122024cdb843SMatthew G. Knepley . F  - Local output vector
122124cdb843SMatthew G. Knepley 
12228db23a53SJed Brown   Notes:
12238db23a53SJed Brown   The residual is summed into F; the caller is responsible for using VecZeroEntries() or otherwise ensuring that any data in F is intentional.
12248db23a53SJed Brown 
122524cdb843SMatthew G. Knepley   Level: developer
122624cdb843SMatthew G. Knepley 
12277a73cf09SMatthew G. Knepley .seealso: DMPlexComputeJacobianAction()
122824cdb843SMatthew G. Knepley @*/
122924cdb843SMatthew G. Knepley PetscErrorCode DMPlexSNESComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
123024cdb843SMatthew G. Knepley {
12316da023fcSToby Isaac   DM             plex;
1232083401c6SMatthew G. Knepley   IS             allcellIS;
12336528b96dSMatthew G. Knepley   PetscInt       Nds, s;
123424cdb843SMatthew G. Knepley 
123524cdb843SMatthew G. Knepley   PetscFunctionBegin;
12369566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
12379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
12389566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
12396528b96dSMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
12406528b96dSMatthew G. Knepley     PetscDS          ds;
12416528b96dSMatthew G. Knepley     IS               cellIS;
124206ad1575SMatthew G. Knepley     PetscFormKey key;
12436528b96dSMatthew G. Knepley 
12449566063dSJacob Faibussowitsch     PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds));
12456528b96dSMatthew G. Knepley     key.value = 0;
12466528b96dSMatthew G. Knepley     key.field = 0;
124706ad1575SMatthew G. Knepley     key.part  = 0;
12486528b96dSMatthew G. Knepley     if (!key.label) {
12499566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject) allcellIS));
12506528b96dSMatthew G. Knepley       cellIS = allcellIS;
12516528b96dSMatthew G. Knepley     } else {
12526528b96dSMatthew G. Knepley       IS pointIS;
12536528b96dSMatthew G. Knepley 
12546528b96dSMatthew G. Knepley       key.value = 1;
12559566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
12569566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
12579566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
12586528b96dSMatthew G. Knepley     }
12599566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeResidual_Internal(plex, key, cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user));
12609566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
12616528b96dSMatthew G. Knepley   }
12629566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
12639566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
12646528b96dSMatthew G. Knepley   PetscFunctionReturn(0);
12656528b96dSMatthew G. Knepley }
12666528b96dSMatthew G. Knepley 
12676528b96dSMatthew G. Knepley PetscErrorCode DMSNESComputeResidual(DM dm, Vec X, Vec F, void *user)
12686528b96dSMatthew G. Knepley {
12696528b96dSMatthew G. Knepley   DM             plex;
12706528b96dSMatthew G. Knepley   IS             allcellIS;
12716528b96dSMatthew G. Knepley   PetscInt       Nds, s;
12726528b96dSMatthew G. Knepley 
12736528b96dSMatthew G. Knepley   PetscFunctionBegin;
12749566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
12759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
12769566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
1277083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1278083401c6SMatthew G. Knepley     PetscDS ds;
1279083401c6SMatthew G. Knepley     DMLabel label;
1280083401c6SMatthew G. Knepley     IS      cellIS;
1281083401c6SMatthew G. Knepley 
12829566063dSJacob Faibussowitsch     PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds));
12836528b96dSMatthew G. Knepley     {
128406ad1575SMatthew G. Knepley       PetscWeakFormKind resmap[2] = {PETSC_WF_F0, PETSC_WF_F1};
12856528b96dSMatthew G. Knepley       PetscWeakForm     wf;
12866528b96dSMatthew G. Knepley       PetscInt          Nm = 2, m, Nk = 0, k, kp, off = 0;
128706ad1575SMatthew G. Knepley       PetscFormKey *reskeys;
12886528b96dSMatthew G. Knepley 
12896528b96dSMatthew G. Knepley       /* Get unique residual keys */
12906528b96dSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
12916528b96dSMatthew G. Knepley         PetscInt Nkm;
12929566063dSJacob Faibussowitsch         PetscCall(PetscHMapFormGetSize(ds->wf->form[resmap[m]], &Nkm));
12936528b96dSMatthew G. Knepley         Nk  += Nkm;
12946528b96dSMatthew G. Knepley       }
12959566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nk, &reskeys));
12966528b96dSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
12979566063dSJacob Faibussowitsch         PetscCall(PetscHMapFormGetKeys(ds->wf->form[resmap[m]], &off, reskeys));
12986528b96dSMatthew G. Knepley       }
1299*08401ef6SPierre Jolivet       PetscCheck(off == Nk,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %D should be %D", off, Nk);
13009566063dSJacob Faibussowitsch       PetscCall(PetscFormKeySort(Nk, reskeys));
13016528b96dSMatthew G. Knepley       for (k = 0, kp = 1; kp < Nk; ++kp) {
13026528b96dSMatthew G. Knepley         if ((reskeys[k].label != reskeys[kp].label) || (reskeys[k].value != reskeys[kp].value)) {
13036528b96dSMatthew G. Knepley           ++k;
13046528b96dSMatthew G. Knepley           if (kp != k) reskeys[k] = reskeys[kp];
13056528b96dSMatthew G. Knepley         }
13066528b96dSMatthew G. Knepley       }
13076528b96dSMatthew G. Knepley       Nk = k;
13086528b96dSMatthew G. Knepley 
13099566063dSJacob Faibussowitsch       PetscCall(PetscDSGetWeakForm(ds, &wf));
13106528b96dSMatthew G. Knepley       for (k = 0; k < Nk; ++k) {
13116528b96dSMatthew G. Knepley         DMLabel  label = reskeys[k].label;
13126528b96dSMatthew G. Knepley         PetscInt val   = reskeys[k].value;
13136528b96dSMatthew G. Knepley 
1314083401c6SMatthew G. Knepley         if (!label) {
13159566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject) allcellIS));
1316083401c6SMatthew G. Knepley           cellIS = allcellIS;
1317083401c6SMatthew G. Knepley         } else {
1318083401c6SMatthew G. Knepley           IS pointIS;
1319083401c6SMatthew G. Knepley 
13209566063dSJacob Faibussowitsch           PetscCall(DMLabelGetStratumIS(label, val, &pointIS));
13219566063dSJacob Faibussowitsch           PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
13229566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&pointIS));
13234a3e9fdbSToby Isaac         }
13249566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeResidual_Internal(plex, reskeys[k], cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user));
13259566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&cellIS));
1326083401c6SMatthew G. Knepley       }
13279566063dSJacob Faibussowitsch       PetscCall(PetscFree(reskeys));
13286528b96dSMatthew G. Knepley     }
13296528b96dSMatthew G. Knepley   }
13309566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
13319566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
133224cdb843SMatthew G. Knepley   PetscFunctionReturn(0);
133324cdb843SMatthew G. Knepley }
133424cdb843SMatthew G. Knepley 
1335bdd6f66aSToby Isaac /*@
1336bdd6f66aSToby Isaac   DMPlexSNESComputeBoundaryFEM - Form the boundary values for the local input X
1337bdd6f66aSToby Isaac 
1338bdd6f66aSToby Isaac   Input Parameters:
1339bdd6f66aSToby Isaac + dm - The mesh
1340bdd6f66aSToby Isaac - user - The user context
1341bdd6f66aSToby Isaac 
1342bdd6f66aSToby Isaac   Output Parameter:
1343bdd6f66aSToby Isaac . X  - Local solution
1344bdd6f66aSToby Isaac 
1345bdd6f66aSToby Isaac   Level: developer
1346bdd6f66aSToby Isaac 
13477a73cf09SMatthew G. Knepley .seealso: DMPlexComputeJacobianAction()
1348bdd6f66aSToby Isaac @*/
1349bdd6f66aSToby Isaac PetscErrorCode DMPlexSNESComputeBoundaryFEM(DM dm, Vec X, void *user)
1350bdd6f66aSToby Isaac {
1351bdd6f66aSToby Isaac   DM             plex;
1352bdd6f66aSToby Isaac 
1353bdd6f66aSToby Isaac   PetscFunctionBegin;
13549566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm,&plex,PETSC_TRUE));
13559566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, X, PETSC_MIN_REAL, NULL, NULL, NULL));
13569566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
1357bdd6f66aSToby Isaac   PetscFunctionReturn(0);
1358bdd6f66aSToby Isaac }
1359bdd6f66aSToby Isaac 
13607a73cf09SMatthew G. Knepley /*@
13618e3a2eefSMatthew G. Knepley   DMSNESComputeJacobianAction - Compute the action of the Jacobian J(X) on Y
13627a73cf09SMatthew G. Knepley 
13637a73cf09SMatthew G. Knepley   Input Parameters:
13648e3a2eefSMatthew G. Knepley + dm   - The DM
13657a73cf09SMatthew G. Knepley . X    - Local solution vector
13667a73cf09SMatthew G. Knepley . Y    - Local input vector
13677a73cf09SMatthew G. Knepley - user - The user context
13687a73cf09SMatthew G. Knepley 
13697a73cf09SMatthew G. Knepley   Output Parameter:
13708e3a2eefSMatthew G. Knepley . F    - lcoal output vector
13717a73cf09SMatthew G. Knepley 
13727a73cf09SMatthew G. Knepley   Level: developer
13737a73cf09SMatthew G. Knepley 
13748e3a2eefSMatthew G. Knepley   Notes:
13758e3a2eefSMatthew G. Knepley   Users will typically use DMSNESCreateJacobianMF() followed by MatMult() instead of calling this routine directly.
13768e3a2eefSMatthew G. Knepley 
1377a509fe9cSSatish Balay .seealso: DMSNESCreateJacobianMF(), DMPlexSNESComputeResidualFEM()
13787a73cf09SMatthew G. Knepley @*/
13798e3a2eefSMatthew G. Knepley PetscErrorCode DMSNESComputeJacobianAction(DM dm, Vec X, Vec Y, Vec F, void *user)
1380a925c78cSMatthew G. Knepley {
13818e3a2eefSMatthew G. Knepley   DM             plex;
13828e3a2eefSMatthew G. Knepley   IS             allcellIS;
13838e3a2eefSMatthew G. Knepley   PetscInt       Nds, s;
1384a925c78cSMatthew G. Knepley 
1385a925c78cSMatthew G. Knepley   PetscFunctionBegin;
13869566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
13879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
13889566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
13898e3a2eefSMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
13908e3a2eefSMatthew G. Knepley     PetscDS ds;
13918e3a2eefSMatthew G. Knepley     DMLabel label;
13928e3a2eefSMatthew G. Knepley     IS      cellIS;
13937a73cf09SMatthew G. Knepley 
13949566063dSJacob Faibussowitsch     PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds));
13958e3a2eefSMatthew G. Knepley     {
139606ad1575SMatthew G. Knepley       PetscWeakFormKind jacmap[4] = {PETSC_WF_G0, PETSC_WF_G1, PETSC_WF_G2, PETSC_WF_G3};
13978e3a2eefSMatthew G. Knepley       PetscWeakForm     wf;
13988e3a2eefSMatthew G. Knepley       PetscInt          Nm = 4, m, Nk = 0, k, kp, off = 0;
139906ad1575SMatthew G. Knepley       PetscFormKey *jackeys;
14008e3a2eefSMatthew G. Knepley 
14018e3a2eefSMatthew G. Knepley       /* Get unique Jacobian keys */
14028e3a2eefSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
14038e3a2eefSMatthew G. Knepley         PetscInt Nkm;
14049566063dSJacob Faibussowitsch         PetscCall(PetscHMapFormGetSize(ds->wf->form[jacmap[m]], &Nkm));
14058e3a2eefSMatthew G. Knepley         Nk  += Nkm;
14068e3a2eefSMatthew G. Knepley       }
14079566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nk, &jackeys));
14088e3a2eefSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
14099566063dSJacob Faibussowitsch         PetscCall(PetscHMapFormGetKeys(ds->wf->form[jacmap[m]], &off, jackeys));
14108e3a2eefSMatthew G. Knepley       }
1411*08401ef6SPierre Jolivet       PetscCheck(off == Nk,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %D should be %D", off, Nk);
14129566063dSJacob Faibussowitsch       PetscCall(PetscFormKeySort(Nk, jackeys));
14138e3a2eefSMatthew G. Knepley       for (k = 0, kp = 1; kp < Nk; ++kp) {
14148e3a2eefSMatthew G. Knepley         if ((jackeys[k].label != jackeys[kp].label) || (jackeys[k].value != jackeys[kp].value)) {
14158e3a2eefSMatthew G. Knepley           ++k;
14168e3a2eefSMatthew G. Knepley           if (kp != k) jackeys[k] = jackeys[kp];
14178e3a2eefSMatthew G. Knepley         }
14188e3a2eefSMatthew G. Knepley       }
14198e3a2eefSMatthew G. Knepley       Nk = k;
14208e3a2eefSMatthew G. Knepley 
14219566063dSJacob Faibussowitsch       PetscCall(PetscDSGetWeakForm(ds, &wf));
14228e3a2eefSMatthew G. Knepley       for (k = 0; k < Nk; ++k) {
14238e3a2eefSMatthew G. Knepley         DMLabel  label = jackeys[k].label;
14248e3a2eefSMatthew G. Knepley         PetscInt val   = jackeys[k].value;
14258e3a2eefSMatthew G. Knepley 
14268e3a2eefSMatthew G. Knepley         if (!label) {
14279566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject) allcellIS));
14288e3a2eefSMatthew G. Knepley           cellIS = allcellIS;
14297a73cf09SMatthew G. Knepley         } else {
14308e3a2eefSMatthew G. Knepley           IS pointIS;
1431a925c78cSMatthew G. Knepley 
14329566063dSJacob Faibussowitsch           PetscCall(DMLabelGetStratumIS(label, val, &pointIS));
14339566063dSJacob Faibussowitsch           PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
14349566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&pointIS));
1435a925c78cSMatthew G. Knepley         }
14369566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeJacobian_Action_Internal(plex, jackeys[k], cellIS, 0.0, 0.0, X, NULL, Y, F, user));
14379566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&cellIS));
14388e3a2eefSMatthew G. Knepley       }
14399566063dSJacob Faibussowitsch       PetscCall(PetscFree(jackeys));
14408e3a2eefSMatthew G. Knepley     }
14418e3a2eefSMatthew G. Knepley   }
14429566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
14439566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
1444a925c78cSMatthew G. Knepley   PetscFunctionReturn(0);
1445a925c78cSMatthew G. Knepley }
1446a925c78cSMatthew G. Knepley 
144724cdb843SMatthew G. Knepley /*@
144824cdb843SMatthew G. Knepley   DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
144924cdb843SMatthew G. Knepley 
145024cdb843SMatthew G. Knepley   Input Parameters:
145124cdb843SMatthew G. Knepley + dm - The mesh
145224cdb843SMatthew G. Knepley . X  - Local input vector
145324cdb843SMatthew G. Knepley - user - The user context
145424cdb843SMatthew G. Knepley 
145524cdb843SMatthew G. Knepley   Output Parameter:
145624cdb843SMatthew G. Knepley . Jac  - Jacobian matrix
145724cdb843SMatthew G. Knepley 
145824cdb843SMatthew G. Knepley   Note:
145924cdb843SMatthew G. Knepley   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
146024cdb843SMatthew G. Knepley   like a GPU, or vectorize on a multicore machine.
146124cdb843SMatthew G. Knepley 
146224cdb843SMatthew G. Knepley   Level: developer
146324cdb843SMatthew G. Knepley 
146424cdb843SMatthew G. Knepley .seealso: FormFunctionLocal()
146524cdb843SMatthew G. Knepley @*/
146624cdb843SMatthew G. Knepley PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP,void *user)
146724cdb843SMatthew G. Knepley {
14686da023fcSToby Isaac   DM             plex;
1469083401c6SMatthew G. Knepley   IS             allcellIS;
1470f04eb4edSMatthew G. Knepley   PetscBool      hasJac, hasPrec;
14716528b96dSMatthew G. Knepley   PetscInt       Nds, s;
147224cdb843SMatthew G. Knepley 
147324cdb843SMatthew G. Knepley   PetscFunctionBegin;
14749566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
14759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
14769566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
1477083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1478083401c6SMatthew G. Knepley     PetscDS          ds;
1479083401c6SMatthew G. Knepley     IS               cellIS;
148006ad1575SMatthew G. Knepley     PetscFormKey key;
1481083401c6SMatthew G. Knepley 
14829566063dSJacob Faibussowitsch     PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds));
14836528b96dSMatthew G. Knepley     key.value = 0;
14846528b96dSMatthew G. Knepley     key.field = 0;
148506ad1575SMatthew G. Knepley     key.part  = 0;
14866528b96dSMatthew G. Knepley     if (!key.label) {
14879566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject) allcellIS));
1488083401c6SMatthew G. Knepley       cellIS = allcellIS;
1489083401c6SMatthew G. Knepley     } else {
1490083401c6SMatthew G. Knepley       IS pointIS;
1491083401c6SMatthew G. Knepley 
14926528b96dSMatthew G. Knepley       key.value = 1;
14939566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
14949566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
14959566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
1496083401c6SMatthew G. Knepley     }
1497083401c6SMatthew G. Knepley     if (!s) {
14989566063dSJacob Faibussowitsch       PetscCall(PetscDSHasJacobian(ds, &hasJac));
14999566063dSJacob Faibussowitsch       PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
15009566063dSJacob Faibussowitsch       if (hasJac && hasPrec) PetscCall(MatZeroEntries(Jac));
15019566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(JacP));
1502083401c6SMatthew G. Knepley     }
15039566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeJacobian_Internal(plex, key, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, user));
15049566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
1505083401c6SMatthew G. Knepley   }
15069566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
15079566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
150824cdb843SMatthew G. Knepley   PetscFunctionReturn(0);
150924cdb843SMatthew G. Knepley }
15101878804aSMatthew G. Knepley 
15118e3a2eefSMatthew G. Knepley struct _DMSNESJacobianMFCtx
15128e3a2eefSMatthew G. Knepley {
15138e3a2eefSMatthew G. Knepley   DM    dm;
15148e3a2eefSMatthew G. Knepley   Vec   X;
15158e3a2eefSMatthew G. Knepley   void *ctx;
15168e3a2eefSMatthew G. Knepley };
15178e3a2eefSMatthew G. Knepley 
15188e3a2eefSMatthew G. Knepley static PetscErrorCode DMSNESJacobianMF_Destroy_Private(Mat A)
15198e3a2eefSMatthew G. Knepley {
15208e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15218e3a2eefSMatthew G. Knepley 
15228e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15239566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
15249566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(A, NULL));
15259566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&ctx->dm));
15269566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ctx->X));
15279566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
15288e3a2eefSMatthew G. Knepley   PetscFunctionReturn(0);
15298e3a2eefSMatthew G. Knepley }
15308e3a2eefSMatthew G. Knepley 
15318e3a2eefSMatthew G. Knepley static PetscErrorCode DMSNESJacobianMF_Mult_Private(Mat A, Vec Y, Vec Z)
15328e3a2eefSMatthew G. Knepley {
15338e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15348e3a2eefSMatthew G. Knepley 
15358e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15369566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
15379566063dSJacob Faibussowitsch   PetscCall(DMSNESComputeJacobianAction(ctx->dm, ctx->X, Y, Z, ctx->ctx));
15388e3a2eefSMatthew G. Knepley   PetscFunctionReturn(0);
15398e3a2eefSMatthew G. Knepley }
15408e3a2eefSMatthew G. Knepley 
15418e3a2eefSMatthew G. Knepley /*@
15428e3a2eefSMatthew G. Knepley   DMSNESCreateJacobianMF - Create a Mat which computes the action of the Jacobian matrix-free
15438e3a2eefSMatthew G. Knepley 
15448e3a2eefSMatthew G. Knepley   Collective on dm
15458e3a2eefSMatthew G. Knepley 
15468e3a2eefSMatthew G. Knepley   Input Parameters:
15478e3a2eefSMatthew G. Knepley + dm   - The DM
15488e3a2eefSMatthew G. Knepley . X    - The evaluation point for the Jacobian
15498e3a2eefSMatthew G. Knepley - user - A user context, or NULL
15508e3a2eefSMatthew G. Knepley 
15518e3a2eefSMatthew G. Knepley   Output Parameter:
15528e3a2eefSMatthew G. Knepley . J    - The Mat
15538e3a2eefSMatthew G. Knepley 
15548e3a2eefSMatthew G. Knepley   Level: advanced
15558e3a2eefSMatthew G. Knepley 
15568e3a2eefSMatthew G. Knepley   Notes:
15578e3a2eefSMatthew G. Knepley   Vec X is kept in Mat J, so updating X then updates the evaluation point.
15588e3a2eefSMatthew G. Knepley 
15598e3a2eefSMatthew G. Knepley .seealso: DMSNESComputeJacobianAction()
15608e3a2eefSMatthew G. Knepley @*/
15618e3a2eefSMatthew G. Knepley PetscErrorCode DMSNESCreateJacobianMF(DM dm, Vec X, void *user, Mat *J)
15628e3a2eefSMatthew G. Knepley {
15638e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
15648e3a2eefSMatthew G. Knepley   PetscInt                     n, N;
15658e3a2eefSMatthew G. Knepley 
15668e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
15679566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject) dm), J));
15689566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, MATSHELL));
15699566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(X, &n));
15709566063dSJacob Faibussowitsch   PetscCall(VecGetSize(X, &N));
15719566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, n, n, N, N));
15729566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject) dm));
15739566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject) X));
15749566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &ctx));
15758e3a2eefSMatthew G. Knepley   ctx->dm  = dm;
15768e3a2eefSMatthew G. Knepley   ctx->X   = X;
15778e3a2eefSMatthew G. Knepley   ctx->ctx = user;
15789566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*J, ctx));
15799566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(*J, MATOP_DESTROY, (void (*)(void)) DMSNESJacobianMF_Destroy_Private));
15809566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(*J, MATOP_MULT,    (void (*)(void)) DMSNESJacobianMF_Mult_Private));
15818e3a2eefSMatthew G. Knepley   PetscFunctionReturn(0);
15828e3a2eefSMatthew G. Knepley }
15838e3a2eefSMatthew G. Knepley 
158438cfc46eSPierre Jolivet /*
158538cfc46eSPierre Jolivet      MatComputeNeumannOverlap - Computes an unassembled (Neumann) local overlapping Mat in nonlinear context.
158638cfc46eSPierre Jolivet 
158738cfc46eSPierre Jolivet    Input Parameters:
158838cfc46eSPierre Jolivet +     X - SNES linearization point
158938cfc46eSPierre Jolivet .     ovl - index set of overlapping subdomains
159038cfc46eSPierre Jolivet 
159138cfc46eSPierre Jolivet    Output Parameter:
159238cfc46eSPierre Jolivet .     J - unassembled (Neumann) local matrix
159338cfc46eSPierre Jolivet 
159438cfc46eSPierre Jolivet    Level: intermediate
159538cfc46eSPierre Jolivet 
159638cfc46eSPierre Jolivet .seealso: DMCreateNeumannOverlap(), MATIS, PCHPDDMSetAuxiliaryMat()
159738cfc46eSPierre Jolivet */
159838cfc46eSPierre Jolivet static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, void *ctx)
159938cfc46eSPierre Jolivet {
160038cfc46eSPierre Jolivet   SNES           snes;
160138cfc46eSPierre Jolivet   Mat            pJ;
160238cfc46eSPierre Jolivet   DM             ovldm,origdm;
160338cfc46eSPierre Jolivet   DMSNES         sdm;
160438cfc46eSPierre Jolivet   PetscErrorCode (*bfun)(DM,Vec,void*);
160538cfc46eSPierre Jolivet   PetscErrorCode (*jfun)(DM,Vec,Mat,Mat,void*);
160638cfc46eSPierre Jolivet   void           *bctx,*jctx;
160738cfc46eSPierre Jolivet 
160838cfc46eSPierre Jolivet   PetscFunctionBegin;
16099566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl,"_DM_Overlap_HPDDM_MATIS",(PetscObject*)&pJ));
161028b400f6SJacob Faibussowitsch   PetscCheck(pJ,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing overlapping Mat");
16119566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl,"_DM_Original_HPDDM",(PetscObject*)&origdm));
161228b400f6SJacob Faibussowitsch   PetscCheck(origdm,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing original DM");
16139566063dSJacob Faibussowitsch   PetscCall(MatGetDM(pJ,&ovldm));
16149566063dSJacob Faibussowitsch   PetscCall(DMSNESGetBoundaryLocal(origdm,&bfun,&bctx));
16159566063dSJacob Faibussowitsch   PetscCall(DMSNESSetBoundaryLocal(ovldm,bfun,bctx));
16169566063dSJacob Faibussowitsch   PetscCall(DMSNESGetJacobianLocal(origdm,&jfun,&jctx));
16179566063dSJacob Faibussowitsch   PetscCall(DMSNESSetJacobianLocal(ovldm,jfun,jctx));
16189566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl,"_DM_Overlap_HPDDM_SNES",(PetscObject*)&snes));
161938cfc46eSPierre Jolivet   if (!snes) {
16209566063dSJacob Faibussowitsch     PetscCall(SNESCreate(PetscObjectComm((PetscObject)ovl),&snes));
16219566063dSJacob Faibussowitsch     PetscCall(SNESSetDM(snes,ovldm));
16229566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)ovl,"_DM_Overlap_HPDDM_SNES",(PetscObject)snes));
16239566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)snes));
162438cfc46eSPierre Jolivet   }
16259566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(ovldm,&sdm));
16269566063dSJacob Faibussowitsch   PetscCall(VecLockReadPush(X));
162738cfc46eSPierre Jolivet   PetscStackPush("SNES user Jacobian function");
16289566063dSJacob Faibussowitsch   PetscCall((*sdm->ops->computejacobian)(snes,X,pJ,pJ,sdm->jacobianctx));
162938cfc46eSPierre Jolivet   PetscStackPop;
16309566063dSJacob Faibussowitsch   PetscCall(VecLockReadPop(X));
163138cfc46eSPierre Jolivet   /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */
163238cfc46eSPierre Jolivet   {
163338cfc46eSPierre Jolivet     Mat locpJ;
163438cfc46eSPierre Jolivet 
16359566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pJ,&locpJ));
16369566063dSJacob Faibussowitsch     PetscCall(MatCopy(locpJ,J,SAME_NONZERO_PATTERN));
163738cfc46eSPierre Jolivet   }
163838cfc46eSPierre Jolivet   PetscFunctionReturn(0);
163938cfc46eSPierre Jolivet }
164038cfc46eSPierre Jolivet 
1641a925c78cSMatthew G. Knepley /*@
16429f520fc2SToby Isaac   DMPlexSetSNESLocalFEM - Use DMPlex's internal FEM routines to compute SNES boundary values, residual, and Jacobian.
16439f520fc2SToby Isaac 
16449f520fc2SToby Isaac   Input Parameters:
16459f520fc2SToby Isaac + dm - The DM object
1646dff059c6SToby Isaac . boundaryctx - the user context that will be passed to pointwise evaluation of boundary values (see PetscDSAddBoundary())
16479f520fc2SToby Isaac . residualctx - the user context that will be passed to pointwise evaluation of finite element residual computations (see PetscDSSetResidual())
16489f520fc2SToby Isaac - jacobianctx - the user context that will be passed to pointwise evaluation of finite element Jacobian construction (see PetscDSSetJacobian())
16491a244344SSatish Balay 
16501a244344SSatish Balay   Level: developer
16519f520fc2SToby Isaac @*/
16529f520fc2SToby Isaac PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, void *boundaryctx, void *residualctx, void *jacobianctx)
16539f520fc2SToby Isaac {
16549f520fc2SToby Isaac   PetscFunctionBegin;
16559566063dSJacob Faibussowitsch   PetscCall(DMSNESSetBoundaryLocal(dm,DMPlexSNESComputeBoundaryFEM,boundaryctx));
16569566063dSJacob Faibussowitsch   PetscCall(DMSNESSetFunctionLocal(dm,DMPlexSNESComputeResidualFEM,residualctx));
16579566063dSJacob Faibussowitsch   PetscCall(DMSNESSetJacobianLocal(dm,DMPlexSNESComputeJacobianFEM,jacobianctx));
16589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",MatComputeNeumannOverlap_Plex));
16599f520fc2SToby Isaac   PetscFunctionReturn(0);
16609f520fc2SToby Isaac }
16619f520fc2SToby Isaac 
1662f017bcb6SMatthew G. Knepley /*@C
1663f017bcb6SMatthew G. Knepley   DMSNESCheckDiscretization - Check the discretization error of the exact solution
1664f017bcb6SMatthew G. Knepley 
1665f017bcb6SMatthew G. Knepley   Input Parameters:
1666f017bcb6SMatthew G. Knepley + snes - the SNES object
1667f017bcb6SMatthew G. Knepley . dm   - the DM
1668f2cacb80SMatthew G. Knepley . t    - the time
1669f017bcb6SMatthew G. Knepley . u    - a DM vector
1670f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1671f017bcb6SMatthew G. Knepley 
1672f3c94560SMatthew G. Knepley   Output Parameters:
1673f3c94560SMatthew G. Knepley . error - An array which holds the discretization error in each field, or NULL
1674f3c94560SMatthew G. Knepley 
16757f96f943SMatthew G. Knepley   Note: The user must call PetscDSSetExactSolution() beforehand
16767f96f943SMatthew G. Knepley 
1677f017bcb6SMatthew G. Knepley   Level: developer
1678f017bcb6SMatthew G. Knepley 
16797f96f943SMatthew G. Knepley .seealso: DNSNESCheckFromOptions(), DMSNESCheckResidual(), DMSNESCheckJacobian(), PetscDSSetExactSolution()
1680f017bcb6SMatthew G. Knepley @*/
1681f2cacb80SMatthew G. Knepley PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[])
16821878804aSMatthew G. Knepley {
1683f017bcb6SMatthew G. Knepley   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
1684f017bcb6SMatthew G. Knepley   void            **ectxs;
1685f3c94560SMatthew G. Knepley   PetscReal        *err;
16867f96f943SMatthew G. Knepley   MPI_Comm          comm;
16877f96f943SMatthew G. Knepley   PetscInt          Nf, f;
16881878804aSMatthew G. Knepley 
16891878804aSMatthew G. Knepley   PetscFunctionBegin;
1690f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1691f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1692064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(u, VEC_CLASSID, 4);
1693534a8f05SLisandro Dalcin   if (error) PetscValidRealPointer(error, 6);
16947f96f943SMatthew G. Knepley 
16959566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, t, u, NULL));
16969566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(u, NULL, "-vec_view"));
16977f96f943SMatthew G. Knepley 
16989566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) snes, &comm));
16999566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
17009566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err));
17017f96f943SMatthew G. Knepley   {
17027f96f943SMatthew G. Knepley     PetscInt Nds, s;
17037f96f943SMatthew G. Knepley 
17049566063dSJacob Faibussowitsch     PetscCall(DMGetNumDS(dm, &Nds));
1705083401c6SMatthew G. Knepley     for (s = 0; s < Nds; ++s) {
17067f96f943SMatthew G. Knepley       PetscDS         ds;
1707083401c6SMatthew G. Knepley       DMLabel         label;
1708083401c6SMatthew G. Knepley       IS              fieldIS;
17097f96f943SMatthew G. Knepley       const PetscInt *fields;
17107f96f943SMatthew G. Knepley       PetscInt        dsNf, f;
1711083401c6SMatthew G. Knepley 
17129566063dSJacob Faibussowitsch       PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
17139566063dSJacob Faibussowitsch       PetscCall(PetscDSGetNumFields(ds, &dsNf));
17149566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(fieldIS, &fields));
1715083401c6SMatthew G. Knepley       for (f = 0; f < dsNf; ++f) {
1716083401c6SMatthew G. Knepley         const PetscInt field = fields[f];
17179566063dSJacob Faibussowitsch         PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]));
1718083401c6SMatthew G. Knepley       }
17199566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(fieldIS, &fields));
1720083401c6SMatthew G. Knepley     }
1721083401c6SMatthew G. Knepley   }
1722f017bcb6SMatthew G. Knepley   if (Nf > 1) {
17239566063dSJacob Faibussowitsch     PetscCall(DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err));
1724f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
1725f017bcb6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
1726*08401ef6SPierre Jolivet         PetscCheck(err[f] <= tol,comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g for field %D exceeds tolerance %g", (double) err[f], f, (double) tol);
17271878804aSMatthew G. Knepley       }
1728b878532fSMatthew G. Knepley     } else if (error) {
1729b878532fSMatthew G. Knepley       for (f = 0; f < Nf; ++f) error[f] = err[f];
17301878804aSMatthew G. Knepley     } else {
17319566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "L_2 Error: ["));
1732f017bcb6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
17339566063dSJacob Faibussowitsch         if (f) PetscCall(PetscPrintf(comm, ", "));
17349566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(comm, "%g", (double)err[f]));
17351878804aSMatthew G. Knepley       }
17369566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "]\n"));
1737f017bcb6SMatthew G. Knepley     }
1738f017bcb6SMatthew G. Knepley   } else {
17399566063dSJacob Faibussowitsch     PetscCall(DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0]));
1740f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
1741*08401ef6SPierre Jolivet       PetscCheck(err[0] <= tol,comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double) err[0], (double) tol);
1742b878532fSMatthew G. Knepley     } else if (error) {
1743b878532fSMatthew G. Knepley       error[0] = err[0];
1744f017bcb6SMatthew G. Knepley     } else {
17459566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "L_2 Error: %g\n", (double) err[0]));
1746f017bcb6SMatthew G. Knepley     }
1747f017bcb6SMatthew G. Knepley   }
17489566063dSJacob Faibussowitsch   PetscCall(PetscFree3(exacts, ectxs, err));
1749f017bcb6SMatthew G. Knepley   PetscFunctionReturn(0);
1750f017bcb6SMatthew G. Knepley }
1751f017bcb6SMatthew G. Knepley 
1752f017bcb6SMatthew G. Knepley /*@C
1753f017bcb6SMatthew G. Knepley   DMSNESCheckResidual - Check the residual of the exact solution
1754f017bcb6SMatthew G. Knepley 
1755f017bcb6SMatthew G. Knepley   Input Parameters:
1756f017bcb6SMatthew G. Knepley + snes - the SNES object
1757f017bcb6SMatthew G. Knepley . dm   - the DM
1758f017bcb6SMatthew G. Knepley . u    - a DM vector
1759f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1760f017bcb6SMatthew G. Knepley 
1761f3c94560SMatthew G. Knepley   Output Parameters:
1762f3c94560SMatthew G. Knepley . residual - The residual norm of the exact solution, or NULL
1763f3c94560SMatthew G. Knepley 
1764f017bcb6SMatthew G. Knepley   Level: developer
1765f017bcb6SMatthew G. Knepley 
1766f017bcb6SMatthew G. Knepley .seealso: DNSNESCheckFromOptions(), DMSNESCheckDiscretization(), DMSNESCheckJacobian()
1767f017bcb6SMatthew G. Knepley @*/
1768f3c94560SMatthew G. Knepley PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual)
1769f017bcb6SMatthew G. Knepley {
1770f017bcb6SMatthew G. Knepley   MPI_Comm       comm;
1771f017bcb6SMatthew G. Knepley   Vec            r;
1772f017bcb6SMatthew G. Knepley   PetscReal      res;
1773f017bcb6SMatthew G. Knepley 
1774f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1775f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1776f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1777f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1778534a8f05SLisandro Dalcin   if (residual) PetscValidRealPointer(residual, 5);
17799566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) snes, &comm));
17809566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL));
17819566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(u, &r));
17829566063dSJacob Faibussowitsch   PetscCall(SNESComputeFunction(snes, u, r));
17839566063dSJacob Faibussowitsch   PetscCall(VecNorm(r, NORM_2, &res));
1784f017bcb6SMatthew G. Knepley   if (tol >= 0.0) {
1785*08401ef6SPierre Jolivet     PetscCheck(res <= tol,comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double) res, (double) tol);
1786b878532fSMatthew G. Knepley   } else if (residual) {
1787b878532fSMatthew G. Knepley     *residual = res;
1788f017bcb6SMatthew G. Knepley   } else {
17899566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "L_2 Residual: %g\n", (double)res));
17909566063dSJacob Faibussowitsch     PetscCall(VecChop(r, 1.0e-10));
17919566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject) r, "Initial Residual"));
17929566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)r,"res_"));
17939566063dSJacob Faibussowitsch     PetscCall(VecViewFromOptions(r, NULL, "-vec_view"));
1794f017bcb6SMatthew G. Knepley   }
17959566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
1796f017bcb6SMatthew G. Knepley   PetscFunctionReturn(0);
1797f017bcb6SMatthew G. Knepley }
1798f017bcb6SMatthew G. Knepley 
1799f017bcb6SMatthew G. Knepley /*@C
1800f3c94560SMatthew G. Knepley   DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test
1801f017bcb6SMatthew G. Knepley 
1802f017bcb6SMatthew G. Knepley   Input Parameters:
1803f017bcb6SMatthew G. Knepley + snes - the SNES object
1804f017bcb6SMatthew G. Knepley . dm   - the DM
1805f017bcb6SMatthew G. Knepley . u    - a DM vector
1806f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
1807f017bcb6SMatthew G. Knepley 
1808f3c94560SMatthew G. Knepley   Output Parameters:
1809f3c94560SMatthew G. Knepley + isLinear - Flag indicaing that the function looks linear, or NULL
1810f3c94560SMatthew G. Knepley - convRate - The rate of convergence of the linear model, or NULL
1811f3c94560SMatthew G. Knepley 
1812f017bcb6SMatthew G. Knepley   Level: developer
1813f017bcb6SMatthew G. Knepley 
1814f017bcb6SMatthew G. Knepley .seealso: DNSNESCheckFromOptions(), DMSNESCheckDiscretization(), DMSNESCheckResidual()
1815f017bcb6SMatthew G. Knepley @*/
1816f3c94560SMatthew G. Knepley PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate)
1817f017bcb6SMatthew G. Knepley {
1818f017bcb6SMatthew G. Knepley   MPI_Comm       comm;
1819f017bcb6SMatthew G. Knepley   PetscDS        ds;
1820f017bcb6SMatthew G. Knepley   Mat            J, M;
1821f017bcb6SMatthew G. Knepley   MatNullSpace   nullspace;
1822f3c94560SMatthew G. Knepley   PetscReal      slope, intercept;
18237f96f943SMatthew G. Knepley   PetscBool      hasJac, hasPrec, isLin = PETSC_FALSE;
1824f017bcb6SMatthew G. Knepley 
1825f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
1826f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1827f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1828f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
1829534a8f05SLisandro Dalcin   if (isLinear) PetscValidBoolPointer(isLinear, 5);
1830064a246eSJacob Faibussowitsch   if (convRate) PetscValidRealPointer(convRate, 6);
18319566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) snes, &comm));
18329566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL));
1833f017bcb6SMatthew G. Knepley   /* Create and view matrices */
18349566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(dm, &J));
18359566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
18369566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobian(ds, &hasJac));
18379566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
1838282e7bb4SMatthew G. Knepley   if (hasJac && hasPrec) {
18399566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dm, &M));
18409566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, u, J, M));
18419566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject) M, "Preconditioning Matrix"));
18429566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) M, "jacpre_"));
18439566063dSJacob Faibussowitsch     PetscCall(MatViewFromOptions(M, NULL, "-mat_view"));
18449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
1845282e7bb4SMatthew G. Knepley   } else {
18469566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, u, J, J));
1847282e7bb4SMatthew G. Knepley   }
18489566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) J, "Jacobian"));
18499566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject) J, "jac_"));
18509566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(J, NULL, "-mat_view"));
1851f017bcb6SMatthew G. Knepley   /* Check nullspace */
18529566063dSJacob Faibussowitsch   PetscCall(MatGetNullSpace(J, &nullspace));
1853f017bcb6SMatthew G. Knepley   if (nullspace) {
18541878804aSMatthew G. Knepley     PetscBool isNull;
18559566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceTest(nullspace, J, &isNull));
185628b400f6SJacob Faibussowitsch     PetscCheck(isNull,comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid.");
18571878804aSMatthew G. Knepley   }
1858f017bcb6SMatthew G. Knepley   /* Taylor test */
1859f017bcb6SMatthew G. Knepley   {
1860f017bcb6SMatthew G. Knepley     PetscRandom rand;
1861f017bcb6SMatthew G. Knepley     Vec         du, uhat, r, rhat, df;
1862f3c94560SMatthew G. Knepley     PetscReal   h;
1863f017bcb6SMatthew G. Knepley     PetscReal  *es, *hs, *errors;
1864f017bcb6SMatthew G. Knepley     PetscReal   hMax = 1.0, hMin = 1e-6, hMult = 0.1;
1865f017bcb6SMatthew G. Knepley     PetscInt    Nv, v;
1866f017bcb6SMatthew G. Knepley 
1867f017bcb6SMatthew G. Knepley     /* Choose a perturbation direction */
18689566063dSJacob Faibussowitsch     PetscCall(PetscRandomCreate(comm, &rand));
18699566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &du));
18709566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(du, rand));
18719566063dSJacob Faibussowitsch     PetscCall(PetscRandomDestroy(&rand));
18729566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &df));
18739566063dSJacob Faibussowitsch     PetscCall(MatMult(J, du, df));
1874f017bcb6SMatthew G. Knepley     /* Evaluate residual at u, F(u), save in vector r */
18759566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &r));
18769566063dSJacob Faibussowitsch     PetscCall(SNESComputeFunction(snes, u, r));
1877f017bcb6SMatthew G. Knepley     /* Look at the convergence of our Taylor approximation as we approach u */
1878f017bcb6SMatthew G. Knepley     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv);
18799566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors));
18809566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &uhat));
18819566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &rhat));
1882f017bcb6SMatthew G. Knepley     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) {
18839566063dSJacob Faibussowitsch       PetscCall(VecWAXPY(uhat, h, du, u));
1884f017bcb6SMatthew G. Knepley       /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */
18859566063dSJacob Faibussowitsch       PetscCall(SNESComputeFunction(snes, uhat, rhat));
18869566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df));
18879566063dSJacob Faibussowitsch       PetscCall(VecNorm(rhat, NORM_2, &errors[Nv]));
1888f017bcb6SMatthew G. Knepley 
1889f017bcb6SMatthew G. Knepley       es[Nv] = PetscLog10Real(errors[Nv]);
1890f017bcb6SMatthew G. Knepley       hs[Nv] = PetscLog10Real(h);
1891f017bcb6SMatthew G. Knepley     }
18929566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&uhat));
18939566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rhat));
18949566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&df));
18959566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&r));
18969566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&du));
1897f017bcb6SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1898f017bcb6SMatthew G. Knepley       if ((tol >= 0) && (errors[v] > tol)) break;
1899f017bcb6SMatthew G. Knepley       else if (errors[v] > PETSC_SMALL)    break;
1900f017bcb6SMatthew G. Knepley     }
1901f3c94560SMatthew G. Knepley     if (v == Nv) isLin = PETSC_TRUE;
19029566063dSJacob Faibussowitsch     PetscCall(PetscLinearRegression(Nv, hs, es, &slope, &intercept));
19039566063dSJacob Faibussowitsch     PetscCall(PetscFree3(es, hs, errors));
1904f017bcb6SMatthew G. Knepley     /* Slope should be about 2 */
1905f017bcb6SMatthew G. Knepley     if (tol >= 0) {
19062c71b3e2SJacob Faibussowitsch       PetscCheckFalse(!isLin && PetscAbsReal(2 - slope) > tol,comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double) slope);
1907b878532fSMatthew G. Knepley     } else if (isLinear || convRate) {
1908b878532fSMatthew G. Knepley       if (isLinear) *isLinear = isLin;
1909b878532fSMatthew G. Knepley       if (convRate) *convRate = slope;
1910f017bcb6SMatthew G. Knepley     } else {
19119566063dSJacob Faibussowitsch       if (!isLin) PetscCall(PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double) slope));
19129566063dSJacob Faibussowitsch       else        PetscCall(PetscPrintf(comm, "Function appears to be linear\n"));
1913f017bcb6SMatthew G. Knepley     }
1914f017bcb6SMatthew G. Knepley   }
19159566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
19161878804aSMatthew G. Knepley   PetscFunctionReturn(0);
19171878804aSMatthew G. Knepley }
19181878804aSMatthew G. Knepley 
19197f96f943SMatthew G. Knepley PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u)
1920f017bcb6SMatthew G. Knepley {
1921f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
19229566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL));
19239566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckResidual(snes, dm, u, -1.0, NULL));
19249566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL));
1925f017bcb6SMatthew G. Knepley   PetscFunctionReturn(0);
1926f017bcb6SMatthew G. Knepley }
1927f017bcb6SMatthew G. Knepley 
1928bee9a294SMatthew G. Knepley /*@C
1929bee9a294SMatthew G. Knepley   DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information
1930bee9a294SMatthew G. Knepley 
1931bee9a294SMatthew G. Knepley   Input Parameters:
1932bee9a294SMatthew G. Knepley + snes - the SNES object
19337f96f943SMatthew G. Knepley - u    - representative SNES vector
19347f96f943SMatthew G. Knepley 
19357f96f943SMatthew G. Knepley   Note: The user must call PetscDSSetExactSolution() beforehand
1936bee9a294SMatthew G. Knepley 
1937bee9a294SMatthew G. Knepley   Level: developer
1938bee9a294SMatthew G. Knepley @*/
19397f96f943SMatthew G. Knepley PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u)
19401878804aSMatthew G. Knepley {
19411878804aSMatthew G. Knepley   DM             dm;
19421878804aSMatthew G. Knepley   Vec            sol;
19431878804aSMatthew G. Knepley   PetscBool      check;
19441878804aSMatthew G. Knepley 
19451878804aSMatthew G. Knepley   PetscFunctionBegin;
19469566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)snes)->options,((PetscObject)snes)->prefix, "-dmsnes_check", &check));
19471878804aSMatthew G. Knepley   if (!check) PetscFunctionReturn(0);
19489566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
19499566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(u, &sol));
19509566063dSJacob Faibussowitsch   PetscCall(SNESSetSolution(snes, sol));
19519566063dSJacob Faibussowitsch   PetscCall(DMSNESCheck_Internal(snes, dm, sol));
19529566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sol));
1953552f7358SJed Brown   PetscFunctionReturn(0);
1954552f7358SJed Brown }
1955