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