xref: /petsc/src/dm/impls/plex/plexproject.c (revision 76be6f4ff3bd4e251c19fc00ebbebfd58b6e7589)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 
3 #include <petsc/private/petscfeimpl.h>
4 
5 /*@
6   DMPlexGetActivePoint - Get the point on which projection is currently working
7 
8   Not collective
9 
10   Input Parameter:
11 . dm   - the DM
12 
13   Output Parameter:
14 . point - The mesh point involved in the current projection
15 
16   Level: developer
17 
18 .seealso: `DMPlexSetActivePoint()`
19 @*/
20 PetscErrorCode DMPlexGetActivePoint(DM dm, PetscInt *point)
21 {
22   PetscFunctionBeginHot;
23   *point = ((DM_Plex *) dm->data)->activePoint;
24   PetscFunctionReturn(0);
25 }
26 
27 /*@
28   DMPlexSetActivePoint - Set the point on which projection is currently working
29 
30   Not collective
31 
32   Input Parameters:
33 + dm   - the DM
34 - point - The mesh point involved in the current projection
35 
36   Level: developer
37 
38 .seealso: `DMPlexGetActivePoint()`
39 @*/
40 PetscErrorCode DMPlexSetActivePoint(DM dm, PetscInt point)
41 {
42   PetscFunctionBeginHot;
43   ((DM_Plex *) dm->data)->activePoint = point;
44   PetscFunctionReturn(0);
45 }
46 
47 /*
48   DMProjectPoint_Func_Private - Interpolate the given function in the output basis on the given point
49 
50   Input Parameters:
51 + dm     - The output DM
52 . ds     - The output DS
53 . dmIn   - The input DM
54 . dsIn   - The input DS
55 . time   - The time for this evaluation
56 . fegeom - The FE geometry for this point
57 . fvgeom - The FV geometry for this point
58 . isFE   - Flag indicating whether each output field has an FE discretization
59 . sp     - The output PetscDualSpace for each field
60 . funcs  - The evaluation function for each field
61 - ctxs   - The user context for each field
62 
63   Output Parameter:
64 . values - The value for each dual basis vector in the output dual space
65 
66   Level: developer
67 
68 .seealso: `DMProjectPoint_Field_Private()`
69 */
70 static PetscErrorCode DMProjectPoint_Func_Private(DM dm, PetscDS ds, DM dmIn, PetscDS dsIn, PetscReal time, PetscFEGeom *fegeom, PetscFVCellGeom *fvgeom, PetscBool isFE[], PetscDualSpace sp[],
71                                                   PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs,
72                                                   PetscScalar values[])
73 {
74   PetscInt       coordDim, Nf, *Nc, f, spDim, d, v, tp;
75   PetscBool      isAffine, isCohesive, transform;
76 
77   PetscFunctionBeginHot;
78   PetscCall(DMGetCoordinateDim(dmIn, &coordDim));
79   PetscCall(DMHasBasisTransform(dmIn, &transform));
80   PetscCall(PetscDSGetNumFields(ds, &Nf));
81   PetscCall(PetscDSGetComponents(ds, &Nc));
82   PetscCall(PetscDSIsCohesive(ds, &isCohesive));
83   /* Get values for closure */
84   isAffine = fegeom->isAffine;
85   for (f = 0, v = 0, tp = 0; f < Nf; ++f) {
86     void * const ctx = ctxs ? ctxs[f] : NULL;
87     PetscBool    cohesive;
88 
89     if (!sp[f]) continue;
90     PetscCall(PetscDSGetCohesive(ds, f, &cohesive));
91     PetscCall(PetscDualSpaceGetDimension(sp[f], &spDim));
92     if (funcs[f]) {
93       if (isFE[f]) {
94         PetscQuadrature   allPoints;
95         PetscInt          q, dim, numPoints;
96         const PetscReal   *points;
97         PetscScalar       *pointEval;
98         PetscReal         *x;
99         DM                rdm;
100 
101         PetscCall(PetscDualSpaceGetDM(sp[f],&rdm));
102         PetscCall(PetscDualSpaceGetAllData(sp[f], &allPoints, NULL));
103         PetscCall(PetscQuadratureGetData(allPoints,&dim,NULL,&numPoints,&points,NULL));
104         PetscCall(DMGetWorkArray(rdm,numPoints*Nc[f],MPIU_SCALAR,&pointEval));
105         PetscCall(DMGetWorkArray(rdm,coordDim,MPIU_REAL,&x));
106         PetscCall(PetscArrayzero(pointEval, numPoints*Nc[f]));
107         for (q = 0; q < numPoints; q++, tp++) {
108           const PetscReal *v0;
109 
110           if (isAffine) {
111             const PetscReal *refpoint = &points[q*dim];
112             PetscReal        injpoint[3] = {0., 0., 0.};
113 
114             if (dim != fegeom->dim) {
115               if (isCohesive) {
116                 /* We just need to inject into the higher dimensional space assuming the last dimension is collapsed */
117                 for (d = 0; d < dim; ++d) injpoint[d] = refpoint[d];
118                 refpoint = injpoint;
119               } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Reference spatial dimension %" PetscInt_FMT " != %" PetscInt_FMT " dual basis spatial dimension", fegeom->dim, dim);
120             }
121             CoordinatesRefToReal(coordDim, fegeom->dim, fegeom->xi, fegeom->v, fegeom->J, refpoint, x);
122             v0 = x;
123           } else {
124             v0 = &fegeom->v[tp*coordDim];
125           }
126           if (transform) {PetscCall(DMPlexBasisTransformApplyReal_Internal(dmIn, v0, PETSC_TRUE, coordDim, v0, x, dm->transformCtx)); v0 = x;}
127           PetscCall((*funcs[f])(coordDim, time, v0, Nc[f], &pointEval[Nc[f]*q], ctx));
128         }
129         /* Transform point evaluations pointEval[q,c] */
130         PetscCall(PetscDualSpacePullback(sp[f], fegeom, numPoints, Nc[f], pointEval));
131         PetscCall(PetscDualSpaceApplyAll(sp[f], pointEval, &values[v]));
132         PetscCall(DMRestoreWorkArray(rdm,coordDim,MPIU_REAL,&x));
133         PetscCall(DMRestoreWorkArray(rdm,numPoints*Nc[f],MPIU_SCALAR,&pointEval));
134         v += spDim;
135         if (isCohesive && !cohesive) {
136           for (d = 0; d < spDim; d++, v++) values[v] = values[v - spDim];
137         }
138       } else {
139         for (d = 0; d < spDim; ++d, ++v) {
140           PetscCall(PetscDualSpaceApplyFVM(sp[f], d, time, fvgeom, Nc[f], funcs[f], ctx, &values[v]));
141         }
142       }
143     } else {
144       for (d = 0; d < spDim; d++, v++) values[v] = 0.;
145       if (isCohesive && !cohesive) {
146         for (d = 0; d < spDim; d++, v++) values[v] = 0.;
147       }
148     }
149   }
150   PetscFunctionReturn(0);
151 }
152 
153 /*
154   DMProjectPoint_Field_Private - Interpolate a function of the given field, in the input basis, using the output basis on the given point
155 
156   Input Parameters:
157 + dm             - The output DM
158 . ds             - The output DS
159 . dmIn           - The input DM
160 . dsIn           - The input DS
161 . dmAux          - The auxiliary DM, which is always for the input space
162 . dsAux          - The auxiliary DS, which is always for the input space
163 . time           - The time for this evaluation
164 . localU         - The local solution
165 . localA         - The local auziliary fields
166 . cgeom          - The FE geometry for this point
167 . sp             - The output PetscDualSpace for each field
168 . p              - The point in the output DM
169 . T              - Input basis and derivatives for each field tabulated on the quadrature points
170 . TAux           - Auxiliary basis and derivatives for each aux field tabulated on the quadrature points
171 . funcs          - The evaluation function for each field
172 - ctxs           - The user context for each field
173 
174   Output Parameter:
175 . values         - The value for each dual basis vector in the output dual space
176 
177   Note: Not supported for FV
178 
179   Level: developer
180 
181 .seealso: `DMProjectPoint_Field_Private()`
182 */
183 static PetscErrorCode DMProjectPoint_Field_Private(DM dm, PetscDS ds, DM dmIn, DMEnclosureType encIn, PetscDS dsIn, DM dmAux, DMEnclosureType encAux, PetscDS dsAux, PetscReal time, Vec localU, Vec localA, PetscFEGeom *cgeom, PetscDualSpace sp[], PetscInt p,
184                                                    PetscTabulation *T, PetscTabulation *TAux,
185                                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
186                                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
187                                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
188                                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void **ctxs,
189                                                    PetscScalar values[])
190 {
191   PetscSection       section, sectionAux = NULL;
192   PetscScalar       *u, *u_t = NULL, *u_x, *a = NULL, *a_t = NULL, *a_x = NULL, *bc;
193   PetscScalar       *coefficients   = NULL, *coefficientsAux   = NULL;
194   PetscScalar       *coefficients_t = NULL, *coefficientsAux_t = NULL;
195   const PetscScalar *constants;
196   PetscReal         *x;
197   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL, *Nc;
198   PetscFEGeom        fegeom;
199   const PetscInt     dE = cgeom->dimEmbed;
200   PetscInt           numConstants, Nf, NfIn, NfAux = 0, f, spDim, d, v, inp, tp = 0;
201   PetscBool          isAffine, isCohesive, transform;
202 
203   PetscFunctionBeginHot;
204   PetscCall(PetscDSGetNumFields(ds, &Nf));
205   PetscCall(PetscDSGetComponents(ds, &Nc));
206   PetscCall(PetscDSIsCohesive(ds, &isCohesive));
207   PetscCall(PetscDSGetNumFields(dsIn, &NfIn));
208   PetscCall(PetscDSGetComponentOffsets(dsIn, &uOff));
209   PetscCall(PetscDSGetComponentDerivativeOffsets(dsIn, &uOff_x));
210   PetscCall(PetscDSGetEvaluationArrays(dsIn, &u, &bc /*&u_t*/, &u_x));
211   PetscCall(PetscDSGetWorkspace(dsIn, &x, NULL, NULL, NULL, NULL));
212   PetscCall(PetscDSGetConstants(dsIn, &numConstants, &constants));
213   PetscCall(DMHasBasisTransform(dmIn, &transform));
214   PetscCall(DMGetLocalSection(dmIn, &section));
215   PetscCall(DMGetEnclosurePoint(dmIn, dm, encIn, p, &inp));
216   PetscCall(DMPlexVecGetClosure(dmIn, section, localU, inp, NULL, &coefficients));
217   if (dmAux) {
218     PetscInt subp;
219 
220     PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, p, &subp));
221     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
222     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
223     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
224     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
225     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL /*&a_t*/, &a_x));
226     PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, localA, subp, NULL, &coefficientsAux));
227   }
228   /* Get values for closure */
229   isAffine = cgeom->isAffine;
230   fegeom.dim      = cgeom->dim;
231   fegeom.dimEmbed = cgeom->dimEmbed;
232   if (isAffine) {
233     fegeom.v    = x;
234     fegeom.xi   = cgeom->xi;
235     fegeom.J    = cgeom->J;
236     fegeom.invJ = cgeom->invJ;
237     fegeom.detJ = cgeom->detJ;
238   }
239   for (f = 0, v = 0; f < Nf; ++f) {
240     PetscQuadrature  allPoints;
241     PetscInt         q, dim, numPoints;
242     const PetscReal *points;
243     PetscScalar     *pointEval;
244     PetscBool        cohesive;
245     DM               dm;
246 
247     if (!sp[f]) continue;
248     PetscCall(PetscDSGetCohesive(ds, f, &cohesive));
249     PetscCall(PetscDualSpaceGetDimension(sp[f], &spDim));
250     if (!funcs[f]) {
251       for (d = 0; d < spDim; d++, v++) values[v] = 0.;
252       if (isCohesive && !cohesive) {
253         for (d = 0; d < spDim; d++, v++) values[v] = 0.;
254       }
255       continue;
256     }
257     PetscCall(PetscDualSpaceGetDM(sp[f],&dm));
258     PetscCall(PetscDualSpaceGetAllData(sp[f], &allPoints, NULL));
259     PetscCall(PetscQuadratureGetData(allPoints,&dim,NULL,&numPoints,&points,NULL));
260     PetscCall(DMGetWorkArray(dm,numPoints*Nc[f],MPIU_SCALAR,&pointEval));
261     for (q = 0; q < numPoints; ++q, ++tp) {
262       if (isAffine) {
263         CoordinatesRefToReal(dE, cgeom->dim, fegeom.xi, cgeom->v, fegeom.J, &points[q*dim], x);
264       } else {
265         fegeom.v    = &cgeom->v[tp*dE];
266         fegeom.J    = &cgeom->J[tp*dE*dE];
267         fegeom.invJ = &cgeom->invJ[tp*dE*dE];
268         fegeom.detJ = &cgeom->detJ[tp];
269       }
270       PetscCall(PetscFEEvaluateFieldJets_Internal(dsIn, NfIn, 0, tp, T, &fegeom, coefficients, coefficients_t, u, u_x, u_t));
271       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, tp, TAux, &fegeom, coefficientsAux, coefficientsAux_t, a, a_x, a_t));
272       if (transform) PetscCall(DMPlexBasisTransformApplyReal_Internal(dmIn, fegeom.v, PETSC_TRUE, dE, fegeom.v, fegeom.v, dm->transformCtx));
273       (*funcs[f])(dE, NfIn, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, a_t, a_x, time, fegeom.v, numConstants, constants, &pointEval[Nc[f]*q]);
274     }
275     PetscCall(PetscDualSpaceApplyAll(sp[f], pointEval, &values[v]));
276     PetscCall(DMRestoreWorkArray(dm,numPoints*Nc[f],MPIU_SCALAR,&pointEval));
277     v += spDim;
278     /* TODO: For now, set both sides equal, but this should use info from other support cell */
279     if (isCohesive && !cohesive) {
280       for (d = 0; d < spDim; d++, v++) values[v] = values[v - spDim];
281     }
282   }
283   PetscCall(DMPlexVecRestoreClosure(dmIn, section, localU, inp, NULL, &coefficients));
284   if (dmAux) PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, localA, p, NULL, &coefficientsAux));
285   PetscFunctionReturn(0);
286 }
287 
288 static PetscErrorCode DMProjectPoint_BdField_Private(DM dm, PetscDS ds, DM dmIn, PetscDS dsIn, DM dmAux, DMEnclosureType encAux, PetscDS dsAux, PetscReal time, Vec localU, Vec localA, PetscFEGeom *fgeom, PetscDualSpace sp[], PetscInt p,
289                                                      PetscTabulation *T, PetscTabulation *TAux,
290                                                      void (**funcs)(PetscInt, PetscInt, PetscInt,
291                                                                     const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
292                                                                     const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
293                                                                     PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void **ctxs,
294                                                      PetscScalar values[])
295 {
296   PetscSection       section, sectionAux = NULL;
297   PetscScalar       *u, *u_t = NULL, *u_x, *a = NULL, *a_t = NULL, *a_x = NULL, *bc;
298   PetscScalar       *coefficients   = NULL, *coefficientsAux   = NULL;
299   PetscScalar       *coefficients_t = NULL, *coefficientsAux_t = NULL;
300   const PetscScalar *constants;
301   PetscReal         *x;
302   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL, *Nc;
303   PetscFEGeom        fegeom, cgeom;
304   const PetscInt     dE = fgeom->dimEmbed;
305   PetscInt           numConstants, Nf, NfAux = 0, f, spDim, d, v, tp = 0;
306   PetscBool          isAffine;
307 
308   PetscFunctionBeginHot;
309   PetscCheck(dm == dmIn,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Not yet upgraded to use different input DM");
310   PetscCall(PetscDSGetNumFields(ds, &Nf));
311   PetscCall(PetscDSGetComponents(ds, &Nc));
312   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
313   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
314   PetscCall(PetscDSGetEvaluationArrays(ds, &u, &bc /*&u_t*/, &u_x));
315   PetscCall(PetscDSGetWorkspace(ds, &x, NULL, NULL, NULL, NULL));
316   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
317   PetscCall(DMGetLocalSection(dm, &section));
318   PetscCall(DMPlexVecGetClosure(dmIn, section, localU, p, NULL, &coefficients));
319   if (dmAux) {
320     PetscInt subp;
321 
322     PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, p, &subp));
323     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
324     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
325     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
326     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
327     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL /*&a_t*/, &a_x));
328     PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, localA, subp, NULL, &coefficientsAux));
329   }
330   /* Get values for closure */
331   isAffine = fgeom->isAffine;
332   fegeom.n  = NULL;
333   fegeom.J  = NULL;
334   fegeom.v  = NULL;
335   fegeom.xi = NULL;
336   cgeom.dim      = fgeom->dim;
337   cgeom.dimEmbed = fgeom->dimEmbed;
338   if (isAffine) {
339     fegeom.v    = x;
340     fegeom.xi   = fgeom->xi;
341     fegeom.J    = fgeom->J;
342     fegeom.invJ = fgeom->invJ;
343     fegeom.detJ = fgeom->detJ;
344     fegeom.n    = fgeom->n;
345 
346     cgeom.J     = fgeom->suppJ[0];
347     cgeom.invJ  = fgeom->suppInvJ[0];
348     cgeom.detJ  = fgeom->suppDetJ[0];
349   }
350   for (f = 0, v = 0; f < Nf; ++f) {
351     PetscQuadrature   allPoints;
352     PetscInt          q, dim, numPoints;
353     const PetscReal   *points;
354     PetscScalar       *pointEval;
355     DM                dm;
356 
357     if (!sp[f]) continue;
358     PetscCall(PetscDualSpaceGetDimension(sp[f], &spDim));
359     if (!funcs[f]) {
360       for (d = 0; d < spDim; d++, v++) values[v] = 0.;
361       continue;
362     }
363     PetscCall(PetscDualSpaceGetDM(sp[f],&dm));
364     PetscCall(PetscDualSpaceGetAllData(sp[f], &allPoints, NULL));
365     PetscCall(PetscQuadratureGetData(allPoints,&dim,NULL,&numPoints,&points,NULL));
366     PetscCall(DMGetWorkArray(dm,numPoints*Nc[f],MPIU_SCALAR,&pointEval));
367     for (q = 0; q < numPoints; ++q, ++tp) {
368       if (isAffine) {
369         CoordinatesRefToReal(dE, fgeom->dim, fegeom.xi, fgeom->v, fegeom.J, &points[q*dim], x);
370       } else {
371         fegeom.v    = &fgeom->v[tp*dE];
372         fegeom.J    = &fgeom->J[tp*dE*dE];
373         fegeom.invJ = &fgeom->invJ[tp*dE*dE];
374         fegeom.detJ = &fgeom->detJ[tp];
375         fegeom.n    = &fgeom->n[tp*dE];
376 
377         cgeom.J     = &fgeom->suppJ[0][tp*dE*dE];
378         cgeom.invJ  = &fgeom->suppInvJ[0][tp*dE*dE];
379         cgeom.detJ  = &fgeom->suppDetJ[0][tp];
380       }
381       /* TODO We should use cgeom here, instead of fegeom, however the geometry coming in through fgeom does not have the support cell geometry */
382       PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, 0, tp, T, &cgeom, coefficients, coefficients_t, u, u_x, u_t));
383       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, tp, TAux, &cgeom, coefficientsAux, coefficientsAux_t, a, a_x, a_t));
384       (*funcs[f])(dE, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, a_t, a_x, time, fegeom.v, fegeom.n, numConstants, constants, &pointEval[Nc[f]*q]);
385     }
386     PetscCall(PetscDualSpaceApplyAll(sp[f], pointEval, &values[v]));
387     PetscCall(DMRestoreWorkArray(dm,numPoints*Nc[f],MPIU_SCALAR,&pointEval));
388     v += spDim;
389   }
390   PetscCall(DMPlexVecRestoreClosure(dmIn, section, localU, p, NULL, &coefficients));
391   if (dmAux) PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, localA, p, NULL, &coefficientsAux));
392   PetscFunctionReturn(0);
393 }
394 
395 static PetscErrorCode DMProjectPoint_Private(DM dm, PetscDS ds, DM dmIn, DMEnclosureType encIn, PetscDS dsIn, DM dmAux, DMEnclosureType encAux, PetscDS dsAux, PetscFEGeom *fegeom, PetscInt effectiveHeight, PetscReal time, Vec localU, Vec localA, PetscBool hasFE, PetscBool hasFV, PetscBool isFE[],
396                                              PetscDualSpace sp[], PetscInt p, PetscTabulation *T, PetscTabulation *TAux,
397                                              DMBoundaryConditionType type, void (**funcs)(void), void **ctxs, PetscBool fieldActive[], PetscScalar values[])
398 {
399   PetscFVCellGeom fvgeom;
400   PetscInt        dim, dimEmbed;
401 
402   PetscFunctionBeginHot;
403   PetscCall(DMGetDimension(dm, &dim));
404   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
405   if (hasFV) PetscCall(DMPlexComputeCellGeometryFVM(dm, p, &fvgeom.volume, fvgeom.centroid, NULL));
406   switch (type) {
407   case DM_BC_ESSENTIAL:
408   case DM_BC_NATURAL:
409     PetscCall(DMProjectPoint_Func_Private(dm, ds, dmIn, dsIn, time, fegeom, &fvgeom, isFE, sp, (PetscErrorCode (**)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *)) funcs, ctxs, values));break;
410   case DM_BC_ESSENTIAL_FIELD:
411   case DM_BC_NATURAL_FIELD:
412     PetscCall(DMProjectPoint_Field_Private(dm, ds, dmIn, encIn, dsIn, dmAux, encAux, dsAux, time, localU, localA, fegeom, sp, p, T, TAux,
413                                            (void (**)(PetscInt, PetscInt, PetscInt,
414                                                       const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
415                                                       const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
416                                                       PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) funcs, ctxs, values));
417     break;
418   case DM_BC_ESSENTIAL_BD_FIELD:
419     PetscCall(DMProjectPoint_BdField_Private(dm, ds, dmIn, dsIn, dmAux, encAux, dsAux, time, localU, localA, fegeom, sp, p, T, TAux,
420                                              (void (**)(PetscInt, PetscInt, PetscInt,
421                                                         const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
422                                                         const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
423                                                         PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) funcs, ctxs, values));
424     break;
425   default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown boundary condition type: %d", (int) type);
426   }
427   PetscFunctionReturn(0);
428 }
429 
430 static PetscErrorCode PetscDualSpaceGetAllPointsUnion(PetscInt Nf, PetscDualSpace *sp, PetscInt dim, void (**funcs)(void), PetscQuadrature *allPoints)
431 {
432   PetscReal      *points;
433   PetscInt       f, numPoints;
434 
435   PetscFunctionBegin;
436   if (!dim) {
437     PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allPoints));
438     PetscFunctionReturn(0);
439   }
440   numPoints = 0;
441   for (f = 0; f < Nf; ++f) {
442     if (funcs[f]) {
443       PetscQuadrature fAllPoints;
444       PetscInt        fNumPoints;
445 
446       PetscCall(PetscDualSpaceGetAllData(sp[f],&fAllPoints, NULL));
447       PetscCall(PetscQuadratureGetData(fAllPoints, NULL, NULL, &fNumPoints, NULL, NULL));
448       numPoints += fNumPoints;
449     }
450   }
451   PetscCall(PetscMalloc1(dim*numPoints,&points));
452   numPoints = 0;
453   for (f = 0; f < Nf; ++f) {
454     if (funcs[f]) {
455       PetscQuadrature fAllPoints;
456       PetscInt        qdim, fNumPoints, q;
457       const PetscReal *fPoints;
458 
459       PetscCall(PetscDualSpaceGetAllData(sp[f],&fAllPoints, NULL));
460       PetscCall(PetscQuadratureGetData(fAllPoints, &qdim, NULL, &fNumPoints, &fPoints, NULL));
461       PetscCheck(qdim == dim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Spatial dimension %" PetscInt_FMT " for dual basis does not match input dimension %" PetscInt_FMT, qdim, dim);
462       for (q = 0; q < fNumPoints*dim; ++q) points[numPoints*dim+q] = fPoints[q];
463       numPoints += fNumPoints;
464     }
465   }
466   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF,allPoints));
467   PetscCall(PetscQuadratureSetData(*allPoints,dim,0,numPoints,points,NULL));
468   PetscFunctionReturn(0);
469 }
470 
471 /*@C
472   DMGetFirstLabeledPoint - Find first labeled point p_o in odm such that the corresponding point p in dm has the specified height. Return p and the corresponding ds.
473 
474   Input Parameters:
475   dm - the DM
476   odm - the enclosing DM
477   label - label for DM domain, or NULL for whole domain
478   numIds - the number of ids
479   ids - An array of the label ids in sequence for the domain
480   height - Height of target cells in DMPlex topology
481 
482   Output Parameters:
483   point - the first labeled point
484   ds - the ds corresponding to the first labeled point
485 
486   Level: developer
487 @*/
488 PetscErrorCode DMGetFirstLabeledPoint(DM dm, DM odm, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt height, PetscInt *point, PetscDS *ds)
489 {
490   DM              plex;
491   DMEnclosureType enc;
492   PetscInt        ls = -1;
493 
494   PetscFunctionBegin;
495   if (point) *point = -1;
496   if (!label) PetscFunctionReturn(0);
497   PetscCall(DMGetEnclosureRelation(dm, odm, &enc));
498   PetscCall(DMConvert(dm, DMPLEX, &plex));
499   for (PetscInt i = 0; i < numIds; ++i) {
500     IS       labelIS;
501     PetscInt num_points, pStart, pEnd;
502     PetscCall(DMLabelGetStratumIS(label, ids[i], &labelIS));
503     if (!labelIS) continue; /* No points with that id on this process */
504     PetscCall(DMPlexGetHeightStratum(plex, height, &pStart, &pEnd));
505     PetscCall(ISGetSize(labelIS, &num_points));
506     if (num_points) {
507       const PetscInt *points;
508       PetscCall(ISGetIndices(labelIS, &points));
509       for (PetscInt i=0; i<num_points; i++) {
510         PetscInt point;
511         PetscCall(DMGetEnclosurePoint(dm, odm, enc, points[i], &point));
512         if (pStart <= point && point < pEnd) {
513           ls = point;
514           if (ds) PetscCall(DMGetCellDS(dm, ls, ds));
515         }
516       }
517       PetscCall(ISRestoreIndices(labelIS, &points));
518     }
519     PetscCall(ISDestroy(&labelIS));
520     if (ls >= 0) break;
521   }
522   if (point) *point = ls;
523   PetscCall(DMDestroy(&plex));
524   PetscFunctionReturn(0);
525 }
526 
527 /*
528   This function iterates over a manifold, and interpolates the input function/field using the basis provided by the DS in our DM
529 
530   There are several different scenarios:
531 
532   1) Volumetric mesh with volumetric auxiliary data
533 
534      Here minHeight=0 since we loop over cells.
535 
536   2) Boundary mesh with boundary auxiliary data
537 
538      Here minHeight=1 since we loop over faces. This normally happens since we hang cells off of our boundary meshes to facilitate computation.
539 
540   3) Volumetric mesh with boundary auxiliary data
541 
542      Here minHeight=1 and auxbd=PETSC_TRUE since we loop over faces and use data only supported on those faces. This is common when imposing Dirichlet boundary conditions.
543 
544   4) Volumetric input mesh with boundary output mesh
545 
546      Here we must get a subspace for the input DS
547 
548   The maxHeight is used to support enforcement of constraints in DMForest.
549 
550   If localU is given and not equal to localX, we call DMPlexInsertBoundaryValues() to complete it.
551 
552   If we are using an input field (DM_BC_ESSENTIAL_FIELD or DM_BC_NATURAL_FIELD), we need to evaluate it at all the quadrature points of the dual basis functionals.
553     - We use effectiveHeight to mean the height above our incoming DS. For example, if the DS is for a submesh then the effective height is zero, whereas if the DS
554       is for the volumetric mesh, but we are iterating over a surface, then the effective height is nonzero. When the effective height is nonzero, we need to extract
555       dual spaces for the boundary from our input spaces.
556     - After extracting all quadrature points, we tabulate the input fields and auxiliary fields on them.
557 
558   We check that the #dof(closure(p)) == #dual basis functionals(p) for a representative p in the iteration
559 
560   If we have a label, we iterate over those points. This will probably break the maxHeight functionality since we do not check the height of those points.
561 */
562 static PetscErrorCode DMProjectLocal_Generic_Plex(DM dm, PetscReal time, Vec localU,
563                                                   PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt numIds, const PetscInt ids[],
564                                                   DMBoundaryConditionType type, void (**funcs)(void), void **ctxs,
565                                                   InsertMode mode, Vec localX)
566 {
567   DM                 plex, dmIn, plexIn, dmAux = NULL, plexAux = NULL, tdm;
568   DMEnclosureType    encIn, encAux;
569   PetscDS            ds = NULL, dsIn = NULL, dsAux = NULL;
570   Vec                localA = NULL, tv;
571   IS                 fieldIS;
572   PetscSection       section;
573   PetscDualSpace    *sp, *cellsp, *spIn, *cellspIn;
574   PetscTabulation *T = NULL, *TAux = NULL;
575   PetscInt          *Nc;
576   PetscInt           dim, dimEmbed, depth, htInc = 0, htIncIn = 0, htIncAux = 0, minHeight, maxHeight, h, regionNum, Nf, NfIn, NfAux = 0, NfTot, f;
577   PetscBool         *isFE, hasFE = PETSC_FALSE, hasFV = PETSC_FALSE, isCohesive = PETSC_FALSE, transform;
578   DMField            coordField;
579   DMLabel            depthLabel;
580   PetscQuadrature    allPoints = NULL;
581 
582   PetscFunctionBegin;
583   if (localU) PetscCall(VecGetDM(localU, &dmIn));
584   else        {dmIn = dm;}
585   PetscCall(DMGetAuxiliaryVec(dm, label, numIds ? ids[0] : 0, 0, &localA));
586   if (localA) PetscCall(VecGetDM(localA, &dmAux)); else {dmAux = NULL;}
587   PetscCall(DMConvert(dm, DMPLEX, &plex));
588   PetscCall(DMConvert(dmIn, DMPLEX, &plexIn));
589   PetscCall(DMGetEnclosureRelation(dmIn, dm, &encIn));
590   PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
591   PetscCall(DMGetDimension(dm, &dim));
592   PetscCall(DMPlexGetVTKCellHeight(plex, &minHeight));
593   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
594   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
595   PetscCall(DMHasBasisTransform(dm, &transform));
596   /* Auxiliary information can only be used with interpolation of field functions */
597   if (dmAux) {
598     PetscCall(DMConvert(dmAux, DMPLEX, &plexAux));
599     if (type == DM_BC_ESSENTIAL_FIELD || type == DM_BC_ESSENTIAL_BD_FIELD || type == DM_BC_NATURAL_FIELD) {
600       PetscCheck(localA,PETSC_COMM_SELF, PETSC_ERR_USER, "Missing localA vector");
601     }
602   }
603   /* Determine height for iteration of all meshes */
604   {
605     DMPolytopeType ct, ctIn, ctAux;
606     PetscInt       minHeightIn, minHeightAux, lStart, pStart, pEnd, p, pStartIn, pStartAux, pEndAux;
607     PetscInt       dim = -1, dimIn = -1, dimAux = -1;
608 
609     PetscCall(DMPlexGetSimplexOrBoxCells(plex, minHeight, &pStart, &pEnd));
610     if (pEnd > pStart) {
611       PetscCall(DMGetFirstLabeledPoint(dm, dm, label, numIds, ids, minHeight, &lStart, NULL));
612       p    = lStart < 0 ? pStart : lStart;
613       PetscCall(DMPlexGetCellType(plex, p, &ct));
614       dim  = DMPolytopeTypeGetDim(ct);
615       PetscCall(DMPlexGetVTKCellHeight(plexIn, &minHeightIn));
616       PetscCall(DMPlexGetSimplexOrBoxCells(plexIn, minHeightIn, &pStartIn, NULL));
617       PetscCall(DMPlexGetCellType(plexIn, pStartIn, &ctIn));
618       dimIn = DMPolytopeTypeGetDim(ctIn);
619       if (dmAux) {
620         PetscCall(DMPlexGetVTKCellHeight(plexAux, &minHeightAux));
621         PetscCall(DMPlexGetSimplexOrBoxCells(plexAux, minHeightAux, &pStartAux, &pEndAux));
622         if (pStartAux < pEndAux) {
623           PetscCall(DMPlexGetCellType(plexAux, pStartAux, &ctAux));
624           dimAux = DMPolytopeTypeGetDim(ctAux);
625         }
626       } else dimAux = dim;
627     }
628     if (dim < 0) {
629       DMLabel spmap = NULL, spmapIn = NULL, spmapAux = NULL;
630 
631       /* Fall back to determination based on being a submesh */
632       PetscCall(DMPlexGetSubpointMap(plex,   &spmap));
633       PetscCall(DMPlexGetSubpointMap(plexIn, &spmapIn));
634       if (plexAux) PetscCall(DMPlexGetSubpointMap(plexAux, &spmapAux));
635       dim    = spmap    ? 1 : 0;
636       dimIn  = spmapIn  ? 1 : 0;
637       dimAux = spmapAux ? 1 : 0;
638     }
639     {
640       PetscInt dimProj   = PetscMin(PetscMin(dim, dimIn), (dimAux < 0 ? PETSC_MAX_INT : dimAux));
641       PetscInt dimAuxEff = dimAux < 0 ? dimProj : dimAux;
642 
643       PetscCheck(PetscAbsInt(dimProj - dim) <= 1 && PetscAbsInt(dimProj - dimIn) <= 1 && PetscAbsInt(dimProj - dimAuxEff) <= 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Do not currently support differences of more than 1 in dimension");
644       if (dimProj < dim) minHeight = 1;
645       htInc    =  dim       - dimProj;
646       htIncIn  =  dimIn     - dimProj;
647       htIncAux =  dimAuxEff - dimProj;
648     }
649   }
650   PetscCall(DMPlexGetDepth(plex, &depth));
651   PetscCall(DMPlexGetDepthLabel(plex, &depthLabel));
652   PetscCall(DMPlexGetMaxProjectionHeight(plex, &maxHeight));
653   maxHeight = PetscMax(maxHeight, minHeight);
654   PetscCheck(maxHeight >= 0 && maxHeight <= dim,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Maximum projection height %" PetscInt_FMT " not in [0, %" PetscInt_FMT ")", maxHeight, dim);
655   PetscCall(DMGetFirstLabeledPoint(dm, dm, label, numIds, ids, 0, NULL, &ds));
656   if (!ds) PetscCall(DMGetDS(dm, &ds));
657   PetscCall(DMGetFirstLabeledPoint(dmIn, dm, label, numIds, ids, 0, NULL, &dsIn));
658   if (!dsIn) PetscCall(DMGetDS(dmIn, &dsIn));
659   PetscCall(PetscDSGetNumFields(ds, &Nf));
660   PetscCall(PetscDSGetNumFields(dsIn, &NfIn));
661   PetscCall(DMGetNumFields(dm, &NfTot));
662   PetscCall(DMFindRegionNum(dm, ds, &regionNum));
663   PetscCall(DMGetRegionNumDS(dm, regionNum, NULL, &fieldIS, NULL));
664   PetscCall(PetscDSIsCohesive(ds, &isCohesive));
665   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
666   PetscCall(DMGetLocalSection(dm, &section));
667   if (dmAux) {
668     PetscCall(DMGetDS(dmAux, &dsAux));
669     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
670   }
671   PetscCall(PetscDSGetComponents(ds, &Nc));
672   PetscCall(PetscMalloc3(Nf, &isFE, Nf, &sp, NfIn, &spIn));
673   if (maxHeight > 0) PetscCall(PetscMalloc2(Nf, &cellsp, NfIn, &cellspIn));
674   else               {cellsp = sp; cellspIn = spIn;}
675   if (localU && localU != localX) PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, localU, time, NULL, NULL, NULL));
676   /* Get cell dual spaces */
677   for (f = 0; f < Nf; ++f) {
678     PetscDiscType disctype;
679 
680     PetscCall(PetscDSGetDiscType_Internal(ds, f, &disctype));
681     if (disctype == PETSC_DISC_FE) {
682       PetscFE fe;
683 
684       isFE[f] = PETSC_TRUE;
685       hasFE   = PETSC_TRUE;
686       PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *) &fe));
687       PetscCall(PetscFEGetDualSpace(fe, &cellsp[f]));
688     } else if (disctype == PETSC_DISC_FV) {
689       PetscFV fv;
690 
691       isFE[f] = PETSC_FALSE;
692       hasFV   = PETSC_TRUE;
693       PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *) &fv));
694       PetscCall(PetscFVGetDualSpace(fv, &cellsp[f]));
695     } else {
696       isFE[f]   = PETSC_FALSE;
697       cellsp[f] = NULL;
698     }
699   }
700   for (f = 0; f < NfIn; ++f) {
701     PetscDiscType disctype;
702 
703     PetscCall(PetscDSGetDiscType_Internal(dsIn, f, &disctype));
704     if (disctype == PETSC_DISC_FE) {
705       PetscFE fe;
706 
707       PetscCall(PetscDSGetDiscretization(dsIn, f, (PetscObject *) &fe));
708       PetscCall(PetscFEGetDualSpace(fe, &cellspIn[f]));
709     } else if (disctype == PETSC_DISC_FV) {
710       PetscFV fv;
711 
712       PetscCall(PetscDSGetDiscretization(dsIn, f, (PetscObject *) &fv));
713       PetscCall(PetscFVGetDualSpace(fv, &cellspIn[f]));
714     } else {
715       cellspIn[f] = NULL;
716     }
717   }
718   PetscCall(DMGetCoordinateField(dm,&coordField));
719   for (f = 0; f < Nf; ++f) {
720     if (!htInc) {sp[f] = cellsp[f];}
721     else        PetscCall(PetscDualSpaceGetHeightSubspace(cellsp[f], htInc, &sp[f]));
722   }
723   if (type == DM_BC_ESSENTIAL_FIELD || type == DM_BC_ESSENTIAL_BD_FIELD || type == DM_BC_NATURAL_FIELD) {
724     PetscFE          fem, subfem;
725     PetscDiscType    disctype;
726     const PetscReal *points;
727     PetscInt         numPoints;
728 
729     PetscCheck(maxHeight <= minHeight,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Field projection not supported for face interpolation");
730     PetscCall(PetscDualSpaceGetAllPointsUnion(Nf, sp, dim-htInc, funcs, &allPoints));
731     PetscCall(PetscQuadratureGetData(allPoints, NULL, NULL, &numPoints, &points, NULL));
732     PetscCall(PetscMalloc2(NfIn, &T, NfAux, &TAux));
733     for (f = 0; f < NfIn; ++f) {
734       if (!htIncIn) {spIn[f] = cellspIn[f];}
735       else          PetscCall(PetscDualSpaceGetHeightSubspace(cellspIn[f], htIncIn, &spIn[f]));
736 
737       PetscCall(PetscDSGetDiscType_Internal(dsIn, f, &disctype));
738       if (disctype != PETSC_DISC_FE) continue;
739       PetscCall(PetscDSGetDiscretization(dsIn, f, (PetscObject *) &fem));
740       if (!htIncIn) {subfem = fem;}
741       else          PetscCall(PetscFEGetHeightSubspace(fem, htIncIn, &subfem));
742       PetscCall(PetscFECreateTabulation(subfem, 1, numPoints, points, 1, &T[f]));
743     }
744     for (f = 0; f < NfAux; ++f) {
745       PetscCall(PetscDSGetDiscType_Internal(dsAux, f, &disctype));
746       if (disctype != PETSC_DISC_FE) continue;
747       PetscCall(PetscDSGetDiscretization(dsAux, f, (PetscObject *) &fem));
748       if (!htIncAux) {subfem = fem;}
749       else           PetscCall(PetscFEGetHeightSubspace(fem, htIncAux, &subfem));
750       PetscCall(PetscFECreateTabulation(subfem, 1, numPoints, points, 1, &TAux[f]));
751     }
752   }
753   /* Note: We make no attempt to optimize for height. Higher height things just overwrite the lower height results. */
754   for (h = minHeight; h <= maxHeight; h++) {
755     PetscInt     hEff     = h - minHeight + htInc;
756     PetscInt     hEffIn   = h - minHeight + htIncIn;
757     PetscInt     hEffAux  = h - minHeight + htIncAux;
758     PetscDS      dsEff    = ds;
759     PetscDS      dsEffIn  = dsIn;
760     PetscDS      dsEffAux = dsAux;
761     PetscScalar *values;
762     PetscBool   *fieldActive;
763     PetscInt     maxDegree;
764     PetscInt     pStart, pEnd, p, lStart, spDim, totDim, numValues;
765     IS           heightIS;
766 
767     if (h > minHeight) {
768       for (f = 0; f < Nf; ++f) PetscCall(PetscDualSpaceGetHeightSubspace(cellsp[f], hEff, &sp[f]));
769     }
770     PetscCall(DMPlexGetSimplexOrBoxCells(plex, h, &pStart, &pEnd));
771     PetscCall(DMGetFirstLabeledPoint(dm, dm, label, numIds, ids, h, &lStart, NULL));
772     PetscCall(DMLabelGetStratumIS(depthLabel, depth - h, &heightIS));
773     if (pEnd <= pStart) {
774       PetscCall(ISDestroy(&heightIS));
775       continue;
776     }
777     /* Compute totDim, the number of dofs in the closure of a point at this height */
778     totDim = 0;
779     for (f = 0; f < Nf; ++f) {
780       PetscBool cohesive;
781 
782       if (!sp[f]) continue;
783       PetscCall(PetscDSGetCohesive(ds, f, &cohesive));
784       PetscCall(PetscDualSpaceGetDimension(sp[f], &spDim));
785       totDim += spDim;
786       if (isCohesive && !cohesive) totDim += spDim;
787     }
788     p    = lStart < 0 ? pStart : lStart;
789     PetscCall(DMPlexVecGetClosure(plex, section, localX, p, &numValues, NULL));
790     PetscCheck(numValues == totDim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The output section point (%" PetscInt_FMT ") closure size %" PetscInt_FMT " != dual space dimension %" PetscInt_FMT " at height %" PetscInt_FMT " in [%" PetscInt_FMT ", %" PetscInt_FMT "]", p, numValues, totDim, h, minHeight, maxHeight);
791     if (!totDim) {
792       PetscCall(ISDestroy(&heightIS));
793       continue;
794     }
795     if (htInc) PetscCall(PetscDSGetHeightSubspace(ds, hEff, &dsEff));
796     /* Compute totDimIn, the number of dofs in the closure of a point at this height */
797     if (localU) {
798       PetscInt totDimIn, pIn, numValuesIn;
799 
800       totDimIn = 0;
801       for (f = 0; f < NfIn; ++f) {
802         PetscBool cohesive;
803 
804         if (!spIn[f]) continue;
805         PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive));
806         PetscCall(PetscDualSpaceGetDimension(spIn[f], &spDim));
807         totDimIn += spDim;
808         if (isCohesive && !cohesive) totDimIn += spDim;
809       }
810       PetscCall(DMGetEnclosurePoint(dmIn, dm, encIn, lStart < 0 ? pStart : lStart, &pIn));
811       PetscCall(DMPlexVecGetClosure(plexIn, NULL, localU, pIn, &numValuesIn, NULL));
812       PetscCheck(numValuesIn == totDimIn,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The input section point (%" PetscInt_FMT ") closure size %" PetscInt_FMT " != dual space dimension %" PetscInt_FMT " at height %" PetscInt_FMT, pIn, numValuesIn, totDimIn, htIncIn);
813       if (htIncIn) PetscCall(PetscDSGetHeightSubspace(dsIn, hEffIn, &dsEffIn));
814     }
815     if (htIncAux) PetscCall(PetscDSGetHeightSubspace(dsAux, hEffAux, &dsEffAux));
816     /* Loop over points at this height */
817     PetscCall(DMGetWorkArray(dm, numValues, MPIU_SCALAR, &values));
818     PetscCall(DMGetWorkArray(dm, NfTot, MPI_INT, &fieldActive));
819     {
820       const PetscInt *fields;
821 
822       PetscCall(ISGetIndices(fieldIS, &fields));
823       for (f = 0; f < NfTot; ++f) {fieldActive[f] = PETSC_FALSE;}
824       for (f = 0; f < Nf; ++f) {fieldActive[fields[f]] = (funcs[f] && sp[f]) ? PETSC_TRUE : PETSC_FALSE;}
825       PetscCall(ISRestoreIndices(fieldIS, &fields));
826     }
827     if (label) {
828       PetscInt i;
829 
830       for (i = 0; i < numIds; ++i) {
831         IS              pointIS, isectIS;
832         const PetscInt *points;
833         PetscInt        n;
834         PetscFEGeom  *fegeom = NULL, *chunkgeom = NULL;
835         PetscQuadrature quad = NULL;
836 
837         PetscCall(DMLabelGetStratumIS(label, ids[i], &pointIS));
838         if (!pointIS) continue; /* No points with that id on this process */
839         PetscCall(ISIntersect(pointIS,heightIS,&isectIS));
840         PetscCall(ISDestroy(&pointIS));
841         if (!isectIS) continue;
842         PetscCall(ISGetLocalSize(isectIS, &n));
843         PetscCall(ISGetIndices(isectIS, &points));
844         PetscCall(DMFieldGetDegree(coordField,isectIS,NULL,&maxDegree));
845         if (maxDegree <= 1) {
846           PetscCall(DMFieldCreateDefaultQuadrature(coordField,isectIS,&quad));
847         }
848         if (!quad) {
849           if (!h && allPoints) {
850             quad = allPoints;
851             allPoints = NULL;
852           } else {
853             PetscCall(PetscDualSpaceGetAllPointsUnion(Nf,sp,isCohesive ? dim-htInc-1 : dim-htInc,funcs,&quad));
854           }
855         }
856         PetscCall(DMFieldCreateFEGeom(coordField, isectIS, quad, (htInc && h == minHeight) ? PETSC_TRUE : PETSC_FALSE, &fegeom));
857         for (p = 0; p < n; ++p) {
858           const PetscInt  point = points[p];
859 
860           PetscCall(PetscArrayzero(values, numValues));
861           PetscCall(PetscFEGeomGetChunk(fegeom,p,p+1,&chunkgeom));
862           PetscCall(DMPlexSetActivePoint(dm, point));
863           PetscCall(DMProjectPoint_Private(dm, dsEff, plexIn, encIn, dsEffIn, plexAux, encAux, dsEffAux, chunkgeom, htInc, time, localU, localA, hasFE, hasFV, isFE, sp, point, T, TAux, type, funcs, ctxs, fieldActive, values));
864           if (transform) PetscCall(DMPlexBasisTransformPoint_Internal(plex, tdm, tv, point, fieldActive, PETSC_FALSE, values));
865           PetscCall(DMPlexVecSetFieldClosure_Internal(plex, section, localX, fieldActive, point, Ncc, comps, label, ids[i], values, mode));
866         }
867         PetscCall(PetscFEGeomRestoreChunk(fegeom,p,p+1,&chunkgeom));
868         PetscCall(PetscFEGeomDestroy(&fegeom));
869         PetscCall(PetscQuadratureDestroy(&quad));
870         PetscCall(ISRestoreIndices(isectIS, &points));
871         PetscCall(ISDestroy(&isectIS));
872       }
873     } else {
874       PetscFEGeom    *fegeom = NULL, *chunkgeom = NULL;
875       PetscQuadrature quad = NULL;
876       IS              pointIS;
877 
878       PetscCall(ISCreateStride(PETSC_COMM_SELF,pEnd-pStart,pStart,1,&pointIS));
879       PetscCall(DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree));
880       if (maxDegree <= 1) {
881         PetscCall(DMFieldCreateDefaultQuadrature(coordField,pointIS,&quad));
882       }
883       if (!quad) {
884         if (!h && allPoints) {
885           quad = allPoints;
886           allPoints = NULL;
887         } else {
888           PetscCall(PetscDualSpaceGetAllPointsUnion(Nf, sp, dim-htInc, funcs, &quad));
889         }
890       }
891       PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, (htInc && h == minHeight) ? PETSC_TRUE : PETSC_FALSE, &fegeom));
892       for (p = pStart; p < pEnd; ++p) {
893         PetscCall(PetscArrayzero(values, numValues));
894         PetscCall(PetscFEGeomGetChunk(fegeom,p-pStart,p-pStart+1,&chunkgeom));
895         PetscCall(DMPlexSetActivePoint(dm, p));
896         PetscCall(DMProjectPoint_Private(dm, dsEff, plexIn, encIn, dsEffIn, plexAux, encAux, dsEffAux, chunkgeom, htInc, time, localU, localA, hasFE, hasFV, isFE, sp, p, T, TAux, type, funcs, ctxs, fieldActive, values));
897         if (transform) PetscCall(DMPlexBasisTransformPoint_Internal(plex, tdm, tv, p, fieldActive, PETSC_FALSE, values));
898         PetscCall(DMPlexVecSetFieldClosure_Internal(plex, section, localX, fieldActive, p, Ncc, comps, NULL, -1, values, mode));
899       }
900       PetscCall(PetscFEGeomRestoreChunk(fegeom,p-pStart,pStart-p+1,&chunkgeom));
901       PetscCall(PetscFEGeomDestroy(&fegeom));
902       PetscCall(PetscQuadratureDestroy(&quad));
903       PetscCall(ISDestroy(&pointIS));
904     }
905     PetscCall(ISDestroy(&heightIS));
906     PetscCall(DMRestoreWorkArray(dm, numValues, MPIU_SCALAR, &values));
907     PetscCall(DMRestoreWorkArray(dm, Nf, MPI_INT, &fieldActive));
908   }
909   /* Cleanup */
910   if (type == DM_BC_ESSENTIAL_FIELD || type == DM_BC_ESSENTIAL_BD_FIELD || type == DM_BC_NATURAL_FIELD) {
911     for (f = 0; f < NfIn;  ++f) PetscCall(PetscTabulationDestroy(&T[f]));
912     for (f = 0; f < NfAux; ++f) PetscCall(PetscTabulationDestroy(&TAux[f]));
913     PetscCall(PetscFree2(T, TAux));
914   }
915   PetscCall(PetscQuadratureDestroy(&allPoints));
916   PetscCall(PetscFree3(isFE, sp, spIn));
917   if (maxHeight > 0) PetscCall(PetscFree2(cellsp, cellspIn));
918   PetscCall(DMDestroy(&plex));
919   PetscCall(DMDestroy(&plexIn));
920   if (dmAux) PetscCall(DMDestroy(&plexAux));
921   PetscFunctionReturn(0);
922 }
923 
924 PetscErrorCode DMProjectFunctionLocal_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
925 {
926   PetscFunctionBegin;
927   PetscCall(DMProjectLocal_Generic_Plex(dm, time, NULL, 0, NULL, NULL, 0, NULL, DM_BC_ESSENTIAL, (void (**)(void)) funcs, ctxs, mode, localX));
928   PetscFunctionReturn(0);
929 }
930 
931 PetscErrorCode DMProjectFunctionLabelLocal_Plex(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Ncc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
932 {
933   PetscFunctionBegin;
934   PetscCall(DMProjectLocal_Generic_Plex(dm, time, NULL, Ncc, comps, label, numIds, ids, DM_BC_ESSENTIAL, (void (**)(void)) funcs, ctxs, mode, localX));
935   PetscFunctionReturn(0);
936 }
937 
938 PetscErrorCode DMProjectFieldLocal_Plex(DM dm, PetscReal time, Vec localU,
939                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
940                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
941                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
942                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
943                                         InsertMode mode, Vec localX)
944 {
945   PetscFunctionBegin;
946   PetscCall(DMProjectLocal_Generic_Plex(dm, time, localU, 0, NULL, NULL, 0, NULL, DM_BC_ESSENTIAL_FIELD, (void (**)(void)) funcs, NULL, mode, localX));
947   PetscFunctionReturn(0);
948 }
949 
950 PetscErrorCode DMProjectFieldLabelLocal_Plex(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Ncc, const PetscInt comps[], Vec localU,
951                                              void (**funcs)(PetscInt, PetscInt, PetscInt,
952                                                             const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
953                                                             const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
954                                                             PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
955                                              InsertMode mode, Vec localX)
956 {
957   PetscFunctionBegin;
958   PetscCall(DMProjectLocal_Generic_Plex(dm, time, localU, Ncc, comps, label, numIds, ids, DM_BC_ESSENTIAL_FIELD, (void (**)(void)) funcs, NULL, mode, localX));
959   PetscFunctionReturn(0);
960 }
961 
962 PetscErrorCode DMProjectBdFieldLabelLocal_Plex(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Ncc, const PetscInt comps[], Vec localU,
963                                                void (**funcs)(PetscInt, PetscInt, PetscInt,
964                                                               const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
965                                                               const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
966                                                               PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
967                                                InsertMode mode, Vec localX)
968 {
969   PetscFunctionBegin;
970   PetscCall(DMProjectLocal_Generic_Plex(dm, time, localU, Ncc, comps, label, numIds, ids, DM_BC_ESSENTIAL_BD_FIELD, (void (**)(void)) funcs, NULL, mode, localX));
971   PetscFunctionReturn(0);
972 }
973