xref: /petsc/src/dm/impls/plex/plexfem.c (revision 00d931fe9835bef04c3bcd2a9a1bf118d64cc4c2)
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, PetscReal t, 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, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody;
158 
159     ctx[0] = dimEmbed;
160     ctx[1] = d;
161     ierr = DMPlexProjectFunction(dm, 0.0, &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, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscErrorCode (**funcs)(PetscInt, PetscReal, 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, time, &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, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, 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) {
406           ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr);
407           ierr = PetscFVGetDualSpace(fv, &cellsp[f]);CHKERRQ(ierr);
408           ierr = PetscObjectReference((PetscObject) cellsp[f]);CHKERRQ(ierr);
409           sp[f] = cellsp[f];
410         }
411         else {
412           sp[f] = NULL;
413           continue; /* FV doesn't have fields that can be evaluated at faces, corners, etc. */
414         }
415       } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
416       ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr);
417       totDim += spDim*numComp[f];
418     }
419     ierr = DMPlexVecGetClosure(dm, section, localX, pStart, &numValues, NULL);CHKERRQ(ierr);
420     if (numValues != totDim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The section point closure size %d != dual space dimension %d", numValues, totDim);
421     if (!totDim) continue;
422     ierr = DMGetWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr);
423     for (p = pStart; p < pEnd; ++p) {
424       PetscFECellGeom geom;
425 
426       ierr          = DMPlexComputeCellGeometryFEM(dm, p, NULL, geom.v0, geom.J, NULL, &geom.detJ);CHKERRQ(ierr);
427       geom.dim      = dim - h;
428       geom.dimEmbed = dimEmbed;
429       for (f = 0, v = 0; f < Nf; ++f) {
430         void * const ctx = ctxs ? ctxs[f] : NULL;
431 
432         if (!sp[f]) continue;
433         ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr);
434         for (d = 0; d < spDim; ++d) {
435           if (funcs[f]) {
436             ierr = PetscDualSpaceApply(sp[f], d, time, &geom, numComp[f], funcs[f], ctx, &values[v]);CHKERRQ(ierr);
437           } else {
438             for (comp = 0; comp < numComp[f]; ++comp) values[v+comp] = 0.0;
439           }
440           v += numComp[f];
441         }
442       }
443       ierr = DMPlexVecSetClosure(dm, section, localX, p, values, mode);CHKERRQ(ierr);
444     }
445     ierr = DMRestoreWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr);
446     if (h || !maxHeight) {
447       for (f = 0; f < Nf; f++) {ierr = PetscDualSpaceDestroy(&sp[f]);CHKERRQ(ierr);}
448     }
449   }
450   ierr = PetscFree2(sp, numComp);CHKERRQ(ierr);
451   if (maxHeight > 0) {
452     for (f = 0; f < Nf; f++) {ierr = PetscDualSpaceDestroy(&cellsp[f]);CHKERRQ(ierr);}
453     ierr = PetscFree(cellsp);CHKERRQ(ierr);
454   }
455   PetscFunctionReturn(0);
456 }
457 
458 #undef __FUNCT__
459 #define __FUNCT__ "DMPlexProjectFunction"
460 /*@C
461   DMPlexProjectFunction - This projects the given function into the function space provided.
462 
463   Input Parameters:
464 + dm      - The DM
465 . funcs   - The coordinate functions to evaluate, one per field
466 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
467 - mode    - The insertion mode for values
468 
469   Output Parameter:
470 . X - vector
471 
472    Calling sequence of func:
473 $    func(PetscInt dim, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
474 
475 +  dim - The spatial dimension
476 .  x   - The coordinates
477 .  Nf  - The number of fields
478 .  u   - The output field values
479 -  ctx - optional user-defined function context
480 
481   Level: developer
482 
483 .seealso: DMPlexComputeL2Diff()
484 @*/
485 PetscErrorCode DMPlexProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
486 {
487   Vec            localX;
488   PetscErrorCode ierr;
489 
490   PetscFunctionBegin;
491   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
492   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
493   ierr = DMPlexProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
494   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
495   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
496   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
497   PetscFunctionReturn(0);
498 }
499 
500 #undef __FUNCT__
501 #define __FUNCT__ "DMPlexProjectFieldLocal"
502 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)
503 {
504   DM                dmAux;
505   PetscDS           prob, probAux = NULL;
506   Vec               A;
507   PetscSection      section, sectionAux = NULL;
508   PetscDualSpace   *sp;
509   PetscInt         *Ncf;
510   PetscScalar      *values, *u, *u_x, *a, *a_x;
511   PetscReal        *x, *v0, *J, *invJ, detJ;
512   PetscInt          Nf, dim, spDim, totDim, numValues, cStart, cEnd, cEndInterior, c, f, d, v, comp, maxHeight;
513   PetscErrorCode    ierr;
514 
515   PetscFunctionBegin;
516   ierr = DMPlexGetMaxProjectionHeight(dm,&maxHeight);CHKERRQ(ierr);
517   if (maxHeight > 0) {SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Field projection for height > 0 not supported yet");}
518   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
519   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
520   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
521   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
522   ierr = PetscMalloc2(Nf, &sp, Nf, &Ncf);CHKERRQ(ierr);
523   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
524   ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr);
525   ierr = PetscDSGetEvaluationArrays(prob, &u, NULL, &u_x);CHKERRQ(ierr);
526   ierr = PetscDSGetRefCoordArrays(prob, &x, NULL);CHKERRQ(ierr);
527   ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr);
528   ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr);
529   if (dmAux) {
530     ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr);
531     ierr = DMGetDefaultSection(dmAux, &sectionAux);CHKERRQ(ierr);
532     ierr = PetscDSGetEvaluationArrays(probAux, &a, NULL, &a_x);CHKERRQ(ierr);
533   }
534   ierr = DMPlexInsertBoundaryValues(dm, localU, 0.0, NULL, NULL, NULL);CHKERRQ(ierr);
535   ierr = DMPlexVecGetClosure(dm, section, localX, cStart, &numValues, NULL);CHKERRQ(ierr);
536   if (numValues != totDim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The section cell closure size %d != dual space dimension %d", numValues, totDim);
537   ierr = DMGetWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr);
538   ierr = PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr);
539   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
540   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
541   for (c = cStart; c < cEnd; ++c) {
542     PetscScalar *coefficients = NULL, *coefficientsAux = NULL;
543 
544     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
545     ierr = DMPlexVecGetClosure(dm, section, localU, c, NULL, &coefficients);CHKERRQ(ierr);
546     if (dmAux) {ierr = DMPlexVecGetClosure(dmAux, sectionAux, A, c, NULL, &coefficientsAux);CHKERRQ(ierr);}
547     for (f = 0, v = 0; f < Nf; ++f) {
548       PetscObject  obj;
549       PetscClassId id;
550 
551       ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
552       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
553       if (id == PETSCFE_CLASSID) {
554         PetscFE fe = (PetscFE) obj;
555 
556         ierr = PetscFEGetDualSpace(fe, &sp[f]);CHKERRQ(ierr);
557         ierr  = PetscObjectReference((PetscObject) sp[f]);CHKERRQ(ierr);
558         ierr = PetscFEGetNumComponents(fe, &Ncf[f]);CHKERRQ(ierr);
559       } else if (id == PETSCFV_CLASSID) {
560         PetscFV fv = (PetscFV) obj;
561 
562         ierr = PetscFVGetNumComponents(fv, &Ncf[f]);CHKERRQ(ierr);
563         ierr = PetscFVGetDualSpace(fv, &sp[f]);CHKERRQ(ierr);
564         ierr = PetscObjectReference((PetscObject) sp[f]);CHKERRQ(ierr);
565       }
566       ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr);
567       for (d = 0; d < spDim; ++d) {
568         PetscQuadrature  quad;
569         const PetscReal *points, *weights;
570         PetscInt         numPoints, q;
571 
572         if (funcs[f]) {
573           ierr = PetscDualSpaceGetFunctional(sp[f], d, &quad);CHKERRQ(ierr);
574           ierr = PetscQuadratureGetData(quad, NULL, &numPoints, &points, &weights);CHKERRQ(ierr);
575           for (q = 0; q < numPoints; ++q) {
576             CoordinatesRefToReal(dim, dim, v0, J, &points[q*dim], x);
577             ierr = EvaluateFieldJets(prob,    PETSC_FALSE, q, invJ, coefficients,    NULL, u, u_x, NULL);CHKERRQ(ierr);
578             ierr = EvaluateFieldJets(probAux, PETSC_FALSE, q, invJ, coefficientsAux, NULL, a, a_x, NULL);CHKERRQ(ierr);
579             (*funcs[f])(u, NULL, u_x, a, NULL, a_x, x, &values[v]);
580           }
581         } else {
582           for (comp = 0; comp < Ncf[f]; ++comp) values[v+comp] = 0.0;
583         }
584         v += Ncf[f];
585       }
586     }
587     ierr = DMPlexVecRestoreClosure(dm, section, localU, c, NULL, &coefficients);CHKERRQ(ierr);
588     if (dmAux) {ierr = DMPlexVecRestoreClosure(dmAux, sectionAux, A, c, NULL, &coefficientsAux);CHKERRQ(ierr);}
589     ierr = DMPlexVecSetClosure(dm, section, localX, c, values, mode);CHKERRQ(ierr);
590   }
591   ierr = DMRestoreWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr);
592   ierr = PetscFree3(v0,J,invJ);CHKERRQ(ierr);
593   for (f = 0; f < Nf; f++) {ierr = PetscDualSpaceDestroy(&sp[f]);CHKERRQ(ierr);}
594   ierr = PetscFree2(sp, Ncf);CHKERRQ(ierr);
595   PetscFunctionReturn(0);
596 }
597 
598 #undef __FUNCT__
599 #define __FUNCT__ "DMPlexInsertBoundaryValues_FEM_Internal"
600 static PetscErrorCode DMPlexInsertBoundaryValues_FEM_Internal(DM dm, PetscReal time, PetscInt field, DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void *ctx, Vec locX)
601 {
602   PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
603   void            **ctxs;
604   PetscInt          numFields;
605   PetscErrorCode    ierr;
606 
607   PetscFunctionBegin;
608   ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
609   ierr = PetscCalloc2(numFields,&funcs,numFields,&ctxs);CHKERRQ(ierr);
610   funcs[field] = func;
611   ctxs[field]  = ctx;
612   ierr = DMPlexProjectFunctionLabelLocal(dm, time, label, numids, ids, funcs, ctxs, INSERT_BC_VALUES, locX);CHKERRQ(ierr);
613   ierr = PetscFree2(funcs,ctxs);CHKERRQ(ierr);
614   PetscFunctionReturn(0);
615 }
616 
617 #undef __FUNCT__
618 #define __FUNCT__ "DMPlexInsertBoundaryValues_FVM_Internal"
619 /* This ignores numcomps/comps */
620 static PetscErrorCode DMPlexInsertBoundaryValues_FVM_Internal(DM dm, PetscReal time, Vec faceGeometry, Vec cellGeometry, Vec Grad,
621                                                               PetscInt field, DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*), void *ctx, Vec locX)
622 {
623   PetscDS            prob;
624   PetscSF            sf;
625   DM                 dmFace, dmCell, dmGrad;
626   const PetscScalar *facegeom, *cellgeom, *grad;
627   const PetscInt    *leaves;
628   PetscScalar       *x, *fx;
629   PetscInt           dim, nleaves, loc, fStart, fEnd, pdim, i;
630   PetscErrorCode     ierr;
631 
632   PetscFunctionBegin;
633   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
634   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);CHKERRQ(ierr);
635   nleaves = PetscMax(0, nleaves);
636   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
637   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
638   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
639   ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr);
640   ierr = VecGetArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr);
641   ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr);
642   ierr = VecGetArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr);
643   if (Grad) {
644     PetscFV fv;
645 
646     ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &fv);CHKERRQ(ierr);
647     ierr = VecGetDM(Grad, &dmGrad);CHKERRQ(ierr);
648     ierr = VecGetArrayRead(Grad, &grad);CHKERRQ(ierr);
649     ierr = PetscFVGetNumComponents(fv, &pdim);CHKERRQ(ierr);
650     ierr = DMGetWorkArray(dm, pdim, PETSC_SCALAR, &fx);CHKERRQ(ierr);
651   }
652   ierr = VecGetArray(locX, &x);CHKERRQ(ierr);
653   for (i = 0; i < numids; ++i) {
654     IS              faceIS;
655     const PetscInt *faces;
656     PetscInt        numFaces, f;
657 
658     ierr = DMLabelGetStratumIS(label, ids[i], &faceIS);CHKERRQ(ierr);
659     if (!faceIS) continue; /* No points with that id on this process */
660     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
661     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
662     for (f = 0; f < numFaces; ++f) {
663       const PetscInt         face = faces[f], *cells;
664       const PetscFVFaceGeom *fg;
665 
666       if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */
667       ierr = PetscFindInt(face, nleaves, (PetscInt *) leaves, &loc);CHKERRQ(ierr);
668       if (loc >= 0) continue;
669       ierr = DMPlexPointLocalRead(dmFace, face, facegeom, &fg);CHKERRQ(ierr);
670       ierr = DMPlexGetSupport(dm, face, &cells);CHKERRQ(ierr);
671       if (Grad) {
672         const PetscFVCellGeom *cg;
673         const PetscScalar     *cx, *cgrad;
674         PetscScalar           *xG;
675         PetscReal              dx[3];
676         PetscInt               d;
677 
678         ierr = DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg);CHKERRQ(ierr);
679         ierr = DMPlexPointLocalRead(dm, cells[0], x, &cx);CHKERRQ(ierr);
680         ierr = DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad);CHKERRQ(ierr);
681         ierr = DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);CHKERRQ(ierr);
682         DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx);
683         for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d*dim], dx);
684         ierr = (*func)(time, fg->centroid, fg->normal, fx, xG, ctx);CHKERRQ(ierr);
685       } else {
686         const PetscScalar *xI;
687         PetscScalar       *xG;
688 
689         ierr = DMPlexPointLocalRead(dm, cells[0], x, &xI);CHKERRQ(ierr);
690         ierr = DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);CHKERRQ(ierr);
691         ierr = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx);CHKERRQ(ierr);
692       }
693     }
694     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
695     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
696   }
697   ierr = VecRestoreArray(locX, &x);CHKERRQ(ierr);
698   if (Grad) {
699     ierr = DMRestoreWorkArray(dm, pdim, PETSC_SCALAR, &fx);CHKERRQ(ierr);
700     ierr = VecRestoreArrayRead(Grad, &grad);CHKERRQ(ierr);
701   }
702   ierr = VecRestoreArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr);
703   ierr = VecRestoreArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr);
704   PetscFunctionReturn(0);
705 }
706 
707 #undef __FUNCT__
708 #define __FUNCT__ "DMPlexInsertBoundaryValues"
709 PetscErrorCode DMPlexInsertBoundaryValues(DM dm, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
710 {
711   PetscInt       numBd, b;
712   PetscErrorCode ierr;
713 
714   PetscFunctionBegin;
715   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
716   PetscValidHeaderSpecific(locX, VEC_CLASSID, 2);
717   if (faceGeomFVM) {PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 4);}
718   if (cellGeomFVM) {PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 5);}
719   if (gradFVM)     {PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 6);}
720   ierr = DMPlexGetNumBoundary(dm, &numBd);CHKERRQ(ierr);
721   for (b = 0; b < numBd; ++b) {
722     PetscBool       isEssential;
723     const char     *labelname;
724     DMLabel         label;
725     PetscInt        field;
726     PetscObject     obj;
727     PetscClassId    id;
728     void          (*func)();
729     PetscInt        numids;
730     const PetscInt *ids;
731     void           *ctx;
732 
733     ierr = DMPlexGetBoundary(dm, b, &isEssential, NULL, &labelname, &field, NULL, NULL, &func, &numids, &ids, &ctx);CHKERRQ(ierr);
734     if (!isEssential) continue;
735     ierr = DMGetLabel(dm, labelname, &label);CHKERRQ(ierr);
736     ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
737     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
738     if (id == PETSCFE_CLASSID) {
739       ierr = DMPlexInsertBoundaryValues_FEM_Internal(dm, time, field, label, numids, ids, (PetscErrorCode (*)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *)) func, ctx, locX);CHKERRQ(ierr);
740     } else if (id == PETSCFV_CLASSID) {
741       if (!faceGeomFVM) continue;
742       ierr = DMPlexInsertBoundaryValues_FVM_Internal(dm, time, faceGeomFVM, cellGeomFVM, gradFVM,
743                                                      field, label, numids, ids, (PetscErrorCode (*)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*)) func, ctx, locX);CHKERRQ(ierr);
744     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
745   }
746   PetscFunctionReturn(0);
747 }
748 
749 #undef __FUNCT__
750 #define __FUNCT__ "DMPlexComputeL2Diff"
751 /*@C
752   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
753 
754   Input Parameters:
755 + dm    - The DM
756 . time  - The time
757 . funcs - The functions to evaluate for each field component
758 . ctxs  - Optional array of contexts to pass to each function, or NULL.
759 - X     - The coefficient vector u_h
760 
761   Output Parameter:
762 . diff - The diff ||u - u_h||_2
763 
764   Level: developer
765 
766 .seealso: DMPlexProjectFunction(), DMPlexComputeL2FieldDiff(), DMPlexComputeL2GradientDiff()
767 @*/
768 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
769 {
770   const PetscInt   debug = 0;
771   PetscSection     section;
772   PetscQuadrature  quad;
773   Vec              localX;
774   PetscScalar     *funcVal, *interpolant;
775   PetscReal       *coords, *v0, *J, *invJ, detJ;
776   PetscReal        localDiff = 0.0;
777   const PetscReal *quadPoints, *quadWeights;
778   PetscInt         dim, numFields, numComponents = 0, numQuadPoints, cStart, cEnd, cEndInterior, c, field, fieldOffset;
779   PetscErrorCode   ierr;
780 
781   PetscFunctionBegin;
782   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
783   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
784   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
785   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
786   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
787   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
788   for (field = 0; field < numFields; ++field) {
789     PetscObject  obj;
790     PetscClassId id;
791     PetscInt     Nc;
792 
793     ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
794     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
795     if (id == PETSCFE_CLASSID) {
796       PetscFE fe = (PetscFE) obj;
797 
798       ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr);
799       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
800     } else if (id == PETSCFV_CLASSID) {
801       PetscFV fv = (PetscFV) obj;
802 
803       ierr = PetscFVGetQuadrature(fv, &quad);CHKERRQ(ierr);
804       ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
805     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
806     numComponents += Nc;
807   }
808   ierr = PetscQuadratureGetData(quad, NULL, &numQuadPoints, &quadPoints, &quadWeights);CHKERRQ(ierr);
809   ierr = DMPlexProjectFunctionLocal(dm, 0.0, funcs, ctxs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
810   ierr = PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,dim,&coords,dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr);
811   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
812   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
813   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
814   for (c = cStart; c < cEnd; ++c) {
815     PetscScalar *x = NULL;
816     PetscReal    elemDiff = 0.0;
817 
818     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
819     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
820     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
821 
822     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
823       PetscObject  obj;
824       PetscClassId id;
825       void * const ctx = ctxs ? ctxs[field] : NULL;
826       PetscInt     Nb, Nc, q, fc;
827 
828       ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
829       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
830       if (id == PETSCFE_CLASSID)      {ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);ierr = PetscFEGetDimension((PetscFE) obj, &Nb);CHKERRQ(ierr);}
831       else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);Nb = 1;}
832       else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
833       if (debug) {
834         char title[1024];
835         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
836         ierr = DMPrintCellVector(c, title, Nb*Nc, &x[fieldOffset]);CHKERRQ(ierr);
837       }
838       for (q = 0; q < numQuadPoints; ++q) {
839         CoordinatesRefToReal(dim, dim, v0, J, &quadPoints[q*dim], coords);
840         ierr = (*funcs[field])(dim, time, coords, Nc, funcVal, ctx);CHKERRQ(ierr);
841         if (id == PETSCFE_CLASSID)      {ierr = PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);}
842         else if (id == PETSCFV_CLASSID) {ierr = PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);}
843         else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
844         for (fc = 0; fc < Nc; ++fc) {
845           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);}
846           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*quadWeights[q]*detJ;
847         }
848       }
849       fieldOffset += Nb*Nc;
850     }
851     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
852     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
853     localDiff += elemDiff;
854   }
855   ierr  = PetscFree6(funcVal,interpolant,coords,v0,J,invJ);CHKERRQ(ierr);
856   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
857   ierr  = MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
858   *diff = PetscSqrtReal(*diff);
859   PetscFunctionReturn(0);
860 }
861 
862 #undef __FUNCT__
863 #define __FUNCT__ "DMPlexComputeL2GradientDiff"
864 /*@C
865   DMPlexComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
866 
867   Input Parameters:
868 + dm    - The DM
869 , time  - The time
870 . funcs - The gradient functions to evaluate for each field component
871 . ctxs  - Optional array of contexts to pass to each function, or NULL.
872 . X     - The coefficient vector u_h
873 - n     - The vector to project along
874 
875   Output Parameter:
876 . diff - The diff ||(grad u - grad u_h) . n||_2
877 
878   Level: developer
879 
880 .seealso: DMPlexProjectFunction(), DMPlexComputeL2Diff()
881 @*/
882 PetscErrorCode DMPlexComputeL2GradientDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
883 {
884   const PetscInt  debug = 0;
885   PetscSection    section;
886   PetscQuadrature quad;
887   Vec             localX;
888   PetscScalar    *funcVal, *interpolantVec;
889   PetscReal      *coords, *realSpaceDer, *v0, *J, *invJ, detJ;
890   PetscReal       localDiff = 0.0;
891   PetscInt        dim, numFields, numComponents = 0, cStart, cEnd, cEndInterior, c, field, fieldOffset, comp;
892   PetscErrorCode  ierr;
893 
894   PetscFunctionBegin;
895   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
896   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
897   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
898   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
899   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
900   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
901   for (field = 0; field < numFields; ++field) {
902     PetscFE  fe;
903     PetscInt Nc;
904 
905     ierr = DMGetField(dm, field, (PetscObject *) &fe);CHKERRQ(ierr);
906     ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr);
907     ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
908     numComponents += Nc;
909   }
910   /* ierr = DMPlexProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr); */
911   ierr = PetscMalloc7(numComponents,&funcVal,dim,&coords,dim,&realSpaceDer,dim,&v0,dim*dim,&J,dim*dim,&invJ,dim,&interpolantVec);CHKERRQ(ierr);
912   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
913   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
914   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
915   for (c = cStart; c < cEnd; ++c) {
916     PetscScalar *x = NULL;
917     PetscReal    elemDiff = 0.0;
918 
919     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
920     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
921     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
922 
923     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
924       PetscFE          fe;
925       void * const     ctx = ctxs ? ctxs[field] : NULL;
926       const PetscReal *quadPoints, *quadWeights;
927       PetscReal       *basisDer;
928       PetscInt         numQuadPoints, Nb, Ncomp, q, d, e, fc, f, g;
929 
930       ierr = DMGetField(dm, field, (PetscObject *) &fe);CHKERRQ(ierr);
931       ierr = PetscQuadratureGetData(quad, NULL, &numQuadPoints, &quadPoints, &quadWeights);CHKERRQ(ierr);
932       ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr);
933       ierr = PetscFEGetNumComponents(fe, &Ncomp);CHKERRQ(ierr);
934       ierr = PetscFEGetDefaultTabulation(fe, NULL, &basisDer, NULL);CHKERRQ(ierr);
935       if (debug) {
936         char title[1024];
937         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
938         ierr = DMPrintCellVector(c, title, Nb*Ncomp, &x[fieldOffset]);CHKERRQ(ierr);
939       }
940       for (q = 0; q < numQuadPoints; ++q) {
941         for (d = 0; d < dim; d++) {
942           coords[d] = v0[d];
943           for (e = 0; e < dim; e++) {
944             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
945           }
946         }
947         ierr = (*funcs[field])(dim, time, coords, n, numFields, funcVal, ctx);CHKERRQ(ierr);
948         for (fc = 0; fc < Ncomp; ++fc) {
949           PetscScalar interpolant = 0.0;
950 
951           for (d = 0; d < dim; ++d) interpolantVec[d] = 0.0;
952           for (f = 0; f < Nb; ++f) {
953             const PetscInt fidx = f*Ncomp+fc;
954 
955             for (d = 0; d < dim; ++d) {
956               realSpaceDer[d] = 0.0;
957               for (g = 0; g < dim; ++g) {
958                 realSpaceDer[d] += invJ[g*dim+d]*basisDer[(q*Nb*Ncomp+fidx)*dim+g];
959               }
960               interpolantVec[d] += x[fieldOffset+fidx]*realSpaceDer[d];
961             }
962           }
963           for (d = 0; d < dim; ++d) interpolant += interpolantVec[d]*n[d];
964           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);}
965           elemDiff += PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ;
966         }
967       }
968       comp        += Ncomp;
969       fieldOffset += Nb*Ncomp;
970     }
971     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
972     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
973     localDiff += elemDiff;
974   }
975   ierr  = PetscFree7(funcVal,coords,realSpaceDer,v0,J,invJ,interpolantVec);CHKERRQ(ierr);
976   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
977   ierr  = MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
978   *diff = PetscSqrtReal(*diff);
979   PetscFunctionReturn(0);
980 }
981 
982 #undef __FUNCT__
983 #define __FUNCT__ "DMPlexComputeL2FieldDiff"
984 /*@C
985   DMPlexComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
986 
987   Input Parameters:
988 + dm    - The DM
989 . time  - The time
990 . funcs - The functions to evaluate for each field component
991 . ctxs  - Optional array of contexts to pass to each function, or NULL.
992 - X     - The coefficient vector u_h
993 
994   Output Parameter:
995 . diff - The array of differences, ||u^f - u^f_h||_2
996 
997   Level: developer
998 
999 .seealso: DMPlexProjectFunction(), DMPlexComputeL2Diff(), DMPlexComputeL2GradientDiff()
1000 @*/
1001 PetscErrorCode DMPlexComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
1002 {
1003   const PetscInt   debug = 0;
1004   PetscSection     section;
1005   PetscQuadrature  quad;
1006   Vec              localX;
1007   PetscScalar     *funcVal, *interpolant;
1008   PetscReal       *coords, *v0, *J, *invJ, detJ;
1009   PetscReal       *localDiff;
1010   const PetscReal *quadPoints, *quadWeights;
1011   PetscInt         dim, numFields, numComponents = 0, numQuadPoints, cStart, cEnd, cEndInterior, c, field, fieldOffset;
1012   PetscErrorCode   ierr;
1013 
1014   PetscFunctionBegin;
1015   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1016   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1017   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
1018   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
1019   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
1020   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
1021   for (field = 0; field < numFields; ++field) {
1022     PetscObject  obj;
1023     PetscClassId id;
1024     PetscInt     Nc;
1025 
1026     ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
1027     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1028     if (id == PETSCFE_CLASSID) {
1029       PetscFE fe = (PetscFE) obj;
1030 
1031       ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr);
1032       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
1033     } else if (id == PETSCFV_CLASSID) {
1034       PetscFV fv = (PetscFV) obj;
1035 
1036       ierr = PetscFVGetQuadrature(fv, &quad);CHKERRQ(ierr);
1037       ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
1038     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1039     numComponents += Nc;
1040   }
1041   ierr = PetscQuadratureGetData(quad, NULL, &numQuadPoints, &quadPoints, &quadWeights);CHKERRQ(ierr);
1042   ierr = DMPlexProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
1043   ierr = PetscCalloc7(numFields,&localDiff,numComponents,&funcVal,numComponents,&interpolant,dim,&coords,dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr);
1044   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1045   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
1046   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1047   for (c = cStart; c < cEnd; ++c) {
1048     PetscScalar *x = NULL;
1049 
1050     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
1051     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
1052     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
1053 
1054     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1055       PetscObject  obj;
1056       PetscClassId id;
1057       void * const ctx = ctxs ? ctxs[field] : NULL;
1058       PetscInt     Nb, Nc, q, fc;
1059 
1060       PetscReal       elemDiff = 0.0;
1061 
1062       ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
1063       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1064       if (id == PETSCFE_CLASSID)      {ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);ierr = PetscFEGetDimension((PetscFE) obj, &Nb);CHKERRQ(ierr);}
1065       else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);Nb = 1;}
1066       else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1067       if (debug) {
1068         char title[1024];
1069         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
1070         ierr = DMPrintCellVector(c, title, Nb*Nc, &x[fieldOffset]);CHKERRQ(ierr);
1071       }
1072       for (q = 0; q < numQuadPoints; ++q) {
1073         CoordinatesRefToReal(dim, dim, v0, J, &quadPoints[q*dim], coords);
1074         ierr = (*funcs[field])(dim, time, coords, numFields, funcVal, ctx);CHKERRQ(ierr);
1075         if (id == PETSCFE_CLASSID)      {ierr = PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);}
1076         else if (id == PETSCFV_CLASSID) {ierr = PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);}
1077         else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1078         for (fc = 0; fc < Nc; ++fc) {
1079           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);}
1080           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*quadWeights[q]*detJ;
1081         }
1082       }
1083       fieldOffset += Nb*Nc;
1084       localDiff[field] += elemDiff;
1085     }
1086     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
1087   }
1088   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
1089   ierr = MPIU_Allreduce(localDiff, diff, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1090   for (field = 0; field < numFields; ++field) diff[field] = PetscSqrtReal(diff[field]);
1091   ierr = PetscFree7(localDiff,funcVal,interpolant,coords,v0,J,invJ);CHKERRQ(ierr);
1092   PetscFunctionReturn(0);
1093 }
1094 
1095 #undef __FUNCT__
1096 #define __FUNCT__ "DMPlexComputeL2DiffVec"
1097 /*@C
1098   DMPlexComputeL2DiffVec - This function computes the cellwise L_2 difference between a function u and an FEM interpolant solution u_h, and stores it in a Vec.
1099 
1100   Input Parameters:
1101 + dm    - The DM
1102 . time  - The time
1103 . funcs - The functions to evaluate for each field component
1104 . ctxs  - Optional array of contexts to pass to each function, or NULL.
1105 - X     - The coefficient vector u_h
1106 
1107   Output Parameter:
1108 . D - A Vec which holds the difference ||u - u_h||_2 for each cell
1109 
1110   Level: developer
1111 
1112 .seealso: DMPlexProjectFunction(), DMPlexComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMPlexComputeL2GradientDiff()
1113 @*/
1114 PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D)
1115 {
1116   PetscSection     section;
1117   PetscQuadrature  quad;
1118   Vec              localX;
1119   PetscScalar     *funcVal, *interpolant;
1120   PetscReal       *coords, *v0, *J, *invJ, detJ;
1121   const PetscReal *quadPoints, *quadWeights;
1122   PetscInt         dim, numFields, numComponents = 0, numQuadPoints, cStart, cEnd, cEndInterior, c, field, fieldOffset;
1123   PetscErrorCode   ierr;
1124 
1125   PetscFunctionBegin;
1126   ierr = VecSet(D, 0.0);CHKERRQ(ierr);
1127   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1128   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1129   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
1130   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
1131   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
1132   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
1133   for (field = 0; field < numFields; ++field) {
1134     PetscObject  obj;
1135     PetscClassId id;
1136     PetscInt     Nc;
1137 
1138     ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
1139     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1140     if (id == PETSCFE_CLASSID) {
1141       PetscFE fe = (PetscFE) obj;
1142 
1143       ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr);
1144       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
1145     } else if (id == PETSCFV_CLASSID) {
1146       PetscFV fv = (PetscFV) obj;
1147 
1148       ierr = PetscFVGetQuadrature(fv, &quad);CHKERRQ(ierr);
1149       ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
1150     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1151     numComponents += Nc;
1152   }
1153   ierr = PetscQuadratureGetData(quad, NULL, &numQuadPoints, &quadPoints, &quadWeights);CHKERRQ(ierr);
1154   ierr = DMPlexProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
1155   ierr = PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,dim,&coords,dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr);
1156   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1157   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
1158   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1159   for (c = cStart; c < cEnd; ++c) {
1160     PetscScalar *x = NULL;
1161     PetscScalar  elemDiff = 0.0;
1162 
1163     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
1164     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
1165     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
1166 
1167     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1168       PetscObject  obj;
1169       PetscClassId id;
1170       void * const ctx = ctxs ? ctxs[field] : NULL;
1171       PetscInt     Nb, Nc, q, fc;
1172 
1173       ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr);
1174       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1175       if (id == PETSCFE_CLASSID)      {ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);ierr = PetscFEGetDimension((PetscFE) obj, &Nb);CHKERRQ(ierr);}
1176       else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);Nb = 1;}
1177       else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1178       for (q = 0; q < numQuadPoints; ++q) {
1179         CoordinatesRefToReal(dim, dim, v0, J, &quadPoints[q*dim], coords);
1180         ierr = (*funcs[field])(dim, time, coords, Nc, funcVal, ctx);CHKERRQ(ierr);
1181         if (id == PETSCFE_CLASSID)      {ierr = PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);}
1182         else if (id == PETSCFV_CLASSID) {ierr = PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);}
1183         else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1184         for (fc = 0; fc < Nc; ++fc) {
1185           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*quadWeights[q]*detJ;
1186         }
1187       }
1188       fieldOffset += Nb*Nc;
1189     }
1190     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
1191     ierr = VecSetValuesSection(D, section, c, &elemDiff, ADD_VALUES);CHKERRQ(ierr);
1192   }
1193   ierr = PetscFree6(funcVal,interpolant,coords,v0,J,invJ);CHKERRQ(ierr);
1194   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
1195   ierr = VecSqrtAbs(D);CHKERRQ(ierr);
1196   PetscFunctionReturn(0);
1197 }
1198 
1199 #undef __FUNCT__
1200 #define __FUNCT__ "DMPlexComputeIntegralFEM"
1201 /*@
1202   DMPlexComputeIntegralFEM - Form the local integral F from the local input X using pointwise functions specified by the user
1203 
1204   Input Parameters:
1205 + dm - The mesh
1206 . X  - Local input vector
1207 - user - The user context
1208 
1209   Output Parameter:
1210 . integral - Local integral for each field
1211 
1212   Level: developer
1213 
1214 .seealso: DMPlexComputeResidualFEM()
1215 @*/
1216 PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscReal *integral, void *user)
1217 {
1218   DM_Plex          *mesh  = (DM_Plex *) dm->data;
1219   DM                dmAux;
1220   Vec               localX, A;
1221   PetscDS           prob, probAux = NULL;
1222   PetscSection      section, sectionAux;
1223   PetscFECellGeom  *cgeom;
1224   PetscScalar      *u, *a = NULL;
1225   PetscReal        *lintegral, *vol;
1226   PetscInt          dim, Nf, f, numCells, cStart, cEnd, cEndInterior, c;
1227   PetscInt          totDim, totDimAux;
1228   PetscErrorCode    ierr;
1229 
1230   PetscFunctionBegin;
1231   ierr = PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr);
1232   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
1233   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
1234   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
1235   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1236   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1237   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
1238   ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr);
1239   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
1240   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1241   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
1242   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1243   numCells = cEnd - cStart;
1244   ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr);
1245   ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr);
1246   if (dmAux) {
1247     ierr = DMGetDefaultSection(dmAux, &sectionAux);CHKERRQ(ierr);
1248     ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr);
1249     ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr);
1250   }
1251   ierr = DMPlexInsertBoundaryValues(dm, localX, 0.0, NULL, NULL, NULL);CHKERRQ(ierr);
1252   ierr = PetscMalloc4(Nf,&lintegral,numCells*totDim,&u,numCells,&cgeom,numCells,&vol);CHKERRQ(ierr);
1253   if (dmAux) {ierr = PetscMalloc1(numCells*totDimAux, &a);CHKERRQ(ierr);}
1254   for (f = 0; f < Nf; ++f) {lintegral[f] = 0.0;}
1255   for (c = cStart; c < cEnd; ++c) {
1256     PetscScalar *x = NULL;
1257     PetscInt     i;
1258 
1259     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, cgeom[c].v0, cgeom[c].J, cgeom[c].invJ, &cgeom[c].detJ);CHKERRQ(ierr);
1260     ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol[c], NULL, NULL);CHKERRQ(ierr);
1261     if (cgeom[c].detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", cgeom[c].detJ, c);
1262     ierr = DMPlexVecGetClosure(dm, section, localX, c, NULL, &x);CHKERRQ(ierr);
1263     for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
1264     ierr = DMPlexVecRestoreClosure(dm, section, localX, c, NULL, &x);CHKERRQ(ierr);
1265     if (dmAux) {
1266       ierr = DMPlexVecGetClosure(dmAux, sectionAux, A, c, NULL, &x);CHKERRQ(ierr);
1267       for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
1268       ierr = DMPlexVecRestoreClosure(dmAux, sectionAux, A, c, NULL, &x);CHKERRQ(ierr);
1269     }
1270   }
1271   for (f = 0; f < Nf; ++f) {
1272     PetscObject  obj;
1273     PetscClassId id;
1274     PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
1275 
1276     ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
1277     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1278     if (id == PETSCFE_CLASSID) {
1279       PetscFE         fe = (PetscFE) obj;
1280       PetscQuadrature q;
1281       PetscInt        Nq, Nb;
1282 
1283       ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr);
1284       ierr = PetscFEGetQuadrature(fe, &q);CHKERRQ(ierr);
1285       ierr = PetscQuadratureGetData(q, NULL, &Nq, NULL, NULL);CHKERRQ(ierr);
1286       ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr);
1287       blockSize = Nb*Nq;
1288       batchSize = numBlocks * blockSize;
1289       ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr);
1290       numChunks = numCells / (numBatches*batchSize);
1291       Ne        = numChunks*numBatches*batchSize;
1292       Nr        = numCells % (numBatches*batchSize);
1293       offset    = numCells - Nr;
1294       ierr = PetscFEIntegrate(fe, prob, f, Ne, cgeom, u, probAux, a, lintegral);CHKERRQ(ierr);
1295       ierr = PetscFEIntegrate(fe, prob, f, Nr, &cgeom[offset], &u[offset*totDim], probAux, &a[offset*totDimAux], lintegral);CHKERRQ(ierr);
1296     } else if (id == PETSCFV_CLASSID) {
1297       /* PetscFV  fv = (PetscFV) obj; */
1298       PetscInt       foff;
1299       PetscPointFunc obj_func;
1300       PetscScalar    lint;
1301 
1302       ierr = PetscDSGetObjective(prob, f, &obj_func);CHKERRQ(ierr);
1303       ierr = PetscDSGetFieldOffset(prob, f, &foff);CHKERRQ(ierr);
1304       if (obj_func) {
1305         for (c = 0; c < numCells; ++c) {
1306           /* TODO: Need full pointwise interpolation and get centroid for x argument */
1307           obj_func(dim, Nf, 0, NULL, NULL, &u[totDim*c+foff], NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0.0, NULL, &lint);
1308           lintegral[f] = PetscRealPart(lint)*vol[c];
1309         }
1310       }
1311     } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
1312   }
1313   if (dmAux) {ierr = PetscFree(a);CHKERRQ(ierr);}
1314   if (mesh->printFEM) {
1315     ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "Local integral:");CHKERRQ(ierr);
1316     for (f = 0; f < Nf; ++f) {ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), " %g", lintegral[f]);CHKERRQ(ierr);}
1317     ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "\n");CHKERRQ(ierr);
1318   }
1319   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
1320   ierr = MPIU_Allreduce(lintegral, integral, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
1321   ierr = PetscFree4(lintegral,u,cgeom,vol);CHKERRQ(ierr);
1322   ierr = PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr);
1323   PetscFunctionReturn(0);
1324 }
1325 
1326 #undef __FUNCT__
1327 #define __FUNCT__ "DMPlexComputeInterpolatorNested"
1328 /*@
1329   DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse DM to the uniformly refined DM.
1330 
1331   Input Parameters:
1332 + dmf  - The fine mesh
1333 . dmc  - The coarse mesh
1334 - user - The user context
1335 
1336   Output Parameter:
1337 . In  - The interpolation matrix
1338 
1339   Level: developer
1340 
1341 .seealso: DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM()
1342 @*/
1343 PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, Mat In, void *user)
1344 {
1345   DM_Plex          *mesh  = (DM_Plex *) dmc->data;
1346   const char       *name  = "Interpolator";
1347   PetscDS           prob;
1348   PetscFE          *feRef;
1349   PetscFV          *fvRef;
1350   PetscSection      fsection, fglobalSection;
1351   PetscSection      csection, cglobalSection;
1352   PetscScalar      *elemMat;
1353   PetscInt          dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, cEndInterior, c;
1354   PetscInt          cTotDim, rTotDim = 0;
1355   PetscErrorCode    ierr;
1356 
1357   PetscFunctionBegin;
1358   ierr = PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr);
1359   ierr = DMGetDimension(dmf, &dim);CHKERRQ(ierr);
1360   ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);
1361   ierr = DMGetDefaultGlobalSection(dmf, &fglobalSection);CHKERRQ(ierr);
1362   ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);
1363   ierr = DMGetDefaultGlobalSection(dmc, &cglobalSection);CHKERRQ(ierr);
1364   ierr = PetscSectionGetNumFields(fsection, &Nf);CHKERRQ(ierr);
1365   ierr = DMPlexGetHeightStratum(dmc, 0, &cStart, &cEnd);CHKERRQ(ierr);
1366   ierr = DMPlexGetHybridBounds(dmc, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
1367   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1368   ierr = DMGetDS(dmf, &prob);CHKERRQ(ierr);
1369   ierr = PetscCalloc2(Nf,&feRef,Nf,&fvRef);CHKERRQ(ierr);
1370   for (f = 0; f < Nf; ++f) {
1371     PetscObject  obj;
1372     PetscClassId id;
1373     PetscInt     rNb = 0, Nc = 0;
1374 
1375     ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
1376     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1377     if (id == PETSCFE_CLASSID) {
1378       PetscFE fe = (PetscFE) obj;
1379 
1380       ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr);
1381       ierr = PetscFEGetDimension(feRef[f], &rNb);CHKERRQ(ierr);
1382       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
1383     } else if (id == PETSCFV_CLASSID) {
1384       PetscFV        fv = (PetscFV) obj;
1385       PetscDualSpace Q;
1386 
1387       ierr = PetscFVRefine(fv, &fvRef[f]);CHKERRQ(ierr);
1388       ierr = PetscFVGetDualSpace(fvRef[f], &Q);CHKERRQ(ierr);
1389       ierr = PetscDualSpaceGetDimension(Q, &rNb);CHKERRQ(ierr);
1390       ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
1391     }
1392     rTotDim += rNb*Nc;
1393   }
1394   ierr = PetscDSGetTotalDimension(prob, &cTotDim);CHKERRQ(ierr);
1395   ierr = PetscMalloc1(rTotDim*cTotDim,&elemMat);CHKERRQ(ierr);
1396   ierr = PetscMemzero(elemMat, rTotDim*cTotDim * sizeof(PetscScalar));CHKERRQ(ierr);
1397   for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
1398     PetscDualSpace   Qref;
1399     PetscQuadrature  f;
1400     const PetscReal *qpoints, *qweights;
1401     PetscReal       *points;
1402     PetscInt         npoints = 0, Nc, Np, fpdim, i, k, p, d;
1403 
1404     /* Compose points from all dual basis functionals */
1405     if (feRef[fieldI]) {
1406       ierr = PetscFEGetDualSpace(feRef[fieldI], &Qref);CHKERRQ(ierr);
1407       ierr = PetscFEGetNumComponents(feRef[fieldI], &Nc);CHKERRQ(ierr);
1408     } else {
1409       ierr = PetscFVGetDualSpace(fvRef[fieldI], &Qref);CHKERRQ(ierr);
1410       ierr = PetscFVGetNumComponents(fvRef[fieldI], &Nc);CHKERRQ(ierr);
1411     }
1412     ierr = PetscDualSpaceGetDimension(Qref, &fpdim);CHKERRQ(ierr);
1413     for (i = 0; i < fpdim; ++i) {
1414       ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr);
1415       ierr = PetscQuadratureGetData(f, NULL, &Np, NULL, NULL);CHKERRQ(ierr);
1416       npoints += Np;
1417     }
1418     ierr = PetscMalloc1(npoints*dim,&points);CHKERRQ(ierr);
1419     for (i = 0, k = 0; i < fpdim; ++i) {
1420       ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr);
1421       ierr = PetscQuadratureGetData(f, NULL, &Np, &qpoints, NULL);CHKERRQ(ierr);
1422       for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d];
1423     }
1424 
1425     for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
1426       PetscObject  obj;
1427       PetscClassId id;
1428       PetscReal   *B;
1429       PetscInt     NcJ = 0, cpdim = 0, j;
1430 
1431       ierr = PetscDSGetDiscretization(prob, fieldJ, &obj);CHKERRQ(ierr);
1432       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1433       if (id == PETSCFE_CLASSID) {
1434         PetscFE fe = (PetscFE) obj;
1435 
1436         /* Evaluate basis at points */
1437         ierr = PetscFEGetNumComponents(fe, &NcJ);CHKERRQ(ierr);
1438         ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr);
1439         /* For now, fields only interpolate themselves */
1440         if (fieldI == fieldJ) {
1441           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);
1442           ierr = PetscFEGetTabulation(fe, npoints, points, &B, NULL, NULL);CHKERRQ(ierr);
1443           for (i = 0, k = 0; i < fpdim; ++i) {
1444             ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr);
1445             ierr = PetscQuadratureGetData(f, NULL, &Np, NULL, &qweights);CHKERRQ(ierr);
1446             for (p = 0; p < Np; ++p, ++k) {
1447               for (j = 0; j < cpdim; ++j) {
1448                 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];
1449               }
1450             }
1451           }
1452           ierr = PetscFERestoreTabulation(fe, npoints, points, &B, NULL, NULL);CHKERRQ(ierr);CHKERRQ(ierr);
1453         }
1454       } else if (id == PETSCFV_CLASSID) {
1455         PetscFV        fv = (PetscFV) obj;
1456 
1457         /* Evaluate constant function at points */
1458         ierr = PetscFVGetNumComponents(fv, &NcJ);CHKERRQ(ierr);
1459         cpdim = 1;
1460         /* For now, fields only interpolate themselves */
1461         if (fieldI == fieldJ) {
1462           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);
1463           for (i = 0, k = 0; i < fpdim; ++i) {
1464             ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr);
1465             ierr = PetscQuadratureGetData(f, NULL, &Np, NULL, &qweights);CHKERRQ(ierr);
1466             for (p = 0; p < Np; ++p, ++k) {
1467               for (j = 0; j < cpdim; ++j) {
1468                 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i*Nc + c)*cTotDim + offsetJ + j*NcJ + c] += 1.0*qweights[p];
1469               }
1470             }
1471           }
1472         }
1473       }
1474       offsetJ += cpdim*NcJ;
1475     }
1476     offsetI += fpdim*Nc;
1477     ierr = PetscFree(points);CHKERRQ(ierr);
1478   }
1479   if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);CHKERRQ(ierr);}
1480   /* Preallocate matrix */
1481   {
1482     Mat          preallocator;
1483     PetscScalar *vals;
1484     PetscInt    *cellCIndices, *cellFIndices;
1485     PetscInt     locRows, locCols, cell;
1486 
1487     ierr = MatGetLocalSize(In, &locRows, &locCols);CHKERRQ(ierr);
1488     ierr = MatCreate(PetscObjectComm((PetscObject) In), &preallocator);CHKERRQ(ierr);
1489     ierr = MatSetType(preallocator, MATPREALLOCATOR);CHKERRQ(ierr);
1490     ierr = MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1491     ierr = MatSetUp(preallocator);CHKERRQ(ierr);
1492     ierr = PetscCalloc3(rTotDim*cTotDim, &vals,cTotDim,&cellCIndices,rTotDim,&cellFIndices);CHKERRQ(ierr);
1493     for (cell = cStart; cell < cEnd; ++cell) {
1494       ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);CHKERRQ(ierr);
1495       ierr = MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES);CHKERRQ(ierr);
1496     }
1497     ierr = PetscFree3(vals,cellCIndices,cellFIndices);CHKERRQ(ierr);
1498     ierr = MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1499     ierr = MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1500     ierr = MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In);CHKERRQ(ierr);
1501     ierr = MatDestroy(&preallocator);CHKERRQ(ierr);
1502   }
1503   /* Fill matrix */
1504   ierr = MatZeroEntries(In);CHKERRQ(ierr);
1505   for (c = cStart; c < cEnd; ++c) {
1506     ierr = DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);CHKERRQ(ierr);
1507   }
1508   for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);}
1509   ierr = PetscFree2(feRef,fvRef);CHKERRQ(ierr);
1510   ierr = PetscFree(elemMat);CHKERRQ(ierr);
1511   ierr = MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1512   ierr = MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1513   if (mesh->printFEM) {
1514     ierr = PetscPrintf(PETSC_COMM_WORLD, "%s:\n", name);CHKERRQ(ierr);
1515     ierr = MatChop(In, 1.0e-10);CHKERRQ(ierr);
1516     ierr = MatView(In, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
1517   }
1518   ierr = PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr);
1519   PetscFunctionReturn(0);
1520 }
1521 
1522 #undef __FUNCT__
1523 #define __FUNCT__ "DMPlexComputeInterpolatorGeneral"
1524 /*@
1525   DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse DM to a non-nested fine DM.
1526 
1527   Input Parameters:
1528 + dmf  - The fine mesh
1529 . dmc  - The coarse mesh
1530 - user - The user context
1531 
1532   Output Parameter:
1533 . In  - The interpolation matrix
1534 
1535   Level: developer
1536 
1537 .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM()
1538 @*/
1539 PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user)
1540 {
1541   DM_Plex       *mesh = (DM_Plex *) dmf->data;
1542   const char    *name = "Interpolator";
1543   PetscDS        prob;
1544   PetscSection   fsection, csection, globalFSection, globalCSection;
1545   PetscHashJK    ht;
1546   PetscLayout    rLayout;
1547   PetscInt      *dnz, *onz;
1548   PetscInt       locRows, rStart, rEnd;
1549   PetscReal     *x, *v0, *J, *invJ, detJ;
1550   PetscReal     *v0c, *Jc, *invJc, detJc;
1551   PetscScalar   *elemMat;
1552   PetscInt       dim, Nf, field, totDim, cStart, cEnd, cell, ccell;
1553   PetscErrorCode ierr;
1554 
1555   PetscFunctionBegin;
1556   ierr = DMGetCoordinateDim(dmc, &dim);CHKERRQ(ierr);
1557   ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr);
1558   ierr = PetscDSGetRefCoordArrays(prob, &x, NULL);CHKERRQ(ierr);
1559   ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr);
1560   ierr = PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr);
1561   ierr = PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);CHKERRQ(ierr);
1562   ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);
1563   ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);
1564   ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);
1565   ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);
1566   ierr = DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);CHKERRQ(ierr);
1567   ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr);
1568   ierr = PetscMalloc1(totDim*totDim, &elemMat);CHKERRQ(ierr);
1569 
1570   ierr = MatGetLocalSize(In, &locRows, NULL);CHKERRQ(ierr);
1571   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout);CHKERRQ(ierr);
1572   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
1573   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
1574   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
1575   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
1576   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
1577   ierr = PetscCalloc2(locRows,&dnz,locRows,&onz);CHKERRQ(ierr);
1578   ierr = PetscHashJKCreate(&ht);CHKERRQ(ierr);
1579   for (field = 0; field < Nf; ++field) {
1580     PetscObject      obj;
1581     PetscClassId     id;
1582     PetscDualSpace   Q = NULL;
1583     PetscQuadrature  f;
1584     const PetscReal *qpoints;
1585     PetscInt         Nc, Np, fpdim, i, d;
1586 
1587     ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr);
1588     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1589     if (id == PETSCFE_CLASSID) {
1590       PetscFE fe = (PetscFE) obj;
1591 
1592       ierr = PetscFEGetDualSpace(fe, &Q);CHKERRQ(ierr);
1593       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
1594     } else if (id == PETSCFV_CLASSID) {
1595       PetscFV fv = (PetscFV) obj;
1596 
1597       ierr = PetscFVGetDualSpace(fv, &Q);CHKERRQ(ierr);
1598       Nc   = 1;
1599     }
1600     ierr = PetscDualSpaceGetDimension(Q, &fpdim);CHKERRQ(ierr);
1601     /* For each fine grid cell */
1602     for (cell = cStart; cell < cEnd; ++cell) {
1603       PetscInt *findices,   *cindices;
1604       PetscInt  numFIndices, numCIndices;
1605 
1606       ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices);CHKERRQ(ierr);CHKERRQ(ierr);
1607       ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
1608       if (numFIndices != fpdim*Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %d != %d dual basis vecs", numFIndices, fpdim*Nc);
1609       for (i = 0; i < fpdim; ++i) {
1610         Vec             pointVec;
1611         PetscScalar    *pV;
1612         IS              coarseCellIS;
1613         const PetscInt *coarseCells;
1614         PetscInt        numCoarseCells, q, r, c;
1615 
1616         /* Get points from the dual basis functional quadrature */
1617         ierr = PetscDualSpaceGetFunctional(Q, i, &f);CHKERRQ(ierr);
1618         ierr = PetscQuadratureGetData(f, NULL, &Np, &qpoints, NULL);CHKERRQ(ierr);
1619         ierr = VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);CHKERRQ(ierr);
1620         ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr);
1621         ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr);
1622         for (q = 0; q < Np; ++q) {
1623           /* Transform point to real space */
1624           CoordinatesRefToReal(dim, dim, v0, J, &qpoints[q*dim], x);
1625           for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
1626         }
1627         ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr);
1628         /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
1629         ierr = DMLocatePoints(dmc, pointVec, &coarseCellIS);CHKERRQ(ierr);
1630         ierr = ISViewFromOptions(coarseCellIS, NULL, "-interp_is_view");CHKERRQ(ierr);
1631         /* Update preallocation info */
1632         ierr = ISGetLocalSize(coarseCellIS, &numCoarseCells);CHKERRQ(ierr);
1633         ierr = ISGetIndices(coarseCellIS, &coarseCells);CHKERRQ(ierr);
1634         for (r = 0; r < Nc; ++r) {
1635           PetscHashJKKey  key;
1636           PetscHashJKIter missing, iter;
1637 
1638           key.j = findices[i*Nc+r];
1639           if (key.j < 0) continue;
1640           /* Get indices for coarse elements */
1641           for (ccell = 0; ccell < numCoarseCells; ++ccell) {
1642             ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell], &numCIndices, &cindices);CHKERRQ(ierr);CHKERRQ(ierr);
1643             for (c = 0; c < numCIndices; ++c) {
1644               key.k = cindices[c];
1645               if (key.k < 0) continue;
1646               ierr = PetscHashJKPut(ht, key, &missing, &iter);CHKERRQ(ierr);
1647               if (missing) {
1648                 ierr = PetscHashJKSet(ht, iter, 1);CHKERRQ(ierr);
1649                 if ((key.k >= rStart) && (key.k < rEnd)) ++dnz[key.j-rStart];
1650                 else                                     ++onz[key.j-rStart];
1651               }
1652             }
1653             ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell], &numCIndices, &cindices);CHKERRQ(ierr);CHKERRQ(ierr);
1654           }
1655         }
1656         ierr = ISRestoreIndices(coarseCellIS, &coarseCells);CHKERRQ(ierr);
1657         ierr = ISDestroy(&coarseCellIS);CHKERRQ(ierr);
1658         ierr = VecDestroy(&pointVec);CHKERRQ(ierr);
1659       }
1660       ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices);CHKERRQ(ierr);CHKERRQ(ierr);
1661     }
1662   }
1663   ierr = PetscHashJKDestroy(&ht);CHKERRQ(ierr);
1664   ierr = MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL);CHKERRQ(ierr);
1665   ierr = MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
1666   ierr = PetscFree2(dnz,onz);CHKERRQ(ierr);
1667   for (field = 0; field < Nf; ++field) {
1668     PetscObject      obj;
1669     PetscClassId     id;
1670     PetscDualSpace   Q = NULL;
1671     PetscQuadrature  f;
1672     const PetscReal *qpoints, *qweights;
1673     PetscInt         Nc, Np, fpdim, i, d;
1674 
1675     ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr);
1676     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1677     if (id == PETSCFE_CLASSID) {
1678       PetscFE fe = (PetscFE) obj;
1679 
1680       ierr = PetscFEGetDualSpace(fe, &Q);CHKERRQ(ierr);
1681       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
1682     } else if (id == PETSCFV_CLASSID) {
1683       PetscFV fv = (PetscFV) obj;
1684 
1685       ierr = PetscFVGetDualSpace(fv, &Q);CHKERRQ(ierr);
1686       Nc   = 1;
1687     }
1688     ierr = PetscDualSpaceGetDimension(Q, &fpdim);CHKERRQ(ierr);
1689     /* For each fine grid cell */
1690     for (cell = cStart; cell < cEnd; ++cell) {
1691       PetscInt *findices,   *cindices;
1692       PetscInt  numFIndices, numCIndices;
1693 
1694       ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices);CHKERRQ(ierr);CHKERRQ(ierr);
1695       ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
1696       if (numFIndices != fpdim*Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %d != %d dual basis vecs", numFIndices, fpdim*Nc);
1697       for (i = 0; i < fpdim; ++i) {
1698         Vec             pointVec;
1699         PetscScalar    *pV;
1700         IS              coarseCellIS;
1701         const PetscInt *coarseCells;
1702         PetscInt        numCoarseCells, cpdim, q, c, j;
1703 
1704         /* Get points from the dual basis functional quadrature */
1705         ierr = PetscDualSpaceGetFunctional(Q, i, &f);CHKERRQ(ierr);
1706         ierr = PetscQuadratureGetData(f, NULL, &Np, &qpoints, &qweights);CHKERRQ(ierr);
1707         ierr = VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);CHKERRQ(ierr);
1708         ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr);
1709         ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr);
1710         for (q = 0; q < Np; ++q) {
1711           /* Transform point to real space */
1712           CoordinatesRefToReal(dim, dim, v0, J, &qpoints[q*dim], x);
1713           for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
1714         }
1715         ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr);
1716         /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
1717         ierr = DMLocatePoints(dmc, pointVec, &coarseCellIS);CHKERRQ(ierr);
1718         /* Update preallocation info */
1719         ierr = ISGetLocalSize(coarseCellIS, &numCoarseCells);CHKERRQ(ierr);
1720         ierr = ISGetIndices(coarseCellIS, &coarseCells);CHKERRQ(ierr);
1721         ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr);
1722         for (ccell = 0; ccell < numCoarseCells; ++ccell) {
1723           PetscReal pVReal[3];
1724 
1725           ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell], &numCIndices, &cindices);CHKERRQ(ierr);CHKERRQ(ierr);
1726           /* Transform points from real space to coarse reference space */
1727           ierr = DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell], NULL, v0c, Jc, invJc, &detJc);CHKERRQ(ierr);
1728           for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]);
1729           CoordinatesRealToRef(dim, dim, v0c, invJc, pVReal, x);
1730 
1731           if (id == PETSCFE_CLASSID) {
1732             PetscFE    fe = (PetscFE) obj;
1733             PetscReal *B;
1734 
1735             /* Evaluate coarse basis on contained point */
1736             ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr);
1737             ierr = PetscFEGetTabulation(fe, 1, x, &B, NULL, NULL);CHKERRQ(ierr);
1738             /* Get elemMat entries by multiplying by weight */
1739             for (j = 0; j < cpdim; ++j) {
1740               for (c = 0; c < Nc; ++c) elemMat[(c*cpdim + j)*Nc + c] = B[j*Nc + c]*qweights[ccell];
1741             }
1742             ierr = PetscFERestoreTabulation(fe, 1, x, &B, NULL, NULL);CHKERRQ(ierr);CHKERRQ(ierr);
1743           } else {
1744             cpdim = 1;
1745             for (j = 0; j < cpdim; ++j) {
1746               for (c = 0; c < Nc; ++c) elemMat[(c*cpdim + j)*Nc + c] = 1.0*qweights[ccell];
1747             }
1748           }
1749           /* Update interpolator */
1750           if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, Nc, numCIndices, elemMat);CHKERRQ(ierr);}
1751           ierr = MatSetValues(In, Nc, &findices[i*Nc], numCIndices, cindices, elemMat, INSERT_VALUES);CHKERRQ(ierr);
1752           ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell], &numCIndices, &cindices);CHKERRQ(ierr);CHKERRQ(ierr);
1753         }
1754         ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr);
1755         ierr = ISRestoreIndices(coarseCellIS, &coarseCells);CHKERRQ(ierr);
1756         ierr = ISDestroy(&coarseCellIS);CHKERRQ(ierr);
1757         ierr = VecDestroy(&pointVec);CHKERRQ(ierr);
1758       }
1759       ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices);CHKERRQ(ierr);CHKERRQ(ierr);
1760     }
1761   }
1762   ierr = PetscFree3(v0,J,invJ);CHKERRQ(ierr);
1763   ierr = PetscFree3(v0c,Jc,invJc);CHKERRQ(ierr);
1764   ierr = PetscFree(elemMat);CHKERRQ(ierr);
1765   ierr = MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1766   ierr = MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1767   PetscFunctionReturn(0);
1768 }
1769 
1770 #undef __FUNCT__
1771 #define __FUNCT__ "DMPlexComputeInjectorFEM"
1772 PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user)
1773 {
1774   PetscDS        prob;
1775   PetscFE       *feRef;
1776   PetscFV       *fvRef;
1777   Vec            fv, cv;
1778   IS             fis, cis;
1779   PetscSection   fsection, fglobalSection, csection, cglobalSection;
1780   PetscInt      *cmap, *cellCIndices, *cellFIndices, *cindices, *findices;
1781   PetscInt       cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, cEndInterior, c, dim, d, startC, endC, offsetC, offsetF, m;
1782   PetscErrorCode ierr;
1783 
1784   PetscFunctionBegin;
1785   ierr = PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr);
1786   ierr = DMGetDimension(dmf, &dim);CHKERRQ(ierr);
1787   ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);
1788   ierr = DMGetDefaultGlobalSection(dmf, &fglobalSection);CHKERRQ(ierr);
1789   ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);
1790   ierr = DMGetDefaultGlobalSection(dmc, &cglobalSection);CHKERRQ(ierr);
1791   ierr = PetscSectionGetNumFields(fsection, &Nf);CHKERRQ(ierr);
1792   ierr = DMPlexGetHeightStratum(dmc, 0, &cStart, &cEnd);CHKERRQ(ierr);
1793   ierr = DMPlexGetHybridBounds(dmc, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
1794   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1795   ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr);
1796   ierr = PetscCalloc2(Nf,&feRef,Nf,&fvRef);CHKERRQ(ierr);
1797   for (f = 0; f < Nf; ++f) {
1798     PetscObject  obj;
1799     PetscClassId id;
1800     PetscInt     fNb = 0, Nc = 0;
1801 
1802     ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
1803     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
1804     if (id == PETSCFE_CLASSID) {
1805       PetscFE fe = (PetscFE) obj;
1806 
1807       ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr);
1808       ierr = PetscFEGetDimension(feRef[f], &fNb);CHKERRQ(ierr);
1809       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
1810     } else if (id == PETSCFV_CLASSID) {
1811       PetscFV        fv = (PetscFV) obj;
1812       PetscDualSpace Q;
1813 
1814       ierr = PetscFVRefine(fv, &fvRef[f]);CHKERRQ(ierr);
1815       ierr = PetscFVGetDualSpace(fvRef[f], &Q);CHKERRQ(ierr);
1816       ierr = PetscDualSpaceGetDimension(Q, &fNb);CHKERRQ(ierr);
1817       ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
1818     }
1819     fTotDim += fNb*Nc;
1820   }
1821   ierr = PetscDSGetTotalDimension(prob, &cTotDim);CHKERRQ(ierr);
1822   ierr = PetscMalloc1(cTotDim,&cmap);CHKERRQ(ierr);
1823   for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) {
1824     PetscFE        feC;
1825     PetscFV        fvC;
1826     PetscDualSpace QF, QC;
1827     PetscInt       NcF, NcC, fpdim, cpdim;
1828 
1829     if (feRef[field]) {
1830       ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &feC);CHKERRQ(ierr);
1831       ierr = PetscFEGetNumComponents(feC, &NcC);CHKERRQ(ierr);
1832       ierr = PetscFEGetNumComponents(feRef[field], &NcF);CHKERRQ(ierr);
1833       ierr = PetscFEGetDualSpace(feRef[field], &QF);CHKERRQ(ierr);
1834       ierr = PetscDualSpaceGetDimension(QF, &fpdim);CHKERRQ(ierr);
1835       ierr = PetscFEGetDualSpace(feC, &QC);CHKERRQ(ierr);
1836       ierr = PetscDualSpaceGetDimension(QC, &cpdim);CHKERRQ(ierr);
1837     } else {
1838       ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &fvC);CHKERRQ(ierr);
1839       ierr = PetscFVGetNumComponents(fvC, &NcC);CHKERRQ(ierr);
1840       ierr = PetscFVGetNumComponents(fvRef[field], &NcF);CHKERRQ(ierr);
1841       ierr = PetscFVGetDualSpace(fvRef[field], &QF);CHKERRQ(ierr);
1842       ierr = PetscDualSpaceGetDimension(QF, &fpdim);CHKERRQ(ierr);
1843       ierr = PetscFVGetDualSpace(fvC, &QC);CHKERRQ(ierr);
1844       ierr = PetscDualSpaceGetDimension(QC, &cpdim);CHKERRQ(ierr);
1845     }
1846     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);
1847     for (c = 0; c < cpdim; ++c) {
1848       PetscQuadrature  cfunc;
1849       const PetscReal *cqpoints;
1850       PetscInt         NpC;
1851       PetscBool        found = PETSC_FALSE;
1852 
1853       ierr = PetscDualSpaceGetFunctional(QC, c, &cfunc);CHKERRQ(ierr);
1854       ierr = PetscQuadratureGetData(cfunc, NULL, &NpC, &cqpoints, NULL);CHKERRQ(ierr);
1855       if (NpC != 1 && feRef[field]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments");
1856       for (f = 0; f < fpdim; ++f) {
1857         PetscQuadrature  ffunc;
1858         const PetscReal *fqpoints;
1859         PetscReal        sum = 0.0;
1860         PetscInt         NpF, comp;
1861 
1862         ierr = PetscDualSpaceGetFunctional(QF, f, &ffunc);CHKERRQ(ierr);
1863         ierr = PetscQuadratureGetData(ffunc, NULL, &NpF, &fqpoints, NULL);CHKERRQ(ierr);
1864         if (NpC != NpF) continue;
1865         for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
1866         if (sum > 1.0e-9) continue;
1867         for (comp = 0; comp < NcC; ++comp) {
1868           cmap[(offsetC+c)*NcC+comp] = (offsetF+f)*NcF+comp;
1869         }
1870         found = PETSC_TRUE;
1871         break;
1872       }
1873       if (!found) {
1874         /* TODO We really want the average here, but some asshole put VecScatter in the interface */
1875         if (fvRef[field]) {
1876           PetscInt comp;
1877           for (comp = 0; comp < NcC; ++comp) {
1878             cmap[(offsetC+c)*NcC+comp] = (offsetF+0)*NcF+comp;
1879           }
1880         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
1881       }
1882     }
1883     offsetC += cpdim*NcC;
1884     offsetF += fpdim*NcF;
1885   }
1886   for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);ierr = PetscFVDestroy(&fvRef[f]);CHKERRQ(ierr);}
1887   ierr = PetscFree2(feRef,fvRef);CHKERRQ(ierr);
1888 
1889   ierr = DMGetGlobalVector(dmf, &fv);CHKERRQ(ierr);
1890   ierr = DMGetGlobalVector(dmc, &cv);CHKERRQ(ierr);
1891   ierr = VecGetOwnershipRange(cv, &startC, &endC);CHKERRQ(ierr);
1892   ierr = PetscSectionGetConstrainedStorageSize(cglobalSection, &m);CHKERRQ(ierr);
1893   ierr = PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices);CHKERRQ(ierr);
1894   ierr = PetscMalloc1(m,&cindices);CHKERRQ(ierr);
1895   ierr = PetscMalloc1(m,&findices);CHKERRQ(ierr);
1896   for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1;
1897   for (c = cStart; c < cEnd; ++c) {
1898     ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);CHKERRQ(ierr);
1899     for (d = 0; d < cTotDim; ++d) {
1900       if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue;
1901       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]]);
1902       cindices[cellCIndices[d]-startC] = cellCIndices[d];
1903       findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]];
1904     }
1905   }
1906   ierr = PetscFree(cmap);CHKERRQ(ierr);
1907   ierr = PetscFree2(cellCIndices,cellFIndices);CHKERRQ(ierr);
1908 
1909   ierr = ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr);
1910   ierr = ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr);
1911   ierr = VecScatterCreate(cv, cis, fv, fis, sc);CHKERRQ(ierr);
1912   ierr = ISDestroy(&cis);CHKERRQ(ierr);
1913   ierr = ISDestroy(&fis);CHKERRQ(ierr);
1914   ierr = DMRestoreGlobalVector(dmf, &fv);CHKERRQ(ierr);
1915   ierr = DMRestoreGlobalVector(dmc, &cv);CHKERRQ(ierr);
1916   ierr = PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr);
1917   PetscFunctionReturn(0);
1918 }
1919