xref: /petsc/src/snes/utils/dmplexsnes.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
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 
7d2b2dc1eSMatthew G. Knepley #ifdef PETSC_HAVE_LIBCEED
8d2b2dc1eSMatthew G. Knepley   #include <petscdmceed.h>
9d2b2dc1eSMatthew G. Knepley   #include <petscdmplexceed.h>
10d2b2dc1eSMatthew G. Knepley #endif
11d2b2dc1eSMatthew G. Knepley 
pressure_Private(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar p[])12d71ae5a4SJacob Faibussowitsch static void pressure_Private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar p[])
13d71ae5a4SJacob Faibussowitsch {
14649ef022SMatthew Knepley   p[0] = u[uOff[1]];
15649ef022SMatthew Knepley }
16649ef022SMatthew Knepley 
17649ef022SMatthew Knepley /*
1820f4b53cSBarry Smith   SNESCorrectDiscretePressure_Private - Add a vector in the nullspace to make the continuum integral of the pressure field equal to zero.
1920f4b53cSBarry Smith   This is normally used only to evaluate convergence rates for the pressure accurately.
20649ef022SMatthew Knepley 
21c3339decSBarry Smith   Collective
22649ef022SMatthew Knepley 
23649ef022SMatthew Knepley   Input Parameters:
24420bcc1bSBarry Smith + snes      - The `SNES`
25649ef022SMatthew Knepley . pfield    - The field number for pressure
26649ef022SMatthew Knepley . nullspace - The pressure nullspace
27649ef022SMatthew Knepley . u         - The solution vector
28*2a8381b2SBarry Smith - ctx       - An optional application context
29649ef022SMatthew Knepley 
30649ef022SMatthew Knepley   Output Parameter:
31649ef022SMatthew Knepley . u         - The solution with a continuum pressure integral of zero
32649ef022SMatthew Knepley 
332fe279fdSBarry Smith   Level: developer
342fe279fdSBarry Smith 
35420bcc1bSBarry Smith   Note:
36649ef022SMatthew 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.
37649ef022SMatthew Knepley 
38420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESConvergedCorrectPressure()`
39649ef022SMatthew Knepley */
SNESCorrectDiscretePressure_Private(SNES snes,PetscInt pfield,MatNullSpace nullspace,Vec u,PetscCtx ctx)40*2a8381b2SBarry Smith static PetscErrorCode SNESCorrectDiscretePressure_Private(SNES snes, PetscInt pfield, MatNullSpace nullspace, Vec u, PetscCtx ctx)
41d71ae5a4SJacob Faibussowitsch {
42649ef022SMatthew Knepley   DM          dm;
43649ef022SMatthew Knepley   PetscDS     ds;
44649ef022SMatthew Knepley   const Vec  *nullvecs;
45649ef022SMatthew Knepley   PetscScalar pintd, *intc, *intn;
46649ef022SMatthew Knepley   MPI_Comm    comm;
47649ef022SMatthew Knepley   PetscInt    Nf, Nv;
48649ef022SMatthew Knepley 
49649ef022SMatthew Knepley   PetscFunctionBegin;
509566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
519566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
5228b400f6SJacob Faibussowitsch   PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a SNES DM");
5328b400f6SJacob Faibussowitsch   PetscCheck(nullspace, comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a Jacobian nullspace");
549566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
559566063dSJacob Faibussowitsch   PetscCall(PetscDSSetObjective(ds, pfield, pressure_Private));
569566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceGetVecs(nullspace, NULL, &Nv, &nullvecs));
5763a3b9bcSJacob Faibussowitsch   PetscCheck(Nv == 1, comm, PETSC_ERR_ARG_OUTOFRANGE, "Can only handle a single null vector for pressure, not %" PetscInt_FMT, Nv);
589566063dSJacob Faibussowitsch   PetscCall(VecDot(nullvecs[0], u, &pintd));
5908401ef6SPierre Jolivet   PetscCheck(PetscAbsScalar(pintd) <= PETSC_SMALL, comm, PETSC_ERR_ARG_WRONG, "Discrete integral of pressure: %g", (double)PetscRealPart(pintd));
609566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(Nf, &intc, Nf, &intn));
629566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegralFEM(dm, nullvecs[0], intn, ctx));
639566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegralFEM(dm, u, intc, ctx));
649566063dSJacob Faibussowitsch   PetscCall(VecAXPY(u, -intc[pfield] / intn[pfield], nullvecs[0]));
65649ef022SMatthew Knepley #if defined(PETSC_USE_DEBUG)
669566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegralFEM(dm, u, intc, ctx));
6708401ef6SPierre Jolivet   PetscCheck(PetscAbsScalar(intc[pfield]) <= PETSC_SMALL, comm, PETSC_ERR_ARG_WRONG, "Continuum integral of pressure after correction: %g", (double)PetscRealPart(intc[pfield]));
68649ef022SMatthew Knepley #endif
699566063dSJacob Faibussowitsch   PetscCall(PetscFree2(intc, intn));
703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
71649ef022SMatthew Knepley }
72649ef022SMatthew Knepley 
73649ef022SMatthew Knepley /*@C
74ceaaa498SBarry Smith   SNESConvergedCorrectPressure - The regular `SNES` convergence test that, up on convergence, adds a vector in the nullspace
75ceaaa498SBarry Smith   to make the continuum integral of the pressure field equal to zero.
76649ef022SMatthew Knepley 
77c3339decSBarry Smith   Logically Collective
78649ef022SMatthew Knepley 
79649ef022SMatthew Knepley   Input Parameters:
80f6dfbefdSBarry Smith + snes  - the `SNES` context
81649ef022SMatthew Knepley . it    - the iteration (0 indicates before any Newton steps)
82649ef022SMatthew Knepley . xnorm - 2-norm of current iterate
83e4094ef1SJacob Faibussowitsch . gnorm - 2-norm of current step
84e4094ef1SJacob Faibussowitsch . f     - 2-norm of function at current iterate
85*2a8381b2SBarry Smith - ctx   - Optional application context
86649ef022SMatthew Knepley 
87649ef022SMatthew Knepley   Output Parameter:
8876c63389SBarry Smith . reason - `SNES_CONVERGED_ITERATING`, `SNES_CONVERGED_ITS`, or `SNES_DIVERGED_FUNCTION_NANORINF`
89649ef022SMatthew Knepley 
9020f4b53cSBarry Smith   Options Database Key:
9120f4b53cSBarry Smith . -snes_convergence_test correct_pressure - see `SNESSetFromOptions()`
9220f4b53cSBarry Smith 
9320f4b53cSBarry Smith   Level: advanced
9420f4b53cSBarry Smith 
95649ef022SMatthew Knepley   Notes:
96f6dfbefdSBarry Smith   In order to use this convergence test, you must set up several PETSc structures. First fields must be added to the `DM`, and a `PetscDS`
97f6dfbefdSBarry Smith   must be created with discretizations of those fields. We currently assume that the pressure field has index 1.
98f6dfbefdSBarry Smith   The pressure field must have a nullspace, likely created using the `DMSetNullSpaceConstructor()` interface.
99f6dfbefdSBarry Smith   Last we must be able to integrate the pressure over the domain, so the `DM` attached to the SNES `must` be a `DMPLEX` at this time.
100f362779dSJed Brown 
101ceaaa498SBarry Smith   Developer Note:
102ceaaa498SBarry Smith   This is a total misuse of the `SNES` convergence test handling system. It should be removed. Perhaps a `SNESSetPostSolve()` could
103ceaaa498SBarry Smith   be constructed to handle this process.
104ceaaa498SBarry Smith 
105420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `DM`, `SNESConvergedDefault()`, `SNESSetConvergenceTest()`, `DMSetNullSpaceConstructor()`
106649ef022SMatthew Knepley @*/
SNESConvergedCorrectPressure(SNES snes,PetscInt it,PetscReal xnorm,PetscReal gnorm,PetscReal f,SNESConvergedReason * reason,PetscCtx ctx)107*2a8381b2SBarry Smith PetscErrorCode SNESConvergedCorrectPressure(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, PetscCtx ctx)
108d71ae5a4SJacob Faibussowitsch {
109649ef022SMatthew Knepley   PetscBool monitorIntegral = PETSC_FALSE;
110649ef022SMatthew Knepley 
111649ef022SMatthew Knepley   PetscFunctionBegin;
1129566063dSJacob Faibussowitsch   PetscCall(SNESConvergedDefault(snes, it, xnorm, gnorm, f, reason, ctx));
113649ef022SMatthew Knepley   if (monitorIntegral) {
114649ef022SMatthew Knepley     Mat          J;
115649ef022SMatthew Knepley     Vec          u;
116649ef022SMatthew Knepley     MatNullSpace nullspace;
117649ef022SMatthew Knepley     const Vec   *nullvecs;
118649ef022SMatthew Knepley     PetscScalar  pintd;
119649ef022SMatthew Knepley 
1209566063dSJacob Faibussowitsch     PetscCall(SNESGetSolution(snes, &u));
1219566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
1229566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(J, &nullspace));
1239566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceGetVecs(nullspace, NULL, NULL, &nullvecs));
1249566063dSJacob Faibussowitsch     PetscCall(VecDot(nullvecs[0], u, &pintd));
1259566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "SNES: Discrete integral of pressure: %g\n", (double)PetscRealPart(pintd)));
126649ef022SMatthew Knepley   }
127649ef022SMatthew Knepley   if (*reason > 0) {
128649ef022SMatthew Knepley     Mat          J;
129649ef022SMatthew Knepley     Vec          u;
130649ef022SMatthew Knepley     MatNullSpace nullspace;
131649ef022SMatthew Knepley     PetscInt     pfield = 1;
132649ef022SMatthew Knepley 
1339566063dSJacob Faibussowitsch     PetscCall(SNESGetSolution(snes, &u));
1349566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL));
1359566063dSJacob Faibussowitsch     PetscCall(MatGetNullSpace(J, &nullspace));
1369566063dSJacob Faibussowitsch     PetscCall(SNESCorrectDiscretePressure_Private(snes, pfield, nullspace, u, ctx));
137649ef022SMatthew Knepley   }
1383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
139649ef022SMatthew Knepley }
140649ef022SMatthew Knepley 
DMSNESConvertPlex(DM dm,DM * plex,PetscBool copy)141d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESConvertPlex(DM dm, DM *plex, PetscBool copy)
142d71ae5a4SJacob Faibussowitsch {
1436da023fcSToby Isaac   PetscBool isPlex;
1446da023fcSToby Isaac 
1456da023fcSToby Isaac   PetscFunctionBegin;
1469566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
1476da023fcSToby Isaac   if (isPlex) {
1486da023fcSToby Isaac     *plex = dm;
1499566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
150f7148743SMatthew G. Knepley   } else {
1519566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex));
152f7148743SMatthew G. Knepley     if (!*plex) {
1539566063dSJacob Faibussowitsch       PetscCall(DMConvert(dm, DMPLEX, plex));
1549566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex));
155cbf8eb3cSStefano Zampini     } else {
156cbf8eb3cSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)*plex));
157cbf8eb3cSStefano Zampini     }
1586da023fcSToby Isaac     if (copy) {
1599566063dSJacob Faibussowitsch       PetscCall(DMCopyDMSNES(dm, *plex));
1609566063dSJacob Faibussowitsch       PetscCall(DMCopyAuxiliaryVec(dm, *plex));
1616da023fcSToby Isaac     }
1626da023fcSToby Isaac   }
1633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1646da023fcSToby Isaac }
1656da023fcSToby Isaac 
1664267b1a3SMatthew G. Knepley /*@C
167cc0c4584SMatthew G. Knepley   SNESMonitorFields - Monitors the residual for each field separately
168cc0c4584SMatthew G. Knepley 
169c3339decSBarry Smith   Collective
170cc0c4584SMatthew G. Knepley 
171cc0c4584SMatthew G. Knepley   Input Parameters:
172420bcc1bSBarry Smith + snes   - the `SNES` context, must have an attached `DM`
173cc0c4584SMatthew G. Knepley . its    - iteration number
174cc0c4584SMatthew G. Knepley . fgnorm - 2-norm of residual
175f6dfbefdSBarry Smith - vf     - `PetscViewerAndFormat` of `PetscViewerType` `PETSCVIEWERASCII`
176cc0c4584SMatthew G. Knepley 
1772fe279fdSBarry Smith   Level: intermediate
1782fe279fdSBarry Smith 
179f6dfbefdSBarry Smith   Note:
180cc0c4584SMatthew G. Knepley   This routine prints the residual norm at each iteration.
181cc0c4584SMatthew G. Knepley 
182420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESMonitorSet()`, `SNESMonitorDefault()`
183cc0c4584SMatthew G. Knepley @*/
SNESMonitorFields(SNES snes,PetscInt its,PetscReal fgnorm,PetscViewerAndFormat * vf)184d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
185d71ae5a4SJacob Faibussowitsch {
186d43b4f6eSBarry Smith   PetscViewer        viewer = vf->viewer;
187cc0c4584SMatthew G. Knepley   Vec                res;
188cc0c4584SMatthew G. Knepley   DM                 dm;
189cc0c4584SMatthew G. Knepley   PetscSection       s;
190cc0c4584SMatthew G. Knepley   const PetscScalar *r;
191cc0c4584SMatthew G. Knepley   PetscReal         *lnorms, *norms;
192cc0c4584SMatthew G. Knepley   PetscInt           numFields, f, pStart, pEnd, p;
193cc0c4584SMatthew G. Knepley 
194cc0c4584SMatthew G. Knepley   PetscFunctionBegin;
1954d4332d5SBarry Smith   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
1969566063dSJacob Faibussowitsch   PetscCall(SNESGetFunction(snes, &res, NULL, NULL));
1979566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
1989566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
1999566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &numFields));
2009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2019566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &lnorms, numFields, &norms));
2029566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(res, &r));
203cc0c4584SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
204cc0c4584SMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
205cc0c4584SMatthew G. Knepley       PetscInt fdof, foff, d;
206cc0c4584SMatthew G. Knepley 
2079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof));
2089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff));
209cc0c4584SMatthew G. Knepley       for (d = 0; d < fdof; ++d) lnorms[f] += PetscRealPart(PetscSqr(r[foff + d]));
210cc0c4584SMatthew G. Knepley     }
211cc0c4584SMatthew G. Knepley   }
2129566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(res, &r));
213e91c04dfSPierre Jolivet   PetscCallMPI(MPIU_Allreduce(lnorms, norms, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
2149566063dSJacob Faibussowitsch   PetscCall(PetscViewerPushFormat(viewer, vf->format));
2159566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
21663a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e [", its, (double)fgnorm));
217cc0c4584SMatthew G. Knepley   for (f = 0; f < numFields; ++f) {
2189566063dSJacob Faibussowitsch     if (f > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
2199566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "%14.12e", (double)PetscSqrtReal(norms[f])));
220cc0c4584SMatthew G. Knepley   }
2219566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "]\n"));
2229566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
2239566063dSJacob Faibussowitsch   PetscCall(PetscViewerPopFormat(viewer));
2249566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lnorms, norms));
2253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
226cc0c4584SMatthew G. Knepley }
22724cdb843SMatthew G. Knepley 
2286493148fSStefano Zampini /********************* SNES callbacks **************************/
2296493148fSStefano Zampini 
2306493148fSStefano Zampini /*@
2316493148fSStefano Zampini   DMPlexSNESComputeObjectiveFEM - Sums the local objectives from the local input X using pointwise functions specified by the user
2326493148fSStefano Zampini 
2336493148fSStefano Zampini   Input Parameters:
2346493148fSStefano Zampini + dm  - The mesh
2356493148fSStefano Zampini . X   - Local solution
236*2a8381b2SBarry Smith - ctx - The application context
2376493148fSStefano Zampini 
2386493148fSStefano Zampini   Output Parameter:
2396493148fSStefano Zampini . obj - Local objective value
2406493148fSStefano Zampini 
2416493148fSStefano Zampini   Level: developer
2426493148fSStefano Zampini 
2436493148fSStefano Zampini .seealso: `DM`, `DMPlexSNESComputeResidualFEM()`
2446493148fSStefano Zampini @*/
DMPlexSNESComputeObjectiveFEM(DM dm,Vec X,PetscReal * obj,PetscCtx ctx)245*2a8381b2SBarry Smith PetscErrorCode DMPlexSNESComputeObjectiveFEM(DM dm, Vec X, PetscReal *obj, PetscCtx ctx)
2466493148fSStefano Zampini {
2476493148fSStefano Zampini   PetscInt     Nf, cellHeight, cStart, cEnd;
2486493148fSStefano Zampini   PetscScalar *cintegral;
2496493148fSStefano Zampini 
2506493148fSStefano Zampini   PetscFunctionBegin;
2516493148fSStefano Zampini   PetscCall(DMGetNumFields(dm, &Nf));
2526493148fSStefano Zampini   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
2536493148fSStefano Zampini   PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
2546493148fSStefano Zampini   PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral));
2556493148fSStefano Zampini   PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0));
256*2a8381b2SBarry Smith   PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, ctx));
2576493148fSStefano Zampini   /* Sum up values */
2586493148fSStefano Zampini   *obj = 0;
2596493148fSStefano Zampini   for (PetscInt c = cStart; c < cEnd; ++c)
2606493148fSStefano Zampini     for (PetscInt f = 0; f < Nf; ++f) *obj += PetscRealPart(cintegral[(c - cStart) * Nf + f]);
2616493148fSStefano Zampini   PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0));
2626493148fSStefano Zampini   PetscCall(PetscFree(cintegral));
2636493148fSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2646493148fSStefano Zampini }
26524cdb843SMatthew G. Knepley 
26624cdb843SMatthew G. Knepley /*@
267420bcc1bSBarry Smith   DMPlexSNESComputeResidualFEM - Sums the local residual into vector `F` from the local input `X` using pointwise functions specified by the user
26824cdb843SMatthew G. Knepley 
26924cdb843SMatthew G. Knepley   Input Parameters:
27024cdb843SMatthew G. Knepley + dm  - The mesh
27124cdb843SMatthew G. Knepley . X   - Local solution
272*2a8381b2SBarry Smith - ctx - The application context
27324cdb843SMatthew G. Knepley 
27424cdb843SMatthew G. Knepley   Output Parameter:
27524cdb843SMatthew G. Knepley . F - Local output vector
27624cdb843SMatthew G. Knepley 
2772fe279fdSBarry Smith   Level: developer
2782fe279fdSBarry Smith 
279f6dfbefdSBarry Smith   Note:
280420bcc1bSBarry Smith   The residual is summed into `F`; the caller is responsible for using `VecZeroEntries()` or otherwise ensuring that any data in `F` is intentional.
2818db23a53SJed Brown 
2826493148fSStefano Zampini .seealso: [](ch_snes), `DM`, `DMPLEX`, `DMSNESComputeJacobianAction()`
28324cdb843SMatthew G. Knepley @*/
DMPlexSNESComputeResidualFEM(DM dm,Vec X,Vec F,PetscCtx ctx)284*2a8381b2SBarry Smith PetscErrorCode DMPlexSNESComputeResidualFEM(DM dm, Vec X, Vec F, PetscCtx ctx)
285d71ae5a4SJacob Faibussowitsch {
2866da023fcSToby Isaac   DM       plex;
287083401c6SMatthew G. Knepley   IS       allcellIS;
2886528b96dSMatthew G. Knepley   PetscInt Nds, s;
28924cdb843SMatthew G. Knepley 
29024cdb843SMatthew G. Knepley   PetscFunctionBegin;
2919566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
2929566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
2939566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
2946528b96dSMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
2956528b96dSMatthew G. Knepley     PetscDS      ds;
2966528b96dSMatthew G. Knepley     IS           cellIS;
29706ad1575SMatthew G. Knepley     PetscFormKey key;
2986528b96dSMatthew G. Knepley 
29907218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds, NULL));
3006528b96dSMatthew G. Knepley     key.value = 0;
3016528b96dSMatthew G. Knepley     key.field = 0;
30206ad1575SMatthew G. Knepley     key.part  = 0;
3036528b96dSMatthew G. Knepley     if (!key.label) {
3049566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)allcellIS));
3056528b96dSMatthew G. Knepley       cellIS = allcellIS;
3066528b96dSMatthew G. Knepley     } else {
3076528b96dSMatthew G. Knepley       IS pointIS;
3086528b96dSMatthew G. Knepley 
3096528b96dSMatthew G. Knepley       key.value = 1;
3109566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
3119566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
3129566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
3136528b96dSMatthew G. Knepley     }
314*2a8381b2SBarry Smith     PetscCall(DMPlexComputeResidualByKey(plex, key, cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, ctx));
3159566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
3166528b96dSMatthew G. Knepley   }
3179566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
3189566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
3193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3206528b96dSMatthew G. Knepley }
3216528b96dSMatthew G. Knepley 
322bdd6f66aSToby Isaac /*@
323420bcc1bSBarry Smith   DMPlexSNESComputeResidualDS - Sums the local residual into vector `F` from the local input `X` using all pointwise functions with unique keys in the `PetscDS`
324d2b2dc1eSMatthew G. Knepley 
325d2b2dc1eSMatthew G. Knepley   Input Parameters:
326d2b2dc1eSMatthew G. Knepley + dm  - The mesh
327d2b2dc1eSMatthew G. Knepley . X   - Local solution
328*2a8381b2SBarry Smith - ctx - The application context
329d2b2dc1eSMatthew G. Knepley 
330d2b2dc1eSMatthew G. Knepley   Output Parameter:
331d2b2dc1eSMatthew G. Knepley . F - Local output vector
332d2b2dc1eSMatthew G. Knepley 
333d2b2dc1eSMatthew G. Knepley   Level: developer
334d2b2dc1eSMatthew G. Knepley 
335d2b2dc1eSMatthew G. Knepley   Note:
336420bcc1bSBarry Smith   The residual is summed into `F`; the caller is responsible for using `VecZeroEntries()` or otherwise ensuring that any data in `F` is intentional.
337d2b2dc1eSMatthew G. Knepley 
338420bcc1bSBarry Smith .seealso: [](ch_snes), `DM`, `DMPLEX`, `DMPlexComputeJacobianAction()`
339d2b2dc1eSMatthew G. Knepley @*/
DMPlexSNESComputeResidualDS(DM dm,Vec X,Vec F,PetscCtx ctx)340*2a8381b2SBarry Smith PetscErrorCode DMPlexSNESComputeResidualDS(DM dm, Vec X, Vec F, PetscCtx ctx)
341d2b2dc1eSMatthew G. Knepley {
342d2b2dc1eSMatthew G. Knepley   DM       plex;
343d2b2dc1eSMatthew G. Knepley   IS       allcellIS;
344d2b2dc1eSMatthew G. Knepley   PetscInt Nds, s;
345d2b2dc1eSMatthew G. Knepley 
346d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
347d2b2dc1eSMatthew G. Knepley   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
348d2b2dc1eSMatthew G. Knepley   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
349d2b2dc1eSMatthew G. Knepley   PetscCall(DMGetNumDS(dm, &Nds));
350d2b2dc1eSMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
351d2b2dc1eSMatthew G. Knepley     PetscDS ds;
352d2b2dc1eSMatthew G. Knepley     DMLabel label;
353d2b2dc1eSMatthew G. Knepley     IS      cellIS;
354d2b2dc1eSMatthew G. Knepley 
355d2b2dc1eSMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds, NULL));
356d2b2dc1eSMatthew G. Knepley     {
357d2b2dc1eSMatthew G. Knepley       PetscWeakFormKind resmap[2] = {PETSC_WF_F0, PETSC_WF_F1};
358d2b2dc1eSMatthew G. Knepley       PetscWeakForm     wf;
359d2b2dc1eSMatthew G. Knepley       PetscInt          Nm = 2, m, Nk = 0, k, kp, off = 0;
360d2b2dc1eSMatthew G. Knepley       PetscFormKey     *reskeys;
361d2b2dc1eSMatthew G. Knepley 
362d2b2dc1eSMatthew G. Knepley       /* Get unique residual keys */
363d2b2dc1eSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
364d2b2dc1eSMatthew G. Knepley         PetscInt Nkm;
365d2b2dc1eSMatthew G. Knepley         PetscCall(PetscHMapFormGetSize(ds->wf->form[resmap[m]], &Nkm));
366d2b2dc1eSMatthew G. Knepley         Nk += Nkm;
367d2b2dc1eSMatthew G. Knepley       }
368d2b2dc1eSMatthew G. Knepley       PetscCall(PetscMalloc1(Nk, &reskeys));
369d2b2dc1eSMatthew G. Knepley       for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[resmap[m]], &off, reskeys));
370d2b2dc1eSMatthew G. Knepley       PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk);
371d2b2dc1eSMatthew G. Knepley       PetscCall(PetscFormKeySort(Nk, reskeys));
372d2b2dc1eSMatthew G. Knepley       for (k = 0, kp = 1; kp < Nk; ++kp) {
373d2b2dc1eSMatthew G. Knepley         if ((reskeys[k].label != reskeys[kp].label) || (reskeys[k].value != reskeys[kp].value)) {
374d2b2dc1eSMatthew G. Knepley           ++k;
375d2b2dc1eSMatthew G. Knepley           if (kp != k) reskeys[k] = reskeys[kp];
376d2b2dc1eSMatthew G. Knepley         }
377d2b2dc1eSMatthew G. Knepley       }
378d2b2dc1eSMatthew G. Knepley       Nk = k;
379d2b2dc1eSMatthew G. Knepley 
380d2b2dc1eSMatthew G. Knepley       PetscCall(PetscDSGetWeakForm(ds, &wf));
381d2b2dc1eSMatthew G. Knepley       for (k = 0; k < Nk; ++k) {
382d2b2dc1eSMatthew G. Knepley         DMLabel  label = reskeys[k].label;
383d2b2dc1eSMatthew G. Knepley         PetscInt val   = reskeys[k].value;
384d2b2dc1eSMatthew G. Knepley 
385d2b2dc1eSMatthew G. Knepley         if (!label) {
386d2b2dc1eSMatthew G. Knepley           PetscCall(PetscObjectReference((PetscObject)allcellIS));
387d2b2dc1eSMatthew G. Knepley           cellIS = allcellIS;
388d2b2dc1eSMatthew G. Knepley         } else {
389d2b2dc1eSMatthew G. Knepley           IS pointIS;
390d2b2dc1eSMatthew G. Knepley 
391d2b2dc1eSMatthew G. Knepley           PetscCall(DMLabelGetStratumIS(label, val, &pointIS));
392d2b2dc1eSMatthew G. Knepley           PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
393d2b2dc1eSMatthew G. Knepley           PetscCall(ISDestroy(&pointIS));
394d2b2dc1eSMatthew G. Knepley         }
395*2a8381b2SBarry Smith         PetscCall(DMPlexComputeResidualByKey(plex, reskeys[k], cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, ctx));
396d2b2dc1eSMatthew G. Knepley         PetscCall(ISDestroy(&cellIS));
397d2b2dc1eSMatthew G. Knepley       }
398d2b2dc1eSMatthew G. Knepley       PetscCall(PetscFree(reskeys));
399d2b2dc1eSMatthew G. Knepley     }
400d2b2dc1eSMatthew G. Knepley   }
401d2b2dc1eSMatthew G. Knepley   PetscCall(ISDestroy(&allcellIS));
402d2b2dc1eSMatthew G. Knepley   PetscCall(DMDestroy(&plex));
403d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
404d2b2dc1eSMatthew G. Knepley }
405d2b2dc1eSMatthew G. Knepley 
406d2b2dc1eSMatthew G. Knepley /*@
407420bcc1bSBarry Smith   DMPlexSNESComputeBoundaryFEM - Form the boundary values for the local input `X`
408bdd6f66aSToby Isaac 
409bdd6f66aSToby Isaac   Input Parameters:
410bdd6f66aSToby Isaac + dm  - The mesh
411*2a8381b2SBarry Smith - ctx - The application context
412bdd6f66aSToby Isaac 
413bdd6f66aSToby Isaac   Output Parameter:
414bdd6f66aSToby Isaac . X - Local solution
415bdd6f66aSToby Isaac 
416bdd6f66aSToby Isaac   Level: developer
417bdd6f66aSToby Isaac 
418420bcc1bSBarry Smith .seealso: [](ch_snes), `DM`, `DMPLEX`, `DMPlexComputeJacobianAction()`
419bdd6f66aSToby Isaac @*/
DMPlexSNESComputeBoundaryFEM(DM dm,Vec X,PetscCtx ctx)420*2a8381b2SBarry Smith PetscErrorCode DMPlexSNESComputeBoundaryFEM(DM dm, Vec X, PetscCtx ctx)
421d71ae5a4SJacob Faibussowitsch {
422bdd6f66aSToby Isaac   DM plex;
423bdd6f66aSToby Isaac 
424bdd6f66aSToby Isaac   PetscFunctionBegin;
4259566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
4269566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, X, PETSC_MIN_REAL, NULL, NULL, NULL));
4279566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
4283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
429bdd6f66aSToby Isaac }
430bdd6f66aSToby Isaac 
4317a73cf09SMatthew G. Knepley /*@
432c118d280SBarry Smith   DMSNESComputeJacobianAction - Compute the action of the Jacobian J(`X`) on `Y`
4337a73cf09SMatthew G. Knepley 
4347a73cf09SMatthew G. Knepley   Input Parameters:
435f6dfbefdSBarry Smith + dm  - The `DM`
4367a73cf09SMatthew G. Knepley . X   - Local solution vector
4377a73cf09SMatthew G. Knepley . Y   - Local input vector
438*2a8381b2SBarry Smith - ctx - The application context
4397a73cf09SMatthew G. Knepley 
4407a73cf09SMatthew G. Knepley   Output Parameter:
44169d47153SPierre Jolivet . F - local output vector
4427a73cf09SMatthew G. Knepley 
4437a73cf09SMatthew G. Knepley   Level: developer
4447a73cf09SMatthew G. Knepley 
445c118d280SBarry Smith   Note:
446f6dfbefdSBarry Smith   Users will typically use `DMSNESCreateJacobianMF()` followed by `MatMult()` instead of calling this routine directly.
4478e3a2eefSMatthew G. Knepley 
448c118d280SBarry Smith   This only works with `DMPLEX`
449c118d280SBarry Smith 
450c118d280SBarry Smith   Developer Note:
451c118d280SBarry Smith   This should be called `DMPlexSNESComputeJacobianAction()`
452c118d280SBarry Smith 
453a94f484eSPierre Jolivet .seealso: [](ch_snes), `DM`, `DMSNESCreateJacobianMF()`, `DMPlexSNESComputeResidualFEM()`
4547a73cf09SMatthew G. Knepley @*/
DMSNESComputeJacobianAction(DM dm,Vec X,Vec Y,Vec F,PetscCtx ctx)455*2a8381b2SBarry Smith PetscErrorCode DMSNESComputeJacobianAction(DM dm, Vec X, Vec Y, Vec F, PetscCtx ctx)
456d71ae5a4SJacob Faibussowitsch {
4578e3a2eefSMatthew G. Knepley   DM       plex;
4588e3a2eefSMatthew G. Knepley   IS       allcellIS;
4598e3a2eefSMatthew G. Knepley   PetscInt Nds, s;
460a925c78cSMatthew G. Knepley 
461a925c78cSMatthew G. Knepley   PetscFunctionBegin;
4629566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
4639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
4649566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
4658e3a2eefSMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
4668e3a2eefSMatthew G. Knepley     PetscDS ds;
4678e3a2eefSMatthew G. Knepley     DMLabel label;
4688e3a2eefSMatthew G. Knepley     IS      cellIS;
4697a73cf09SMatthew G. Knepley 
47007218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds, NULL));
4718e3a2eefSMatthew G. Knepley     {
47206ad1575SMatthew G. Knepley       PetscWeakFormKind jacmap[4] = {PETSC_WF_G0, PETSC_WF_G1, PETSC_WF_G2, PETSC_WF_G3};
4738e3a2eefSMatthew G. Knepley       PetscWeakForm     wf;
4748e3a2eefSMatthew G. Knepley       PetscInt          Nm = 4, m, Nk = 0, k, kp, off = 0;
47506ad1575SMatthew G. Knepley       PetscFormKey     *jackeys;
4768e3a2eefSMatthew G. Knepley 
4778e3a2eefSMatthew G. Knepley       /* Get unique Jacobian keys */
4788e3a2eefSMatthew G. Knepley       for (m = 0; m < Nm; ++m) {
4798e3a2eefSMatthew G. Knepley         PetscInt Nkm;
4809566063dSJacob Faibussowitsch         PetscCall(PetscHMapFormGetSize(ds->wf->form[jacmap[m]], &Nkm));
4818e3a2eefSMatthew G. Knepley         Nk += Nkm;
4828e3a2eefSMatthew G. Knepley       }
4839566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Nk, &jackeys));
48448a46eb9SPierre Jolivet       for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[jacmap[m]], &off, jackeys));
48563a3b9bcSJacob Faibussowitsch       PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk);
4869566063dSJacob Faibussowitsch       PetscCall(PetscFormKeySort(Nk, jackeys));
4878e3a2eefSMatthew G. Knepley       for (k = 0, kp = 1; kp < Nk; ++kp) {
4888e3a2eefSMatthew G. Knepley         if ((jackeys[k].label != jackeys[kp].label) || (jackeys[k].value != jackeys[kp].value)) {
4898e3a2eefSMatthew G. Knepley           ++k;
4908e3a2eefSMatthew G. Knepley           if (kp != k) jackeys[k] = jackeys[kp];
4918e3a2eefSMatthew G. Knepley         }
4928e3a2eefSMatthew G. Knepley       }
4938e3a2eefSMatthew G. Knepley       Nk = k;
4948e3a2eefSMatthew G. Knepley 
4959566063dSJacob Faibussowitsch       PetscCall(PetscDSGetWeakForm(ds, &wf));
4968e3a2eefSMatthew G. Knepley       for (k = 0; k < Nk; ++k) {
4978e3a2eefSMatthew G. Knepley         DMLabel  label = jackeys[k].label;
4988e3a2eefSMatthew G. Knepley         PetscInt val   = jackeys[k].value;
4998e3a2eefSMatthew G. Knepley 
5008e3a2eefSMatthew G. Knepley         if (!label) {
5019566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)allcellIS));
5028e3a2eefSMatthew G. Knepley           cellIS = allcellIS;
5037a73cf09SMatthew G. Knepley         } else {
5048e3a2eefSMatthew G. Knepley           IS pointIS;
505a925c78cSMatthew G. Knepley 
5069566063dSJacob Faibussowitsch           PetscCall(DMLabelGetStratumIS(label, val, &pointIS));
5079566063dSJacob Faibussowitsch           PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
5089566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&pointIS));
509a925c78cSMatthew G. Knepley         }
510*2a8381b2SBarry Smith         PetscCall(DMPlexComputeJacobianActionByKey(plex, jackeys[k], cellIS, 0.0, 0.0, X, NULL, Y, F, ctx));
5119566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&cellIS));
5128e3a2eefSMatthew G. Knepley       }
5139566063dSJacob Faibussowitsch       PetscCall(PetscFree(jackeys));
5148e3a2eefSMatthew G. Knepley     }
5158e3a2eefSMatthew G. Knepley   }
5169566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
5179566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
5183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
519a925c78cSMatthew G. Knepley }
520a925c78cSMatthew G. Knepley 
52124cdb843SMatthew G. Knepley /*@
5222fe279fdSBarry Smith   DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix `Jac` at the local solution `X` using pointwise functions specified by the user.
52324cdb843SMatthew G. Knepley 
52424cdb843SMatthew G. Knepley   Input Parameters:
5252fe279fdSBarry Smith + dm  - The `DM`
52624cdb843SMatthew G. Knepley . X   - Local input vector
527*2a8381b2SBarry Smith - ctx - The application context
52824cdb843SMatthew G. Knepley 
5292fe279fdSBarry Smith   Output Parameters:
5302fe279fdSBarry Smith + Jac  - Jacobian matrix
5312fe279fdSBarry Smith - JacP - approximate Jacobian from which the preconditioner will be built, often `Jac`
5322fe279fdSBarry Smith 
5332fe279fdSBarry Smith   Level: developer
53424cdb843SMatthew G. Knepley 
53524cdb843SMatthew G. Knepley   Note:
53624cdb843SMatthew G. Knepley   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
53724cdb843SMatthew G. Knepley   like a GPU, or vectorize on a multicore machine.
53824cdb843SMatthew G. Knepley 
539420bcc1bSBarry Smith .seealso: [](ch_snes), `DMPLEX`, `Mat`
54024cdb843SMatthew G. Knepley @*/
DMPlexSNESComputeJacobianFEM(DM dm,Vec X,Mat Jac,Mat JacP,PetscCtx ctx)541*2a8381b2SBarry Smith PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, PetscCtx ctx)
542d71ae5a4SJacob Faibussowitsch {
5436da023fcSToby Isaac   DM        plex;
544083401c6SMatthew G. Knepley   IS        allcellIS;
545f04eb4edSMatthew G. Knepley   PetscBool hasJac, hasPrec;
5466528b96dSMatthew G. Knepley   PetscInt  Nds, s;
54724cdb843SMatthew G. Knepley 
54824cdb843SMatthew G. Knepley   PetscFunctionBegin;
5499566063dSJacob Faibussowitsch   PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE));
5509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS));
5519566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
552083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
553083401c6SMatthew G. Knepley     PetscDS      ds;
554083401c6SMatthew G. Knepley     IS           cellIS;
55506ad1575SMatthew G. Knepley     PetscFormKey key;
556083401c6SMatthew G. Knepley 
55707218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds, NULL));
5586528b96dSMatthew G. Knepley     key.value = 0;
5596528b96dSMatthew G. Knepley     key.field = 0;
56006ad1575SMatthew G. Knepley     key.part  = 0;
5616528b96dSMatthew G. Knepley     if (!key.label) {
5629566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)allcellIS));
563083401c6SMatthew G. Knepley       cellIS = allcellIS;
564083401c6SMatthew G. Knepley     } else {
565083401c6SMatthew G. Knepley       IS pointIS;
566083401c6SMatthew G. Knepley 
5676528b96dSMatthew G. Knepley       key.value = 1;
5689566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
5699566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS));
5709566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
571083401c6SMatthew G. Knepley     }
572083401c6SMatthew G. Knepley     if (!s) {
5739566063dSJacob Faibussowitsch       PetscCall(PetscDSHasJacobian(ds, &hasJac));
5749566063dSJacob Faibussowitsch       PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
5759566063dSJacob Faibussowitsch       if (hasJac && hasPrec) PetscCall(MatZeroEntries(Jac));
5769566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(JacP));
577083401c6SMatthew G. Knepley     }
578*2a8381b2SBarry Smith     PetscCall(DMPlexComputeJacobianByKey(plex, key, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, ctx));
5799566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cellIS));
580083401c6SMatthew G. Knepley   }
5819566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&allcellIS));
5829566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
5833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58424cdb843SMatthew G. Knepley }
5851878804aSMatthew G. Knepley 
5869371c9d4SSatish Balay struct _DMSNESJacobianMFCtx {
5878e3a2eefSMatthew G. Knepley   DM       dm;
5888e3a2eefSMatthew G. Knepley   Vec      X;
589*2a8381b2SBarry Smith   PetscCtx ctx;
5908e3a2eefSMatthew G. Knepley };
5918e3a2eefSMatthew G. Knepley 
DMSNESJacobianMF_Destroy_Private(Mat A)592d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Destroy_Private(Mat A)
593d71ae5a4SJacob Faibussowitsch {
5948e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
5958e3a2eefSMatthew G. Knepley 
5968e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
5979566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
5989566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(A, NULL));
5999566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&ctx->dm));
6009566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ctx->X));
6019566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
6023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6038e3a2eefSMatthew G. Knepley }
6048e3a2eefSMatthew G. Knepley 
DMSNESJacobianMF_Mult_Private(Mat A,Vec Y,Vec Z)605d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Mult_Private(Mat A, Vec Y, Vec Z)
606d71ae5a4SJacob Faibussowitsch {
6078e3a2eefSMatthew G. Knepley   struct _DMSNESJacobianMFCtx *ctx;
6088e3a2eefSMatthew G. Knepley 
6098e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
6109566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(A, &ctx));
6119566063dSJacob Faibussowitsch   PetscCall(DMSNESComputeJacobianAction(ctx->dm, ctx->X, Y, Z, ctx->ctx));
6123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6138e3a2eefSMatthew G. Knepley }
6148e3a2eefSMatthew G. Knepley 
6158e3a2eefSMatthew G. Knepley /*@
616f6dfbefdSBarry Smith   DMSNESCreateJacobianMF - Create a `Mat` which computes the action of the Jacobian matrix-free
6178e3a2eefSMatthew G. Knepley 
618c3339decSBarry Smith   Collective
6198e3a2eefSMatthew G. Knepley 
6208e3a2eefSMatthew G. Knepley   Input Parameters:
621f6dfbefdSBarry Smith + dm  - The `DM`
6228e3a2eefSMatthew G. Knepley . X   - The evaluation point for the Jacobian
623*2a8381b2SBarry Smith - ctx - An application context, or `NULL`
6248e3a2eefSMatthew G. Knepley 
6258e3a2eefSMatthew G. Knepley   Output Parameter:
626f6dfbefdSBarry Smith . J - The `Mat`
6278e3a2eefSMatthew G. Knepley 
6288e3a2eefSMatthew G. Knepley   Level: advanced
6298e3a2eefSMatthew G. Knepley 
630c118d280SBarry Smith   Notes:
6312fe279fdSBarry Smith   Vec `X` is kept in `J`, so updating `X` then updates the evaluation point.
6328e3a2eefSMatthew G. Knepley 
633c118d280SBarry Smith   This only works for `DMPLEX`
634c118d280SBarry Smith 
635420bcc1bSBarry Smith .seealso: [](ch_snes), `DM`, `SNES`, `DMSNESComputeJacobianAction()`
6368e3a2eefSMatthew G. Knepley @*/
DMSNESCreateJacobianMF(DM dm,Vec X,PetscCtx ctx,Mat * J)637*2a8381b2SBarry Smith PetscErrorCode DMSNESCreateJacobianMF(DM dm, Vec X, PetscCtx ctx, Mat *J)
638d71ae5a4SJacob Faibussowitsch {
639*2a8381b2SBarry Smith   struct _DMSNESJacobianMFCtx *ictx;
6408e3a2eefSMatthew G. Knepley   PetscInt                     n, N;
6418e3a2eefSMatthew G. Knepley 
6428e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
6439566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
6449566063dSJacob Faibussowitsch   PetscCall(MatSetType(*J, MATSHELL));
6459566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(X, &n));
6469566063dSJacob Faibussowitsch   PetscCall(VecGetSize(X, &N));
6479566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*J, n, n, N, N));
6489566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)dm));
6499566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)X));
650*2a8381b2SBarry Smith   PetscCall(PetscMalloc1(1, &ictx));
651*2a8381b2SBarry Smith   ictx->dm  = dm;
652*2a8381b2SBarry Smith   ictx->X   = X;
653*2a8381b2SBarry Smith   ictx->ctx = ctx;
654*2a8381b2SBarry Smith   PetscCall(MatShellSetContext(*J, ictx));
65557d50842SBarry Smith   PetscCall(MatShellSetOperation(*J, MATOP_DESTROY, (PetscErrorCodeFn *)DMSNESJacobianMF_Destroy_Private));
65657d50842SBarry Smith   PetscCall(MatShellSetOperation(*J, MATOP_MULT, (PetscErrorCodeFn *)DMSNESJacobianMF_Mult_Private));
6573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6588e3a2eefSMatthew G. Knepley }
6598e3a2eefSMatthew G. Knepley 
MatComputeNeumannOverlap_Plex(Mat J,PetscReal t,Vec X,Vec X_t,PetscReal s,IS ovl,PetscCtx ctx)660*2a8381b2SBarry Smith static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, PetscCtx ctx)
661d71ae5a4SJacob Faibussowitsch {
66238cfc46eSPierre Jolivet   SNES   snes;
66338cfc46eSPierre Jolivet   Mat    pJ;
66438cfc46eSPierre Jolivet   DM     ovldm, origdm;
66538cfc46eSPierre Jolivet   DMSNES sdm;
66638cfc46eSPierre Jolivet   PetscErrorCode (*bfun)(DM, Vec, void *);
66738cfc46eSPierre Jolivet   PetscErrorCode (*jfun)(DM, Vec, Mat, Mat, void *);
66838cfc46eSPierre Jolivet   void *bctx, *jctx;
66938cfc46eSPierre Jolivet 
67038cfc46eSPierre Jolivet   PetscFunctionBegin;
6719566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_MATIS", (PetscObject *)&pJ));
67228b400f6SJacob Faibussowitsch   PetscCheck(pJ, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing overlapping Mat");
6739566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Original_HPDDM", (PetscObject *)&origdm));
67428b400f6SJacob Faibussowitsch   PetscCheck(origdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing original DM");
6759566063dSJacob Faibussowitsch   PetscCall(MatGetDM(pJ, &ovldm));
6769566063dSJacob Faibussowitsch   PetscCall(DMSNESGetBoundaryLocal(origdm, &bfun, &bctx));
6779566063dSJacob Faibussowitsch   PetscCall(DMSNESSetBoundaryLocal(ovldm, bfun, bctx));
6789566063dSJacob Faibussowitsch   PetscCall(DMSNESGetJacobianLocal(origdm, &jfun, &jctx));
6799566063dSJacob Faibussowitsch   PetscCall(DMSNESSetJacobianLocal(ovldm, jfun, jctx));
6809566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject *)&snes));
68138cfc46eSPierre Jolivet   if (!snes) {
6829566063dSJacob Faibussowitsch     PetscCall(SNESCreate(PetscObjectComm((PetscObject)ovl), &snes));
6839566063dSJacob Faibussowitsch     PetscCall(SNESSetDM(snes, ovldm));
6849566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject)snes));
6859566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)snes));
68638cfc46eSPierre Jolivet   }
6879566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(ovldm, &sdm));
6889566063dSJacob Faibussowitsch   PetscCall(VecLockReadPush(X));
689800f99ffSJeremy L Thompson   {
690*2a8381b2SBarry Smith     PetscCtx ctx;
691800f99ffSJeremy L Thompson     PetscErrorCode (*J)(SNES, Vec, Mat, Mat, void *);
692800f99ffSJeremy L Thompson     PetscCall(DMSNESGetJacobian(ovldm, &J, &ctx));
693800f99ffSJeremy L Thompson     PetscCallBack("SNES callback Jacobian", (*J)(snes, X, pJ, pJ, ctx));
694800f99ffSJeremy L Thompson   }
6959566063dSJacob Faibussowitsch   PetscCall(VecLockReadPop(X));
69638cfc46eSPierre Jolivet   /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */
69738cfc46eSPierre Jolivet   {
69838cfc46eSPierre Jolivet     Mat locpJ;
69938cfc46eSPierre Jolivet 
7009566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(pJ, &locpJ));
7019566063dSJacob Faibussowitsch     PetscCall(MatCopy(locpJ, J, SAME_NONZERO_PATTERN));
70238cfc46eSPierre Jolivet   }
7033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
70438cfc46eSPierre Jolivet }
70538cfc46eSPierre Jolivet 
706a925c78cSMatthew G. Knepley /*@
7076493148fSStefano Zampini   DMPlexSetSNESLocalFEM - Use `DMPLEX`'s internal FEM routines to compute `SNES` boundary values, objective, residual, and Jacobian.
7089f520fc2SToby Isaac 
7099f520fc2SToby Isaac   Input Parameters:
710f6dfbefdSBarry Smith + dm      - The `DM` object
7116493148fSStefano Zampini . use_obj - Use the objective function callback
712*2a8381b2SBarry Smith - ctx     - The application context that will be passed to pointwise evaluation routines
7131a244344SSatish Balay 
7141a244344SSatish Balay   Level: developer
715f6dfbefdSBarry Smith 
7166493148fSStefano Zampini .seealso: [](ch_snes),`DMPLEX`, `SNES`, `PetscDSAddBoundary()`, `PetscDSSetObjective()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`
7179f520fc2SToby Isaac @*/
DMPlexSetSNESLocalFEM(DM dm,PetscBool use_obj,PetscCtx ctx)718*2a8381b2SBarry Smith PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, PetscBool use_obj, PetscCtx ctx)
719d71ae5a4SJacob Faibussowitsch {
720d2b2dc1eSMatthew G. Knepley   PetscBool useCeed;
721d2b2dc1eSMatthew G. Knepley 
7229f520fc2SToby Isaac   PetscFunctionBegin;
723d2b2dc1eSMatthew G. Knepley   PetscCall(DMPlexGetUseCeed(dm, &useCeed));
7246493148fSStefano Zampini   PetscCall(DMSNESSetBoundaryLocal(dm, DMPlexSNESComputeBoundaryFEM, ctx));
7256493148fSStefano Zampini   if (use_obj) PetscCall(DMSNESSetObjectiveLocal(dm, DMPlexSNESComputeObjectiveFEM, ctx));
726d2b2dc1eSMatthew G. Knepley   if (useCeed) {
727d2b2dc1eSMatthew G. Knepley #ifdef PETSC_HAVE_LIBCEED
7286493148fSStefano Zampini     PetscCall(DMSNESSetFunctionLocal(dm, DMPlexSNESComputeResidualCEED, ctx));
729d2b2dc1eSMatthew G. Knepley #else
730d2b2dc1eSMatthew G. Knepley     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot use CEED traversals without LibCEED. Rerun configure with --download-ceed");
731d2b2dc1eSMatthew G. Knepley #endif
7326493148fSStefano Zampini   } else PetscCall(DMSNESSetFunctionLocal(dm, DMPlexSNESComputeResidualFEM, ctx));
7336493148fSStefano Zampini   PetscCall(DMSNESSetJacobianLocal(dm, DMPlexSNESComputeJacobianFEM, ctx));
7349566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", MatComputeNeumannOverlap_Plex));
7353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7369f520fc2SToby Isaac }
7379f520fc2SToby Isaac 
738cc4c1da9SBarry Smith /*@
739f017bcb6SMatthew G. Knepley   DMSNESCheckDiscretization - Check the discretization error of the exact solution
740f017bcb6SMatthew G. Knepley 
741f017bcb6SMatthew G. Knepley   Input Parameters:
742f6dfbefdSBarry Smith + snes - the `SNES` object
743f6dfbefdSBarry Smith . dm   - the `DM`
744f2cacb80SMatthew G. Knepley . t    - the time
745f6dfbefdSBarry Smith . u    - a `DM` vector
746f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
747f017bcb6SMatthew G. Knepley 
7482fe279fdSBarry Smith   Output Parameter:
7492fe279fdSBarry Smith . error - An array which holds the discretization error in each field, or `NULL`
7502fe279fdSBarry Smith 
7512fe279fdSBarry Smith   Level: developer
752f3c94560SMatthew G. Knepley 
753f6dfbefdSBarry Smith   Note:
754f6dfbefdSBarry Smith   The user must call `PetscDSSetExactSolution()` beforehand
7557f96f943SMatthew G. Knepley 
756420bcc1bSBarry Smith   Developer Note:
757420bcc1bSBarry Smith   How is this related to `PetscConvEst`?
758420bcc1bSBarry Smith 
759420bcc1bSBarry Smith .seealso: [](ch_snes), `PetscDSSetExactSolution()`, `DNSNESCheckFromOptions()`, `DMSNESCheckResidual()`, `DMSNESCheckJacobian()`
760f017bcb6SMatthew G. Knepley @*/
DMSNESCheckDiscretization(SNES snes,DM dm,PetscReal t,Vec u,PetscReal tol,PetscReal error[])761d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[])
762d71ae5a4SJacob Faibussowitsch {
763*2a8381b2SBarry Smith   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, PetscCtx ctx);
764f017bcb6SMatthew G. Knepley   void     **ectxs;
765f3c94560SMatthew G. Knepley   PetscReal *err;
7667f96f943SMatthew G. Knepley   MPI_Comm   comm;
7677f96f943SMatthew G. Knepley   PetscInt   Nf, f;
7681878804aSMatthew G. Knepley 
7691878804aSMatthew G. Knepley   PetscFunctionBegin;
770f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
771f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
772064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(u, VEC_CLASSID, 4);
7734f572ea9SToby Isaac   if (error) PetscAssertPointer(error, 6);
7747f96f943SMatthew G. Knepley 
7759566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, t, u, NULL));
7769566063dSJacob Faibussowitsch   PetscCall(VecViewFromOptions(u, NULL, "-vec_view"));
7777f96f943SMatthew G. Knepley 
7789566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
7799566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
7809566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err));
7817f96f943SMatthew G. Knepley   {
7827f96f943SMatthew G. Knepley     PetscInt Nds, s;
7837f96f943SMatthew G. Knepley 
7849566063dSJacob Faibussowitsch     PetscCall(DMGetNumDS(dm, &Nds));
785083401c6SMatthew G. Knepley     for (s = 0; s < Nds; ++s) {
7867f96f943SMatthew G. Knepley       PetscDS         ds;
787083401c6SMatthew G. Knepley       DMLabel         label;
788083401c6SMatthew G. Knepley       IS              fieldIS;
7897f96f943SMatthew G. Knepley       const PetscInt *fields;
7907f96f943SMatthew G. Knepley       PetscInt        dsNf, f;
791083401c6SMatthew G. Knepley 
79207218a29SMatthew G. Knepley       PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
7939566063dSJacob Faibussowitsch       PetscCall(PetscDSGetNumFields(ds, &dsNf));
7949566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(fieldIS, &fields));
795083401c6SMatthew G. Knepley       for (f = 0; f < dsNf; ++f) {
796083401c6SMatthew G. Knepley         const PetscInt field = fields[f];
7979566063dSJacob Faibussowitsch         PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]));
798083401c6SMatthew G. Knepley       }
7999566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(fieldIS, &fields));
800083401c6SMatthew G. Knepley     }
801083401c6SMatthew G. Knepley   }
802f017bcb6SMatthew G. Knepley   if (Nf > 1) {
8039566063dSJacob Faibussowitsch     PetscCall(DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err));
804f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
805ad540459SPierre Jolivet       for (f = 0; f < Nf; ++f) PetscCheck(err[f] <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g for field %" PetscInt_FMT " exceeds tolerance %g", (double)err[f], f, (double)tol);
806b878532fSMatthew G. Knepley     } else if (error) {
807b878532fSMatthew G. Knepley       for (f = 0; f < Nf; ++f) error[f] = err[f];
8081878804aSMatthew G. Knepley     } else {
8099566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "L_2 Error: ["));
810f017bcb6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
8119566063dSJacob Faibussowitsch         if (f) PetscCall(PetscPrintf(comm, ", "));
8129566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(comm, "%g", (double)err[f]));
8131878804aSMatthew G. Knepley       }
8149566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "]\n"));
815f017bcb6SMatthew G. Knepley     }
816f017bcb6SMatthew G. Knepley   } else {
8179566063dSJacob Faibussowitsch     PetscCall(DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0]));
818f017bcb6SMatthew G. Knepley     if (tol >= 0.0) {
81908401ef6SPierre Jolivet       PetscCheck(err[0] <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double)err[0], (double)tol);
820b878532fSMatthew G. Knepley     } else if (error) {
821b878532fSMatthew G. Knepley       error[0] = err[0];
822f017bcb6SMatthew G. Knepley     } else {
8239566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "L_2 Error: %g\n", (double)err[0]));
824f017bcb6SMatthew G. Knepley     }
825f017bcb6SMatthew G. Knepley   }
8269566063dSJacob Faibussowitsch   PetscCall(PetscFree3(exacts, ectxs, err));
8273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
828f017bcb6SMatthew G. Knepley }
829f017bcb6SMatthew G. Knepley 
830cc4c1da9SBarry Smith /*@
831f017bcb6SMatthew G. Knepley   DMSNESCheckResidual - Check the residual of the exact solution
832f017bcb6SMatthew G. Knepley 
833f017bcb6SMatthew G. Knepley   Input Parameters:
834f6dfbefdSBarry Smith + snes - the `SNES` object
835f6dfbefdSBarry Smith . dm   - the `DM`
836f6dfbefdSBarry Smith . u    - a `DM` vector
837f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
838f017bcb6SMatthew G. Knepley 
839f6dfbefdSBarry Smith   Output Parameter:
8402fe279fdSBarry Smith . residual - The residual norm of the exact solution, or `NULL`
841f3c94560SMatthew G. Knepley 
842f017bcb6SMatthew G. Knepley   Level: developer
843f017bcb6SMatthew G. Knepley 
844420bcc1bSBarry Smith .seealso: [](ch_snes), `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckJacobian()`
845f017bcb6SMatthew G. Knepley @*/
DMSNESCheckResidual(SNES snes,DM dm,Vec u,PetscReal tol,PetscReal * residual)846d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual)
847d71ae5a4SJacob Faibussowitsch {
848f017bcb6SMatthew G. Knepley   MPI_Comm  comm;
849f017bcb6SMatthew G. Knepley   Vec       r;
850f017bcb6SMatthew G. Knepley   PetscReal res;
851f017bcb6SMatthew G. Knepley 
852f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
853f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
854f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
855f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
8564f572ea9SToby Isaac   if (residual) PetscAssertPointer(residual, 5);
8579566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
8589566063dSJacob Faibussowitsch   PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL));
8599566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(u, &r));
8609566063dSJacob Faibussowitsch   PetscCall(SNESComputeFunction(snes, u, r));
8619566063dSJacob Faibussowitsch   PetscCall(VecNorm(r, NORM_2, &res));
862f017bcb6SMatthew G. Knepley   if (tol >= 0.0) {
86308401ef6SPierre Jolivet     PetscCheck(res <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double)res, (double)tol);
864b878532fSMatthew G. Knepley   } else if (residual) {
865b878532fSMatthew G. Knepley     *residual = res;
866f017bcb6SMatthew G. Knepley   } else {
8679566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "L_2 Residual: %g\n", (double)res));
86893ec0da9SPierre Jolivet     PetscCall(VecFilter(r, 1.0e-10));
8699566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)r, "Initial Residual"));
8709566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)r, "res_"));
87164bbb635SMatthew G. Knepley     PetscCall(PetscObjectCompose((PetscObject)r, "__Vec_bc_zero__", (PetscObject)snes));
8729566063dSJacob Faibussowitsch     PetscCall(VecViewFromOptions(r, NULL, "-vec_view"));
87364bbb635SMatthew G. Knepley     PetscCall(PetscObjectCompose((PetscObject)r, "__Vec_bc_zero__", NULL));
874f017bcb6SMatthew G. Knepley   }
8759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
8763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
877f017bcb6SMatthew G. Knepley }
878f017bcb6SMatthew G. Knepley 
879cc4c1da9SBarry Smith /*@
880f3c94560SMatthew G. Knepley   DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test
881f017bcb6SMatthew G. Knepley 
882f017bcb6SMatthew G. Knepley   Input Parameters:
883f6dfbefdSBarry Smith + snes - the `SNES` object
884f6dfbefdSBarry Smith . dm   - the `DM`
885f6dfbefdSBarry Smith . u    - a `DM` vector
886f0fc11ceSJed Brown - tol  - A tolerance for the check, or -1 to print the results instead
887f017bcb6SMatthew G. Knepley 
888f3c94560SMatthew G. Knepley   Output Parameters:
8892fe279fdSBarry Smith + isLinear - Flag indicaing that the function looks linear, or `NULL`
8902fe279fdSBarry Smith - convRate - The rate of convergence of the linear model, or `NULL`
891f3c94560SMatthew G. Knepley 
892f017bcb6SMatthew G. Knepley   Level: developer
893f017bcb6SMatthew G. Knepley 
894420bcc1bSBarry Smith .seealso: [](ch_snes), `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckResidual()`
895f017bcb6SMatthew G. Knepley @*/
DMSNESCheckJacobian(SNES snes,DM dm,Vec u,PetscReal tol,PetscBool * isLinear,PetscReal * convRate)896d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate)
897d71ae5a4SJacob Faibussowitsch {
898f017bcb6SMatthew G. Knepley   MPI_Comm     comm;
899f017bcb6SMatthew G. Knepley   PetscDS      ds;
900f017bcb6SMatthew G. Knepley   Mat          J, M;
901f017bcb6SMatthew G. Knepley   MatNullSpace nullspace;
902f3c94560SMatthew G. Knepley   PetscReal    slope, intercept;
9037f96f943SMatthew G. Knepley   PetscBool    hasJac, hasPrec, isLin = PETSC_FALSE;
904f017bcb6SMatthew G. Knepley 
905f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
906f3c94560SMatthew G. Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
907d5d53b22SStefano Zampini   if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
908d5d53b22SStefano Zampini   if (u) PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
9094f572ea9SToby Isaac   if (isLinear) PetscAssertPointer(isLinear, 5);
9104f572ea9SToby Isaac   if (convRate) PetscAssertPointer(convRate, 6);
9119566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
912d5d53b22SStefano Zampini   if (!dm) PetscCall(SNESGetDM(snes, &dm));
913d5d53b22SStefano Zampini   if (u) PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL));
914d5d53b22SStefano Zampini   else PetscCall(SNESGetSolution(snes, &u));
915f017bcb6SMatthew G. Knepley   /* Create and view matrices */
9169566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(dm, &J));
9179566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
9189566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobian(ds, &hasJac));
9199566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec));
920282e7bb4SMatthew G. Knepley   if (hasJac && hasPrec) {
9219566063dSJacob Faibussowitsch     PetscCall(DMCreateMatrix(dm, &M));
9229566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, u, J, M));
9237addb90fSBarry Smith     PetscCall(PetscObjectSetName((PetscObject)M, "Matrix used to construct preconditioner"));
9249566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)M, "jacpre_"));
9259566063dSJacob Faibussowitsch     PetscCall(MatViewFromOptions(M, NULL, "-mat_view"));
9269566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
927282e7bb4SMatthew G. Knepley   } else {
9289566063dSJacob Faibussowitsch     PetscCall(SNESComputeJacobian(snes, u, J, J));
929282e7bb4SMatthew G. Knepley   }
9309566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)J, "Jacobian"));
9319566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)J, "jac_"));
9329566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(J, NULL, "-mat_view"));
933f017bcb6SMatthew G. Knepley   /* Check nullspace */
9349566063dSJacob Faibussowitsch   PetscCall(MatGetNullSpace(J, &nullspace));
935f017bcb6SMatthew G. Knepley   if (nullspace) {
9361878804aSMatthew G. Knepley     PetscBool isNull;
9379566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceTest(nullspace, J, &isNull));
93828b400f6SJacob Faibussowitsch     PetscCheck(isNull, comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid.");
9391878804aSMatthew G. Knepley   }
940f017bcb6SMatthew G. Knepley   /* Taylor test */
941f017bcb6SMatthew G. Knepley   {
942f017bcb6SMatthew G. Knepley     PetscRandom rand;
943f017bcb6SMatthew G. Knepley     Vec         du, uhat, r, rhat, df;
944f3c94560SMatthew G. Knepley     PetscReal   h;
945f017bcb6SMatthew G. Knepley     PetscReal  *es, *hs, *errors;
946f017bcb6SMatthew G. Knepley     PetscReal   hMax = 1.0, hMin = 1e-6, hMult = 0.1;
947f017bcb6SMatthew G. Knepley     PetscInt    Nv, v;
948f017bcb6SMatthew G. Knepley 
949f017bcb6SMatthew G. Knepley     /* Choose a perturbation direction */
9509566063dSJacob Faibussowitsch     PetscCall(PetscRandomCreate(comm, &rand));
9519566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &du));
9529566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(du, rand));
9539566063dSJacob Faibussowitsch     PetscCall(PetscRandomDestroy(&rand));
9549566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &df));
9559566063dSJacob Faibussowitsch     PetscCall(MatMult(J, du, df));
956f017bcb6SMatthew G. Knepley     /* Evaluate residual at u, F(u), save in vector r */
9579566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &r));
9589566063dSJacob Faibussowitsch     PetscCall(SNESComputeFunction(snes, u, r));
959f017bcb6SMatthew G. Knepley     /* Look at the convergence of our Taylor approximation as we approach u */
960fbccb6d4SPierre Jolivet     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv);
9619566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors));
9629566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &uhat));
9639566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(u, &rhat));
964f017bcb6SMatthew G. Knepley     for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) {
9659566063dSJacob Faibussowitsch       PetscCall(VecWAXPY(uhat, h, du, u));
966f017bcb6SMatthew G. Knepley       /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */
9679566063dSJacob Faibussowitsch       PetscCall(SNESComputeFunction(snes, uhat, rhat));
9689566063dSJacob Faibussowitsch       PetscCall(VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df));
9699566063dSJacob Faibussowitsch       PetscCall(VecNorm(rhat, NORM_2, &errors[Nv]));
970f017bcb6SMatthew G. Knepley 
97138d69901SMatthew G. Knepley       es[Nv] = errors[Nv] == 0 ? -16.0 : PetscLog10Real(errors[Nv]);
972f017bcb6SMatthew G. Knepley       hs[Nv] = PetscLog10Real(h);
973f017bcb6SMatthew G. Knepley     }
9749566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&uhat));
9759566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rhat));
9769566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&df));
9779566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&r));
9789566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&du));
979f017bcb6SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
980f017bcb6SMatthew G. Knepley       if ((tol >= 0) && (errors[v] > tol)) break;
981f017bcb6SMatthew G. Knepley       else if (errors[v] > PETSC_SMALL) break;
982f017bcb6SMatthew G. Knepley     }
983f3c94560SMatthew G. Knepley     if (v == Nv) isLin = PETSC_TRUE;
9849566063dSJacob Faibussowitsch     PetscCall(PetscLinearRegression(Nv, hs, es, &slope, &intercept));
9859566063dSJacob Faibussowitsch     PetscCall(PetscFree3(es, hs, errors));
986f017bcb6SMatthew G. Knepley     /* Slope should be about 2 */
987f017bcb6SMatthew G. Knepley     if (tol >= 0) {
9880b121fc5SBarry Smith       PetscCheck(isLin || PetscAbsReal(2 - slope) <= tol, comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double)slope);
989b878532fSMatthew G. Knepley     } else if (isLinear || convRate) {
990b878532fSMatthew G. Knepley       if (isLinear) *isLinear = isLin;
991b878532fSMatthew G. Knepley       if (convRate) *convRate = slope;
992f017bcb6SMatthew G. Knepley     } else {
9939566063dSJacob Faibussowitsch       if (!isLin) PetscCall(PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double)slope));
9949566063dSJacob Faibussowitsch       else PetscCall(PetscPrintf(comm, "Function appears to be linear\n"));
995f017bcb6SMatthew G. Knepley     }
996f017bcb6SMatthew G. Knepley   }
9979566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
9983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9991878804aSMatthew G. Knepley }
10001878804aSMatthew G. Knepley 
DMSNESCheck_Internal(SNES snes,DM dm,Vec u)1001d6acfc2dSPierre Jolivet static PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u)
1002d71ae5a4SJacob Faibussowitsch {
1003f017bcb6SMatthew G. Knepley   PetscFunctionBegin;
10049566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL));
10059566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckResidual(snes, dm, u, -1.0, NULL));
10069566063dSJacob Faibussowitsch   PetscCall(DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL));
10073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1008f017bcb6SMatthew G. Knepley }
1009f017bcb6SMatthew G. Knepley 
1010cc4c1da9SBarry Smith /*@
1011bee9a294SMatthew G. Knepley   DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information
1012bee9a294SMatthew G. Knepley 
1013bee9a294SMatthew G. Knepley   Input Parameters:
1014f6dfbefdSBarry Smith + snes - the `SNES` object
1015f6dfbefdSBarry Smith - u    - representative `SNES` vector
10167f96f943SMatthew G. Knepley 
10172fe279fdSBarry Smith   Level: developer
10182fe279fdSBarry Smith 
1019f6dfbefdSBarry Smith   Note:
1020420bcc1bSBarry Smith   The user must call `PetscDSSetExactSolution()` before this call
1021bee9a294SMatthew G. Knepley 
1022420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `DM`
1023bee9a294SMatthew G. Knepley @*/
DMSNESCheckFromOptions(SNES snes,Vec u)1024d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u)
1025d71ae5a4SJacob Faibussowitsch {
10261878804aSMatthew G. Knepley   DM        dm;
10271878804aSMatthew G. Knepley   Vec       sol;
10281878804aSMatthew G. Knepley   PetscBool check;
10291878804aSMatthew G. Knepley 
10301878804aSMatthew G. Knepley   PetscFunctionBegin;
10319566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-dmsnes_check", &check));
10323ba16761SJacob Faibussowitsch   if (!check) PetscFunctionReturn(PETSC_SUCCESS);
10339566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
10349566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(u, &sol));
10359566063dSJacob Faibussowitsch   PetscCall(SNESSetSolution(snes, sol));
10369566063dSJacob Faibussowitsch   PetscCall(DMSNESCheck_Internal(snes, dm, sol));
10379566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sol));
10383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1039552f7358SJed Brown }
10402eace19aSMatthew G. Knepley 
104101468941SMatthew G. Knepley /*@
104201468941SMatthew G. Knepley   DMPlexSetSNESVariableBounds - Compute upper and lower bounds for the solution using pointsie functions from the `PetscDS`
10432eace19aSMatthew G. Knepley 
104401468941SMatthew G. Knepley   Collective
10452eace19aSMatthew G. Knepley 
104601468941SMatthew G. Knepley   Input Parameters:
104701468941SMatthew G. Knepley + dm   - The `DM` object
104801468941SMatthew G. Knepley - snes - the `SNES` object
104901468941SMatthew G. Knepley 
105001468941SMatthew G. Knepley   Level: intermediate
105101468941SMatthew G. Knepley 
105201468941SMatthew G. Knepley   Notes:
105301468941SMatthew G. Knepley   This calls `SNESVISetVariableBounds()` after generating the bounds vectors, so it only applied to `SNESVI` solves.
105401468941SMatthew G. Knepley 
105501468941SMatthew G. Knepley   We project the actual bounds into the current finite element space so that they become more accurate with refinement.
105601468941SMatthew G. Knepley 
105701468941SMatthew G. Knepley .seealso: `SNESVISetVariableBounds()`, `SNESVI`, [](ch_snes), `DM`
105801468941SMatthew G. Knepley @*/
DMPlexSetSNESVariableBounds(DM dm,SNES snes)10592eace19aSMatthew G. Knepley PetscErrorCode DMPlexSetSNESVariableBounds(DM dm, SNES snes)
10602eace19aSMatthew G. Knepley {
10612eace19aSMatthew G. Knepley   PetscDS              ds;
10622eace19aSMatthew G. Knepley   Vec                  lb, ub;
10632192575eSBarry Smith   PetscSimplePointFn **lfuncs, **ufuncs;
10642eace19aSMatthew G. Knepley   void               **lctxs, **uctxs;
106501468941SMatthew G. Knepley   PetscBool            hasBound, hasLower = PETSC_FALSE, hasUpper = PETSC_FALSE;
10662eace19aSMatthew G. Knepley   PetscInt             Nf;
10672eace19aSMatthew G. Knepley 
10682eace19aSMatthew G. Knepley   PetscFunctionBegin;
106901468941SMatthew G. Knepley   PetscCall(DMHasBound(dm, &hasBound));
107001468941SMatthew G. Knepley   if (!hasBound) PetscFunctionReturn(PETSC_SUCCESS);
10712eace19aSMatthew G. Knepley   // TODO Generalize for multiple DSes
10722eace19aSMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
10732eace19aSMatthew G. Knepley   PetscCall(PetscDSGetNumFields(ds, &Nf));
10742eace19aSMatthew G. Knepley   PetscCall(PetscMalloc4(Nf, &lfuncs, Nf, &lctxs, Nf, &ufuncs, Nf, &uctxs));
10752eace19aSMatthew G. Knepley   for (PetscInt f = 0; f < Nf; ++f) {
10762eace19aSMatthew G. Knepley     PetscCall(PetscDSGetLowerBound(ds, f, &lfuncs[f], &lctxs[f]));
10772eace19aSMatthew G. Knepley     PetscCall(PetscDSGetUpperBound(ds, f, &ufuncs[f], &uctxs[f]));
107801468941SMatthew G. Knepley     if (lfuncs[f]) hasLower = PETSC_TRUE;
107901468941SMatthew G. Knepley     if (ufuncs[f]) hasUpper = PETSC_TRUE;
10802eace19aSMatthew G. Knepley   }
10812eace19aSMatthew G. Knepley   PetscCall(DMCreateGlobalVector(dm, &lb));
10822eace19aSMatthew G. Knepley   PetscCall(DMCreateGlobalVector(dm, &ub));
108301468941SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)lb, "Lower Bound"));
108401468941SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)ub, "Upper Bound"));
108501468941SMatthew G. Knepley   PetscCall(VecSet(lb, PETSC_NINFINITY));
108601468941SMatthew G. Knepley   PetscCall(VecSet(ub, PETSC_INFINITY));
108701468941SMatthew G. Knepley   if (hasLower) PetscCall(DMProjectFunction(dm, 0., lfuncs, lctxs, INSERT_VALUES, lb));
108801468941SMatthew G. Knepley   if (hasUpper) PetscCall(DMProjectFunction(dm, 0., ufuncs, uctxs, INSERT_VALUES, ub));
108901468941SMatthew G. Knepley   PetscCall(DMPlexInsertBounds(dm, PETSC_TRUE, 0., lb));
109001468941SMatthew G. Knepley   PetscCall(DMPlexInsertBounds(dm, PETSC_FALSE, 0., ub));
10912eace19aSMatthew G. Knepley   PetscCall(VecViewFromOptions(lb, NULL, "-dm_plex_snes_lb_view"));
10922eace19aSMatthew G. Knepley   PetscCall(VecViewFromOptions(ub, NULL, "-dm_plex_snes_ub_view"));
10932eace19aSMatthew G. Knepley   PetscCall(SNESVISetVariableBounds(snes, lb, ub));
10942eace19aSMatthew G. Knepley   PetscCall(VecDestroy(&lb));
10952eace19aSMatthew G. Knepley   PetscCall(VecDestroy(&ub));
10962eace19aSMatthew G. Knepley   PetscCall(PetscFree4(lfuncs, lctxs, ufuncs, uctxs));
10972eace19aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
10982eace19aSMatthew G. Knepley }
1099