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