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