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