xref: /petsc/src/dm/impls/plex/plexproject.c (revision 5c6496ba940341816c82c3b7fcda2e06e7ddfa20)
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 SETERRQ(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   PetscCheckFalse(dm != dmIn,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: SETERRQ(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       PetscCheckFalse(qdim != dim,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 /*@C
470   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.
471 
472   Input Parameters:
473   dm - the DM
474   odm - the enclosing DM
475   label - label for DM domain, or NULL for whole domain
476   numIds - the number of ids
477   ids - An array of the label ids in sequence for the domain
478   height - Height of target cells in DMPlex topology
479 
480   Output Parameters:
481   point - the first labeled point
482   ds - the ds corresponding to the first labeled point
483 
484   Level: developer
485 */
486 PetscErrorCode DMGetFirstLabeledPoint(DM dm, DM odm, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt height, PetscInt *point, PetscDS *ds)
487 {
488   DM              plex;
489   DMEnclosureType enc;
490   PetscInt        ls = -1;
491   PetscErrorCode  ierr;
492 
493   PetscFunctionBegin;
494   if (point) *point = -1;
495   if (!label) PetscFunctionReturn(0);
496   ierr = DMGetEnclosureRelation(dm, odm, &enc);CHKERRQ(ierr);
497   ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
498   for (PetscInt i = 0; i < numIds; ++i) {
499     IS       labelIS;
500     PetscInt num_points, pStart, pEnd;
501     ierr = DMLabelGetStratumIS(label, ids[i], &labelIS);CHKERRQ(ierr);
502     if (!labelIS) continue; /* No points with that id on this process */
503     ierr = DMPlexGetHeightStratum(plex, height, &pStart, &pEnd);CHKERRQ(ierr);
504     ierr = ISGetSize(labelIS, &num_points);CHKERRQ(ierr);
505     if (num_points) {
506       const PetscInt *points;
507       ierr = ISGetIndices(labelIS, &points);CHKERRQ(ierr);
508       for (PetscInt i=0; i<num_points; i++) {
509         PetscInt point;
510         ierr = DMGetEnclosurePoint(dm, odm, enc, points[i], &point);CHKERRQ(ierr);
511         if (pStart <= point && point < pEnd) {
512           ls = point;
513           if (ds) {ierr = DMGetCellDS(dm, ls, ds);CHKERRQ(ierr);}
514         }
515       }
516       ierr = ISRestoreIndices(labelIS, &points);CHKERRQ(ierr);
517     }
518     ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
519     if (ls >= 0) break;
520   }
521   if (point) *point = ls;
522   ierr = DMDestroy(&plex);CHKERRQ(ierr);
523   PetscFunctionReturn(0);
524 }
525 
526 /*
527   This function iterates over a manifold, and interpolates the input function/field using the basis provided by the DS in our DM
528 
529   There are several different scenarios:
530 
531   1) Volumetric mesh with volumetric auxiliary data
532 
533      Here minHeight=0 since we loop over cells.
534 
535   2) Boundary mesh with boundary auxiliary data
536 
537      Here minHeight=1 since we loop over faces. This normally happens since we hang cells off of our boundary meshes to facilitate computation.
538 
539   3) Volumetric mesh with boundary auxiliary data
540 
541      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.
542 
543   4) Volumetric input mesh with boundary output mesh
544 
545      Here we must get a subspace for the input DS
546 
547   The maxHeight is used to support enforcement of constraints in DMForest.
548 
549   If localU is given and not equal to localX, we call DMPlexInsertBoundaryValues() to complete it.
550 
551   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.
552     - 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
553       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
554       dual spaces for the boundary from our input spaces.
555     - After extracting all quadrature points, we tabulate the input fields and auxiliary fields on them.
556 
557   We check that the #dof(closure(p)) == #dual basis functionals(p) for a representative p in the iteration
558 
559   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.
560 */
561 static PetscErrorCode DMProjectLocal_Generic_Plex(DM dm, PetscReal time, Vec localU,
562                                                   PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt numIds, const PetscInt ids[],
563                                                   DMBoundaryConditionType type, void (**funcs)(void), void **ctxs,
564                                                   InsertMode mode, Vec localX)
565 {
566   DM                 plex, dmIn, plexIn, dmAux = NULL, plexAux = NULL, tdm;
567   DMEnclosureType    encIn, encAux;
568   PetscDS            ds = NULL, dsIn = NULL, dsAux = NULL;
569   Vec                localA = NULL, tv;
570   IS                 fieldIS;
571   PetscSection       section;
572   PetscDualSpace    *sp, *cellsp, *spIn, *cellspIn;
573   PetscTabulation *T = NULL, *TAux = NULL;
574   PetscInt          *Nc;
575   PetscInt           dim, dimEmbed, depth, htInc = 0, htIncIn = 0, htIncAux = 0, minHeight, maxHeight, h, regionNum, Nf, NfIn, NfAux = 0, NfTot, f;
576   PetscBool         *isFE, hasFE = PETSC_FALSE, hasFV = PETSC_FALSE, isCohesive = PETSC_FALSE, transform;
577   DMField            coordField;
578   DMLabel            depthLabel;
579   PetscQuadrature    allPoints = NULL;
580   PetscErrorCode     ierr;
581 
582   PetscFunctionBegin;
583   if (localU) {ierr = VecGetDM(localU, &dmIn);CHKERRQ(ierr);}
584   else        {dmIn = dm;}
585   ierr = DMGetAuxiliaryVec(dm, label, numIds ? ids[0] : 0, &localA);CHKERRQ(ierr);
586   if (localA) {ierr = VecGetDM(localA, &dmAux);CHKERRQ(ierr);} else {dmAux = NULL;}
587   ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
588   ierr = DMConvert(dmIn, DMPLEX, &plexIn);CHKERRQ(ierr);
589   ierr = DMGetEnclosureRelation(dmIn, dm, &encIn);CHKERRQ(ierr);
590   ierr = DMGetEnclosureRelation(dmAux, dm, &encAux);CHKERRQ(ierr);
591   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
592   ierr = DMPlexGetVTKCellHeight(plex, &minHeight);CHKERRQ(ierr);
593   ierr = DMGetBasisTransformDM_Internal(dm, &tdm);CHKERRQ(ierr);
594   ierr = DMGetBasisTransformVec_Internal(dm, &tv);CHKERRQ(ierr);
595   ierr = DMHasBasisTransform(dm, &transform);CHKERRQ(ierr);
596   /* Auxiliary information can only be used with interpolation of field functions */
597   if (dmAux) {
598     ierr = DMConvert(dmAux, DMPLEX, &plexAux);CHKERRQ(ierr);
599     if (type == DM_BC_ESSENTIAL_FIELD || type == DM_BC_ESSENTIAL_BD_FIELD || type == DM_BC_NATURAL_FIELD) {
600       PetscCheckFalse(!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;
607     PetscInt       dim = -1, dimIn, dimAux;
608 
609     ierr = DMPlexGetSimplexOrBoxCells(plex, minHeight, &pStart, &pEnd);CHKERRQ(ierr);
610     if (pEnd > pStart) {
611       ierr = DMGetFirstLabeledPoint(dm, dm, label, numIds, ids, minHeight, &lStart, NULL);CHKERRQ(ierr);
612       p    = lStart < 0 ? pStart : lStart;
613       ierr = DMPlexGetCellType(plex, p, &ct);CHKERRQ(ierr);
614       dim  = DMPolytopeTypeGetDim(ct);
615       ierr = DMPlexGetVTKCellHeight(plexIn, &minHeightIn);CHKERRQ(ierr);
616       ierr = DMPlexGetSimplexOrBoxCells(plexIn, minHeightIn, &pStartIn, NULL);CHKERRQ(ierr);
617       ierr = DMPlexGetCellType(plexIn, pStartIn, &ctIn);CHKERRQ(ierr);
618       dimIn = DMPolytopeTypeGetDim(ctIn);
619       if (dmAux) {
620         ierr = DMPlexGetVTKCellHeight(plexAux, &minHeightAux);CHKERRQ(ierr);
621         ierr = DMPlexGetSimplexOrBoxCells(plexAux, minHeightAux, &pStartAux, NULL);CHKERRQ(ierr);
622         ierr = DMPlexGetCellType(plexAux, pStartAux, &ctAux);CHKERRQ(ierr);
623         dimAux = DMPolytopeTypeGetDim(ctAux);
624       } else dimAux = dim;
625     }
626     if (dim < 0) {
627       DMLabel spmap = NULL, spmapIn = NULL, spmapAux = NULL;
628 
629       /* Fall back to determination based on being a submesh */
630       ierr = DMPlexGetSubpointMap(plex,   &spmap);CHKERRQ(ierr);
631       ierr = DMPlexGetSubpointMap(plexIn, &spmapIn);CHKERRQ(ierr);
632       if (plexAux) {ierr = DMPlexGetSubpointMap(plexAux, &spmapAux);CHKERRQ(ierr);}
633       dim    = spmap    ? 1 : 0;
634       dimIn  = spmapIn  ? 1 : 0;
635       dimAux = spmapAux ? 1 : 0;
636     }
637     {
638       PetscInt dimProj = PetscMin(PetscMin(dim, dimIn), dimAux);
639 
640       PetscCheckFalse(PetscAbsInt(dimProj - dim) > 1 || PetscAbsInt(dimProj - dimIn) > 1 || PetscAbsInt(dimProj - dimAux) > 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Do not currently support differences of more than 1 in dimension");
641       if (dimProj < dim) minHeight = 1;
642       htInc    =  dim    - dimProj;
643       htIncIn  =  dimIn  - dimProj;
644       htIncAux =  dimAux - dimProj;
645     }
646   }
647   ierr = DMPlexGetDepth(plex, &depth);CHKERRQ(ierr);
648   ierr = DMPlexGetDepthLabel(plex, &depthLabel);CHKERRQ(ierr);
649   ierr = DMPlexGetMaxProjectionHeight(plex, &maxHeight);CHKERRQ(ierr);
650   maxHeight = PetscMax(maxHeight, minHeight);
651   PetscCheck(maxHeight >= 0 && maxHeight <= dim,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Maximum projection height %D not in [0, %D)", maxHeight, dim);
652   ierr = DMGetFirstLabeledPoint(dm, dm, label, numIds, ids, 0, NULL, &ds);CHKERRQ(ierr);
653   if (!ds) {ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);}
654   ierr = DMGetFirstLabeledPoint(dmIn, dm, label, numIds, ids, 0, NULL, &dsIn);CHKERRQ(ierr);
655   if (!dsIn) {ierr = DMGetDS(dmIn, &dsIn);CHKERRQ(ierr);}
656   ierr = PetscDSGetNumFields(ds, &Nf);CHKERRQ(ierr);
657   ierr = PetscDSGetNumFields(dsIn, &NfIn);CHKERRQ(ierr);
658   ierr = DMGetNumFields(dm, &NfTot);CHKERRQ(ierr);
659   ierr = DMFindRegionNum(dm, ds, &regionNum);CHKERRQ(ierr);
660   ierr = DMGetRegionNumDS(dm, regionNum, NULL, &fieldIS, NULL);CHKERRQ(ierr);
661   ierr = PetscDSIsCohesive(ds, &isCohesive);CHKERRQ(ierr);
662   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
663   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
664   if (dmAux) {
665     ierr = DMGetDS(dmAux, &dsAux);CHKERRQ(ierr);
666     ierr = PetscDSGetNumFields(dsAux, &NfAux);CHKERRQ(ierr);
667   }
668   ierr = PetscDSGetComponents(ds, &Nc);CHKERRQ(ierr);
669   ierr = PetscMalloc3(Nf, &isFE, Nf, &sp, NfIn, &spIn);CHKERRQ(ierr);
670   if (maxHeight > 0) {ierr = PetscMalloc2(Nf, &cellsp, NfIn, &cellspIn);CHKERRQ(ierr);}
671   else               {cellsp = sp; cellspIn = spIn;}
672   if (localU && localU != localX) {ierr = DMPlexInsertBoundaryValues(plex, PETSC_TRUE, localU, time, NULL, NULL, NULL);CHKERRQ(ierr);}
673   /* Get cell dual spaces */
674   for (f = 0; f < Nf; ++f) {
675     PetscDiscType disctype;
676 
677     ierr = PetscDSGetDiscType_Internal(ds, f, &disctype);CHKERRQ(ierr);
678     if (disctype == PETSC_DISC_FE) {
679       PetscFE fe;
680 
681       isFE[f] = PETSC_TRUE;
682       hasFE   = PETSC_TRUE;
683       ierr = PetscDSGetDiscretization(ds, f, (PetscObject *) &fe);CHKERRQ(ierr);
684       ierr = PetscFEGetDualSpace(fe, &cellsp[f]);CHKERRQ(ierr);
685     } else if (disctype == PETSC_DISC_FV) {
686       PetscFV fv;
687 
688       isFE[f] = PETSC_FALSE;
689       hasFV   = PETSC_TRUE;
690       ierr = PetscDSGetDiscretization(ds, f, (PetscObject *) &fv);CHKERRQ(ierr);
691       ierr = PetscFVGetDualSpace(fv, &cellsp[f]);CHKERRQ(ierr);
692     } else {
693       isFE[f]   = PETSC_FALSE;
694       cellsp[f] = NULL;
695     }
696   }
697   for (f = 0; f < NfIn; ++f) {
698     PetscDiscType disctype;
699 
700     ierr = PetscDSGetDiscType_Internal(dsIn, f, &disctype);CHKERRQ(ierr);
701     if (disctype == PETSC_DISC_FE) {
702       PetscFE fe;
703 
704       ierr = PetscDSGetDiscretization(dsIn, f, (PetscObject *) &fe);CHKERRQ(ierr);
705       ierr = PetscFEGetDualSpace(fe, &cellspIn[f]);CHKERRQ(ierr);
706     } else if (disctype == PETSC_DISC_FV) {
707       PetscFV fv;
708 
709       ierr = PetscDSGetDiscretization(dsIn, f, (PetscObject *) &fv);CHKERRQ(ierr);
710       ierr = PetscFVGetDualSpace(fv, &cellspIn[f]);CHKERRQ(ierr);
711     } else {
712       cellspIn[f] = NULL;
713     }
714   }
715   ierr = DMGetCoordinateField(dm,&coordField);CHKERRQ(ierr);
716   for (f = 0; f < Nf; ++f) {
717     if (!htInc) {sp[f] = cellsp[f];}
718     else        {ierr = PetscDualSpaceGetHeightSubspace(cellsp[f], htInc, &sp[f]);CHKERRQ(ierr);}
719   }
720   if (type == DM_BC_ESSENTIAL_FIELD || type == DM_BC_ESSENTIAL_BD_FIELD || type == DM_BC_NATURAL_FIELD) {
721     PetscFE          fem, subfem;
722     PetscDiscType    disctype;
723     const PetscReal *points;
724     PetscInt         numPoints;
725 
726     PetscCheckFalse(maxHeight > minHeight,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Field projection not supported for face interpolation");
727     ierr = PetscDualSpaceGetAllPointsUnion(Nf, sp, dim-htInc, funcs, &allPoints);CHKERRQ(ierr);
728     ierr = PetscQuadratureGetData(allPoints, NULL, NULL, &numPoints, &points, NULL);CHKERRQ(ierr);
729     ierr = PetscMalloc2(NfIn, &T, NfAux, &TAux);CHKERRQ(ierr);
730     for (f = 0; f < NfIn; ++f) {
731       if (!htIncIn) {spIn[f] = cellspIn[f];}
732       else          {ierr = PetscDualSpaceGetHeightSubspace(cellspIn[f], htIncIn, &spIn[f]);CHKERRQ(ierr);}
733 
734       ierr = PetscDSGetDiscType_Internal(dsIn, f, &disctype);CHKERRQ(ierr);
735       if (disctype != PETSC_DISC_FE) continue;
736       ierr = PetscDSGetDiscretization(dsIn, f, (PetscObject *) &fem);CHKERRQ(ierr);
737       if (!htIncIn) {subfem = fem;}
738       else          {ierr = PetscFEGetHeightSubspace(fem, htIncIn, &subfem);CHKERRQ(ierr);}
739       ierr = PetscFECreateTabulation(subfem, 1, numPoints, points, 1, &T[f]);CHKERRQ(ierr);
740     }
741     for (f = 0; f < NfAux; ++f) {
742       ierr = PetscDSGetDiscType_Internal(dsAux, f, &disctype);CHKERRQ(ierr);
743       if (disctype != PETSC_DISC_FE) continue;
744       ierr = PetscDSGetDiscretization(dsAux, f, (PetscObject *) &fem);CHKERRQ(ierr);
745       if (!htIncAux) {subfem = fem;}
746       else           {ierr = PetscFEGetHeightSubspace(fem, htIncAux, &subfem);CHKERRQ(ierr);}
747       ierr = PetscFECreateTabulation(subfem, 1, numPoints, points, 1, &TAux[f]);CHKERRQ(ierr);
748     }
749   }
750   /* Note: We make no attempt to optimize for height. Higher height things just overwrite the lower height results. */
751   for (h = minHeight; h <= maxHeight; h++) {
752     PetscInt     hEff     = h - minHeight + htInc;
753     PetscInt     hEffIn   = h - minHeight + htIncIn;
754     PetscInt     hEffAux  = h - minHeight + htIncAux;
755     PetscDS      dsEff    = ds;
756     PetscDS      dsEffIn  = dsIn;
757     PetscDS      dsEffAux = dsAux;
758     PetscScalar *values;
759     PetscBool   *fieldActive;
760     PetscInt     maxDegree;
761     PetscInt     pStart, pEnd, p, lStart, spDim, totDim, numValues;
762     IS           heightIS;
763 
764     if (h > minHeight) {
765       for (f = 0; f < Nf; ++f) {ierr = PetscDualSpaceGetHeightSubspace(cellsp[f], hEff, &sp[f]);CHKERRQ(ierr);}
766     }
767     ierr = DMPlexGetSimplexOrBoxCells(plex, h, &pStart, &pEnd);CHKERRQ(ierr);
768     ierr = DMGetFirstLabeledPoint(dm, dm, label, numIds, ids, h, &lStart, NULL);CHKERRQ(ierr);
769     ierr = DMLabelGetStratumIS(depthLabel, depth - h, &heightIS);CHKERRQ(ierr);
770     if (pEnd <= pStart) {
771       ierr = ISDestroy(&heightIS);CHKERRQ(ierr);
772       continue;
773     }
774     /* Compute totDim, the number of dofs in the closure of a point at this height */
775     totDim = 0;
776     for (f = 0; f < Nf; ++f) {
777       PetscBool cohesive;
778 
779       if (!sp[f]) continue;
780       ierr = PetscDSGetCohesive(ds, f, &cohesive);CHKERRQ(ierr);
781       ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr);
782       totDim += spDim;
783       if (isCohesive && !cohesive) totDim += spDim;
784     }
785     p    = lStart < 0 ? pStart : lStart;
786     ierr = DMPlexVecGetClosure(plex, section, localX, p, &numValues, NULL);CHKERRQ(ierr);
787     PetscCheckFalse(numValues != totDim,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);
788     if (!totDim) {
789       ierr = ISDestroy(&heightIS);CHKERRQ(ierr);
790       continue;
791     }
792     if (htInc) {ierr = PetscDSGetHeightSubspace(ds, hEff, &dsEff);CHKERRQ(ierr);}
793     /* Compute totDimIn, the number of dofs in the closure of a point at this height */
794     if (localU) {
795       PetscInt totDimIn, pIn, numValuesIn;
796 
797       totDimIn = 0;
798       for (f = 0; f < NfIn; ++f) {
799         PetscBool cohesive;
800 
801         if (!spIn[f]) continue;
802         ierr = PetscDSGetCohesive(dsIn, f, &cohesive);CHKERRQ(ierr);
803         ierr = PetscDualSpaceGetDimension(spIn[f], &spDim);CHKERRQ(ierr);
804         totDimIn += spDim;
805         if (isCohesive && !cohesive) totDimIn += spDim;
806       }
807       ierr = DMGetEnclosurePoint(dmIn, dm, encIn, lStart < 0 ? pStart : lStart, &pIn);CHKERRQ(ierr);
808       ierr = DMPlexVecGetClosure(plexIn, NULL, localU, pIn, &numValuesIn, NULL);CHKERRQ(ierr);
809       PetscCheckFalse(numValuesIn != totDimIn,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);
810       if (htIncIn) {ierr = PetscDSGetHeightSubspace(dsIn, hEffIn, &dsEffIn);CHKERRQ(ierr);}
811     }
812     if (htIncAux) {ierr = PetscDSGetHeightSubspace(dsAux, hEffAux, &dsEffAux);CHKERRQ(ierr);}
813     /* Loop over points at this height */
814     ierr = DMGetWorkArray(dm, numValues, MPIU_SCALAR, &values);CHKERRQ(ierr);
815     ierr = DMGetWorkArray(dm, NfTot, MPI_INT, &fieldActive);CHKERRQ(ierr);
816     {
817       const PetscInt *fields;
818 
819       ierr = ISGetIndices(fieldIS, &fields);CHKERRQ(ierr);
820       for (f = 0; f < NfTot; ++f) {fieldActive[f] = PETSC_FALSE;}
821       for (f = 0; f < Nf; ++f) {fieldActive[fields[f]] = (funcs[f] && sp[f]) ? PETSC_TRUE : PETSC_FALSE;}
822       ierr = ISRestoreIndices(fieldIS, &fields);CHKERRQ(ierr);
823     }
824     if (label) {
825       PetscInt i;
826 
827       for (i = 0; i < numIds; ++i) {
828         IS              pointIS, isectIS;
829         const PetscInt *points;
830         PetscInt        n;
831         PetscFEGeom  *fegeom = NULL, *chunkgeom = NULL;
832         PetscQuadrature quad = NULL;
833 
834         ierr = DMLabelGetStratumIS(label, ids[i], &pointIS);CHKERRQ(ierr);
835         if (!pointIS) continue; /* No points with that id on this process */
836         ierr = ISIntersect(pointIS,heightIS,&isectIS);CHKERRQ(ierr);
837         ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
838         if (!isectIS) continue;
839         ierr = ISGetLocalSize(isectIS, &n);CHKERRQ(ierr);
840         ierr = ISGetIndices(isectIS, &points);CHKERRQ(ierr);
841         ierr = DMFieldGetDegree(coordField,isectIS,NULL,&maxDegree);CHKERRQ(ierr);
842         if (maxDegree <= 1) {
843           ierr = DMFieldCreateDefaultQuadrature(coordField,isectIS,&quad);CHKERRQ(ierr);
844         }
845         if (!quad) {
846           if (!h && allPoints) {
847             quad = allPoints;
848             allPoints = NULL;
849           } else {
850             ierr = PetscDualSpaceGetAllPointsUnion(Nf,sp,isCohesive ? dim-htInc-1 : dim-htInc,funcs,&quad);CHKERRQ(ierr);
851           }
852         }
853         ierr = DMFieldCreateFEGeom(coordField, isectIS, quad, (htInc && h == minHeight) ? PETSC_TRUE : PETSC_FALSE, &fegeom);CHKERRQ(ierr);
854         for (p = 0; p < n; ++p) {
855           const PetscInt  point = points[p];
856 
857           ierr = PetscArrayzero(values, numValues);CHKERRQ(ierr);
858           ierr = PetscFEGeomGetChunk(fegeom,p,p+1,&chunkgeom);CHKERRQ(ierr);
859           ierr = DMPlexSetActivePoint(dm, point);CHKERRQ(ierr);
860           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);
861           if (ierr) {
862             PetscErrorCode ierr2;
863             ierr2 = DMRestoreWorkArray(dm, numValues, MPIU_SCALAR, &values);CHKERRQ(ierr2);
864             ierr2 = DMRestoreWorkArray(dm, Nf, MPI_INT, &fieldActive);CHKERRQ(ierr2);
865             CHKERRQ(ierr);
866           }
867           if (transform) {ierr = DMPlexBasisTransformPoint_Internal(plex, tdm, tv, point, fieldActive, PETSC_FALSE, values);CHKERRQ(ierr);}
868           ierr = DMPlexVecSetFieldClosure_Internal(plex, section, localX, fieldActive, point, Ncc, comps, label, ids[i], values, mode);CHKERRQ(ierr);
869         }
870         ierr = PetscFEGeomRestoreChunk(fegeom,p,p+1,&chunkgeom);CHKERRQ(ierr);
871         ierr = PetscFEGeomDestroy(&fegeom);CHKERRQ(ierr);
872         ierr = PetscQuadratureDestroy(&quad);CHKERRQ(ierr);
873         ierr = ISRestoreIndices(isectIS, &points);CHKERRQ(ierr);
874         ierr = ISDestroy(&isectIS);CHKERRQ(ierr);
875       }
876     } else {
877       PetscFEGeom    *fegeom = NULL, *chunkgeom = NULL;
878       PetscQuadrature quad = NULL;
879       IS              pointIS;
880 
881       ierr = ISCreateStride(PETSC_COMM_SELF,pEnd-pStart,pStart,1,&pointIS);CHKERRQ(ierr);
882       ierr = DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);CHKERRQ(ierr);
883       if (maxDegree <= 1) {
884         ierr = DMFieldCreateDefaultQuadrature(coordField,pointIS,&quad);CHKERRQ(ierr);
885       }
886       if (!quad) {
887         if (!h && allPoints) {
888           quad = allPoints;
889           allPoints = NULL;
890         } else {
891           ierr = PetscDualSpaceGetAllPointsUnion(Nf, sp, dim-htInc, funcs, &quad);CHKERRQ(ierr);
892         }
893       }
894       ierr = DMFieldCreateFEGeom(coordField, pointIS, quad, (htInc && h == minHeight) ? PETSC_TRUE : PETSC_FALSE, &fegeom);CHKERRQ(ierr);
895       for (p = pStart; p < pEnd; ++p) {
896         ierr = PetscArrayzero(values, numValues);CHKERRQ(ierr);
897         ierr = PetscFEGeomGetChunk(fegeom,p-pStart,p-pStart+1,&chunkgeom);CHKERRQ(ierr);
898         ierr = DMPlexSetActivePoint(dm, p);CHKERRQ(ierr);
899         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);
900         if (ierr) {
901           PetscErrorCode ierr2;
902           ierr2 = DMRestoreWorkArray(dm, numValues, MPIU_SCALAR, &values);CHKERRQ(ierr2);
903           ierr2 = DMRestoreWorkArray(dm, Nf, MPI_INT, &fieldActive);CHKERRQ(ierr2);
904           CHKERRQ(ierr);
905         }
906         if (transform) {ierr = DMPlexBasisTransformPoint_Internal(plex, tdm, tv, p, fieldActive, PETSC_FALSE, values);CHKERRQ(ierr);}
907         ierr = DMPlexVecSetFieldClosure_Internal(plex, section, localX, fieldActive, p, Ncc, comps, NULL, -1, values, mode);CHKERRQ(ierr);
908       }
909       ierr = PetscFEGeomRestoreChunk(fegeom,p-pStart,pStart-p+1,&chunkgeom);CHKERRQ(ierr);
910       ierr = PetscFEGeomDestroy(&fegeom);CHKERRQ(ierr);
911       ierr = PetscQuadratureDestroy(&quad);CHKERRQ(ierr);
912       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
913     }
914     ierr = ISDestroy(&heightIS);CHKERRQ(ierr);
915     ierr = DMRestoreWorkArray(dm, numValues, MPIU_SCALAR, &values);CHKERRQ(ierr);
916     ierr = DMRestoreWorkArray(dm, Nf, MPI_INT, &fieldActive);CHKERRQ(ierr);
917   }
918   /* Cleanup */
919   if (type == DM_BC_ESSENTIAL_FIELD || type == DM_BC_ESSENTIAL_BD_FIELD || type == DM_BC_NATURAL_FIELD) {
920     for (f = 0; f < NfIn;  ++f) {ierr = PetscTabulationDestroy(&T[f]);CHKERRQ(ierr);}
921     for (f = 0; f < NfAux; ++f) {ierr = PetscTabulationDestroy(&TAux[f]);CHKERRQ(ierr);}
922     ierr = PetscFree2(T, TAux);CHKERRQ(ierr);
923   }
924   ierr = PetscQuadratureDestroy(&allPoints);CHKERRQ(ierr);
925   ierr = PetscFree3(isFE, sp, spIn);CHKERRQ(ierr);
926   if (maxHeight > 0) {ierr = PetscFree2(cellsp, cellspIn);CHKERRQ(ierr);}
927   ierr = DMDestroy(&plex);CHKERRQ(ierr);
928   ierr = DMDestroy(&plexIn);CHKERRQ(ierr);
929   if (dmAux) {ierr = DMDestroy(&plexAux);CHKERRQ(ierr);}
930   PetscFunctionReturn(0);
931 }
932 
933 PetscErrorCode DMProjectFunctionLocal_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
934 {
935   PetscErrorCode ierr;
936 
937   PetscFunctionBegin;
938   ierr = DMProjectLocal_Generic_Plex(dm, time, NULL, 0, NULL, NULL, 0, NULL, DM_BC_ESSENTIAL, (void (**)(void)) funcs, ctxs, mode, localX);CHKERRQ(ierr);
939   PetscFunctionReturn(0);
940 }
941 
942 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)
943 {
944   PetscErrorCode ierr;
945 
946   PetscFunctionBegin;
947   ierr = DMProjectLocal_Generic_Plex(dm, time, NULL, Ncc, comps, label, numIds, ids, DM_BC_ESSENTIAL, (void (**)(void)) funcs, ctxs, mode, localX);CHKERRQ(ierr);
948   PetscFunctionReturn(0);
949 }
950 
951 PetscErrorCode DMProjectFieldLocal_Plex(DM dm, PetscReal time, Vec localU,
952                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
953                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
954                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
955                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
956                                         InsertMode mode, Vec localX)
957 {
958   PetscErrorCode ierr;
959 
960   PetscFunctionBegin;
961   ierr = DMProjectLocal_Generic_Plex(dm, time, localU, 0, NULL, NULL, 0, NULL, DM_BC_ESSENTIAL_FIELD, (void (**)(void)) funcs, NULL, mode, localX);CHKERRQ(ierr);
962   PetscFunctionReturn(0);
963 }
964 
965 PetscErrorCode DMProjectFieldLabelLocal_Plex(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Ncc, const PetscInt comps[], Vec localU,
966                                              void (**funcs)(PetscInt, PetscInt, PetscInt,
967                                                             const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
968                                                             const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
969                                                             PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
970                                              InsertMode mode, Vec localX)
971 {
972   PetscErrorCode ierr;
973 
974   PetscFunctionBegin;
975   ierr = DMProjectLocal_Generic_Plex(dm, time, localU, Ncc, comps, label, numIds, ids, DM_BC_ESSENTIAL_FIELD, (void (**)(void)) funcs, NULL, mode, localX);CHKERRQ(ierr);
976   PetscFunctionReturn(0);
977 }
978 
979 PetscErrorCode DMProjectBdFieldLabelLocal_Plex(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Ncc, const PetscInt comps[], Vec localU,
980                                                void (**funcs)(PetscInt, PetscInt, PetscInt,
981                                                               const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
982                                                               const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
983                                                               PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
984                                                InsertMode mode, Vec localX)
985 {
986   PetscErrorCode ierr;
987 
988   PetscFunctionBegin;
989   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);
990   PetscFunctionReturn(0);
991 }
992