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