xref: /petsc/src/dm/impls/plex/plexfem.c (revision a3e8c5ccf93cc81f4cf2f7ff1027f5e098b72fde)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petscsf.h>
3 
4 #include <petsc/private/petscfeimpl.h>
5 #include <petsc/private/petscfvimpl.h>
6 
7 #undef __FUNCT__
8 #define __FUNCT__ "DMPlexGetScale"
9 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10 {
11   DM_Plex *mesh = (DM_Plex*) dm->data;
12 
13   PetscFunctionBegin;
14   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
15   PetscValidPointer(scale, 3);
16   *scale = mesh->scale[unit];
17   PetscFunctionReturn(0);
18 }
19 
20 #undef __FUNCT__
21 #define __FUNCT__ "DMPlexSetScale"
22 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
23 {
24   DM_Plex *mesh = (DM_Plex*) dm->data;
25 
26   PetscFunctionBegin;
27   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28   mesh->scale[unit] = scale;
29   PetscFunctionReturn(0);
30 }
31 
32 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
33 {
34   switch (i) {
35   case 0:
36     switch (j) {
37     case 0: return 0;
38     case 1:
39       switch (k) {
40       case 0: return 0;
41       case 1: return 0;
42       case 2: return 1;
43       }
44     case 2:
45       switch (k) {
46       case 0: return 0;
47       case 1: return -1;
48       case 2: return 0;
49       }
50     }
51   case 1:
52     switch (j) {
53     case 0:
54       switch (k) {
55       case 0: return 0;
56       case 1: return 0;
57       case 2: return -1;
58       }
59     case 1: return 0;
60     case 2:
61       switch (k) {
62       case 0: return 1;
63       case 1: return 0;
64       case 2: return 0;
65       }
66     }
67   case 2:
68     switch (j) {
69     case 0:
70       switch (k) {
71       case 0: return 0;
72       case 1: return 1;
73       case 2: return 0;
74       }
75     case 1:
76       switch (k) {
77       case 0: return -1;
78       case 1: return 0;
79       case 2: return 0;
80       }
81     case 2: return 0;
82     }
83   }
84   return 0;
85 }
86 
87 #undef __FUNCT__
88 #define __FUNCT__ "DMPlexProjectRigidBody"
89 static PetscErrorCode DMPlexProjectRigidBody(PetscInt dim, const PetscReal X[], PetscInt Nf, PetscScalar *mode, void *ctx)
90 {
91   PetscInt *ctxInt  = (PetscInt *) ctx;
92   PetscInt  dim2    = ctxInt[0];
93   PetscInt  d       = ctxInt[1];
94   PetscInt  i, j, k = dim > 2 ? d - dim : d;
95 
96   PetscFunctionBegin;
97   if (dim != dim2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %d does not match context dimension %d", dim, dim2);
98   for (i = 0; i < dim; i++) mode[i] = 0.;
99   if (d < dim) {
100     mode[d] = 1.;
101   } else {
102     for (i = 0; i < dim; i++) {
103       for (j = 0; j < dim; j++) {
104         mode[j] += epsilon(i, j, k)*X[i];
105       }
106     }
107   }
108   PetscFunctionReturn(0);
109 }
110 
111 #undef __FUNCT__
112 #define __FUNCT__ "DMPlexCreateRigidBody"
113 /*@C
114   DMPlexCreateRigidBody - for the default global section, create rigid body modes from coordinates
115 
116   Collective on DM
117 
118   Input Arguments:
119 . dm - the DM
120 
121   Output Argument:
122 . sp - the null space
123 
124   Note: This is necessary to take account of Dirichlet conditions on the displacements
125 
126   Level: advanced
127 
128 .seealso: MatNullSpaceCreate()
129 @*/
130 PetscErrorCode DMPlexCreateRigidBody(DM dm, MatNullSpace *sp)
131 {
132   MPI_Comm       comm;
133   Vec            mode[6];
134   PetscSection   section, globalSection;
135   PetscInt       dim, dimEmbed, n, m, d, i, j;
136   PetscErrorCode ierr;
137 
138   PetscFunctionBegin;
139   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
140   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
141   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
142   if (dim == 1) {
143     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
144     PetscFunctionReturn(0);
145   }
146   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
147   ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
148   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
149   m    = (dim*(dim+1))/2;
150   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
151   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
152   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
153   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
154   for (d = 0; d < m; d++) {
155     PetscInt ctx[2];
156     void    *voidctx = (void *) (&ctx[0]);
157     PetscErrorCode (*func)(PetscInt, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody;
158 
159     ctx[0] = dimEmbed;
160     ctx[1] = d;
161     ierr = DMPlexProjectFunction(dm, &func, &voidctx, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
162   }
163   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
164   /* Orthonormalize system */
165   for (i = dim; i < m; ++i) {
166     PetscScalar dots[6];
167 
168     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
169     for (j = 0; j < i; ++j) dots[j] *= -1.0;
170     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
171     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
172   }
173   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
174   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
175   PetscFunctionReturn(0);
176 }
177 
178 #undef __FUNCT__
179 #define __FUNCT__ "DMPlexSetMaxProjectionHeight"
180 /*@
181   DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs
182   are computed by associating the basis function with one of the mesh points in its transitively-closed support, and
183   evaluating the dual space basis of that point.  A basis function is associated with the point in its
184   transitively-closed support whose mesh height is highest (w.r.t. DAG height), but not greater than the maximum
185   projection height, which is set with this function.  By default, the maximum projection height is zero, which means
186   that only mesh cells are used to project basis functions.  A height of one, for example, evaluates a cell-interior
187   basis functions using its cells dual space basis, but all other basis functions with the dual space basis of a face.
188 
189   Input Parameters:
190 + dm - the DMPlex object
191 - height - the maximum projection height >= 0
192 
193   Level: advanced
194 
195 .seealso: DMPlexGetMaxProjectionHeight(), DMPlexProjectFunctionLocal(), DMPlexProjectFunctionLabelLocal()
196 @*/
197 PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height)
198 {
199   DM_Plex *plex = (DM_Plex *) dm->data;
200 
201   PetscFunctionBegin;
202   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
203   plex->maxProjectionHeight = height;
204   PetscFunctionReturn(0);
205 }
206 
207 #undef __FUNCT__
208 #define __FUNCT__ "DMPlexGetMaxProjectionHeight"
209 /*@
210   DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in
211   DMPlexProjectXXXLocal() functions.
212 
213   Input Parameters:
214 . dm - the DMPlex object
215 
216   Output Parameters:
217 . height - the maximum projection height
218 
219   Level: intermediate
220 
221 .seealso: DMPlexSetMaxProjectionHeight(), DMPlexProjectFunctionLocal(), DMPlexProjectFunctionLabelLocal()
222 @*/
223 PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height)
224 {
225   DM_Plex *plex = (DM_Plex *) dm->data;
226 
227   PetscFunctionBegin;
228   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
229   *height = plex->maxProjectionHeight;
230   PetscFunctionReturn(0);
231 }
232 
233 #undef __FUNCT__
234 #define __FUNCT__ "DMPlexProjectFunctionLabelLocal"
235 PetscErrorCode DMPlexProjectFunctionLabelLocal(DM dm, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscErrorCode (**funcs)(PetscInt, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
236 {
237   PetscDualSpace *sp, *cellsp;
238   PetscInt       *numComp;
239   PetscSection    section;
240   PetscScalar    *values;
241   PetscBool      *fieldActive;
242   PetscInt        numFields, dim, dimEmbed, spDim, totDim = 0, numValues, pStart, pEnd, cStart, cEnd, cEndInterior, f, d, v, i, comp, maxHeight, h;
243   PetscErrorCode  ierr;
244 
245   PetscFunctionBegin;
246   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
247   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
248   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
249   if (cEnd <= cStart) PetscFunctionReturn(0);
250   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
251   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
252   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
253   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
254   ierr = PetscMalloc2(numFields,&sp,numFields,&numComp);CHKERRQ(ierr);
255   ierr = DMPlexGetMaxProjectionHeight(dm,&maxHeight);CHKERRQ(ierr);
256   if (maxHeight < 0 || maxHeight > dim) {SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"maximum projection height %d not in [0, %d)\n", maxHeight,dim);}
257   if (maxHeight > 0) {ierr = PetscMalloc1(numFields,&cellsp);CHKERRQ(ierr);}
258   else               {cellsp = sp;}
259   for (h = 0; h <= maxHeight; h++) {
260     ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
261     if (!h) {pStart = cStart; pEnd = cEnd;}
262     if (pEnd <= pStart) continue;
263     totDim = 0;
264     for (f = 0; f < numFields; ++f) {
265       PetscObject  obj;
266       PetscClassId id;
267 
268       ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
269       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
270       if (id == PETSCFE_CLASSID) {
271         PetscFE fe = (PetscFE) obj;
272 
273         ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr);
274         if (!h) {
275           ierr = PetscFEGetDualSpace(fe, &cellsp[f]);CHKERRQ(ierr);
276           sp[f] = cellsp[f];
277           ierr = PetscObjectReference((PetscObject) sp[f]);CHKERRQ(ierr);
278         } else {
279           ierr = PetscDualSpaceGetHeightSubspace(cellsp[f], h, &sp[f]);CHKERRQ(ierr);
280           if (!sp[f]) continue;
281         }
282       } else if (id == PETSCFV_CLASSID) {
283         PetscFV fv = (PetscFV) obj;
284 
285         ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr);
286         ierr = PetscFVGetDualSpace(fv, &sp[f]);CHKERRQ(ierr);
287         ierr = PetscObjectReference((PetscObject) sp[f]);CHKERRQ(ierr);
288       } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
289       ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr);
290       totDim += spDim*numComp[f];
291     }
292     ierr = DMPlexVecGetClosure(dm, section, localX, pStart, &numValues, NULL);CHKERRQ(ierr);
293     if (numValues != totDim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The section point closure size %d != dual space dimension %d", numValues, totDim);
294     if (!totDim) continue;
295     ierr = DMGetWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr);
296     ierr = DMGetWorkArray(dm, numFields, PETSC_BOOL, &fieldActive);CHKERRQ(ierr);
297     for (f = 0; f < numFields; ++f) fieldActive[f] = (funcs[f] && sp[f]) ? PETSC_TRUE : PETSC_FALSE;
298     for (i = 0; i < numIds; ++i) {
299       IS              pointIS;
300       const PetscInt *points;
301       PetscInt        n, p;
302 
303       ierr = DMLabelGetStratumIS(label, ids[i], &pointIS);CHKERRQ(ierr);
304       ierr = ISGetLocalSize(pointIS, &n);CHKERRQ(ierr);
305       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
306       for (p = 0; p < n; ++p) {
307         const PetscInt    point = points[p];
308         PetscFECellGeom   geom;
309 
310         if ((point < pStart) || (point >= pEnd)) continue;
311         ierr          = DMPlexComputeCellGeometryFEM(dm, point, NULL, geom.v0, geom.J, NULL, &geom.detJ);CHKERRQ(ierr);
312         geom.dim      = dim - h;
313         geom.dimEmbed = dimEmbed;
314         for (f = 0, v = 0; f < numFields; ++f) {
315           void * const ctx = ctxs ? ctxs[f] : NULL;
316 
317           if (!sp[f]) continue;
318           ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr);
319           for (d = 0; d < spDim; ++d) {
320             if (funcs[f]) {
321               ierr = PetscDualSpaceApply(sp[f], d, &geom, numComp[f], funcs[f], ctx, &values[v]);CHKERRQ(ierr);
322             } else {
323               for (comp = 0; comp < numComp[f]; ++comp) values[v+comp] = 0.0;
324             }
325             v += numComp[f];
326           }
327         }
328         ierr = DMPlexVecSetFieldClosure_Internal(dm, section, localX, fieldActive, point, values, mode);CHKERRQ(ierr);
329       }
330       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
331       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
332     }
333     if (h) {
334       for (f = 0; f < numFields; ++f) {ierr = PetscDualSpaceDestroy(&sp[f]);CHKERRQ(ierr);}
335     }
336   }
337   ierr = DMRestoreWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr);
338   ierr = DMRestoreWorkArray(dm, numFields, PETSC_BOOL, &fieldActive);CHKERRQ(ierr);
339   for (f = 0; f < numFields; ++f) {ierr = PetscDualSpaceDestroy(&sp[f]);CHKERRQ(ierr);}
340   ierr = PetscFree2(sp, numComp);CHKERRQ(ierr);
341   if (maxHeight > 0) {
342     ierr = PetscFree(cellsp);CHKERRQ(ierr);
343   }
344   PetscFunctionReturn(0);
345 }
346 
347 #undef __FUNCT__
348 #define __FUNCT__ "DMPlexProjectFunctionLocal"
349 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscErrorCode (**funcs)(PetscInt, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
350 {
351   PetscDualSpace *sp, *cellsp;
352   PetscInt       *numComp;
353   PetscSection    section;
354   PetscScalar    *values;
355   PetscInt        Nf, dim, dimEmbed, spDim, totDim = 0, numValues, pStart, pEnd, p, cStart, cEnd, cEndInterior, f, d, v, comp, h, maxHeight;
356   PetscErrorCode  ierr;
357 
358   PetscFunctionBegin;
359   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
360   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
361   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
362   if (cEnd <= cStart) PetscFunctionReturn(0);
363   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
364   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
365   ierr = PetscMalloc2(Nf, &sp, Nf, &numComp);CHKERRQ(ierr);
366   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
367   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
368   ierr = DMPlexGetMaxProjectionHeight(dm,&maxHeight);CHKERRQ(ierr);
369   if (maxHeight < 0 || maxHeight > dim) {SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"maximum projection height %d not in [0, %d)\n", maxHeight,dim);}
370   if (maxHeight > 0) {
371     ierr = PetscMalloc1(Nf,&cellsp);CHKERRQ(ierr);
372   }
373   else {
374     cellsp = sp;
375   }
376   for (h = 0; h <= maxHeight; h++) {
377     ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
378     if (!h) {pStart = cStart; pEnd = cEnd;}
379     if (pEnd <= pStart) continue;
380     totDim = 0;
381     for (f = 0; f < Nf; ++f) {
382       PetscObject  obj;
383       PetscClassId id;
384 
385       ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
386       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
387       if (id == PETSCFE_CLASSID) {
388         PetscFE fe = (PetscFE) obj;
389 
390         ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr);
391         if (!h) {
392           ierr  = PetscFEGetDualSpace(fe, &cellsp[f]);CHKERRQ(ierr);
393           sp[f] = cellsp[f];
394           ierr  = PetscObjectReference((PetscObject) sp[f]);CHKERRQ(ierr);
395         }
396         else {
397           ierr = PetscDualSpaceGetHeightSubspace(cellsp[f], h, &sp[f]);CHKERRQ(ierr);
398           if (!sp[f]) {
399             continue;
400           }
401         }
402       } else if (id == PETSCFV_CLASSID) {
403         PetscFV fv = (PetscFV) obj;
404 
405         if (h) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP, "Projection height > 0 not supported for finite volume");
406         ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr);
407         ierr = PetscFVGetDualSpace(fv, &sp[f]);CHKERRQ(ierr);
408         ierr = PetscObjectReference((PetscObject) sp[f]);CHKERRQ(ierr);
409       } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
410       ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr);
411       totDim += spDim*numComp[f];
412     }
413     ierr = DMPlexVecGetClosure(dm, section, localX, pStart, &numValues, NULL);CHKERRQ(ierr);
414     if (numValues != totDim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The section point closure size %d != dual space dimension %d", numValues, totDim);
415     if (!totDim) continue;
416     ierr = DMGetWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr);
417     for (p = pStart; p < pEnd; ++p) {
418       PetscFECellGeom geom;
419 
420       ierr          = DMPlexComputeCellGeometryFEM(dm, p, NULL, geom.v0, geom.J, NULL, &geom.detJ);CHKERRQ(ierr);
421       geom.dim      = dim - h;
422       geom.dimEmbed = dimEmbed;
423       for (f = 0, v = 0; f < Nf; ++f) {
424         void * const ctx = ctxs ? ctxs[f] : NULL;
425 
426         if (!sp[f]) continue;
427         ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr);
428         for (d = 0; d < spDim; ++d) {
429           if (funcs[f]) {
430             ierr = PetscDualSpaceApply(sp[f], d, &geom, numComp[f], funcs[f], ctx, &values[v]);CHKERRQ(ierr);
431           } else {
432             for (comp = 0; comp < numComp[f]; ++comp) values[v+comp] = 0.0;
433           }
434           v += numComp[f];
435         }
436       }
437       ierr = DMPlexVecSetClosure(dm, section, localX, p, values, mode);CHKERRQ(ierr);
438     }
439     ierr = DMRestoreWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr);
440     if (h || !maxHeight) {
441       for (f = 0; f < Nf; f++) {ierr = PetscDualSpaceDestroy(&sp[f]);CHKERRQ(ierr);}
442     }
443   }
444   ierr = PetscFree2(sp, numComp);CHKERRQ(ierr);
445   if (maxHeight > 0) {
446     for (f = 0; f < Nf; f++) {ierr = PetscDualSpaceDestroy(&cellsp[f]);CHKERRQ(ierr);}
447     ierr = PetscFree(cellsp);CHKERRQ(ierr);
448   }
449   PetscFunctionReturn(0);
450 }
451 
452 #undef __FUNCT__
453 #define __FUNCT__ "DMPlexProjectFunction"
454 /*@C
455   DMPlexProjectFunction - This projects the given function into the function space provided.
456 
457   Input Parameters:
458 + dm      - The DM
459 . funcs   - The coordinate functions to evaluate, one per field
460 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
461 - mode    - The insertion mode for values
462 
463   Output Parameter:
464 . X - vector
465 
466    Calling sequence of func:
467 $    func(PetscInt dim, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
468 
469 +  dim - The spatial dimension
470 .  x   - The coordinates
471 .  Nf  - The number of fields
472 .  u   - The output field values
473 -  ctx - optional user-defined function context
474 
475   Level: developer
476 
477 .seealso: DMPlexComputeL2Diff()
478 @*/
479 PetscErrorCode DMPlexProjectFunction(DM dm, PetscErrorCode (**funcs)(PetscInt, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
480 {
481   Vec            localX;
482   PetscErrorCode ierr;
483 
484   PetscFunctionBegin;
485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
486   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
487   ierr = DMPlexProjectFunctionLocal(dm, funcs, ctxs, mode, localX);CHKERRQ(ierr);
488   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
489   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
490   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
491   PetscFunctionReturn(0);
492 }
493 
494 #undef __FUNCT__
495 #define __FUNCT__ "DMPlexProjectFieldLocal"
496 PetscErrorCode DMPlexProjectFieldLocal(DM dm, Vec localU, void (**funcs)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal [], PetscScalar []), InsertMode mode, Vec localX)
497 {
498   DM                dmAux;
499   PetscDS           prob, probAux = NULL;
500   Vec               A;
501   PetscSection      section, sectionAux = NULL;
502   PetscDualSpace   *sp;
503   PetscInt         *Ncf;
504   PetscScalar      *values, *u, *u_x, *a, *a_x;
505   PetscReal        *x, *v0, *J, *invJ, detJ;
506   PetscInt          Nf, dim, spDim, totDim, numValues, cStart, cEnd, cEndInterior, c, f, d, v, comp, maxHeight;
507   PetscErrorCode    ierr;
508 
509   PetscFunctionBegin;
510   ierr = DMPlexGetMaxProjectionHeight(dm,&maxHeight);CHKERRQ(ierr);
511   if (maxHeight > 0) {SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Field projection for height > 0 not supported yet");}
512   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
513   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
514   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
515   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
516   ierr = PetscMalloc2(Nf, &sp, Nf, &Ncf);CHKERRQ(ierr);
517   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
518   ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr);
519   ierr = PetscDSGetEvaluationArrays(prob, &u, NULL, &u_x);CHKERRQ(ierr);
520   ierr = PetscDSGetRefCoordArrays(prob, &x, NULL);CHKERRQ(ierr);
521   ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr);
522   ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr);
523   if (dmAux) {
524     ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr);
525     ierr = DMGetDefaultSection(dmAux, &sectionAux);CHKERRQ(ierr);
526     ierr = PetscDSGetEvaluationArrays(probAux, &a, NULL, &a_x);CHKERRQ(ierr);
527   }
528   ierr = DMPlexInsertBoundaryValues(dm, localU, 0.0, NULL, NULL, NULL);CHKERRQ(ierr);
529   ierr = DMPlexVecGetClosure(dm, section, localX, cStart, &numValues, NULL);CHKERRQ(ierr);
530   if (numValues != totDim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The section cell closure size %d != dual space dimension %d", numValues, totDim);
531   ierr = DMGetWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr);
532   ierr = PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr);
533   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
534   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
535   for (c = cStart; c < cEnd; ++c) {
536     PetscScalar *coefficients = NULL, *coefficientsAux = NULL;
537 
538     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
539     ierr = DMPlexVecGetClosure(dm, section, localU, c, NULL, &coefficients);CHKERRQ(ierr);
540     if (dmAux) {ierr = DMPlexVecGetClosure(dmAux, sectionAux, A, c, NULL, &coefficientsAux);CHKERRQ(ierr);}
541     for (f = 0, v = 0; f < Nf; ++f) {
542       PetscObject  obj;
543       PetscClassId id;
544 
545       ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
546       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
547       if (id == PETSCFE_CLASSID) {
548         PetscFE fe = (PetscFE) obj;
549 
550         ierr = PetscFEGetDualSpace(fe, &sp[f]);CHKERRQ(ierr);
551         ierr  = PetscObjectReference((PetscObject) sp[f]);CHKERRQ(ierr);
552         ierr = PetscFEGetNumComponents(fe, &Ncf[f]);CHKERRQ(ierr);
553       } else if (id == PETSCFV_CLASSID) {
554         PetscFV fv = (PetscFV) obj;
555 
556         ierr = PetscFVGetNumComponents(fv, &Ncf[f]);CHKERRQ(ierr);
557         ierr = PetscFVGetDualSpace(fv, &sp[f]);CHKERRQ(ierr);
558         ierr = PetscObjectReference((PetscObject) sp[f]);CHKERRQ(ierr);
559       }
560       ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr);
561       for (d = 0; d < spDim; ++d) {
562         PetscQuadrature  quad;
563         const PetscReal *points, *weights;
564         PetscInt         numPoints, q;
565 
566         if (funcs[f]) {
567           ierr = PetscDualSpaceGetFunctional(sp[f], d, &quad);CHKERRQ(ierr);
568           ierr = PetscQuadratureGetData(quad, NULL, &numPoints, &points, &weights);CHKERRQ(ierr);
569           for (q = 0; q < numPoints; ++q) {
570             CoordinatesRefToReal(dim, dim, v0, J, &points[q*dim], x);
571             ierr = EvaluateFieldJets(prob,    PETSC_FALSE, q, invJ, coefficients,    NULL, u, u_x, NULL);CHKERRQ(ierr);
572             ierr = EvaluateFieldJets(probAux, PETSC_FALSE, q, invJ, coefficientsAux, NULL, a, a_x, NULL);CHKERRQ(ierr);
573             (*funcs[f])(u, NULL, u_x, a, NULL, a_x, x, &values[v]);
574           }
575         } else {
576           for (comp = 0; comp < Ncf[f]; ++comp) values[v+comp] = 0.0;
577         }
578         v += Ncf[f];
579       }
580     }
581     ierr = DMPlexVecRestoreClosure(dm, section, localU, c, NULL, &coefficients);CHKERRQ(ierr);
582     if (dmAux) {ierr = DMPlexVecRestoreClosure(dmAux, sectionAux, A, c, NULL, &coefficientsAux);CHKERRQ(ierr);}
583     ierr = DMPlexVecSetClosure(dm, section, localX, c, values, mode);CHKERRQ(ierr);
584   }
585   ierr = DMRestoreWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr);
586   ierr = PetscFree3(v0,J,invJ);CHKERRQ(ierr);
587   for (f = 0; f < Nf; f++) {ierr = PetscDualSpaceDestroy(&sp[f]);CHKERRQ(ierr);}
588   ierr = PetscFree2(sp, Ncf);CHKERRQ(ierr);
589   PetscFunctionReturn(0);
590 }
591 
592 #undef __FUNCT__
593 #define __FUNCT__ "DMPlexInsertBoundaryValues_FEM_Internal"
594 static PetscErrorCode DMPlexInsertBoundaryValues_FEM_Internal(DM dm, PetscInt field, DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscInt, const PetscReal[], PetscInt, PetscScalar *, void *), void *ctx, Vec locX)
595 {
596   PetscErrorCode (**funcs)(PetscInt, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
597   void            **ctxs;
598   PetscInt          numFields;
599   PetscErrorCode    ierr;
600 
601   PetscFunctionBegin;
602   ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
603   ierr = PetscCalloc2(numFields,&funcs,numFields,&ctxs);CHKERRQ(ierr);
604   funcs[field] = func;
605   ctxs[field]  = ctx;
606   ierr = DMPlexProjectFunctionLabelLocal(dm, label, numids, ids, funcs, ctxs, INSERT_BC_VALUES, locX);CHKERRQ(ierr);
607   ierr = PetscFree2(funcs,ctxs);CHKERRQ(ierr);
608   PetscFunctionReturn(0);
609 }
610 
611 #undef __FUNCT__
612 #define __FUNCT__ "DMPlexInsertBoundaryValues_FVM_Internal"
613 /* This ignores numcomps/comps */
614 static PetscErrorCode DMPlexInsertBoundaryValues_FVM_Internal(DM dm, PetscReal time, Vec faceGeometry, Vec cellGeometry, Vec Grad,
615                                                               PetscInt field, DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*), void *ctx, Vec locX)
616 {
617   PetscDS            prob;
618   PetscSF            sf;
619   DM                 dmFace, dmCell, dmGrad;
620   const PetscScalar *facegeom, *cellgeom, *grad;
621   const PetscInt    *leaves;
622   PetscScalar       *x, *fx;
623   PetscInt           dim, nleaves, loc, fStart, fEnd, pdim, i;
624   PetscErrorCode     ierr;
625 
626   PetscFunctionBegin;
627   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
628   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);CHKERRQ(ierr);
629   nleaves = PetscMax(0, nleaves);
630   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
631   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
632   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
633   ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr);
634   ierr = VecGetArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr);
635   ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr);
636   ierr = VecGetArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr);
637   if (Grad) {
638     PetscFV fv;
639 
640     ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &fv);CHKERRQ(ierr);
641     ierr = VecGetDM(Grad, &dmGrad);CHKERRQ(ierr);
642     ierr = VecGetArrayRead(Grad, &grad);CHKERRQ(ierr);
643     ierr = PetscFVGetNumComponents(fv, &pdim);CHKERRQ(ierr);
644     ierr = DMGetWorkArray(dm, pdim, PETSC_SCALAR, &fx);CHKERRQ(ierr);
645   }
646   ierr = VecGetArray(locX, &x);CHKERRQ(ierr);
647   for (i = 0; i < numids; ++i) {
648     IS              faceIS;
649     const PetscInt *faces;
650     PetscInt        numFaces, f;
651 
652     ierr = DMLabelGetStratumIS(label, ids[i], &faceIS);CHKERRQ(ierr);
653     if (!faceIS) continue; /* No points with that id on this process */
654     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
655     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
656     for (f = 0; f < numFaces; ++f) {
657       const PetscInt         face = faces[f], *cells;
658       const PetscFVFaceGeom *fg;
659 
660       if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */
661       ierr = PetscFindInt(face, nleaves, (PetscInt *) leaves, &loc);CHKERRQ(ierr);
662       if (loc >= 0) continue;
663       ierr = DMPlexPointLocalRead(dmFace, face, facegeom, &fg);CHKERRQ(ierr);
664       ierr = DMPlexGetSupport(dm, face, &cells);CHKERRQ(ierr);
665       if (Grad) {
666         const PetscFVCellGeom *cg;
667         const PetscScalar     *cx, *cgrad;
668         PetscScalar           *xG;
669         PetscReal              dx[3];
670         PetscInt               d;
671 
672         ierr = DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg);CHKERRQ(ierr);
673         ierr = DMPlexPointLocalRead(dm, cells[0], x, &cx);CHKERRQ(ierr);
674         ierr = DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad);CHKERRQ(ierr);
675         ierr = DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);CHKERRQ(ierr);
676         DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx);
677         for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d*dim], dx);
678         ierr = (*func)(time, fg->centroid, fg->normal, fx, xG, ctx);CHKERRQ(ierr);
679       } else {
680         const PetscScalar *xI;
681         PetscScalar       *xG;
682 
683         ierr = DMPlexPointLocalRead(dm, cells[0], x, &xI);CHKERRQ(ierr);
684         ierr = DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);CHKERRQ(ierr);
685         ierr = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx);CHKERRQ(ierr);
686       }
687     }
688     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
689     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
690   }
691   ierr = VecRestoreArray(locX, &x);CHKERRQ(ierr);
692   if (Grad) {
693     ierr = DMRestoreWorkArray(dm, pdim, PETSC_SCALAR, &fx);CHKERRQ(ierr);
694     ierr = VecRestoreArrayRead(Grad, &grad);CHKERRQ(ierr);
695   }
696   ierr = VecRestoreArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr);
697   ierr = VecRestoreArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr);
698   PetscFunctionReturn(0);
699 }
700 
701 #undef __FUNCT__
702 #define __FUNCT__ "DMPlexInsertBoundaryValues"
703 PetscErrorCode DMPlexInsertBoundaryValues(DM dm, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
704 {
705   PetscInt       numBd, b;
706   PetscErrorCode ierr;
707 
708   PetscFunctionBegin;
709   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
710   PetscValidHeaderSpecific(locX, VEC_CLASSID, 2);
711   if (faceGeomFVM) {PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 4);}
712   if (cellGeomFVM) {PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 5);}
713   if (gradFVM)     {PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 6);}
714   ierr = DMPlexGetNumBoundary(dm, &numBd);CHKERRQ(ierr);
715   for (b = 0; b < numBd; ++b) {
716     PetscBool       isEssential;
717     const char     *labelname;
718     DMLabel         label;
719     PetscInt        field;
720     PetscObject     obj;
721     PetscClassId    id;
722     void          (*func)();
723     PetscInt        numids;
724     const PetscInt *ids;
725     void           *ctx;
726 
727     ierr = DMPlexGetBoundary(dm, b, &isEssential, NULL, &labelname, &field, NULL, NULL, &func, &numids, &ids, &ctx);CHKERRQ(ierr);
728     if (!isEssential) continue;
729     ierr = DMPlexGetLabel(dm, labelname, &label);CHKERRQ(ierr);
730     ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
731     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
732     if (id == PETSCFE_CLASSID) {
733       ierr = DMPlexInsertBoundaryValues_FEM_Internal(dm, field, label, numids, ids, (PetscErrorCode (*)(PetscInt, const PetscReal[], PetscInt, PetscScalar *, void *)) func, ctx, locX);CHKERRQ(ierr);
734     } else if (id == PETSCFV_CLASSID) {
735       if (!faceGeomFVM) continue;
736       ierr = DMPlexInsertBoundaryValues_FVM_Internal(dm, time, faceGeomFVM, cellGeomFVM, gradFVM,
737                                                      field, label, numids, ids, (PetscErrorCode (*)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*)) func, ctx, locX);CHKERRQ(ierr);
738     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
739   }
740   PetscFunctionReturn(0);
741 }
742 
743 #undef __FUNCT__
744 #define __FUNCT__ "DMPlexComputeL2Diff"
745 /*@C
746   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
747 
748   Input Parameters:
749 + dm    - The DM
750 . funcs - The functions to evaluate for each field component
751 . ctxs  - Optional array of contexts to pass to each function, or NULL.
752 - X     - The coefficient vector u_h
753 
754   Output Parameter:
755 . diff - The diff ||u - u_h||_2
756 
757   Level: developer
758 
759 .seealso: DMPlexProjectFunction(), DMPlexComputeL2FieldDiff(), DMPlexComputeL2GradientDiff()
760 @*/
761 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscErrorCode (**funcs)(PetscInt, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
762 {
763   const PetscInt   debug = 0;
764   PetscSection     section;
765   PetscQuadrature  quad;
766   Vec              localX;
767   PetscScalar     *funcVal, *interpolant;
768   PetscReal       *coords, *v0, *J, *invJ, detJ;
769   PetscReal        localDiff = 0.0;
770   const PetscReal *quadPoints, *quadWeights;
771   PetscInt         dim, numFields, numComponents = 0, numQuadPoints, cStart, cEnd, cEndInterior, c, field, fieldOffset;
772   PetscErrorCode   ierr;
773 
774   PetscFunctionBegin;
775   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
776   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
777   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
778   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
779   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
780   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
781   for (field = 0; field < numFields; ++field) {
782     PetscObject  obj;
783     PetscClassId id;
784     PetscInt     Nc;
785 
786     ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
787     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
788     if (id == PETSCFE_CLASSID) {
789       PetscFE fe = (PetscFE) obj;
790 
791       ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr);
792       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
793     } else if (id == PETSCFV_CLASSID) {
794       PetscFV fv = (PetscFV) obj;
795 
796       ierr = PetscFVGetQuadrature(fv, &quad);CHKERRQ(ierr);
797       ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
798     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
799     numComponents += Nc;
800   }
801   ierr = PetscQuadratureGetData(quad, NULL, &numQuadPoints, &quadPoints, &quadWeights);CHKERRQ(ierr);
802   ierr = DMPlexProjectFunctionLocal(dm, funcs, ctxs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
803   ierr = PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,dim,&coords,dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr);
804   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
805   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
806   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
807   for (c = cStart; c < cEnd; ++c) {
808     PetscScalar *x = NULL;
809     PetscReal    elemDiff = 0.0;
810 
811     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
812     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
813     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
814 
815     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
816       PetscObject  obj;
817       PetscClassId id;
818       void * const ctx = ctxs ? ctxs[field] : NULL;
819       PetscInt     Nb, Nc, q, fc;
820 
821       ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
822       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
823       if (id == PETSCFE_CLASSID)      {ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);ierr = PetscFEGetDimension((PetscFE) obj, &Nb);CHKERRQ(ierr);}
824       else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);Nb = 1;}
825       else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
826       if (debug) {
827         char title[1024];
828         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
829         ierr = DMPrintCellVector(c, title, Nb*Nc, &x[fieldOffset]);CHKERRQ(ierr);
830       }
831       for (q = 0; q < numQuadPoints; ++q) {
832         CoordinatesRefToReal(dim, dim, v0, J, &quadPoints[q*dim], coords);
833         ierr = (*funcs[field])(dim, coords, numFields, funcVal, ctx);CHKERRQ(ierr);
834         if (id == PETSCFE_CLASSID)      {ierr = PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);}
835         else if (id == PETSCFV_CLASSID) {ierr = PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);}
836         else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
837         for (fc = 0; fc < Nc; ++fc) {
838           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*quadWeights[q]*detJ);CHKERRQ(ierr);}
839           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*quadWeights[q]*detJ;
840         }
841       }
842       fieldOffset += Nb*Nc;
843     }
844     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
845     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
846     localDiff += elemDiff;
847   }
848   ierr  = PetscFree6(funcVal,interpolant,coords,v0,J,invJ);CHKERRQ(ierr);
849   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
850   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
851   *diff = PetscSqrtReal(*diff);
852   PetscFunctionReturn(0);
853 }
854 
855 #undef __FUNCT__
856 #define __FUNCT__ "DMPlexComputeL2GradientDiff"
857 /*@C
858   DMPlexComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
859 
860   Input Parameters:
861 + dm    - The DM
862 . funcs - The gradient functions to evaluate for each field component
863 . ctxs  - Optional array of contexts to pass to each function, or NULL.
864 . X     - The coefficient vector u_h
865 - n     - The vector to project along
866 
867   Output Parameter:
868 . diff - The diff ||(grad u - grad u_h) . n||_2
869 
870   Level: developer
871 
872 .seealso: DMPlexProjectFunction(), DMPlexComputeL2Diff()
873 @*/
874 PetscErrorCode DMPlexComputeL2GradientDiff(DM dm, PetscErrorCode (**funcs)(PetscInt, const PetscReal [], const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
875 {
876   const PetscInt  debug = 0;
877   PetscSection    section;
878   PetscQuadrature quad;
879   Vec             localX;
880   PetscScalar    *funcVal, *interpolantVec;
881   PetscReal      *coords, *realSpaceDer, *v0, *J, *invJ, detJ;
882   PetscReal       localDiff = 0.0;
883   PetscInt        dim, numFields, numComponents = 0, cStart, cEnd, cEndInterior, c, field, fieldOffset, comp;
884   PetscErrorCode  ierr;
885 
886   PetscFunctionBegin;
887   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
888   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
889   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
890   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
891   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
892   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
893   for (field = 0; field < numFields; ++field) {
894     PetscFE  fe;
895     PetscInt Nc;
896 
897     ierr = DMGetField(dm, field, (PetscObject *) &fe);CHKERRQ(ierr);
898     ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr);
899     ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
900     numComponents += Nc;
901   }
902   /* ierr = DMPlexProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr); */
903   ierr = PetscMalloc7(numComponents,&funcVal,dim,&coords,dim,&realSpaceDer,dim,&v0,dim*dim,&J,dim*dim,&invJ,dim,&interpolantVec);CHKERRQ(ierr);
904   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
905   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
906   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
907   for (c = cStart; c < cEnd; ++c) {
908     PetscScalar *x = NULL;
909     PetscReal    elemDiff = 0.0;
910 
911     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
912     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
913     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
914 
915     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
916       PetscFE          fe;
917       void * const     ctx = ctxs ? ctxs[field] : NULL;
918       const PetscReal *quadPoints, *quadWeights;
919       PetscReal       *basisDer;
920       PetscInt         numQuadPoints, Nb, Ncomp, q, d, e, fc, f, g;
921 
922       ierr = DMGetField(dm, field, (PetscObject *) &fe);CHKERRQ(ierr);
923       ierr = PetscQuadratureGetData(quad, NULL, &numQuadPoints, &quadPoints, &quadWeights);CHKERRQ(ierr);
924       ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr);
925       ierr = PetscFEGetNumComponents(fe, &Ncomp);CHKERRQ(ierr);
926       ierr = PetscFEGetDefaultTabulation(fe, NULL, &basisDer, NULL);CHKERRQ(ierr);
927       if (debug) {
928         char title[1024];
929         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
930         ierr = DMPrintCellVector(c, title, Nb*Ncomp, &x[fieldOffset]);CHKERRQ(ierr);
931       }
932       for (q = 0; q < numQuadPoints; ++q) {
933         for (d = 0; d < dim; d++) {
934           coords[d] = v0[d];
935           for (e = 0; e < dim; e++) {
936             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
937           }
938         }
939         ierr = (*funcs[field])(dim, coords, n, numFields, funcVal, ctx);CHKERRQ(ierr);
940         for (fc = 0; fc < Ncomp; ++fc) {
941           PetscScalar interpolant = 0.0;
942 
943           for (d = 0; d < dim; ++d) interpolantVec[d] = 0.0;
944           for (f = 0; f < Nb; ++f) {
945             const PetscInt fidx = f*Ncomp+fc;
946 
947             for (d = 0; d < dim; ++d) {
948               realSpaceDer[d] = 0.0;
949               for (g = 0; g < dim; ++g) {
950                 realSpaceDer[d] += invJ[g*dim+d]*basisDer[(q*Nb*Ncomp+fidx)*dim+g];
951               }
952               interpolantVec[d] += x[fieldOffset+fidx]*realSpaceDer[d];
953             }
954           }
955           for (d = 0; d < dim; ++d) interpolant += interpolantVec[d]*n[d];
956           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d fieldDer %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ);CHKERRQ(ierr);}
957           elemDiff += PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ;
958         }
959       }
960       comp        += Ncomp;
961       fieldOffset += Nb*Ncomp;
962     }
963     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
964     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
965     localDiff += elemDiff;
966   }
967   ierr  = PetscFree7(funcVal,coords,realSpaceDer,v0,J,invJ,interpolantVec);CHKERRQ(ierr);
968   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
969   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
970   *diff = PetscSqrtReal(*diff);
971   PetscFunctionReturn(0);
972 }
973 
974 #undef __FUNCT__
975 #define __FUNCT__ "DMPlexComputeL2FieldDiff"
976 /*@C
977   DMPlexComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
978 
979   Input Parameters:
980 + dm    - The DM
981 . funcs - The functions to evaluate for each field component
982 . ctxs  - Optional array of contexts to pass to each function, or NULL.
983 - X     - The coefficient vector u_h
984 
985   Output Parameter:
986 . diff - The array of differences, ||u^f - u^f_h||_2
987 
988   Level: developer
989 
990 .seealso: DMPlexProjectFunction(), DMPlexComputeL2Diff(), DMPlexComputeL2GradientDiff()
991 @*/
992 PetscErrorCode DMPlexComputeL2FieldDiff(DM dm, PetscErrorCode (**funcs)(PetscInt, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
993 {
994   const PetscInt   debug = 0;
995   PetscSection     section;
996   PetscQuadrature  quad;
997   Vec              localX;
998   PetscScalar     *funcVal, *interpolant;
999   PetscReal       *coords, *v0, *J, *invJ, detJ;
1000   PetscReal       *localDiff;
1001   const PetscReal *quadPoints, *quadWeights;
1002   PetscInt         dim, numFields, numComponents = 0, numQuadPoints, cStart, cEnd, cEndInterior, c, field, fieldOffset;
1003   PetscErrorCode   ierr;
1004 
1005   PetscFunctionBegin;
1006   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1007   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1008   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
1009   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
1010   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
1011   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
1012   for (field = 0; field < numFields; ++field) {
1013     PetscObject  obj;
1014     PetscClassId id;
1015     PetscInt     Nc;
1016 
1017     ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
1018     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1019     if (id == PETSCFE_CLASSID) {
1020       PetscFE fe = (PetscFE) obj;
1021 
1022       ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr);
1023       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
1024     } else if (id == PETSCFV_CLASSID) {
1025       PetscFV fv = (PetscFV) obj;
1026 
1027       ierr = PetscFVGetQuadrature(fv, &quad);CHKERRQ(ierr);
1028       ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
1029     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1030     numComponents += Nc;
1031   }
1032   ierr = PetscQuadratureGetData(quad, NULL, &numQuadPoints, &quadPoints, &quadWeights);CHKERRQ(ierr);
1033   ierr = DMPlexProjectFunctionLocal(dm, funcs, ctxs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
1034   ierr = PetscCalloc7(numFields,&localDiff,numComponents,&funcVal,numComponents,&interpolant,dim,&coords,dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr);
1035   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1036   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
1037   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1038   for (c = cStart; c < cEnd; ++c) {
1039     PetscScalar *x = NULL;
1040 
1041     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
1042     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
1043     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
1044 
1045     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1046       PetscObject  obj;
1047       PetscClassId id;
1048       void * const ctx = ctxs ? ctxs[field] : NULL;
1049       PetscInt     Nb, Nc, q, fc;
1050 
1051       PetscReal       elemDiff = 0.0;
1052 
1053       ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
1054       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1055       if (id == PETSCFE_CLASSID)      {ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);ierr = PetscFEGetDimension((PetscFE) obj, &Nb);CHKERRQ(ierr);}
1056       else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);Nb = 1;}
1057       else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1058       if (debug) {
1059         char title[1024];
1060         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
1061         ierr = DMPrintCellVector(c, title, Nb*Nc, &x[fieldOffset]);CHKERRQ(ierr);
1062       }
1063       for (q = 0; q < numQuadPoints; ++q) {
1064         CoordinatesRefToReal(dim, dim, v0, J, &quadPoints[q*dim], coords);
1065         ierr = (*funcs[field])(dim, coords, numFields, funcVal, ctx);CHKERRQ(ierr);
1066         if (id == PETSCFE_CLASSID)      {ierr = PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);}
1067         else if (id == PETSCFV_CLASSID) {ierr = PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);}
1068         else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1069         for (fc = 0; fc < Nc; ++fc) {
1070           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*quadWeights[q]*detJ);CHKERRQ(ierr);}
1071           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*quadWeights[q]*detJ;
1072         }
1073       }
1074       fieldOffset += Nb*Nc;
1075       localDiff[field] += elemDiff;
1076     }
1077     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
1078   }
1079   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
1080   ierr = MPI_Allreduce(localDiff, diff, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1081   for (field = 0; field < numFields; ++field) diff[field] = PetscSqrtReal(diff[field]);
1082   ierr = PetscFree7(localDiff,funcVal,interpolant,coords,v0,J,invJ);CHKERRQ(ierr);
1083   PetscFunctionReturn(0);
1084 }
1085 
1086 #undef __FUNCT__
1087 #define __FUNCT__ "DMPlexComputeIntegralFEM"
1088 /*@
1089   DMPlexComputeIntegralFEM - Form the local integral F from the local input X using pointwise functions specified by the user
1090 
1091   Input Parameters:
1092 + dm - The mesh
1093 . X  - Local input vector
1094 - user - The user context
1095 
1096   Output Parameter:
1097 . integral - Local integral for each field
1098 
1099   Level: developer
1100 
1101 .seealso: DMPlexComputeResidualFEM()
1102 @*/
1103 PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscReal *integral, void *user)
1104 {
1105   DM_Plex          *mesh  = (DM_Plex *) dm->data;
1106   DM                dmAux;
1107   Vec               localX, A;
1108   PetscDS           prob, probAux = NULL;
1109   PetscSection      section, sectionAux;
1110   PetscFECellGeom  *cgeom;
1111   PetscScalar      *u, *a = NULL;
1112   PetscReal        *lintegral, *vol;
1113   PetscInt          dim, Nf, f, numCells, cStart, cEnd, cEndInterior, c;
1114   PetscInt          totDim, totDimAux;
1115   PetscErrorCode    ierr;
1116 
1117   PetscFunctionBegin;
1118   ierr = PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr);
1119   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
1120   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
1121   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
1122   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1123   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1124   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
1125   ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr);
1126   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
1127   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1128   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
1129   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1130   numCells = cEnd - cStart;
1131   ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr);
1132   ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr);
1133   if (dmAux) {
1134     ierr = DMGetDefaultSection(dmAux, &sectionAux);CHKERRQ(ierr);
1135     ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr);
1136     ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr);
1137   }
1138   ierr = DMPlexInsertBoundaryValues(dm, localX, 0.0, NULL, NULL, NULL);CHKERRQ(ierr);
1139   ierr = PetscMalloc4(Nf,&lintegral,numCells*totDim,&u,numCells,&cgeom,numCells,&vol);CHKERRQ(ierr);
1140   if (dmAux) {ierr = PetscMalloc1(numCells*totDimAux, &a);CHKERRQ(ierr);}
1141   for (f = 0; f < Nf; ++f) {lintegral[f] = 0.0;}
1142   for (c = cStart; c < cEnd; ++c) {
1143     PetscScalar *x = NULL;
1144     PetscInt     i;
1145 
1146     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, cgeom[c].v0, cgeom[c].J, cgeom[c].invJ, &cgeom[c].detJ);CHKERRQ(ierr);
1147     ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol[c], NULL, NULL);CHKERRQ(ierr);
1148     if (cgeom[c].detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", cgeom[c].detJ, c);
1149     ierr = DMPlexVecGetClosure(dm, section, localX, c, NULL, &x);CHKERRQ(ierr);
1150     for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
1151     ierr = DMPlexVecRestoreClosure(dm, section, localX, c, NULL, &x);CHKERRQ(ierr);
1152     if (dmAux) {
1153       ierr = DMPlexVecGetClosure(dmAux, sectionAux, A, c, NULL, &x);CHKERRQ(ierr);
1154       for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
1155       ierr = DMPlexVecRestoreClosure(dmAux, sectionAux, A, c, NULL, &x);CHKERRQ(ierr);
1156     }
1157   }
1158   for (f = 0; f < Nf; ++f) {
1159     PetscObject  obj;
1160     PetscClassId id;
1161     PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
1162 
1163     ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
1164     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1165     if (id == PETSCFE_CLASSID) {
1166       PetscFE         fe = (PetscFE) obj;
1167       PetscQuadrature q;
1168       PetscInt        Nq, Nb;
1169 
1170       ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr);
1171       ierr = PetscFEGetQuadrature(fe, &q);CHKERRQ(ierr);
1172       ierr = PetscQuadratureGetData(q, NULL, &Nq, NULL, NULL);CHKERRQ(ierr);
1173       ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr);
1174       blockSize = Nb*Nq;
1175       batchSize = numBlocks * blockSize;
1176       ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr);
1177       numChunks = numCells / (numBatches*batchSize);
1178       Ne        = numChunks*numBatches*batchSize;
1179       Nr        = numCells % (numBatches*batchSize);
1180       offset    = numCells - Nr;
1181       ierr = PetscFEIntegrate(fe, prob, f, Ne, cgeom, u, probAux, a, lintegral);CHKERRQ(ierr);
1182       ierr = PetscFEIntegrate(fe, prob, f, Nr, &cgeom[offset], &u[offset*totDim], probAux, &a[offset*totDimAux], lintegral);CHKERRQ(ierr);
1183     } else if (id == PETSCFV_CLASSID) {
1184       /* PetscFV  fv = (PetscFV) obj; */
1185       PetscInt       foff;
1186       PetscPointFunc obj_func;
1187       PetscScalar    lint;
1188 
1189       ierr = PetscDSGetObjective(prob, f, &obj_func);CHKERRQ(ierr);
1190       ierr = PetscDSGetFieldOffset(prob, f, &foff);CHKERRQ(ierr);
1191       if (obj_func) {
1192         for (c = 0; c < numCells; ++c) {
1193           /* TODO: Need full pointwise interpolation and get centroid for x argument */
1194           obj_func(dim, Nf, 0, NULL, NULL, &u[totDim*c+foff], NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0.0, NULL, &lint);
1195           lintegral[f] = PetscRealPart(lint)*vol[c];
1196         }
1197       }
1198     } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
1199   }
1200   if (dmAux) {ierr = PetscFree(a);CHKERRQ(ierr);}
1201   if (mesh->printFEM) {
1202     ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "Local integral:");CHKERRQ(ierr);
1203     for (f = 0; f < Nf; ++f) {ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), " %g", lintegral[f]);CHKERRQ(ierr);}
1204     ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "\n");CHKERRQ(ierr);
1205   }
1206   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
1207   ierr = MPI_Allreduce(lintegral, integral, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
1208   ierr = PetscFree4(lintegral,u,cgeom,vol);CHKERRQ(ierr);
1209   ierr = PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr);
1210   PetscFunctionReturn(0);
1211 }
1212 
1213 #undef __FUNCT__
1214 #define __FUNCT__ "DMPlexComputeInterpolatorFEM"
1215 /*@
1216   DMPlexComputeInterpolatorFEM - Form the local portion of the interpolation matrix I from the coarse DM to the uniformly refined DM.
1217 
1218   Input Parameters:
1219 + dmf  - The fine mesh
1220 . dmc  - The coarse mesh
1221 - user - The user context
1222 
1223   Output Parameter:
1224 . In  - The interpolation matrix
1225 
1226   Note:
1227   The first member of the user context must be an FEMContext.
1228 
1229   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
1230   like a GPU, or vectorize on a multicore machine.
1231 
1232   Level: developer
1233 
1234 .seealso: DMPlexComputeJacobianFEM()
1235 @*/
1236 PetscErrorCode DMPlexComputeInterpolatorFEM(DM dmc, DM dmf, Mat In, void *user)
1237 {
1238   DM_Plex          *mesh  = (DM_Plex *) dmc->data;
1239   const char       *name  = "Interpolator";
1240   PetscDS           prob;
1241   PetscFE          *feRef;
1242   PetscFV          *fvRef;
1243   PetscSection      fsection, fglobalSection;
1244   PetscSection      csection, cglobalSection;
1245   PetscScalar      *elemMat;
1246   PetscInt          dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, cEndInterior, c;
1247   PetscInt          cTotDim, rTotDim = 0;
1248   PetscErrorCode    ierr;
1249 
1250   PetscFunctionBegin;
1251   ierr = PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr);
1252   ierr = DMGetDimension(dmf, &dim);CHKERRQ(ierr);
1253   ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);
1254   ierr = DMGetDefaultGlobalSection(dmf, &fglobalSection);CHKERRQ(ierr);
1255   ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);
1256   ierr = DMGetDefaultGlobalSection(dmc, &cglobalSection);CHKERRQ(ierr);
1257   ierr = PetscSectionGetNumFields(fsection, &Nf);CHKERRQ(ierr);
1258   ierr = DMPlexGetHeightStratum(dmc, 0, &cStart, &cEnd);CHKERRQ(ierr);
1259   ierr = DMPlexGetHybridBounds(dmc, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
1260   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1261   ierr = DMGetDS(dmf, &prob);CHKERRQ(ierr);
1262   ierr = PetscCalloc2(Nf,&feRef,Nf,&fvRef);CHKERRQ(ierr);
1263   for (f = 0; f < Nf; ++f) {
1264     PetscObject  obj;
1265     PetscClassId id;
1266     PetscInt     rNb = 0, Nc = 0;
1267 
1268     ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
1269     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1270     if (id == PETSCFE_CLASSID) {
1271       PetscFE fe = (PetscFE) obj;
1272 
1273       ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr);
1274       ierr = PetscFEGetDimension(feRef[f], &rNb);CHKERRQ(ierr);
1275       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
1276     } else if (id == PETSCFV_CLASSID) {
1277       PetscFV        fv = (PetscFV) obj;
1278       PetscDualSpace Q;
1279 
1280       ierr = PetscFVRefine(fv, &fvRef[f]);CHKERRQ(ierr);
1281       ierr = PetscFVGetDualSpace(fvRef[f], &Q);CHKERRQ(ierr);
1282       ierr = PetscDualSpaceGetDimension(Q, &rNb);CHKERRQ(ierr);
1283       ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
1284     }
1285     rTotDim += rNb*Nc;
1286   }
1287   ierr = PetscDSGetTotalDimension(prob, &cTotDim);CHKERRQ(ierr);
1288   ierr = PetscMalloc1(rTotDim*cTotDim,&elemMat);CHKERRQ(ierr);
1289   ierr = PetscMemzero(elemMat, rTotDim*cTotDim * sizeof(PetscScalar));CHKERRQ(ierr);
1290   for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
1291     PetscDualSpace   Qref;
1292     PetscQuadrature  f;
1293     const PetscReal *qpoints, *qweights;
1294     PetscReal       *points;
1295     PetscInt         npoints = 0, Nc, Np, fpdim, i, k, p, d;
1296 
1297     /* Compose points from all dual basis functionals */
1298     if (feRef[fieldI]) {
1299       ierr = PetscFEGetDualSpace(feRef[fieldI], &Qref);CHKERRQ(ierr);
1300       ierr = PetscFEGetNumComponents(feRef[fieldI], &Nc);CHKERRQ(ierr);
1301     } else {
1302       ierr = PetscFVGetDualSpace(fvRef[fieldI], &Qref);CHKERRQ(ierr);
1303       ierr = PetscFVGetNumComponents(fvRef[fieldI], &Nc);CHKERRQ(ierr);
1304     }
1305     ierr = PetscDualSpaceGetDimension(Qref, &fpdim);CHKERRQ(ierr);
1306     for (i = 0; i < fpdim; ++i) {
1307       ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr);
1308       ierr = PetscQuadratureGetData(f, NULL, &Np, NULL, NULL);CHKERRQ(ierr);
1309       npoints += Np;
1310     }
1311     ierr = PetscMalloc1(npoints*dim,&points);CHKERRQ(ierr);
1312     for (i = 0, k = 0; i < fpdim; ++i) {
1313       ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr);
1314       ierr = PetscQuadratureGetData(f, NULL, &Np, &qpoints, NULL);CHKERRQ(ierr);
1315       for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d];
1316     }
1317 
1318     for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
1319       PetscObject  obj;
1320       PetscClassId id;
1321       PetscReal   *B;
1322       PetscInt     NcJ = 0, cpdim = 0, j;
1323 
1324       ierr = PetscDSGetDiscretization(prob, fieldJ, &obj);CHKERRQ(ierr);
1325       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1326       if (id == PETSCFE_CLASSID) {
1327         PetscFE fe = (PetscFE) obj;
1328 
1329         /* Evaluate basis at points */
1330         ierr = PetscFEGetNumComponents(fe, &NcJ);CHKERRQ(ierr);
1331         ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr);
1332         /* For now, fields only interpolate themselves */
1333         if (fieldI == fieldJ) {
1334           if (Nc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %d does not match coarse field %d", Nc, NcJ);
1335           ierr = PetscFEGetTabulation(fe, npoints, points, &B, NULL, NULL);CHKERRQ(ierr);
1336           for (i = 0, k = 0; i < fpdim; ++i) {
1337             ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr);
1338             ierr = PetscQuadratureGetData(f, NULL, &Np, NULL, &qweights);CHKERRQ(ierr);
1339             for (p = 0; p < Np; ++p, ++k) {
1340               for (j = 0; j < cpdim; ++j) {
1341                 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i*Nc + c)*cTotDim + offsetJ + j*NcJ + c] += B[k*cpdim*NcJ+j*Nc+c]*qweights[p];
1342               }
1343             }
1344           }
1345           ierr = PetscFERestoreTabulation(fe, npoints, points, &B, NULL, NULL);CHKERRQ(ierr);CHKERRQ(ierr);
1346         }
1347       } else if (id == PETSCFV_CLASSID) {
1348         PetscFV        fv = (PetscFV) obj;
1349 
1350         /* Evaluate constant function at points */
1351         ierr = PetscFVGetNumComponents(fv, &NcJ);CHKERRQ(ierr);
1352         cpdim = 1;
1353         /* For now, fields only interpolate themselves */
1354         if (fieldI == fieldJ) {
1355           if (Nc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %d does not match coarse field %d", Nc, NcJ);
1356           for (i = 0, k = 0; i < fpdim; ++i) {
1357             ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr);
1358             ierr = PetscQuadratureGetData(f, NULL, &Np, NULL, &qweights);CHKERRQ(ierr);
1359             for (p = 0; p < Np; ++p, ++k) {
1360               for (j = 0; j < cpdim; ++j) {
1361                 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i*Nc + c)*cTotDim + offsetJ + j*NcJ + c] += 1.0*qweights[p];
1362               }
1363             }
1364           }
1365         }
1366       }
1367       offsetJ += cpdim*NcJ;
1368     }
1369     offsetI += fpdim*Nc;
1370     ierr = PetscFree(points);CHKERRQ(ierr);
1371   }
1372   if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);CHKERRQ(ierr);}
1373   /* Preallocate matrix */
1374   {
1375     PetscHashJK ht;
1376     PetscLayout rLayout;
1377     PetscInt   *dnz, *onz, *cellCIndices, *cellFIndices;
1378     PetscInt    locRows, rStart, rEnd, cell, r;
1379 
1380     ierr = MatGetLocalSize(In, &locRows, NULL);CHKERRQ(ierr);
1381     ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout);CHKERRQ(ierr);
1382     ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
1383     ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
1384     ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
1385     ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
1386     ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
1387     ierr = PetscCalloc4(locRows,&dnz,locRows,&onz,cTotDim,&cellCIndices,rTotDim,&cellFIndices);CHKERRQ(ierr);
1388     ierr = PetscHashJKCreate(&ht);CHKERRQ(ierr);
1389     for (cell = cStart; cell < cEnd; ++cell) {
1390       ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);CHKERRQ(ierr);
1391       for (r = 0; r < rTotDim; ++r) {
1392         PetscHashJKKey  key;
1393         PetscHashJKIter missing, iter;
1394 
1395         key.j = cellFIndices[r];
1396         if (key.j < 0) continue;
1397         for (c = 0; c < cTotDim; ++c) {
1398           key.k = cellCIndices[c];
1399           if (key.k < 0) continue;
1400           ierr = PetscHashJKPut(ht, key, &missing, &iter);CHKERRQ(ierr);
1401           if (missing) {
1402             ierr = PetscHashJKSet(ht, iter, 1);CHKERRQ(ierr);
1403             if ((key.k >= rStart) && (key.k < rEnd)) ++dnz[key.j-rStart];
1404             else                                     ++onz[key.j-rStart];
1405           }
1406         }
1407       }
1408     }
1409     ierr = PetscHashJKDestroy(&ht);CHKERRQ(ierr);
1410     ierr = MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL);CHKERRQ(ierr);
1411     ierr = MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
1412     ierr = PetscFree4(dnz,onz,cellCIndices,cellFIndices);CHKERRQ(ierr);
1413   }
1414   /* Fill matrix */
1415   ierr = MatZeroEntries(In);CHKERRQ(ierr);
1416   for (c = cStart; c < cEnd; ++c) {
1417     ierr = DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);CHKERRQ(ierr);
1418   }
1419   for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);}
1420   ierr = PetscFree2(feRef,fvRef);CHKERRQ(ierr);
1421   ierr = PetscFree(elemMat);CHKERRQ(ierr);
1422   ierr = MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1423   ierr = MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1424   if (mesh->printFEM) {
1425     ierr = PetscPrintf(PETSC_COMM_WORLD, "%s:\n", name);CHKERRQ(ierr);
1426     ierr = MatChop(In, 1.0e-10);CHKERRQ(ierr);
1427     ierr = MatView(In, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
1428   }
1429   ierr = PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr);
1430   PetscFunctionReturn(0);
1431 }
1432 
1433 #undef __FUNCT__
1434 #define __FUNCT__ "DMPlexComputeInjectorFEM"
1435 PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user)
1436 {
1437   PetscDS        prob;
1438   PetscFE       *feRef;
1439   PetscFV       *fvRef;
1440   Vec            fv, cv;
1441   IS             fis, cis;
1442   PetscSection   fsection, fglobalSection, csection, cglobalSection;
1443   PetscInt      *cmap, *cellCIndices, *cellFIndices, *cindices, *findices;
1444   PetscInt       cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, cEndInterior, c, dim, d, startC, offsetC, offsetF, m;
1445   PetscErrorCode ierr;
1446 
1447   PetscFunctionBegin;
1448   ierr = PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr);
1449   ierr = DMGetDimension(dmf, &dim);CHKERRQ(ierr);
1450   ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);
1451   ierr = DMGetDefaultGlobalSection(dmf, &fglobalSection);CHKERRQ(ierr);
1452   ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);
1453   ierr = DMGetDefaultGlobalSection(dmc, &cglobalSection);CHKERRQ(ierr);
1454   ierr = PetscSectionGetNumFields(fsection, &Nf);CHKERRQ(ierr);
1455   ierr = DMPlexGetHeightStratum(dmc, 0, &cStart, &cEnd);CHKERRQ(ierr);
1456   ierr = DMPlexGetHybridBounds(dmc, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
1457   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1458   ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr);
1459   ierr = PetscCalloc2(Nf,&feRef,Nf,&fvRef);CHKERRQ(ierr);
1460   for (f = 0; f < Nf; ++f) {
1461     PetscObject  obj;
1462     PetscClassId id;
1463     PetscInt     fNb = 0, Nc = 0;
1464 
1465     ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
1466     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1467     if (id == PETSCFE_CLASSID) {
1468       PetscFE fe = (PetscFE) obj;
1469 
1470       ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr);
1471       ierr = PetscFEGetDimension(feRef[f], &fNb);CHKERRQ(ierr);
1472       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
1473     } else if (id == PETSCFV_CLASSID) {
1474       PetscFV        fv = (PetscFV) obj;
1475       PetscDualSpace Q;
1476 
1477       ierr = PetscFVRefine(fv, &fvRef[f]);CHKERRQ(ierr);
1478       ierr = PetscFVGetDualSpace(fvRef[f], &Q);CHKERRQ(ierr);
1479       ierr = PetscDualSpaceGetDimension(Q, &fNb);CHKERRQ(ierr);
1480       ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
1481     }
1482     fTotDim += fNb*Nc;
1483   }
1484   ierr = PetscDSGetTotalDimension(prob, &cTotDim);CHKERRQ(ierr);
1485   ierr = PetscMalloc1(cTotDim,&cmap);CHKERRQ(ierr);
1486   for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) {
1487     PetscFE        feC;
1488     PetscFV        fvC;
1489     PetscDualSpace QF, QC;
1490     PetscInt       NcF, NcC, fpdim, cpdim;
1491 
1492     if (feRef[field]) {
1493       ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &feC);CHKERRQ(ierr);
1494       ierr = PetscFEGetNumComponents(feC, &NcC);CHKERRQ(ierr);
1495       ierr = PetscFEGetNumComponents(feRef[field], &NcF);CHKERRQ(ierr);
1496       ierr = PetscFEGetDualSpace(feRef[field], &QF);CHKERRQ(ierr);
1497       ierr = PetscDualSpaceGetDimension(QF, &fpdim);CHKERRQ(ierr);
1498       ierr = PetscFEGetDualSpace(feC, &QC);CHKERRQ(ierr);
1499       ierr = PetscDualSpaceGetDimension(QC, &cpdim);CHKERRQ(ierr);
1500     } else {
1501       ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &fvC);CHKERRQ(ierr);
1502       ierr = PetscFVGetNumComponents(fvC, &NcC);CHKERRQ(ierr);
1503       ierr = PetscFVGetNumComponents(fvRef[field], &NcF);CHKERRQ(ierr);
1504       ierr = PetscFVGetDualSpace(fvRef[field], &QF);CHKERRQ(ierr);
1505       ierr = PetscDualSpaceGetDimension(QF, &fpdim);CHKERRQ(ierr);
1506       ierr = PetscFVGetDualSpace(fvC, &QC);CHKERRQ(ierr);
1507       ierr = PetscDualSpaceGetDimension(QC, &cpdim);CHKERRQ(ierr);
1508     }
1509     if (NcF != NcC) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %d does not match coarse field %d", NcF, NcC);
1510     for (c = 0; c < cpdim; ++c) {
1511       PetscQuadrature  cfunc;
1512       const PetscReal *cqpoints;
1513       PetscInt         NpC;
1514       PetscBool        found = PETSC_FALSE;
1515 
1516       ierr = PetscDualSpaceGetFunctional(QC, c, &cfunc);CHKERRQ(ierr);
1517       ierr = PetscQuadratureGetData(cfunc, NULL, &NpC, &cqpoints, NULL);CHKERRQ(ierr);
1518       if (NpC != 1 && feRef[field]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments");
1519       for (f = 0; f < fpdim; ++f) {
1520         PetscQuadrature  ffunc;
1521         const PetscReal *fqpoints;
1522         PetscReal        sum = 0.0;
1523         PetscInt         NpF, comp;
1524 
1525         ierr = PetscDualSpaceGetFunctional(QF, f, &ffunc);CHKERRQ(ierr);
1526         ierr = PetscQuadratureGetData(ffunc, NULL, &NpF, &fqpoints, NULL);CHKERRQ(ierr);
1527         if (NpC != NpF) continue;
1528         for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
1529         if (sum > 1.0e-9) continue;
1530         for (comp = 0; comp < NcC; ++comp) {
1531           cmap[(offsetC+c)*NcC+comp] = (offsetF+f)*NcF+comp;
1532         }
1533         found = PETSC_TRUE;
1534         break;
1535       }
1536       if (!found) {
1537         /* TODO We really want the average here, but some asshole put VecScatter in the interface */
1538         if (fvRef[field]) {
1539           PetscInt comp;
1540           for (comp = 0; comp < NcC; ++comp) {
1541             cmap[(offsetC+c)*NcC+comp] = (offsetF+0)*NcF+comp;
1542           }
1543         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
1544       }
1545     }
1546     offsetC += cpdim*NcC;
1547     offsetF += fpdim*NcF;
1548   }
1549   for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);ierr = PetscFVDestroy(&fvRef[f]);CHKERRQ(ierr);}
1550   ierr = PetscFree2(feRef,fvRef);CHKERRQ(ierr);
1551 
1552   ierr = DMGetGlobalVector(dmf, &fv);CHKERRQ(ierr);
1553   ierr = DMGetGlobalVector(dmc, &cv);CHKERRQ(ierr);
1554   ierr = VecGetOwnershipRange(cv, &startC, NULL);CHKERRQ(ierr);
1555   ierr = PetscSectionGetConstrainedStorageSize(cglobalSection, &m);CHKERRQ(ierr);
1556   ierr = PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices);CHKERRQ(ierr);
1557   ierr = PetscMalloc1(m,&cindices);CHKERRQ(ierr);
1558   ierr = PetscMalloc1(m,&findices);CHKERRQ(ierr);
1559   for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1;
1560   for (c = cStart; c < cEnd; ++c) {
1561     ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);CHKERRQ(ierr);
1562     for (d = 0; d < cTotDim; ++d) {
1563       if (cellCIndices[d] < 0) continue;
1564       if ((findices[cellCIndices[d]-startC] >= 0) && (findices[cellCIndices[d]-startC] != cellFIndices[cmap[d]])) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Coarse dof %d maps to both %d and %d", cindices[cellCIndices[d]-startC], findices[cellCIndices[d]-startC], cellFIndices[cmap[d]]);
1565       cindices[cellCIndices[d]-startC] = cellCIndices[d];
1566       findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]];
1567     }
1568   }
1569   ierr = PetscFree(cmap);CHKERRQ(ierr);
1570   ierr = PetscFree2(cellCIndices,cellFIndices);CHKERRQ(ierr);
1571 
1572   ierr = ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr);
1573   ierr = ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr);
1574   ierr = VecScatterCreate(cv, cis, fv, fis, sc);CHKERRQ(ierr);
1575   ierr = ISDestroy(&cis);CHKERRQ(ierr);
1576   ierr = ISDestroy(&fis);CHKERRQ(ierr);
1577   ierr = DMRestoreGlobalVector(dmf, &fv);CHKERRQ(ierr);
1578   ierr = DMRestoreGlobalVector(dmc, &cv);CHKERRQ(ierr);
1579   ierr = PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr);
1580   PetscFunctionReturn(0);
1581 }
1582