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