xref: /petsc/src/dm/impls/plex/plextree.c (revision 4d86920da9ee67c835173a5dfffa1b3a52fd24ca)
1 #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/isimpl.h>
3 #include <petsc/private/petscfeimpl.h>
4 #include <petscsf.h>
5 #include <petscds.h>
6 
7 /* hierarchy routines */
8 
9 /*@
10   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
11 
12   Not Collective
13 
14   Input Parameters:
15 + dm  - The `DMPLEX` object
16 - ref - The reference tree `DMPLEX` object
17 
18   Level: intermediate
19 
20 .seealso: [](ch_unstructured), `DM`, `DMPLEX`,`DMPlexGetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
21 @*/
22 PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
23 {
24   DM_Plex *mesh = (DM_Plex *)dm->data;
25 
26   PetscFunctionBegin;
27   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28   if (ref) PetscValidHeaderSpecific(ref, DM_CLASSID, 2);
29   PetscCall(PetscObjectReference((PetscObject)ref));
30   PetscCall(DMDestroy(&mesh->referenceTree));
31   mesh->referenceTree = ref;
32   PetscFunctionReturn(PETSC_SUCCESS);
33 }
34 
35 /*@
36   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
37 
38   Not Collective
39 
40   Input Parameter:
41 . dm - The `DMPLEX` object
42 
43   Output Parameter:
44 . ref - The reference tree `DMPLEX` object
45 
46   Level: intermediate
47 
48   Developer Notes:
49   The reference tree is shallow copied during `DMClone()`, thus it is may be shared by different `DM`s.
50   It is not a topological-only object, since some parts of the library use its local section to compute
51   interpolation and injection matrices. This may lead to unexpected failures during those calls.
52 
53 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
54 @*/
55 PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
56 {
57   DM_Plex *mesh = (DM_Plex *)dm->data;
58 
59   PetscFunctionBegin;
60   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
61   PetscAssertPointer(ref, 2);
62   *ref = mesh->referenceTree;
63   PetscFunctionReturn(PETSC_SUCCESS);
64 }
65 
66 static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
67 {
68   PetscInt coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
69 
70   PetscFunctionBegin;
71   if (parentOrientA == parentOrientB) {
72     if (childOrientB) *childOrientB = childOrientA;
73     if (childB) *childB = childA;
74     PetscFunctionReturn(PETSC_SUCCESS);
75   }
76   for (dim = 0; dim < 3; dim++) {
77     PetscCall(DMPlexGetDepthStratum(dm, dim, &dStart, &dEnd));
78     if (parent >= dStart && parent <= dEnd) break;
79   }
80   PetscCheck(dim <= 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot perform child symmetry for %" PetscInt_FMT "-cells", dim);
81   PetscCheck(dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "A vertex has no children");
82   if (childA < dStart || childA >= dEnd) {
83     /* this is a lower-dimensional child: bootstrap */
84     PetscInt        size, i, sA = -1, sB, sOrientB, sConeSize;
85     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
86 
87     PetscCall(DMPlexGetSupportSize(dm, childA, &size));
88     PetscCall(DMPlexGetSupport(dm, childA, &supp));
89 
90     /* find a point sA in supp(childA) that has the same parent */
91     for (i = 0; i < size; i++) {
92       PetscInt sParent;
93 
94       sA = supp[i];
95       if (sA == parent) continue;
96       PetscCall(DMPlexGetTreeParent(dm, sA, &sParent, NULL));
97       if (sParent == parent) break;
98     }
99     PetscCheck(i != size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "could not find support in children");
100     /* find out which point sB is in an equivalent position to sA under
101      * parentOrientB */
102     PetscCall(DMPlexReferenceTreeGetChildSymmetry_Default(dm, parent, parentOrientA, 0, sA, parentOrientB, &sOrientB, &sB));
103     PetscCall(DMPlexGetConeSize(dm, sA, &sConeSize));
104     PetscCall(DMPlexGetCone(dm, sA, &coneA));
105     PetscCall(DMPlexGetCone(dm, sB, &coneB));
106     PetscCall(DMPlexGetConeOrientation(dm, sA, &oA));
107     PetscCall(DMPlexGetConeOrientation(dm, sB, &oB));
108     /* step through the cone of sA in natural order */
109     for (i = 0; i < sConeSize; i++) {
110       if (coneA[i] == childA) {
111         /* if childA is at position i in coneA,
112          * then we want the point that is at sOrientB*i in coneB */
113         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize - (sOrientB + 1) - i) % sConeSize);
114         if (childB) *childB = coneB[j];
115         if (childOrientB) {
116           DMPolytopeType ct;
117           PetscInt       oBtrue;
118 
119           PetscCall(DMPlexGetConeSize(dm, childA, &coneSize));
120           /* compose sOrientB and oB[j] */
121           PetscCheck(coneSize == 0 || coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected a vertex or an edge");
122           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
123           /* we may have to flip an edge */
124           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientation(ct, -1, oB[j]);
125           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
126           ABswap        = DihedralSwap(coneSize, DMPolytopeConvertNewOrientation_Internal(ct, oA[i]), oBtrue);
127           *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
128         }
129         break;
130       }
131     }
132     PetscCheck(i != sConeSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "support cone mismatch");
133     PetscFunctionReturn(PETSC_SUCCESS);
134   }
135   /* get the cone size and symmetry swap */
136   PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
137   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
138   if (dim == 2) {
139     /* orientations refer to cones: we want them to refer to vertices:
140      * if it's a rotation, they are the same, but if the order is reversed, a
141      * permutation that puts side i first does *not* put vertex i first */
142     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
143     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
144     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
145   } else {
146     ABswapVert = ABswap;
147   }
148   if (childB) {
149     /* assume that each child corresponds to a vertex, in the same order */
150     PetscInt        p, posA = -1, numChildren, i;
151     const PetscInt *children;
152 
153     /* count which position the child is in */
154     PetscCall(DMPlexGetTreeChildren(dm, parent, &numChildren, &children));
155     for (i = 0; i < numChildren; i++) {
156       p = children[i];
157       if (p == childA) {
158         posA = i;
159         break;
160       }
161     }
162     if (posA >= coneSize) {
163       /* this is the triangle in the middle of a uniformly refined triangle: it
164        * is invariant */
165       PetscCheck(dim == 2 && posA == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Expected a middle triangle, got something else");
166       *childB = childA;
167     } else {
168       /* figure out position B by applying ABswapVert */
169       PetscInt posB;
170 
171       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize - (ABswapVert + 1) - posA) % coneSize);
172       if (childB) *childB = children[posB];
173     }
174   }
175   if (childOrientB) *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
176   PetscFunctionReturn(PETSC_SUCCESS);
177 }
178 
179 /*@
180   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
181 
182   Input Parameters:
183 + dm            - the reference tree `DMPLEX` object
184 . parent        - the parent point
185 . parentOrientA - the reference orientation for describing the parent
186 . childOrientA  - the reference orientation for describing the child
187 . childA        - the reference childID for describing the child
188 - parentOrientB - the new orientation for describing the parent
189 
190   Output Parameters:
191 + childOrientB - if not `NULL`, set to the new orientation for describing the child
192 - childB       - if not `NULL`, the new childID for describing the child
193 
194   Level: developer
195 
196 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetReferenceTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetTree()`
197 @*/
198 PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
199 {
200   DM_Plex *mesh = (DM_Plex *)dm->data;
201 
202   PetscFunctionBegin;
203   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
204   PetscCheck(mesh->getchildsymmetry, PETSC_COMM_SELF, PETSC_ERR_SUP, "DMPlexReferenceTreeGetChildSymmetry not implemented");
205   PetscCall(mesh->getchildsymmetry(dm, parent, parentOrientA, childOrientA, childA, parentOrientB, childOrientB, childB));
206   PetscFunctionReturn(PETSC_SUCCESS);
207 }
208 
209 static PetscErrorCode DMPlexSetTree_Internal(DM, PetscSection, PetscInt *, PetscInt *, PetscBool, PetscBool);
210 
211 PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
212 {
213   PetscFunctionBegin;
214   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_TRUE, PETSC_FALSE));
215   PetscFunctionReturn(PETSC_SUCCESS);
216 }
217 
218 PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
219 {
220   MPI_Comm     comm;
221   PetscInt     dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
222   PetscInt    *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
223   DMLabel      identity, identityRef;
224   PetscSection unionSection, unionConeSection, parentSection;
225   PetscScalar *unionCoords;
226   IS           perm;
227 
228   PetscFunctionBegin;
229   comm = PetscObjectComm((PetscObject)K);
230   PetscCall(DMGetDimension(K, &dim));
231   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
232   PetscCall(DMGetLabel(K, labelName, &identity));
233   PetscCall(DMGetLabel(Kref, labelName, &identityRef));
234   PetscCall(DMPlexGetChart(Kref, &pRefStart, &pRefEnd));
235   PetscCall(PetscSectionCreate(comm, &unionSection));
236   PetscCall(PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart)));
237   /* count points that will go in the union */
238   for (p = pStart; p < pEnd; p++) PetscCall(PetscSectionSetDof(unionSection, p - pStart, 1));
239   for (p = pRefStart; p < pRefEnd; p++) {
240     PetscInt q, qSize;
241     PetscCall(DMLabelGetValue(identityRef, p, &q));
242     PetscCall(DMLabelGetStratumSize(identityRef, q, &qSize));
243     if (qSize > 1) PetscCall(PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1));
244   }
245   PetscCall(PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart, &permvals));
246   offset = 0;
247   /* stratify points in the union by topological dimension */
248   for (d = 0; d <= dim; d++) {
249     PetscInt cStart, cEnd, c;
250 
251     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, &cEnd));
252     for (c = cStart; c < cEnd; c++) permvals[offset++] = c;
253 
254     PetscCall(DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd));
255     for (c = cStart; c < cEnd; c++) permvals[offset++] = c + (pEnd - pStart);
256   }
257   PetscCall(ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm));
258   PetscCall(PetscSectionSetPermutation(unionSection, perm));
259   PetscCall(PetscSectionSetUp(unionSection));
260   PetscCall(PetscSectionGetStorageSize(unionSection, &numUnionPoints));
261   PetscCall(PetscMalloc2(numUnionPoints, &coneSizes, dim + 1, &numDimPoints));
262   /* count dimension points */
263   for (d = 0; d <= dim; d++) {
264     PetscInt cStart, cOff, cOff2;
265     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, NULL));
266     PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff));
267     if (d < dim) {
268       PetscCall(DMPlexGetHeightStratum(K, d + 1, &cStart, NULL));
269       PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff2));
270     } else {
271       cOff2 = numUnionPoints;
272     }
273     numDimPoints[dim - d] = cOff2 - cOff;
274   }
275   PetscCall(PetscSectionCreate(comm, &unionConeSection));
276   PetscCall(PetscSectionSetChart(unionConeSection, 0, numUnionPoints));
277   /* count the cones in the union */
278   for (p = pStart; p < pEnd; p++) {
279     PetscInt dof, uOff;
280 
281     PetscCall(DMPlexGetConeSize(K, p, &dof));
282     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
283     PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
284     coneSizes[uOff] = dof;
285   }
286   for (p = pRefStart; p < pRefEnd; p++) {
287     PetscInt dof, uDof, uOff;
288 
289     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
290     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
291     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
292     if (uDof) {
293       PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
294       coneSizes[uOff] = dof;
295     }
296   }
297   PetscCall(PetscSectionSetUp(unionConeSection));
298   PetscCall(PetscSectionGetStorageSize(unionConeSection, &numCones));
299   PetscCall(PetscMalloc2(numCones, &unionCones, numCones, &unionOrientations));
300   /* write the cones in the union */
301   for (p = pStart; p < pEnd; p++) {
302     PetscInt        dof, uOff, c, cOff;
303     const PetscInt *cone, *orientation;
304 
305     PetscCall(DMPlexGetConeSize(K, p, &dof));
306     PetscCall(DMPlexGetCone(K, p, &cone));
307     PetscCall(DMPlexGetConeOrientation(K, p, &orientation));
308     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
309     PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
310     for (c = 0; c < dof; c++) {
311       PetscInt e, eOff;
312       e = cone[c];
313       PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
314       unionCones[cOff + c]        = eOff;
315       unionOrientations[cOff + c] = orientation[c];
316     }
317   }
318   for (p = pRefStart; p < pRefEnd; p++) {
319     PetscInt        dof, uDof, uOff, c, cOff;
320     const PetscInt *cone, *orientation;
321 
322     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
323     PetscCall(DMPlexGetCone(Kref, p, &cone));
324     PetscCall(DMPlexGetConeOrientation(Kref, p, &orientation));
325     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
326     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
327     if (uDof) {
328       PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
329       for (c = 0; c < dof; c++) {
330         PetscInt e, eOff, eDof;
331 
332         e = cone[c];
333         PetscCall(PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart), &eDof));
334         if (eDof) {
335           PetscCall(PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff));
336         } else {
337           PetscCall(DMLabelGetValue(identityRef, e, &e));
338           PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
339         }
340         unionCones[cOff + c]        = eOff;
341         unionOrientations[cOff + c] = orientation[c];
342       }
343     }
344   }
345   /* get the coordinates */
346   {
347     PetscInt     vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
348     PetscSection KcoordsSec, KrefCoordsSec;
349     Vec          KcoordsVec, KrefCoordsVec;
350     PetscScalar *Kcoords;
351 
352     PetscCall(DMGetCoordinateSection(K, &KcoordsSec));
353     PetscCall(DMGetCoordinatesLocal(K, &KcoordsVec));
354     PetscCall(DMGetCoordinateSection(Kref, &KrefCoordsSec));
355     PetscCall(DMGetCoordinatesLocal(Kref, &KrefCoordsVec));
356 
357     numVerts = numDimPoints[0];
358     PetscCall(PetscMalloc1(numVerts * dim, &unionCoords));
359     PetscCall(DMPlexGetDepthStratum(K, 0, &vStart, &vEnd));
360 
361     offset = 0;
362     for (v = vStart; v < vEnd; v++) {
363       PetscCall(PetscSectionGetOffset(unionSection, v - pStart, &vOff));
364       PetscCall(VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords));
365       for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
366       offset++;
367     }
368     PetscCall(DMPlexGetDepthStratum(Kref, 0, &vRefStart, &vRefEnd));
369     for (v = vRefStart; v < vRefEnd; v++) {
370       PetscCall(PetscSectionGetDof(unionSection, v - pRefStart + (pEnd - pStart), &vDof));
371       PetscCall(PetscSectionGetOffset(unionSection, v - pRefStart + (pEnd - pStart), &vOff));
372       PetscCall(VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords));
373       if (vDof) {
374         for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
375         offset++;
376       }
377     }
378   }
379   PetscCall(DMCreate(comm, ref));
380   PetscCall(DMSetType(*ref, DMPLEX));
381   PetscCall(DMSetDimension(*ref, dim));
382   PetscCall(DMPlexCreateFromDAG(*ref, dim, numDimPoints, coneSizes, unionCones, unionOrientations, unionCoords));
383   /* set the tree */
384   PetscCall(PetscSectionCreate(comm, &parentSection));
385   PetscCall(PetscSectionSetChart(parentSection, 0, numUnionPoints));
386   for (p = pRefStart; p < pRefEnd; p++) {
387     PetscInt uDof, uOff;
388 
389     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
390     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
391     if (uDof) PetscCall(PetscSectionSetDof(parentSection, uOff, 1));
392   }
393   PetscCall(PetscSectionSetUp(parentSection));
394   PetscCall(PetscSectionGetStorageSize(parentSection, &parentSize));
395   PetscCall(PetscMalloc2(parentSize, &parents, parentSize, &childIDs));
396   for (p = pRefStart; p < pRefEnd; p++) {
397     PetscInt uDof, uOff;
398 
399     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
400     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
401     if (uDof) {
402       PetscInt pOff, parent, parentU;
403       PetscCall(PetscSectionGetOffset(parentSection, uOff, &pOff));
404       PetscCall(DMLabelGetValue(identityRef, p, &parent));
405       PetscCall(PetscSectionGetOffset(unionSection, parent - pStart, &parentU));
406       parents[pOff]  = parentU;
407       childIDs[pOff] = uOff;
408     }
409   }
410   PetscCall(DMPlexCreateReferenceTree_SetTree(*ref, parentSection, parents, childIDs));
411   PetscCall(PetscSectionDestroy(&parentSection));
412   PetscCall(PetscFree2(parents, childIDs));
413 
414   /* clean up */
415   PetscCall(PetscSectionDestroy(&unionSection));
416   PetscCall(PetscSectionDestroy(&unionConeSection));
417   PetscCall(ISDestroy(&perm));
418   PetscCall(PetscFree(unionCoords));
419   PetscCall(PetscFree2(unionCones, unionOrientations));
420   PetscCall(PetscFree2(coneSizes, numDimPoints));
421   PetscFunctionReturn(PETSC_SUCCESS);
422 }
423 
424 /*@
425   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
426 
427   Collective
428 
429   Input Parameters:
430 + comm    - the MPI communicator
431 . dim     - the spatial dimension
432 - simplex - Flag for simplex, otherwise use a tensor-product cell
433 
434   Output Parameter:
435 . ref - the reference tree `DMPLEX` object
436 
437   Level: intermediate
438 
439 .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`
440 @*/
441 PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
442 {
443   DM_Plex *mesh;
444   DM       K, Kref;
445   PetscInt p, pStart, pEnd;
446   DMLabel  identity;
447 
448   PetscFunctionBegin;
449 #if 1
450   comm = PETSC_COMM_SELF;
451 #endif
452   /* create a reference element */
453   PetscCall(DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K));
454   PetscCall(DMCreateLabel(K, "identity"));
455   PetscCall(DMGetLabel(K, "identity", &identity));
456   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
457   for (p = pStart; p < pEnd; p++) PetscCall(DMLabelSetValue(identity, p, p));
458   /* refine it */
459   PetscCall(DMRefine(K, comm, &Kref));
460 
461   /* the reference tree is the union of these two, without duplicating
462    * points that appear in both */
463   PetscCall(DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref));
464   mesh                   = (DM_Plex *)(*ref)->data;
465   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
466   PetscCall(DMDestroy(&K));
467   PetscCall(DMDestroy(&Kref));
468   PetscFunctionReturn(PETSC_SUCCESS);
469 }
470 
471 static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
472 {
473   DM_Plex     *mesh = (DM_Plex *)dm->data;
474   PetscSection childSec, pSec;
475   PetscInt     p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
476   PetscInt    *offsets, *children, pStart, pEnd;
477 
478   PetscFunctionBegin;
479   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
480   PetscCall(PetscSectionDestroy(&mesh->childSection));
481   PetscCall(PetscFree(mesh->children));
482   pSec = mesh->parentSection;
483   if (!pSec) PetscFunctionReturn(PETSC_SUCCESS);
484   PetscCall(PetscSectionGetStorageSize(pSec, &pSize));
485   for (p = 0; p < pSize; p++) {
486     PetscInt par = mesh->parents[p];
487 
488     parMax = PetscMax(parMax, par + 1);
489     parMin = PetscMin(parMin, par);
490   }
491   if (parMin > parMax) {
492     parMin = -1;
493     parMax = -1;
494   }
495   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)pSec), &childSec));
496   PetscCall(PetscSectionSetChart(childSec, parMin, parMax));
497   for (p = 0; p < pSize; p++) {
498     PetscInt par = mesh->parents[p];
499 
500     PetscCall(PetscSectionAddDof(childSec, par, 1));
501   }
502   PetscCall(PetscSectionSetUp(childSec));
503   PetscCall(PetscSectionGetStorageSize(childSec, &cSize));
504   PetscCall(PetscMalloc1(cSize, &children));
505   PetscCall(PetscCalloc1(parMax - parMin, &offsets));
506   PetscCall(PetscSectionGetChart(pSec, &pStart, &pEnd));
507   for (p = pStart; p < pEnd; p++) {
508     PetscInt dof, off, i;
509 
510     PetscCall(PetscSectionGetDof(pSec, p, &dof));
511     PetscCall(PetscSectionGetOffset(pSec, p, &off));
512     for (i = 0; i < dof; i++) {
513       PetscInt par = mesh->parents[off + i], cOff;
514 
515       PetscCall(PetscSectionGetOffset(childSec, par, &cOff));
516       children[cOff + offsets[par - parMin]++] = p;
517     }
518   }
519   mesh->childSection = childSec;
520   mesh->children     = children;
521   PetscCall(PetscFree(offsets));
522   PetscFunctionReturn(PETSC_SUCCESS);
523 }
524 
525 static PetscErrorCode AnchorsFlatten(PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
526 {
527   PetscInt        pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
528   const PetscInt *vals;
529   PetscSection    secNew;
530   PetscBool       anyNew, globalAnyNew;
531   PetscBool       compress;
532 
533   PetscFunctionBegin;
534   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
535   PetscCall(ISGetLocalSize(is, &size));
536   PetscCall(ISGetIndices(is, &vals));
537   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secNew));
538   PetscCall(PetscSectionSetChart(secNew, pStart, pEnd));
539   for (i = 0; i < size; i++) {
540     PetscInt dof;
541 
542     p = vals[i];
543     if (p < pStart || p >= pEnd) continue;
544     PetscCall(PetscSectionGetDof(section, p, &dof));
545     if (dof) break;
546   }
547   if (i == size) {
548     PetscCall(PetscSectionSetUp(secNew));
549     anyNew   = PETSC_FALSE;
550     compress = PETSC_FALSE;
551     sizeNew  = 0;
552   } else {
553     anyNew = PETSC_TRUE;
554     for (p = pStart; p < pEnd; p++) {
555       PetscInt dof, off;
556 
557       PetscCall(PetscSectionGetDof(section, p, &dof));
558       PetscCall(PetscSectionGetOffset(section, p, &off));
559       for (i = 0; i < dof; i++) {
560         PetscInt q = vals[off + i], qDof = 0;
561 
562         if (q >= pStart && q < pEnd) PetscCall(PetscSectionGetDof(section, q, &qDof));
563         if (qDof) PetscCall(PetscSectionAddDof(secNew, p, qDof));
564         else PetscCall(PetscSectionAddDof(secNew, p, 1));
565       }
566     }
567     PetscCall(PetscSectionSetUp(secNew));
568     PetscCall(PetscSectionGetStorageSize(secNew, &sizeNew));
569     PetscCall(PetscMalloc1(sizeNew, &valsNew));
570     compress = PETSC_FALSE;
571     for (p = pStart; p < pEnd; p++) {
572       PetscInt dof, off, count, offNew, dofNew;
573 
574       PetscCall(PetscSectionGetDof(section, p, &dof));
575       PetscCall(PetscSectionGetOffset(section, p, &off));
576       PetscCall(PetscSectionGetDof(secNew, p, &dofNew));
577       PetscCall(PetscSectionGetOffset(secNew, p, &offNew));
578       count = 0;
579       for (i = 0; i < dof; i++) {
580         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
581 
582         if (q >= pStart && q < pEnd) {
583           PetscCall(PetscSectionGetDof(section, q, &qDof));
584           PetscCall(PetscSectionGetOffset(section, q, &qOff));
585         }
586         if (qDof) {
587           PetscInt oldCount = count;
588 
589           for (j = 0; j < qDof; j++) {
590             PetscInt k, r = vals[qOff + j];
591 
592             for (k = 0; k < oldCount; k++) {
593               if (valsNew[offNew + k] == r) break;
594             }
595             if (k == oldCount) valsNew[offNew + count++] = r;
596           }
597         } else {
598           PetscInt k, oldCount = count;
599 
600           for (k = 0; k < oldCount; k++) {
601             if (valsNew[offNew + k] == q) break;
602           }
603           if (k == oldCount) valsNew[offNew + count++] = q;
604         }
605       }
606       if (count < dofNew) {
607         PetscCall(PetscSectionSetDof(secNew, p, count));
608         compress = PETSC_TRUE;
609       }
610     }
611   }
612   PetscCall(ISRestoreIndices(is, &vals));
613   PetscCall(MPIU_Allreduce(&anyNew, &globalAnyNew, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
614   if (!globalAnyNew) {
615     PetscCall(PetscSectionDestroy(&secNew));
616     *sectionNew = NULL;
617     *isNew      = NULL;
618   } else {
619     PetscBool globalCompress;
620 
621     PetscCall(MPIU_Allreduce(&compress, &globalCompress, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
622     if (compress) {
623       PetscSection secComp;
624       PetscInt    *valsComp = NULL;
625 
626       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secComp));
627       PetscCall(PetscSectionSetChart(secComp, pStart, pEnd));
628       for (p = pStart; p < pEnd; p++) {
629         PetscInt dof;
630 
631         PetscCall(PetscSectionGetDof(secNew, p, &dof));
632         PetscCall(PetscSectionSetDof(secComp, p, dof));
633       }
634       PetscCall(PetscSectionSetUp(secComp));
635       PetscCall(PetscSectionGetStorageSize(secComp, &sizeNew));
636       PetscCall(PetscMalloc1(sizeNew, &valsComp));
637       for (p = pStart; p < pEnd; p++) {
638         PetscInt dof, off, offNew, j;
639 
640         PetscCall(PetscSectionGetDof(secNew, p, &dof));
641         PetscCall(PetscSectionGetOffset(secNew, p, &off));
642         PetscCall(PetscSectionGetOffset(secComp, p, &offNew));
643         for (j = 0; j < dof; j++) valsComp[offNew + j] = valsNew[off + j];
644       }
645       PetscCall(PetscSectionDestroy(&secNew));
646       secNew = secComp;
647       PetscCall(PetscFree(valsNew));
648       valsNew = valsComp;
649     }
650     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), sizeNew, valsNew, PETSC_OWN_POINTER, isNew));
651   }
652   PetscFunctionReturn(PETSC_SUCCESS);
653 }
654 
655 static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
656 {
657   PetscInt     p, pStart, pEnd, *anchors, size;
658   PetscInt     aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
659   PetscSection aSec;
660   DMLabel      canonLabel;
661   IS           aIS;
662 
663   PetscFunctionBegin;
664   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
665   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
666   PetscCall(DMGetLabel(dm, "canonical", &canonLabel));
667   for (p = pStart; p < pEnd; p++) {
668     PetscInt parent;
669 
670     if (canonLabel) {
671       PetscInt canon;
672 
673       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
674       if (p != canon) continue;
675     }
676     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
677     if (parent != p) {
678       aMin = PetscMin(aMin, p);
679       aMax = PetscMax(aMax, p + 1);
680     }
681   }
682   if (aMin > aMax) {
683     aMin = -1;
684     aMax = -1;
685   }
686   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &aSec));
687   PetscCall(PetscSectionSetChart(aSec, aMin, aMax));
688   for (p = aMin; p < aMax; p++) {
689     PetscInt parent, ancestor = p;
690 
691     if (canonLabel) {
692       PetscInt canon;
693 
694       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
695       if (p != canon) continue;
696     }
697     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
698     while (parent != ancestor) {
699       ancestor = parent;
700       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
701     }
702     if (ancestor != p) {
703       PetscInt closureSize, *closure = NULL;
704 
705       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
706       PetscCall(PetscSectionSetDof(aSec, p, closureSize));
707       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
708     }
709   }
710   PetscCall(PetscSectionSetUp(aSec));
711   PetscCall(PetscSectionGetStorageSize(aSec, &size));
712   PetscCall(PetscMalloc1(size, &anchors));
713   for (p = aMin; p < aMax; p++) {
714     PetscInt parent, ancestor = p;
715 
716     if (canonLabel) {
717       PetscInt canon;
718 
719       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
720       if (p != canon) continue;
721     }
722     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
723     while (parent != ancestor) {
724       ancestor = parent;
725       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
726     }
727     if (ancestor != p) {
728       PetscInt j, closureSize, *closure = NULL, aOff;
729 
730       PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
731 
732       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
733       for (j = 0; j < closureSize; j++) anchors[aOff + j] = closure[2 * j];
734       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
735     }
736   }
737   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, anchors, PETSC_OWN_POINTER, &aIS));
738   {
739     PetscSection aSecNew = aSec;
740     IS           aISNew  = aIS;
741 
742     PetscCall(PetscObjectReference((PetscObject)aSec));
743     PetscCall(PetscObjectReference((PetscObject)aIS));
744     while (aSecNew) {
745       PetscCall(PetscSectionDestroy(&aSec));
746       PetscCall(ISDestroy(&aIS));
747       aSec    = aSecNew;
748       aIS     = aISNew;
749       aSecNew = NULL;
750       aISNew  = NULL;
751       PetscCall(AnchorsFlatten(aSec, aIS, &aSecNew, &aISNew));
752     }
753   }
754   PetscCall(DMPlexSetAnchors(dm, aSec, aIS));
755   PetscCall(PetscSectionDestroy(&aSec));
756   PetscCall(ISDestroy(&aIS));
757   PetscFunctionReturn(PETSC_SUCCESS);
758 }
759 
760 static PetscErrorCode DMPlexGetTrueSupportSize(DM dm, PetscInt p, PetscInt *dof, PetscInt *numTrueSupp)
761 {
762   PetscFunctionBegin;
763   if (numTrueSupp[p] == -1) {
764     PetscInt        i, alldof;
765     const PetscInt *supp;
766     PetscInt        count = 0;
767 
768     PetscCall(DMPlexGetSupportSize(dm, p, &alldof));
769     PetscCall(DMPlexGetSupport(dm, p, &supp));
770     for (i = 0; i < alldof; i++) {
771       PetscInt        q = supp[i], numCones, j;
772       const PetscInt *cone;
773 
774       PetscCall(DMPlexGetConeSize(dm, q, &numCones));
775       PetscCall(DMPlexGetCone(dm, q, &cone));
776       for (j = 0; j < numCones; j++) {
777         if (cone[j] == p) break;
778       }
779       if (j < numCones) count++;
780     }
781     numTrueSupp[p] = count;
782   }
783   *dof = numTrueSupp[p];
784   PetscFunctionReturn(PETSC_SUCCESS);
785 }
786 
787 static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
788 {
789   DM_Plex     *mesh = (DM_Plex *)dm->data;
790   PetscSection newSupportSection;
791   PetscInt     newSize, *newSupports, pStart, pEnd, p, d, depth;
792   PetscInt    *numTrueSupp;
793   PetscInt    *offsets;
794 
795   PetscFunctionBegin;
796   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
797   /* symmetrize the hierarchy */
798   PetscCall(DMPlexGetDepth(dm, &depth));
799   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)), &newSupportSection));
800   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
801   PetscCall(PetscSectionSetChart(newSupportSection, pStart, pEnd));
802   PetscCall(PetscCalloc1(pEnd, &offsets));
803   PetscCall(PetscMalloc1(pEnd, &numTrueSupp));
804   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
805   /* if a point is in the (true) support of q, it should be in the support of
806    * parent(q) */
807   for (d = 0; d <= depth; d++) {
808     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
809     for (p = pStart; p < pEnd; ++p) {
810       PetscInt dof, q, qdof, parent;
811 
812       PetscCall(DMPlexGetTrueSupportSize(dm, p, &dof, numTrueSupp));
813       PetscCall(PetscSectionAddDof(newSupportSection, p, dof));
814       q = p;
815       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
816       while (parent != q && parent >= pStart && parent < pEnd) {
817         q = parent;
818 
819         PetscCall(DMPlexGetTrueSupportSize(dm, q, &qdof, numTrueSupp));
820         PetscCall(PetscSectionAddDof(newSupportSection, p, qdof));
821         PetscCall(PetscSectionAddDof(newSupportSection, q, dof));
822         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
823       }
824     }
825   }
826   PetscCall(PetscSectionSetUp(newSupportSection));
827   PetscCall(PetscSectionGetStorageSize(newSupportSection, &newSize));
828   PetscCall(PetscMalloc1(newSize, &newSupports));
829   for (d = 0; d <= depth; d++) {
830     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
831     for (p = pStart; p < pEnd; p++) {
832       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
833 
834       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
835       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
836       PetscCall(PetscSectionGetDof(newSupportSection, p, &newDof));
837       PetscCall(PetscSectionGetOffset(newSupportSection, p, &newOff));
838       for (i = 0; i < dof; i++) {
839         PetscInt        numCones, j;
840         const PetscInt *cone;
841         PetscInt        q = mesh->supports[off + i];
842 
843         PetscCall(DMPlexGetConeSize(dm, q, &numCones));
844         PetscCall(DMPlexGetCone(dm, q, &cone));
845         for (j = 0; j < numCones; j++) {
846           if (cone[j] == p) break;
847         }
848         if (j < numCones) newSupports[newOff + offsets[p]++] = q;
849       }
850 
851       q = p;
852       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
853       while (parent != q && parent >= pStart && parent < pEnd) {
854         q = parent;
855         PetscCall(PetscSectionGetDof(mesh->supportSection, q, &qdof));
856         PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &qoff));
857         PetscCall(PetscSectionGetOffset(newSupportSection, q, &newqOff));
858         for (i = 0; i < qdof; i++) {
859           PetscInt        numCones, j;
860           const PetscInt *cone;
861           PetscInt        r = mesh->supports[qoff + i];
862 
863           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
864           PetscCall(DMPlexGetCone(dm, r, &cone));
865           for (j = 0; j < numCones; j++) {
866             if (cone[j] == q) break;
867           }
868           if (j < numCones) newSupports[newOff + offsets[p]++] = r;
869         }
870         for (i = 0; i < dof; i++) {
871           PetscInt        numCones, j;
872           const PetscInt *cone;
873           PetscInt        r = mesh->supports[off + i];
874 
875           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
876           PetscCall(DMPlexGetCone(dm, r, &cone));
877           for (j = 0; j < numCones; j++) {
878             if (cone[j] == p) break;
879           }
880           if (j < numCones) newSupports[newqOff + offsets[q]++] = r;
881         }
882         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
883       }
884     }
885   }
886   PetscCall(PetscSectionDestroy(&mesh->supportSection));
887   mesh->supportSection = newSupportSection;
888   PetscCall(PetscFree(mesh->supports));
889   mesh->supports = newSupports;
890   PetscCall(PetscFree(offsets));
891   PetscCall(PetscFree(numTrueSupp));
892   PetscFunctionReturn(PETSC_SUCCESS);
893 }
894 
895 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM, PetscSection, PetscSection, Mat);
896 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM, PetscSection, PetscSection, Mat);
897 
898 static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
899 {
900   DM_Plex *mesh = (DM_Plex *)dm->data;
901   DM       refTree;
902   PetscInt size;
903 
904   PetscFunctionBegin;
905   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
906   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
907   PetscCall(PetscObjectReference((PetscObject)parentSection));
908   PetscCall(PetscSectionDestroy(&mesh->parentSection));
909   mesh->parentSection = parentSection;
910   PetscCall(PetscSectionGetStorageSize(parentSection, &size));
911   if (parents != mesh->parents) {
912     PetscCall(PetscFree(mesh->parents));
913     PetscCall(PetscMalloc1(size, &mesh->parents));
914     PetscCall(PetscArraycpy(mesh->parents, parents, size));
915   }
916   if (childIDs != mesh->childIDs) {
917     PetscCall(PetscFree(mesh->childIDs));
918     PetscCall(PetscMalloc1(size, &mesh->childIDs));
919     PetscCall(PetscArraycpy(mesh->childIDs, childIDs, size));
920   }
921   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
922   if (refTree) {
923     DMLabel canonLabel;
924 
925     PetscCall(DMGetLabel(refTree, "canonical", &canonLabel));
926     if (canonLabel) {
927       PetscInt i;
928 
929       for (i = 0; i < size; i++) {
930         PetscInt canon;
931         PetscCall(DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon));
932         if (canon >= 0) mesh->childIDs[i] = canon;
933       }
934     }
935     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
936   } else {
937     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
938   }
939   PetscCall(DMPlexTreeSymmetrize(dm));
940   if (computeCanonical) {
941     PetscInt d, dim;
942 
943     /* add the canonical label */
944     PetscCall(DMGetDimension(dm, &dim));
945     PetscCall(DMCreateLabel(dm, "canonical"));
946     for (d = 0; d <= dim; d++) {
947       PetscInt        p, dStart, dEnd, canon = -1, cNumChildren;
948       const PetscInt *cChildren;
949 
950       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
951       for (p = dStart; p < dEnd; p++) {
952         PetscCall(DMPlexGetTreeChildren(dm, p, &cNumChildren, &cChildren));
953         if (cNumChildren) {
954           canon = p;
955           break;
956         }
957       }
958       if (canon == -1) continue;
959       for (p = dStart; p < dEnd; p++) {
960         PetscInt        numChildren, i;
961         const PetscInt *children;
962 
963         PetscCall(DMPlexGetTreeChildren(dm, p, &numChildren, &children));
964         if (numChildren) {
965           PetscCheck(numChildren == cNumChildren, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "All parent points in a stratum should have the same number of children: %" PetscInt_FMT " != %" PetscInt_FMT, numChildren, cNumChildren);
966           PetscCall(DMSetLabelValue(dm, "canonical", p, canon));
967           for (i = 0; i < numChildren; i++) PetscCall(DMSetLabelValue(dm, "canonical", children[i], cChildren[i]));
968         }
969       }
970     }
971   }
972   if (exchangeSupports) PetscCall(DMPlexTreeExchangeSupports(dm));
973   mesh->createanchors = DMPlexCreateAnchors_Tree;
974   /* reset anchors */
975   PetscCall(DMPlexSetAnchors(dm, NULL, NULL));
976   PetscFunctionReturn(PETSC_SUCCESS);
977 }
978 
979 /*@
980   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
981   the point-to-point constraints determined by the tree: a point is constrained to the points in the closure of its
982   tree root.
983 
984   Collective
985 
986   Input Parameters:
987 + dm            - the `DMPLEX` object
988 . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
989                   offset indexes the parent and childID list; the reference count of parentSection is incremented
990 . parents       - a list of the point parents; copied, can be destroyed
991 - childIDs      - identifies the relationship of the child point to the parent point; if there is a reference tree, then
992              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
993 
994   Level: intermediate
995 
996 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
997 @*/
998 PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
999 {
1000   PetscFunctionBegin;
1001   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_FALSE, PETSC_TRUE));
1002   PetscFunctionReturn(PETSC_SUCCESS);
1003 }
1004 
1005 /*@
1006   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1007   Collective
1008 
1009   Input Parameter:
1010 . dm - the `DMPLEX` object
1011 
1012   Output Parameters:
1013 + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1014                   offset indexes the parent and childID list
1015 . parents       - a list of the point parents
1016 . childIDs      - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1017              the child corresponds to the point in the reference tree with index childID
1018 . childSection  - the inverse of the parent section
1019 - children      - a list of the point children
1020 
1021   Level: intermediate
1022 
1023 .seealso: [](ch_unstructured), `DM`, `DMPLEX`,`DMPlexSetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
1024 @*/
1025 PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1026 {
1027   DM_Plex *mesh = (DM_Plex *)dm->data;
1028 
1029   PetscFunctionBegin;
1030   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1031   if (parentSection) *parentSection = mesh->parentSection;
1032   if (parents) *parents = mesh->parents;
1033   if (childIDs) *childIDs = mesh->childIDs;
1034   if (childSection) *childSection = mesh->childSection;
1035   if (children) *children = mesh->children;
1036   PetscFunctionReturn(PETSC_SUCCESS);
1037 }
1038 
1039 /*@
1040   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)
1041 
1042   Input Parameters:
1043 + dm    - the `DMPLEX` object
1044 - point - the query point
1045 
1046   Output Parameters:
1047 + parent  - if not `NULL`, set to the parent of the point, or the point itself if the point does not have a parent
1048 - childID - if not `NULL`, set to the child ID of the point with respect to its parent, or 0 if the point
1049             does not have a parent
1050 
1051   Level: intermediate
1052 
1053 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeChildren()`
1054 @*/
1055 PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1056 {
1057   DM_Plex     *mesh = (DM_Plex *)dm->data;
1058   PetscSection pSec;
1059 
1060   PetscFunctionBegin;
1061   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1062   pSec = mesh->parentSection;
1063   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1064     PetscInt dof;
1065 
1066     PetscCall(PetscSectionGetDof(pSec, point, &dof));
1067     if (dof) {
1068       PetscInt off;
1069 
1070       PetscCall(PetscSectionGetOffset(pSec, point, &off));
1071       if (parent) *parent = mesh->parents[off];
1072       if (childID) *childID = mesh->childIDs[off];
1073       PetscFunctionReturn(PETSC_SUCCESS);
1074     }
1075   }
1076   if (parent) *parent = point;
1077   if (childID) *childID = 0;
1078   PetscFunctionReturn(PETSC_SUCCESS);
1079 }
1080 
1081 /*@C
1082   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)
1083 
1084   Input Parameters:
1085 + dm    - the `DMPLEX` object
1086 - point - the query point
1087 
1088   Output Parameters:
1089 + numChildren - if not `NULL`, set to the number of children
1090 - children    - if not `NULL`, set to a list children, or set to `NULL` if the point has no children
1091 
1092   Level: intermediate
1093 
1094 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeParent()`
1095 @*/
1096 PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1097 {
1098   DM_Plex     *mesh = (DM_Plex *)dm->data;
1099   PetscSection childSec;
1100   PetscInt     dof = 0;
1101 
1102   PetscFunctionBegin;
1103   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1104   childSec = mesh->childSection;
1105   if (childSec && point >= childSec->pStart && point < childSec->pEnd) PetscCall(PetscSectionGetDof(childSec, point, &dof));
1106   if (numChildren) *numChildren = dof;
1107   if (children) {
1108     if (dof) {
1109       PetscInt off;
1110 
1111       PetscCall(PetscSectionGetOffset(childSec, point, &off));
1112       *children = &mesh->children[off];
1113     } else {
1114       *children = NULL;
1115     }
1116   }
1117   PetscFunctionReturn(PETSC_SUCCESS);
1118 }
1119 
1120 static PetscErrorCode EvaluateBasis(PetscSpace space, PetscInt nBasis, PetscInt nFunctionals, PetscInt nComps, PetscInt nPoints, const PetscInt *pointsPerFn, const PetscReal *points, const PetscReal *weights, PetscReal *work, Mat basisAtPoints)
1121 {
1122   PetscInt f, b, p, c, offset, qPoints;
1123 
1124   PetscFunctionBegin;
1125   PetscCall(PetscSpaceEvaluate(space, nPoints, points, work, NULL, NULL));
1126   for (f = 0, offset = 0; f < nFunctionals; f++) {
1127     qPoints = pointsPerFn[f];
1128     for (b = 0; b < nBasis; b++) {
1129       PetscScalar val = 0.;
1130 
1131       for (p = 0; p < qPoints; p++) {
1132         for (c = 0; c < nComps; c++) val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
1133       }
1134       PetscCall(MatSetValue(basisAtPoints, b, f, val, INSERT_VALUES));
1135     }
1136     offset += qPoints;
1137   }
1138   PetscCall(MatAssemblyBegin(basisAtPoints, MAT_FINAL_ASSEMBLY));
1139   PetscCall(MatAssemblyEnd(basisAtPoints, MAT_FINAL_ASSEMBLY));
1140   PetscFunctionReturn(PETSC_SUCCESS);
1141 }
1142 
1143 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
1144 {
1145   PetscDS         ds;
1146   PetscInt        spdim;
1147   PetscInt        numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
1148   const PetscInt *anchors;
1149   PetscSection    aSec;
1150   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
1151   IS              aIS;
1152 
1153   PetscFunctionBegin;
1154   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1155   PetscCall(DMGetDS(dm, &ds));
1156   PetscCall(PetscDSGetNumFields(ds, &numFields));
1157   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1158   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
1159   PetscCall(ISGetIndices(aIS, &anchors));
1160   PetscCall(PetscSectionGetChart(cSec, &conStart, &conEnd));
1161   PetscCall(DMGetDimension(dm, &spdim));
1162   PetscCall(PetscMalloc6(spdim, &v0, spdim, &v0parent, spdim, &vtmp, spdim * spdim, &J, spdim * spdim, &Jparent, spdim * spdim, &invJparent));
1163 
1164   for (f = 0; f < numFields; f++) {
1165     PetscObject          disc;
1166     PetscClassId         id;
1167     PetscSpace           bspace;
1168     PetscDualSpace       dspace;
1169     PetscInt             i, j, k, nPoints, Nc, offset;
1170     PetscInt             fSize, maxDof;
1171     PetscReal           *weights, *pointsRef, *pointsReal, *work;
1172     PetscScalar         *scwork;
1173     const PetscScalar   *X;
1174     PetscInt            *sizes, *workIndRow, *workIndCol;
1175     Mat                  Amat, Bmat, Xmat;
1176     const PetscInt      *numDof = NULL;
1177     const PetscInt    ***perms  = NULL;
1178     const PetscScalar ***flips  = NULL;
1179 
1180     PetscCall(PetscDSGetDiscretization(ds, f, &disc));
1181     PetscCall(PetscObjectGetClassId(disc, &id));
1182     if (id == PETSCFE_CLASSID) {
1183       PetscFE fe = (PetscFE)disc;
1184 
1185       PetscCall(PetscFEGetBasisSpace(fe, &bspace));
1186       PetscCall(PetscFEGetDualSpace(fe, &dspace));
1187       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
1188       PetscCall(PetscFEGetNumComponents(fe, &Nc));
1189     } else if (id == PETSCFV_CLASSID) {
1190       PetscFV fv = (PetscFV)disc;
1191 
1192       PetscCall(PetscFVGetNumComponents(fv, &Nc));
1193       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)fv), &bspace));
1194       PetscCall(PetscSpaceSetType(bspace, PETSCSPACEPOLYNOMIAL));
1195       PetscCall(PetscSpaceSetDegree(bspace, 0, PETSC_DETERMINE));
1196       PetscCall(PetscSpaceSetNumComponents(bspace, Nc));
1197       PetscCall(PetscSpaceSetNumVariables(bspace, spdim));
1198       PetscCall(PetscSpaceSetUp(bspace));
1199       PetscCall(PetscFVGetDualSpace(fv, &dspace));
1200       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
1201     } else SETERRQ(PetscObjectComm(disc), PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
1202     PetscCall(PetscDualSpaceGetNumDof(dspace, &numDof));
1203     for (i = 0, maxDof = 0; i <= spdim; i++) maxDof = PetscMax(maxDof, numDof[i]);
1204     PetscCall(PetscDualSpaceGetSymmetries(dspace, &perms, &flips));
1205 
1206     PetscCall(MatCreate(PETSC_COMM_SELF, &Amat));
1207     PetscCall(MatSetSizes(Amat, fSize, fSize, fSize, fSize));
1208     PetscCall(MatSetType(Amat, MATSEQDENSE));
1209     PetscCall(MatSetUp(Amat));
1210     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Bmat));
1211     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Xmat));
1212     nPoints = 0;
1213     for (i = 0; i < fSize; i++) {
1214       PetscInt        qPoints, thisNc;
1215       PetscQuadrature quad;
1216 
1217       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
1218       PetscCall(PetscQuadratureGetData(quad, NULL, &thisNc, &qPoints, NULL, NULL));
1219       PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
1220       nPoints += qPoints;
1221     }
1222     PetscCall(PetscMalloc7(fSize, &sizes, nPoints * Nc, &weights, spdim * nPoints, &pointsRef, spdim * nPoints, &pointsReal, nPoints * fSize * Nc, &work, maxDof, &workIndRow, maxDof, &workIndCol));
1223     PetscCall(PetscMalloc1(maxDof * maxDof, &scwork));
1224     offset = 0;
1225     for (i = 0; i < fSize; i++) {
1226       PetscInt         qPoints;
1227       const PetscReal *p, *w;
1228       PetscQuadrature  quad;
1229 
1230       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
1231       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &qPoints, &p, &w));
1232       PetscCall(PetscArraycpy(weights + Nc * offset, w, Nc * qPoints));
1233       PetscCall(PetscArraycpy(pointsRef + spdim * offset, p, spdim * qPoints));
1234       sizes[i] = qPoints;
1235       offset += qPoints;
1236     }
1237     PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsRef, weights, work, Amat));
1238     PetscCall(MatLUFactor(Amat, NULL, NULL, NULL));
1239     for (c = cStart; c < cEnd; c++) {
1240       PetscInt  parent;
1241       PetscInt  closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
1242       PetscInt *childOffsets, *parentOffsets;
1243 
1244       PetscCall(DMPlexGetTreeParent(dm, c, &parent, NULL));
1245       if (parent == c) continue;
1246       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1247       for (i = 0; i < closureSize; i++) {
1248         PetscInt p = closure[2 * i];
1249         PetscInt conDof;
1250 
1251         if (p < conStart || p >= conEnd) continue;
1252         if (numFields) {
1253           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
1254         } else {
1255           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
1256         }
1257         if (conDof) break;
1258       }
1259       if (i == closureSize) {
1260         PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1261         continue;
1262       }
1263 
1264       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ));
1265       PetscCall(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent));
1266       for (i = 0; i < nPoints; i++) {
1267         const PetscReal xi0[3] = {-1., -1., -1.};
1268 
1269         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i * spdim], vtmp);
1270         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i * spdim]);
1271       }
1272       PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsReal, weights, work, Bmat));
1273       PetscCall(MatMatSolve(Amat, Bmat, Xmat));
1274       PetscCall(MatDenseGetArrayRead(Xmat, &X));
1275       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
1276       PetscCall(PetscMalloc2(closureSize + 1, &childOffsets, closureSizeP + 1, &parentOffsets));
1277       childOffsets[0] = 0;
1278       for (i = 0; i < closureSize; i++) {
1279         PetscInt p = closure[2 * i];
1280         PetscInt dof;
1281 
1282         if (numFields) {
1283           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
1284         } else {
1285           PetscCall(PetscSectionGetDof(section, p, &dof));
1286         }
1287         childOffsets[i + 1] = childOffsets[i] + dof;
1288       }
1289       parentOffsets[0] = 0;
1290       for (i = 0; i < closureSizeP; i++) {
1291         PetscInt p = closureP[2 * i];
1292         PetscInt dof;
1293 
1294         if (numFields) {
1295           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
1296         } else {
1297           PetscCall(PetscSectionGetDof(section, p, &dof));
1298         }
1299         parentOffsets[i + 1] = parentOffsets[i] + dof;
1300       }
1301       for (i = 0; i < closureSize; i++) {
1302         PetscInt           conDof, conOff, aDof, aOff, nWork;
1303         PetscInt           p = closure[2 * i];
1304         PetscInt           o = closure[2 * i + 1];
1305         const PetscInt    *perm;
1306         const PetscScalar *flip;
1307 
1308         if (p < conStart || p >= conEnd) continue;
1309         if (numFields) {
1310           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
1311           PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &conOff));
1312         } else {
1313           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
1314           PetscCall(PetscSectionGetOffset(cSec, p, &conOff));
1315         }
1316         if (!conDof) continue;
1317         perm = (perms && perms[i]) ? perms[i][o] : NULL;
1318         flip = (flips && flips[i]) ? flips[i][o] : NULL;
1319         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
1320         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
1321         nWork = childOffsets[i + 1] - childOffsets[i];
1322         for (k = 0; k < aDof; k++) {
1323           PetscInt a = anchors[aOff + k];
1324           PetscInt aSecDof, aSecOff;
1325 
1326           if (numFields) {
1327             PetscCall(PetscSectionGetFieldDof(section, a, f, &aSecDof));
1328             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aSecOff));
1329           } else {
1330             PetscCall(PetscSectionGetDof(section, a, &aSecDof));
1331             PetscCall(PetscSectionGetOffset(section, a, &aSecOff));
1332           }
1333           if (!aSecDof) continue;
1334 
1335           for (j = 0; j < closureSizeP; j++) {
1336             PetscInt q  = closureP[2 * j];
1337             PetscInt oq = closureP[2 * j + 1];
1338 
1339             if (q == a) {
1340               PetscInt           r, s, nWorkP;
1341               const PetscInt    *permP;
1342               const PetscScalar *flipP;
1343 
1344               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1345               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
1346               nWorkP = parentOffsets[j + 1] - parentOffsets[j];
1347               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
1348                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
1349                * column-major, so transpose-transpose = do nothing */
1350               for (r = 0; r < nWork; r++) {
1351                 for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
1352               }
1353               for (r = 0; r < nWork; r++) workIndRow[perm ? perm[r] : r] = conOff + r;
1354               for (s = 0; s < nWorkP; s++) workIndCol[permP ? permP[s] : s] = aSecOff + s;
1355               if (flip) {
1356                 for (r = 0; r < nWork; r++) {
1357                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flip[r];
1358                 }
1359               }
1360               if (flipP) {
1361                 for (r = 0; r < nWork; r++) {
1362                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flipP[s];
1363                 }
1364               }
1365               PetscCall(MatSetValues(cMat, nWork, workIndRow, nWorkP, workIndCol, scwork, INSERT_VALUES));
1366               break;
1367             }
1368           }
1369         }
1370       }
1371       PetscCall(MatDenseRestoreArrayRead(Xmat, &X));
1372       PetscCall(PetscFree2(childOffsets, parentOffsets));
1373       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1374       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
1375     }
1376     PetscCall(MatDestroy(&Amat));
1377     PetscCall(MatDestroy(&Bmat));
1378     PetscCall(MatDestroy(&Xmat));
1379     PetscCall(PetscFree(scwork));
1380     PetscCall(PetscFree7(sizes, weights, pointsRef, pointsReal, work, workIndRow, workIndCol));
1381     if (id == PETSCFV_CLASSID) PetscCall(PetscSpaceDestroy(&bspace));
1382   }
1383   PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
1384   PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
1385   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJparent));
1386   PetscCall(ISRestoreIndices(aIS, &anchors));
1387   PetscFunctionReturn(PETSC_SUCCESS);
1388 }
1389 
1390 static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1391 {
1392   Mat                 refCmat;
1393   PetscDS             ds;
1394   PetscInt            numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
1395   PetscScalar      ***refPointFieldMats;
1396   PetscSection        refConSec, refAnSec, refSection;
1397   IS                  refAnIS;
1398   const PetscInt     *refAnchors;
1399   const PetscInt    **perms;
1400   const PetscScalar **flips;
1401 
1402   PetscFunctionBegin;
1403   PetscCall(DMGetDS(refTree, &ds));
1404   PetscCall(PetscDSGetNumFields(ds, &numFields));
1405   maxFields = PetscMax(1, numFields);
1406   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
1407   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
1408   PetscCall(ISGetIndices(refAnIS, &refAnchors));
1409   PetscCall(DMGetLocalSection(refTree, &refSection));
1410   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
1411   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
1412   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldN));
1413   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
1414   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
1415   PetscCall(PetscMalloc1(maxDof, &rows));
1416   PetscCall(PetscMalloc1(maxDof * maxAnDof, &cols));
1417   for (p = pRefStart; p < pRefEnd; p++) {
1418     PetscInt parent, closureSize, *closure = NULL, pDof;
1419 
1420     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
1421     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
1422     if (!pDof || parent == p) continue;
1423 
1424     PetscCall(PetscMalloc1(maxFields, &refPointFieldMats[p - pRefStart]));
1425     PetscCall(PetscCalloc1(maxFields, &refPointFieldN[p - pRefStart]));
1426     PetscCall(DMPlexGetTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
1427     for (f = 0; f < maxFields; f++) {
1428       PetscInt cDof, cOff, numCols, r, i;
1429 
1430       if (f < numFields) {
1431         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
1432         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
1433         PetscCall(PetscSectionGetFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1434       } else {
1435         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
1436         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
1437         PetscCall(PetscSectionGetPointSyms(refSection, closureSize, closure, &perms, &flips));
1438       }
1439 
1440       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
1441       numCols = 0;
1442       for (i = 0; i < closureSize; i++) {
1443         PetscInt        q = closure[2 * i];
1444         PetscInt        aDof, aOff, j;
1445         const PetscInt *perm = perms ? perms[i] : NULL;
1446 
1447         if (numFields) {
1448           PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
1449           PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
1450         } else {
1451           PetscCall(PetscSectionGetDof(refSection, q, &aDof));
1452           PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
1453         }
1454 
1455         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + (perm ? perm[j] : j);
1456       }
1457       refPointFieldN[p - pRefStart][f] = numCols;
1458       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
1459       PetscCall(MatGetValues(refCmat, cDof, rows, numCols, cols, refPointFieldMats[p - pRefStart][f]));
1460       if (flips) {
1461         PetscInt colOff = 0;
1462 
1463         for (i = 0; i < closureSize; i++) {
1464           PetscInt           q = closure[2 * i];
1465           PetscInt           aDof, aOff, j;
1466           const PetscScalar *flip = flips ? flips[i] : NULL;
1467 
1468           if (numFields) {
1469             PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
1470             PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
1471           } else {
1472             PetscCall(PetscSectionGetDof(refSection, q, &aDof));
1473             PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
1474           }
1475           if (flip) {
1476             PetscInt k;
1477             for (k = 0; k < cDof; k++) {
1478               for (j = 0; j < aDof; j++) refPointFieldMats[p - pRefStart][f][k * numCols + colOff + j] *= flip[j];
1479             }
1480           }
1481           colOff += aDof;
1482         }
1483       }
1484       if (numFields) {
1485         PetscCall(PetscSectionRestoreFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1486       } else {
1487         PetscCall(PetscSectionRestorePointSyms(refSection, closureSize, closure, &perms, &flips));
1488       }
1489     }
1490     PetscCall(DMPlexRestoreTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
1491   }
1492   *childrenMats = refPointFieldMats;
1493   *childrenN    = refPointFieldN;
1494   PetscCall(ISRestoreIndices(refAnIS, &refAnchors));
1495   PetscCall(PetscFree(rows));
1496   PetscCall(PetscFree(cols));
1497   PetscFunctionReturn(PETSC_SUCCESS);
1498 }
1499 
1500 static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1501 {
1502   PetscDS        ds;
1503   PetscInt     **refPointFieldN;
1504   PetscScalar ***refPointFieldMats;
1505   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
1506   PetscSection   refConSec;
1507 
1508   PetscFunctionBegin;
1509   refPointFieldN    = *childrenN;
1510   *childrenN        = NULL;
1511   refPointFieldMats = *childrenMats;
1512   *childrenMats     = NULL;
1513   PetscCall(DMGetDS(refTree, &ds));
1514   PetscCall(PetscDSGetNumFields(ds, &numFields));
1515   maxFields = PetscMax(1, numFields);
1516   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
1517   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
1518   for (p = pRefStart; p < pRefEnd; p++) {
1519     PetscInt parent, pDof;
1520 
1521     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
1522     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
1523     if (!pDof || parent == p) continue;
1524 
1525     for (f = 0; f < maxFields; f++) {
1526       PetscInt cDof;
1527 
1528       if (numFields) {
1529         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
1530       } else {
1531         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
1532       }
1533 
1534       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
1535     }
1536     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
1537     PetscCall(PetscFree(refPointFieldN[p - pRefStart]));
1538   }
1539   PetscCall(PetscFree(refPointFieldMats));
1540   PetscCall(PetscFree(refPointFieldN));
1541   PetscFunctionReturn(PETSC_SUCCESS);
1542 }
1543 
1544 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
1545 {
1546   DM              refTree;
1547   PetscDS         ds;
1548   Mat             refCmat;
1549   PetscInt        numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
1550   PetscScalar  ***refPointFieldMats, *pointWork;
1551   PetscSection    refConSec, refAnSec, anSec;
1552   IS              refAnIS, anIS;
1553   const PetscInt *anchors;
1554 
1555   PetscFunctionBegin;
1556   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1557   PetscCall(DMGetDS(dm, &ds));
1558   PetscCall(PetscDSGetNumFields(ds, &numFields));
1559   maxFields = PetscMax(1, numFields);
1560   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
1561   PetscCall(DMCopyDisc(dm, refTree));
1562   PetscCall(DMSetLocalSection(refTree, NULL));
1563   PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
1564   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
1565   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
1566   PetscCall(DMPlexGetAnchors(dm, &anSec, &anIS));
1567   PetscCall(ISGetIndices(anIS, &anchors));
1568   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
1569   PetscCall(PetscSectionGetChart(conSec, &conStart, &conEnd));
1570   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
1571   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
1572   PetscCall(PetscMalloc1(maxDof * maxDof * maxAnDof, &pointWork));
1573 
1574   /* step 1: get submats for every constrained point in the reference tree */
1575   PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
1576 
1577   /* step 2: compute the preorder */
1578   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1579   PetscCall(PetscMalloc2(pEnd - pStart, &perm, pEnd - pStart, &iperm));
1580   for (p = pStart; p < pEnd; p++) {
1581     perm[p - pStart]  = p;
1582     iperm[p - pStart] = p - pStart;
1583   }
1584   for (p = 0; p < pEnd - pStart;) {
1585     PetscInt point = perm[p];
1586     PetscInt parent;
1587 
1588     PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
1589     if (parent == point) {
1590       p++;
1591     } else {
1592       PetscInt size, closureSize, *closure = NULL, i;
1593 
1594       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1595       for (i = 0; i < closureSize; i++) {
1596         PetscInt q = closure[2 * i];
1597         if (iperm[q - pStart] > iperm[point - pStart]) {
1598           /* swap */
1599           perm[p]                 = q;
1600           perm[iperm[q - pStart]] = point;
1601           iperm[point - pStart]   = iperm[q - pStart];
1602           iperm[q - pStart]       = p;
1603           break;
1604         }
1605       }
1606       size = closureSize;
1607       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1608       if (i == size) p++;
1609     }
1610   }
1611 
1612   /* step 3: fill the constraint matrix */
1613   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
1614    * allow progressive fill without assembly, so we are going to set up the
1615    * values outside of the Mat first.
1616    */
1617   {
1618     PetscInt        nRows, row, nnz;
1619     PetscBool       done;
1620     PetscInt        secStart, secEnd;
1621     const PetscInt *ia, *ja;
1622     PetscScalar    *vals;
1623 
1624     PetscCall(PetscSectionGetChart(section, &secStart, &secEnd));
1625     PetscCall(MatGetRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
1626     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not get RowIJ of constraint matrix");
1627     nnz = ia[nRows];
1628     /* malloc and then zero rows right before we fill them: this way valgrind
1629      * can tell if we are doing progressive fill in the wrong order */
1630     PetscCall(PetscMalloc1(nnz, &vals));
1631     for (p = 0; p < pEnd - pStart; p++) {
1632       PetscInt parent, childid, closureSize, *closure = NULL;
1633       PetscInt point = perm[p], pointDof;
1634 
1635       PetscCall(DMPlexGetTreeParent(dm, point, &parent, &childid));
1636       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
1637       PetscCall(PetscSectionGetDof(conSec, point, &pointDof));
1638       if (!pointDof) continue;
1639       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1640       for (f = 0; f < maxFields; f++) {
1641         PetscInt            cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
1642         PetscScalar        *pointMat;
1643         const PetscInt    **perms;
1644         const PetscScalar **flips;
1645 
1646         if (numFields) {
1647           PetscCall(PetscSectionGetFieldDof(conSec, point, f, &cDof));
1648           PetscCall(PetscSectionGetFieldOffset(conSec, point, f, &cOff));
1649         } else {
1650           PetscCall(PetscSectionGetDof(conSec, point, &cDof));
1651           PetscCall(PetscSectionGetOffset(conSec, point, &cOff));
1652         }
1653         if (!cDof) continue;
1654         if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
1655         else PetscCall(PetscSectionGetPointSyms(section, closureSize, closure, &perms, &flips));
1656 
1657         /* make sure that every row for this point is the same size */
1658         if (PetscDefined(USE_DEBUG)) {
1659           for (r = 0; r < cDof; r++) {
1660             if (cDof > 1 && r) {
1661               PetscCheck((ia[cOff + r + 1] - ia[cOff + r]) == (ia[cOff + r] - ia[cOff + r - 1]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two point rows have different nnz: %" PetscInt_FMT " vs. %" PetscInt_FMT, (ia[cOff + r + 1] - ia[cOff + r]), (ia[cOff + r] - ia[cOff + r - 1]));
1662             }
1663           }
1664         }
1665         /* zero rows */
1666         for (i = ia[cOff]; i < ia[cOff + cDof]; i++) vals[i] = 0.;
1667         matOffset   = ia[cOff];
1668         numFillCols = ia[cOff + 1] - matOffset;
1669         pointMat    = refPointFieldMats[childid - pRefStart][f];
1670         numCols     = refPointFieldN[childid - pRefStart][f];
1671         offset      = 0;
1672         for (i = 0; i < closureSize; i++) {
1673           PetscInt           q = closure[2 * i];
1674           PetscInt           aDof, aOff, j, k, qConDof, qConOff;
1675           const PetscInt    *perm = perms ? perms[i] : NULL;
1676           const PetscScalar *flip = flips ? flips[i] : NULL;
1677 
1678           qConDof = qConOff = 0;
1679           if (q < secStart || q >= secEnd) continue;
1680           if (numFields) {
1681             PetscCall(PetscSectionGetFieldDof(section, q, f, &aDof));
1682             PetscCall(PetscSectionGetFieldOffset(section, q, f, &aOff));
1683             if (q >= conStart && q < conEnd) {
1684               PetscCall(PetscSectionGetFieldDof(conSec, q, f, &qConDof));
1685               PetscCall(PetscSectionGetFieldOffset(conSec, q, f, &qConOff));
1686             }
1687           } else {
1688             PetscCall(PetscSectionGetDof(section, q, &aDof));
1689             PetscCall(PetscSectionGetOffset(section, q, &aOff));
1690             if (q >= conStart && q < conEnd) {
1691               PetscCall(PetscSectionGetDof(conSec, q, &qConDof));
1692               PetscCall(PetscSectionGetOffset(conSec, q, &qConOff));
1693             }
1694           }
1695           if (!aDof) continue;
1696           if (qConDof) {
1697             /* this point has anchors: its rows of the matrix should already
1698              * be filled, thanks to preordering */
1699             /* first multiply into pointWork, then set in matrix */
1700             PetscInt aMatOffset   = ia[qConOff];
1701             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
1702             for (r = 0; r < cDof; r++) {
1703               for (j = 0; j < aNumFillCols; j++) {
1704                 PetscScalar inVal = 0;
1705                 for (k = 0; k < aDof; k++) {
1706                   PetscInt col = perm ? perm[k] : k;
1707 
1708                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
1709                 }
1710                 pointWork[r * aNumFillCols + j] = inVal;
1711               }
1712             }
1713             /* assume that the columns are sorted, spend less time searching */
1714             for (j = 0, k = 0; j < aNumFillCols; j++) {
1715               PetscInt col = ja[aMatOffset + j];
1716               for (; k < numFillCols; k++) {
1717                 if (ja[matOffset + k] == col) break;
1718               }
1719               PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, col);
1720               for (r = 0; r < cDof; r++) vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
1721             }
1722           } else {
1723             /* find where to put this portion of pointMat into the matrix */
1724             for (k = 0; k < numFillCols; k++) {
1725               if (ja[matOffset + k] == aOff) break;
1726             }
1727             PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, aOff);
1728             for (r = 0; r < cDof; r++) {
1729               for (j = 0; j < aDof; j++) {
1730                 PetscInt col = perm ? perm[j] : j;
1731 
1732                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
1733               }
1734             }
1735           }
1736           offset += aDof;
1737         }
1738         if (numFields) {
1739           PetscCall(PetscSectionRestoreFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
1740         } else {
1741           PetscCall(PetscSectionRestorePointSyms(section, closureSize, closure, &perms, &flips));
1742         }
1743       }
1744       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1745     }
1746     for (row = 0; row < nRows; row++) PetscCall(MatSetValues(cMat, 1, &row, ia[row + 1] - ia[row], &ja[ia[row]], &vals[ia[row]], INSERT_VALUES));
1747     PetscCall(MatRestoreRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
1748     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not restore RowIJ of constraint matrix");
1749     PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
1750     PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
1751     PetscCall(PetscFree(vals));
1752   }
1753 
1754   /* clean up */
1755   PetscCall(ISRestoreIndices(anIS, &anchors));
1756   PetscCall(PetscFree2(perm, iperm));
1757   PetscCall(PetscFree(pointWork));
1758   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
1759   PetscFunctionReturn(PETSC_SUCCESS);
1760 }
1761 
1762 /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
1763  * a non-conforming mesh.  Local refinement comes later */
1764 PetscErrorCode DMPlexTreeRefineCell(DM dm, PetscInt cell, DM *ncdm)
1765 {
1766   DM           K;
1767   PetscMPIInt  rank;
1768   PetscInt     dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
1769   PetscInt     numNewCones, *newConeSizes, *newCones, *newOrientations;
1770   PetscInt    *Kembedding;
1771   PetscInt    *cellClosure = NULL, nc;
1772   PetscScalar *newVertexCoords;
1773   PetscInt     numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
1774   PetscSection parentSection;
1775 
1776   PetscFunctionBegin;
1777   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1778   PetscCall(DMGetDimension(dm, &dim));
1779   PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
1780   PetscCall(DMSetDimension(*ncdm, dim));
1781 
1782   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1783   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &parentSection));
1784   PetscCall(DMPlexGetReferenceTree(dm, &K));
1785   PetscCall(DMGetCoordinatesLocalSetUp(dm));
1786   if (rank == 0) {
1787     /* compute the new charts */
1788     PetscCall(PetscMalloc5(dim + 1, &pNewCount, dim + 1, &pNewStart, dim + 1, &pNewEnd, dim + 1, &pOldStart, dim + 1, &pOldEnd));
1789     offset = 0;
1790     for (d = 0; d <= dim; d++) {
1791       PetscInt pOldCount, kStart, kEnd, k;
1792 
1793       pNewStart[d] = offset;
1794       PetscCall(DMPlexGetHeightStratum(dm, d, &pOldStart[d], &pOldEnd[d]));
1795       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
1796       pOldCount = pOldEnd[d] - pOldStart[d];
1797       /* adding the new points */
1798       pNewCount[d] = pOldCount + kEnd - kStart;
1799       if (!d) {
1800         /* removing the cell */
1801         pNewCount[d]--;
1802       }
1803       for (k = kStart; k < kEnd; k++) {
1804         PetscInt parent;
1805         PetscCall(DMPlexGetTreeParent(K, k, &parent, NULL));
1806         if (parent == k) {
1807           /* avoid double counting points that won't actually be new */
1808           pNewCount[d]--;
1809         }
1810       }
1811       pNewEnd[d] = pNewStart[d] + pNewCount[d];
1812       offset     = pNewEnd[d];
1813     }
1814     PetscCheck(cell >= pOldStart[0] && cell < pOldEnd[0], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "%" PetscInt_FMT " not in cell range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cell, pOldStart[0], pOldEnd[0]);
1815     /* get the current closure of the cell that we are removing */
1816     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
1817 
1818     PetscCall(PetscMalloc1(pNewEnd[dim], &newConeSizes));
1819     {
1820       DMPolytopeType pct, qct;
1821       PetscInt       kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
1822 
1823       PetscCall(DMPlexGetChart(K, &kStart, &kEnd));
1824       PetscCall(PetscMalloc4(kEnd - kStart, &Kembedding, kEnd - kStart, &perm, kEnd - kStart, &iperm, kEnd - kStart, &preOrient));
1825 
1826       for (k = kStart; k < kEnd; k++) {
1827         perm[k - kStart]      = k;
1828         iperm[k - kStart]     = k - kStart;
1829         preOrient[k - kStart] = 0;
1830       }
1831 
1832       PetscCall(DMPlexGetTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
1833       for (j = 1; j < closureSizeK; j++) {
1834         PetscInt parentOrientA = closureK[2 * j + 1];
1835         PetscInt parentOrientB = cellClosure[2 * j + 1];
1836         PetscInt p, q;
1837 
1838         p = closureK[2 * j];
1839         q = cellClosure[2 * j];
1840         PetscCall(DMPlexGetCellType(K, p, &pct));
1841         PetscCall(DMPlexGetCellType(dm, q, &qct));
1842         for (d = 0; d <= dim; d++) {
1843           if (q >= pOldStart[d] && q < pOldEnd[d]) Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
1844         }
1845         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1846         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
1847         if (parentOrientA != parentOrientB) {
1848           PetscInt        numChildren, i;
1849           const PetscInt *children;
1850 
1851           PetscCall(DMPlexGetTreeChildren(K, p, &numChildren, &children));
1852           for (i = 0; i < numChildren; i++) {
1853             PetscInt kPerm, oPerm;
1854 
1855             k = children[i];
1856             PetscCall(DMPlexReferenceTreeGetChildSymmetry(K, p, parentOrientA, 0, k, parentOrientB, &oPerm, &kPerm));
1857             /* perm = what refTree position I'm in */
1858             perm[kPerm - kStart] = k;
1859             /* iperm = who is at this position */
1860             iperm[k - kStart]         = kPerm - kStart;
1861             preOrient[kPerm - kStart] = oPerm;
1862           }
1863         }
1864       }
1865       PetscCall(DMPlexRestoreTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
1866     }
1867     PetscCall(PetscSectionSetChart(parentSection, 0, pNewEnd[dim]));
1868     offset      = 0;
1869     numNewCones = 0;
1870     for (d = 0; d <= dim; d++) {
1871       PetscInt kStart, kEnd, k;
1872       PetscInt p;
1873       PetscInt size;
1874 
1875       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
1876         /* skip cell 0 */
1877         if (p == cell) continue;
1878         /* old cones to new cones */
1879         PetscCall(DMPlexGetConeSize(dm, p, &size));
1880         newConeSizes[offset++] = size;
1881         numNewCones += size;
1882       }
1883 
1884       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
1885       for (k = kStart; k < kEnd; k++) {
1886         PetscInt kParent;
1887 
1888         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
1889         if (kParent != k) {
1890           Kembedding[k] = offset;
1891           PetscCall(DMPlexGetConeSize(K, k, &size));
1892           newConeSizes[offset++] = size;
1893           numNewCones += size;
1894           if (kParent != 0) PetscCall(PetscSectionSetDof(parentSection, Kembedding[k], 1));
1895         }
1896       }
1897     }
1898 
1899     PetscCall(PetscSectionSetUp(parentSection));
1900     PetscCall(PetscSectionGetStorageSize(parentSection, &numPointsWithParents));
1901     PetscCall(PetscMalloc2(numNewCones, &newCones, numNewCones, &newOrientations));
1902     PetscCall(PetscMalloc2(numPointsWithParents, &parents, numPointsWithParents, &childIDs));
1903 
1904     /* fill new cones */
1905     offset = 0;
1906     for (d = 0; d <= dim; d++) {
1907       PetscInt        kStart, kEnd, k, l;
1908       PetscInt        p;
1909       PetscInt        size;
1910       const PetscInt *cone, *orientation;
1911 
1912       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
1913         /* skip cell 0 */
1914         if (p == cell) continue;
1915         /* old cones to new cones */
1916         PetscCall(DMPlexGetConeSize(dm, p, &size));
1917         PetscCall(DMPlexGetCone(dm, p, &cone));
1918         PetscCall(DMPlexGetConeOrientation(dm, p, &orientation));
1919         for (l = 0; l < size; l++) {
1920           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
1921           newOrientations[offset++] = orientation[l];
1922         }
1923       }
1924 
1925       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
1926       for (k = kStart; k < kEnd; k++) {
1927         PetscInt kPerm = perm[k], kParent;
1928         PetscInt preO  = preOrient[k];
1929 
1930         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
1931         if (kParent != k) {
1932           /* embed new cones */
1933           PetscCall(DMPlexGetConeSize(K, k, &size));
1934           PetscCall(DMPlexGetCone(K, kPerm, &cone));
1935           PetscCall(DMPlexGetConeOrientation(K, kPerm, &orientation));
1936           for (l = 0; l < size; l++) {
1937             PetscInt       q, m = (preO >= 0) ? ((preO + l) % size) : ((size - (preO + 1) - l) % size);
1938             PetscInt       newO, lSize, oTrue;
1939             DMPolytopeType ct = DM_NUM_POLYTOPES;
1940 
1941             q                = iperm[cone[m]];
1942             newCones[offset] = Kembedding[q];
1943             PetscCall(DMPlexGetConeSize(K, q, &lSize));
1944             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
1945             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
1946             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
1947             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
1948             newO                      = DihedralCompose(lSize, oTrue, preOrient[q]);
1949             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
1950           }
1951           if (kParent != 0) {
1952             PetscInt newPoint = Kembedding[kParent];
1953             PetscCall(PetscSectionGetOffset(parentSection, Kembedding[k], &pOffset));
1954             parents[pOffset]  = newPoint;
1955             childIDs[pOffset] = k;
1956           }
1957         }
1958       }
1959     }
1960 
1961     PetscCall(PetscMalloc1(dim * (pNewEnd[dim] - pNewStart[dim]), &newVertexCoords));
1962 
1963     /* fill coordinates */
1964     offset = 0;
1965     {
1966       PetscInt     kStart, kEnd, l;
1967       PetscSection vSection;
1968       PetscInt     v;
1969       Vec          coords;
1970       PetscScalar *coordvals;
1971       PetscInt     dof, off;
1972       PetscReal    v0[3], J[9], detJ;
1973 
1974       if (PetscDefined(USE_DEBUG)) {
1975         PetscInt k;
1976         PetscCall(DMPlexGetHeightStratum(K, 0, &kStart, &kEnd));
1977         for (k = kStart; k < kEnd; k++) {
1978           PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
1979           PetscCheck(detJ > 0., PETSC_COMM_SELF, PETSC_ERR_PLIB, "reference tree cell %" PetscInt_FMT " has bad determinant", k);
1980         }
1981       }
1982       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
1983       PetscCall(DMGetCoordinateSection(dm, &vSection));
1984       PetscCall(DMGetCoordinatesLocal(dm, &coords));
1985       PetscCall(VecGetArray(coords, &coordvals));
1986       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
1987         PetscCall(PetscSectionGetDof(vSection, v, &dof));
1988         PetscCall(PetscSectionGetOffset(vSection, v, &off));
1989         for (l = 0; l < dof; l++) newVertexCoords[offset++] = coordvals[off + l];
1990       }
1991       PetscCall(VecRestoreArray(coords, &coordvals));
1992 
1993       PetscCall(DMGetCoordinateSection(K, &vSection));
1994       PetscCall(DMGetCoordinatesLocal(K, &coords));
1995       PetscCall(VecGetArray(coords, &coordvals));
1996       PetscCall(DMPlexGetDepthStratum(K, 0, &kStart, &kEnd));
1997       for (v = kStart; v < kEnd; v++) {
1998         PetscReal       coord[3], newCoord[3];
1999         PetscInt        vPerm = perm[v];
2000         PetscInt        kParent;
2001         const PetscReal xi0[3] = {-1., -1., -1.};
2002 
2003         PetscCall(DMPlexGetTreeParent(K, v, &kParent, NULL));
2004         if (kParent != v) {
2005           /* this is a new vertex */
2006           PetscCall(PetscSectionGetOffset(vSection, vPerm, &off));
2007           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off + l]);
2008           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
2009           for (l = 0; l < dim; ++l) newVertexCoords[offset + l] = newCoord[l];
2010           offset += dim;
2011         }
2012       }
2013       PetscCall(VecRestoreArray(coords, &coordvals));
2014     }
2015 
2016     /* need to reverse the order of pNewCount: vertices first, cells last */
2017     for (d = 0; d < (dim + 1) / 2; d++) {
2018       PetscInt tmp;
2019 
2020       tmp                = pNewCount[d];
2021       pNewCount[d]       = pNewCount[dim - d];
2022       pNewCount[dim - d] = tmp;
2023     }
2024 
2025     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, pNewCount, newConeSizes, newCones, newOrientations, newVertexCoords));
2026     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
2027     PetscCall(DMPlexSetTree(*ncdm, parentSection, parents, childIDs));
2028 
2029     /* clean up */
2030     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
2031     PetscCall(PetscFree5(pNewCount, pNewStart, pNewEnd, pOldStart, pOldEnd));
2032     PetscCall(PetscFree(newConeSizes));
2033     PetscCall(PetscFree2(newCones, newOrientations));
2034     PetscCall(PetscFree(newVertexCoords));
2035     PetscCall(PetscFree2(parents, childIDs));
2036     PetscCall(PetscFree4(Kembedding, perm, iperm, preOrient));
2037   } else {
2038     PetscInt     p, counts[4];
2039     PetscInt    *coneSizes, *cones, *orientations;
2040     Vec          coordVec;
2041     PetscScalar *coords;
2042 
2043     for (d = 0; d <= dim; d++) {
2044       PetscInt dStart, dEnd;
2045 
2046       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
2047       counts[d] = dEnd - dStart;
2048     }
2049     PetscCall(PetscMalloc1(pEnd - pStart, &coneSizes));
2050     for (p = pStart; p < pEnd; p++) PetscCall(DMPlexGetConeSize(dm, p, &coneSizes[p - pStart]));
2051     PetscCall(DMPlexGetCones(dm, &cones));
2052     PetscCall(DMPlexGetConeOrientations(dm, &orientations));
2053     PetscCall(DMGetCoordinatesLocal(dm, &coordVec));
2054     PetscCall(VecGetArray(coordVec, &coords));
2055 
2056     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
2057     PetscCall(PetscSectionSetUp(parentSection));
2058     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, counts, coneSizes, cones, orientations, NULL));
2059     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
2060     PetscCall(DMPlexSetTree(*ncdm, parentSection, NULL, NULL));
2061     PetscCall(VecRestoreArray(coordVec, &coords));
2062   }
2063   PetscCall(PetscSectionDestroy(&parentSection));
2064   PetscFunctionReturn(PETSC_SUCCESS);
2065 }
2066 
2067 PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
2068 {
2069   PetscSF              coarseToFineEmbedded;
2070   PetscSection         globalCoarse, globalFine;
2071   PetscSection         localCoarse, localFine;
2072   PetscSection         aSec, cSec;
2073   PetscSection         rootIndicesSec, rootMatricesSec;
2074   PetscSection         leafIndicesSec, leafMatricesSec;
2075   PetscInt            *rootIndices, *leafIndices;
2076   PetscScalar         *rootMatrices, *leafMatrices;
2077   IS                   aIS;
2078   const PetscInt      *anchors;
2079   Mat                  cMat;
2080   PetscInt             numFields, maxFields;
2081   PetscInt             pStartC, pEndC, pStartF, pEndF, p;
2082   PetscInt             aStart, aEnd, cStart, cEnd;
2083   PetscInt            *maxChildIds;
2084   PetscInt            *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
2085   const PetscInt    ***perms;
2086   const PetscScalar ***flips;
2087 
2088   PetscFunctionBegin;
2089   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
2090   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
2091   PetscCall(DMGetGlobalSection(fine, &globalFine));
2092   { /* winnow fine points that don't have global dofs out of the sf */
2093     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
2094     const PetscInt *leaves;
2095 
2096     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
2097     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
2098       p = leaves ? leaves[l] : l;
2099       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
2100       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2101       if ((dof - cdof) > 0) numPointsWithDofs++;
2102     }
2103     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
2104     for (l = 0, offset = 0; l < nleaves; l++) {
2105       p = leaves ? leaves[l] : l;
2106       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
2107       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2108       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
2109     }
2110     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
2111     PetscCall(PetscFree(pointsWithDofs));
2112   }
2113   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
2114   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
2115   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
2116   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
2117   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
2118 
2119   PetscCall(DMGetLocalSection(coarse, &localCoarse));
2120   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
2121 
2122   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
2123   PetscCall(ISGetIndices(aIS, &anchors));
2124   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
2125 
2126   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
2127   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
2128 
2129   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
2130   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
2131   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootMatricesSec));
2132   PetscCall(PetscSectionSetChart(rootIndicesSec, pStartC, pEndC));
2133   PetscCall(PetscSectionSetChart(rootMatricesSec, pStartC, pEndC));
2134   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
2135   maxFields = PetscMax(1, numFields);
2136   PetscCall(PetscMalloc7(maxFields + 1, &offsets, maxFields + 1, &offsetsCopy, maxFields + 1, &newOffsets, maxFields + 1, &newOffsetsCopy, maxFields + 1, &rowOffsets, maxFields + 1, &numD, maxFields + 1, &numO));
2137   PetscCall(PetscMalloc2(maxFields + 1, (PetscInt ****)&perms, maxFields + 1, (PetscScalar ****)&flips));
2138   PetscCall(PetscMemzero((void *)perms, (maxFields + 1) * sizeof(const PetscInt **)));
2139   PetscCall(PetscMemzero((void *)flips, (maxFields + 1) * sizeof(const PetscScalar **)));
2140 
2141   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
2142     PetscInt dof, matSize = 0;
2143     PetscInt aDof          = 0;
2144     PetscInt cDof          = 0;
2145     PetscInt maxChildId    = maxChildIds[p - pStartC];
2146     PetscInt numRowIndices = 0;
2147     PetscInt numColIndices = 0;
2148     PetscInt f;
2149 
2150     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2151     if (dof < 0) dof = -(dof + 1);
2152     if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof));
2153     if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(cSec, p, &cDof));
2154     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2155     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
2156     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2157       PetscInt *closure = NULL, closureSize, cl;
2158 
2159       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
2160       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
2161         PetscInt c = closure[2 * cl], clDof;
2162 
2163         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
2164         numRowIndices += clDof;
2165         for (f = 0; f < numFields; f++) {
2166           PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &clDof));
2167           offsets[f + 1] += clDof;
2168         }
2169       }
2170       for (f = 0; f < numFields; f++) {
2171         offsets[f + 1] += offsets[f];
2172         newOffsets[f + 1] = offsets[f + 1];
2173       }
2174       /* get the number of indices needed and their field offsets */
2175       PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, NULL, NULL, NULL, &numColIndices, NULL, NULL, newOffsets, PETSC_FALSE));
2176       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
2177       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
2178         numColIndices = numRowIndices;
2179         matSize       = 0;
2180       } else if (numFields) { /* we send one submat for each field: sum their sizes */
2181         matSize = 0;
2182         for (f = 0; f < numFields; f++) {
2183           PetscInt numRow, numCol;
2184 
2185           numRow = offsets[f + 1] - offsets[f];
2186           numCol = newOffsets[f + 1] - newOffsets[f];
2187           matSize += numRow * numCol;
2188         }
2189       } else {
2190         matSize = numRowIndices * numColIndices;
2191       }
2192     } else if (maxChildId == -1) {
2193       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2194         PetscInt aOff, a;
2195 
2196         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
2197         for (f = 0; f < numFields; f++) {
2198           PetscInt fDof;
2199 
2200           PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
2201           offsets[f + 1] = fDof;
2202         }
2203         for (a = 0; a < aDof; a++) {
2204           PetscInt anchor = anchors[a + aOff], aLocalDof;
2205 
2206           PetscCall(PetscSectionGetDof(localCoarse, anchor, &aLocalDof));
2207           numColIndices += aLocalDof;
2208           for (f = 0; f < numFields; f++) {
2209             PetscInt fDof;
2210 
2211             PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
2212             newOffsets[f + 1] += fDof;
2213           }
2214         }
2215         if (numFields) {
2216           matSize = 0;
2217           for (f = 0; f < numFields; f++) matSize += offsets[f + 1] * newOffsets[f + 1];
2218         } else {
2219           matSize = numColIndices * dof;
2220         }
2221       } else { /* no children, and no constraints on dofs: just get the global indices */
2222         numColIndices = dof;
2223         matSize       = 0;
2224       }
2225     }
2226     /* we will pack the column indices with the field offsets */
2227     PetscCall(PetscSectionSetDof(rootIndicesSec, p, numColIndices ? numColIndices + 2 * numFields : 0));
2228     PetscCall(PetscSectionSetDof(rootMatricesSec, p, matSize));
2229   }
2230   PetscCall(PetscSectionSetUp(rootIndicesSec));
2231   PetscCall(PetscSectionSetUp(rootMatricesSec));
2232   {
2233     PetscInt numRootIndices, numRootMatrices;
2234 
2235     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
2236     PetscCall(PetscSectionGetStorageSize(rootMatricesSec, &numRootMatrices));
2237     PetscCall(PetscMalloc2(numRootIndices, &rootIndices, numRootMatrices, &rootMatrices));
2238     for (p = pStartC; p < pEndC; p++) {
2239       PetscInt     numRowIndices, numColIndices, matSize, dof;
2240       PetscInt     pIndOff, pMatOff, f;
2241       PetscInt    *pInd;
2242       PetscInt     maxChildId = maxChildIds[p - pStartC];
2243       PetscScalar *pMat       = NULL;
2244 
2245       PetscCall(PetscSectionGetDof(rootIndicesSec, p, &numColIndices));
2246       if (!numColIndices) continue;
2247       for (f = 0; f <= numFields; f++) {
2248         offsets[f]        = 0;
2249         newOffsets[f]     = 0;
2250         offsetsCopy[f]    = 0;
2251         newOffsetsCopy[f] = 0;
2252       }
2253       numColIndices -= 2 * numFields;
2254       PetscCall(PetscSectionGetOffset(rootIndicesSec, p, &pIndOff));
2255       pInd = &(rootIndices[pIndOff]);
2256       PetscCall(PetscSectionGetDof(rootMatricesSec, p, &matSize));
2257       if (matSize) {
2258         PetscCall(PetscSectionGetOffset(rootMatricesSec, p, &pMatOff));
2259         pMat = &rootMatrices[pMatOff];
2260       }
2261       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2262       if (dof < 0) dof = -(dof + 1);
2263       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
2264         PetscInt i, j;
2265         PetscInt numRowIndices = matSize / numColIndices;
2266 
2267         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
2268           PetscInt numIndices, *indices;
2269           PetscCall(DMPlexGetClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
2270           PetscCheck(numIndices == numColIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "mismatching constraint indices calculations");
2271           for (i = 0; i < numColIndices; i++) pInd[i] = indices[i];
2272           for (i = 0; i < numFields; i++) {
2273             pInd[numColIndices + i]             = offsets[i + 1];
2274             pInd[numColIndices + numFields + i] = offsets[i + 1];
2275           }
2276           PetscCall(DMPlexRestoreClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
2277         } else {
2278           PetscInt     closureSize, *closure = NULL, cl;
2279           PetscScalar *pMatIn, *pMatModified;
2280           PetscInt     numPoints, *points;
2281 
2282           PetscCall(DMGetWorkArray(coarse, numRowIndices * numRowIndices, MPIU_SCALAR, &pMatIn));
2283           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
2284             for (j = 0; j < numRowIndices; j++) pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
2285           }
2286           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
2287           for (f = 0; f < maxFields; f++) {
2288             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
2289             else PetscCall(PetscSectionGetPointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
2290           }
2291           if (numFields) {
2292             for (cl = 0; cl < closureSize; cl++) {
2293               PetscInt c = closure[2 * cl];
2294 
2295               for (f = 0; f < numFields; f++) {
2296                 PetscInt fDof;
2297 
2298                 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &fDof));
2299                 offsets[f + 1] += fDof;
2300               }
2301             }
2302             for (f = 0; f < numFields; f++) {
2303               offsets[f + 1] += offsets[f];
2304               newOffsets[f + 1] = offsets[f + 1];
2305             }
2306           }
2307           /* TODO : flips here ? */
2308           /* apply hanging node constraints on the right, get the new points and the new offsets */
2309           PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, perms, pMatIn, &numPoints, NULL, &points, &pMatModified, newOffsets, PETSC_FALSE));
2310           for (f = 0; f < maxFields; f++) {
2311             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
2312             else PetscCall(PetscSectionRestorePointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
2313           }
2314           for (f = 0; f < maxFields; f++) {
2315             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
2316             else PetscCall(PetscSectionGetPointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
2317           }
2318           if (!numFields) {
2319             for (i = 0; i < numRowIndices * numColIndices; i++) pMat[i] = pMatModified[i];
2320           } else {
2321             PetscInt i, j, count;
2322             for (f = 0, count = 0; f < numFields; f++) {
2323               for (i = offsets[f]; i < offsets[f + 1]; i++) {
2324                 for (j = newOffsets[f]; j < newOffsets[f + 1]; j++, count++) pMat[count] = pMatModified[i * numColIndices + j];
2325               }
2326             }
2327           }
2328           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatModified));
2329           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
2330           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatIn));
2331           if (numFields) {
2332             for (f = 0; f < numFields; f++) {
2333               pInd[numColIndices + f]             = offsets[f + 1];
2334               pInd[numColIndices + numFields + f] = newOffsets[f + 1];
2335             }
2336             for (cl = 0; cl < numPoints; cl++) {
2337               PetscInt globalOff, c = points[2 * cl];
2338               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
2339               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
2340             }
2341           } else {
2342             for (cl = 0; cl < numPoints; cl++) {
2343               PetscInt        c    = points[2 * cl], globalOff;
2344               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
2345 
2346               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
2347               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
2348             }
2349           }
2350           for (f = 0; f < maxFields; f++) {
2351             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
2352             else PetscCall(PetscSectionRestorePointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
2353           }
2354           PetscCall(DMRestoreWorkArray(coarse, numPoints, MPIU_SCALAR, &points));
2355         }
2356       } else if (matSize) {
2357         PetscInt  cOff;
2358         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
2359 
2360         numRowIndices = matSize / numColIndices;
2361         PetscCheck(numRowIndices == dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Miscounted dofs");
2362         PetscCall(DMGetWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
2363         PetscCall(DMGetWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
2364         PetscCall(PetscSectionGetOffset(cSec, p, &cOff));
2365         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
2366         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
2367         if (numFields) {
2368           for (f = 0; f < numFields; f++) {
2369             PetscInt fDof;
2370 
2371             PetscCall(PetscSectionGetFieldDof(cSec, p, f, &fDof));
2372             offsets[f + 1] = fDof;
2373             for (a = 0; a < aDof; a++) {
2374               PetscInt anchor = anchors[a + aOff];
2375               PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
2376               newOffsets[f + 1] += fDof;
2377             }
2378           }
2379           for (f = 0; f < numFields; f++) {
2380             offsets[f + 1] += offsets[f];
2381             offsetsCopy[f + 1] = offsets[f + 1];
2382             newOffsets[f + 1] += newOffsets[f];
2383             newOffsetsCopy[f + 1] = newOffsets[f + 1];
2384           }
2385           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, -1, NULL, rowIndices));
2386           for (a = 0; a < aDof; a++) {
2387             PetscInt anchor = anchors[a + aOff], lOff;
2388             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
2389             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, -1, NULL, colIndices));
2390           }
2391         } else {
2392           PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, NULL, rowIndices));
2393           for (a = 0; a < aDof; a++) {
2394             PetscInt anchor = anchors[a + aOff], lOff;
2395             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
2396             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, NULL, colIndices));
2397           }
2398         }
2399         if (numFields) {
2400           PetscInt count, a;
2401 
2402           for (f = 0, count = 0; f < numFields; f++) {
2403             PetscInt iSize = offsets[f + 1] - offsets[f];
2404             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
2405             PetscCall(MatGetValues(cMat, iSize, &rowIndices[offsets[f]], jSize, &colIndices[newOffsets[f]], &pMat[count]));
2406             count += iSize * jSize;
2407             pInd[numColIndices + f]             = offsets[f + 1];
2408             pInd[numColIndices + numFields + f] = newOffsets[f + 1];
2409           }
2410           for (a = 0; a < aDof; a++) {
2411             PetscInt anchor = anchors[a + aOff];
2412             PetscInt gOff;
2413             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
2414             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2415           }
2416         } else {
2417           PetscInt a;
2418           PetscCall(MatGetValues(cMat, numRowIndices, rowIndices, numColIndices, colIndices, pMat));
2419           for (a = 0; a < aDof; a++) {
2420             PetscInt anchor = anchors[a + aOff];
2421             PetscInt gOff;
2422             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
2423             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, NULL, pInd));
2424           }
2425         }
2426         PetscCall(DMRestoreWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
2427         PetscCall(DMRestoreWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
2428       } else {
2429         PetscInt gOff;
2430 
2431         PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
2432         if (numFields) {
2433           for (f = 0; f < numFields; f++) {
2434             PetscInt fDof;
2435             PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
2436             offsets[f + 1] = fDof + offsets[f];
2437           }
2438           for (f = 0; f < numFields; f++) {
2439             pInd[numColIndices + f]             = offsets[f + 1];
2440             pInd[numColIndices + numFields + f] = offsets[f + 1];
2441           }
2442           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2443         } else {
2444           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
2445         }
2446       }
2447     }
2448     PetscCall(PetscFree(maxChildIds));
2449   }
2450   {
2451     PetscSF   indicesSF, matricesSF;
2452     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
2453 
2454     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
2455     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafMatricesSec));
2456     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootIndicesSec, &remoteOffsetsIndices, leafIndicesSec));
2457     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootMatricesSec, &remoteOffsetsMatrices, leafMatricesSec));
2458     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootIndicesSec, remoteOffsetsIndices, leafIndicesSec, &indicesSF));
2459     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootMatricesSec, remoteOffsetsMatrices, leafMatricesSec, &matricesSF));
2460     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
2461     PetscCall(PetscFree(remoteOffsetsIndices));
2462     PetscCall(PetscFree(remoteOffsetsMatrices));
2463     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numLeafIndices));
2464     PetscCall(PetscSectionGetStorageSize(leafMatricesSec, &numLeafMatrices));
2465     PetscCall(PetscMalloc2(numLeafIndices, &leafIndices, numLeafMatrices, &leafMatrices));
2466     PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
2467     PetscCall(PetscSFBcastBegin(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
2468     PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
2469     PetscCall(PetscSFBcastEnd(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
2470     PetscCall(PetscSFDestroy(&matricesSF));
2471     PetscCall(PetscSFDestroy(&indicesSF));
2472     PetscCall(PetscFree2(rootIndices, rootMatrices));
2473     PetscCall(PetscSectionDestroy(&rootIndicesSec));
2474     PetscCall(PetscSectionDestroy(&rootMatricesSec));
2475   }
2476   /* count to preallocate */
2477   PetscCall(DMGetLocalSection(fine, &localFine));
2478   {
2479     PetscInt       nGlobal;
2480     PetscInt      *dnnz, *onnz;
2481     PetscLayout    rowMap, colMap;
2482     PetscInt       rowStart, rowEnd, colStart, colEnd;
2483     PetscInt       maxDof;
2484     PetscInt      *rowIndices;
2485     DM             refTree;
2486     PetscInt     **refPointFieldN;
2487     PetscScalar ***refPointFieldMats;
2488     PetscSection   refConSec, refAnSec;
2489     PetscInt       pRefStart, pRefEnd, maxConDof, maxColumns, leafStart, leafEnd;
2490     PetscScalar   *pointWork;
2491 
2492     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine, &nGlobal));
2493     PetscCall(PetscCalloc2(nGlobal, &dnnz, nGlobal, &onnz));
2494     PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
2495     PetscCall(PetscLayoutSetUp(rowMap));
2496     PetscCall(PetscLayoutSetUp(colMap));
2497     PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
2498     PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
2499     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
2500     PetscCall(PetscSectionGetChart(leafIndicesSec, &leafStart, &leafEnd));
2501     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
2502     for (p = leafStart; p < leafEnd; p++) {
2503       PetscInt gDof, gcDof, gOff;
2504       PetscInt numColIndices, pIndOff, *pInd;
2505       PetscInt matSize;
2506       PetscInt i;
2507 
2508       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
2509       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2510       if ((gDof - gcDof) <= 0) continue;
2511       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
2512       PetscCheck(gOff >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I though having global dofs meant a non-negative offset");
2513       PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I thought the row map would constrain the global dofs");
2514       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
2515       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2516       numColIndices -= 2 * numFields;
2517       PetscCheck(numColIndices > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "global fine dof with no dofs to interpolate from");
2518       pInd              = &leafIndices[pIndOff];
2519       offsets[0]        = 0;
2520       offsetsCopy[0]    = 0;
2521       newOffsets[0]     = 0;
2522       newOffsetsCopy[0] = 0;
2523       if (numFields) {
2524         PetscInt f;
2525         for (f = 0; f < numFields; f++) {
2526           PetscInt rowDof;
2527 
2528           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2529           offsets[f + 1]     = offsets[f] + rowDof;
2530           offsetsCopy[f + 1] = offsets[f + 1];
2531           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2532           numD[f]            = 0;
2533           numO[f]            = 0;
2534         }
2535         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
2536         for (f = 0; f < numFields; f++) {
2537           PetscInt colOffset    = newOffsets[f];
2538           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
2539 
2540           for (i = 0; i < numFieldCols; i++) {
2541             PetscInt gInd = pInd[i + colOffset];
2542 
2543             if (gInd >= colStart && gInd < colEnd) {
2544               numD[f]++;
2545             } else if (gInd >= 0) { /* negative means non-entry */
2546               numO[f]++;
2547             }
2548           }
2549         }
2550       } else {
2551         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
2552         numD[0] = 0;
2553         numO[0] = 0;
2554         for (i = 0; i < numColIndices; i++) {
2555           PetscInt gInd = pInd[i];
2556 
2557           if (gInd >= colStart && gInd < colEnd) {
2558             numD[0]++;
2559           } else if (gInd >= 0) { /* negative means non-entry */
2560             numO[0]++;
2561           }
2562         }
2563       }
2564       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2565       if (!matSize) { /* incoming matrix is identity */
2566         PetscInt childId;
2567 
2568         childId = childIds[p - pStartF];
2569         if (childId < 0) { /* no child interpolation: one nnz per */
2570           if (numFields) {
2571             PetscInt f;
2572             for (f = 0; f < numFields; f++) {
2573               PetscInt numRows = offsets[f + 1] - offsets[f], row;
2574               for (row = 0; row < numRows; row++) {
2575                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
2576                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
2577                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2578                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2579                   dnnz[gIndFine - rowStart] = 1;
2580                 } else if (gIndCoarse >= 0) { /* remote */
2581                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2582                   onnz[gIndFine - rowStart] = 1;
2583                 } else { /* constrained */
2584                   PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2585                 }
2586               }
2587             }
2588           } else {
2589             PetscInt i;
2590             for (i = 0; i < gDof; i++) {
2591               PetscInt gIndCoarse = pInd[i];
2592               PetscInt gIndFine   = rowIndices[i];
2593               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2594                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2595                 dnnz[gIndFine - rowStart] = 1;
2596               } else if (gIndCoarse >= 0) { /* remote */
2597                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2598                 onnz[gIndFine - rowStart] = 1;
2599               } else { /* constrained */
2600                 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2601               }
2602             }
2603           }
2604         } else { /* interpolate from all */
2605           if (numFields) {
2606             PetscInt f;
2607             for (f = 0; f < numFields; f++) {
2608               PetscInt numRows = offsets[f + 1] - offsets[f], row;
2609               for (row = 0; row < numRows; row++) {
2610                 PetscInt gIndFine = rowIndices[offsets[f] + row];
2611                 if (gIndFine >= 0) {
2612                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2613                   dnnz[gIndFine - rowStart] = numD[f];
2614                   onnz[gIndFine - rowStart] = numO[f];
2615                 }
2616               }
2617             }
2618           } else {
2619             PetscInt i;
2620             for (i = 0; i < gDof; i++) {
2621               PetscInt gIndFine = rowIndices[i];
2622               if (gIndFine >= 0) {
2623                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2624                 dnnz[gIndFine - rowStart] = numD[0];
2625                 onnz[gIndFine - rowStart] = numO[0];
2626               }
2627             }
2628           }
2629         }
2630       } else { /* interpolate from all */
2631         if (numFields) {
2632           PetscInt f;
2633           for (f = 0; f < numFields; f++) {
2634             PetscInt numRows = offsets[f + 1] - offsets[f], row;
2635             for (row = 0; row < numRows; row++) {
2636               PetscInt gIndFine = rowIndices[offsets[f] + row];
2637               if (gIndFine >= 0) {
2638                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2639                 dnnz[gIndFine - rowStart] = numD[f];
2640                 onnz[gIndFine - rowStart] = numO[f];
2641               }
2642             }
2643           }
2644         } else { /* every dof get a full row */
2645           PetscInt i;
2646           for (i = 0; i < gDof; i++) {
2647             PetscInt gIndFine = rowIndices[i];
2648             if (gIndFine >= 0) {
2649               PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2650               dnnz[gIndFine - rowStart] = numD[0];
2651               onnz[gIndFine - rowStart] = numO[0];
2652             }
2653           }
2654         }
2655       }
2656     }
2657     PetscCall(MatXAIJSetPreallocation(mat, 1, dnnz, onnz, NULL, NULL));
2658     PetscCall(PetscFree2(dnnz, onnz));
2659 
2660     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
2661     PetscCall(DMCopyDisc(fine, refTree));
2662     PetscCall(DMSetLocalSection(refTree, NULL));
2663     PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
2664     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
2665     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
2666     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
2667     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
2668     PetscCall(PetscSectionGetMaxDof(refConSec, &maxConDof));
2669     PetscCall(PetscSectionGetMaxDof(leafIndicesSec, &maxColumns));
2670     PetscCall(PetscMalloc1(maxConDof * maxColumns, &pointWork));
2671     for (p = leafStart; p < leafEnd; p++) {
2672       PetscInt gDof, gcDof, gOff;
2673       PetscInt numColIndices, pIndOff, *pInd;
2674       PetscInt matSize;
2675       PetscInt childId;
2676 
2677       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
2678       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2679       if ((gDof - gcDof) <= 0) continue;
2680       childId = childIds[p - pStartF];
2681       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
2682       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
2683       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2684       numColIndices -= 2 * numFields;
2685       pInd              = &leafIndices[pIndOff];
2686       offsets[0]        = 0;
2687       offsetsCopy[0]    = 0;
2688       newOffsets[0]     = 0;
2689       newOffsetsCopy[0] = 0;
2690       rowOffsets[0]     = 0;
2691       if (numFields) {
2692         PetscInt f;
2693         for (f = 0; f < numFields; f++) {
2694           PetscInt rowDof;
2695 
2696           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2697           offsets[f + 1]     = offsets[f] + rowDof;
2698           offsetsCopy[f + 1] = offsets[f + 1];
2699           rowOffsets[f + 1]  = pInd[numColIndices + f];
2700           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2701         }
2702         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
2703       } else {
2704         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
2705       }
2706       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2707       if (!matSize) {      /* incoming matrix is identity */
2708         if (childId < 0) { /* no child interpolation: scatter */
2709           if (numFields) {
2710             PetscInt f;
2711             for (f = 0; f < numFields; f++) {
2712               PetscInt numRows = offsets[f + 1] - offsets[f], row;
2713               for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[offsets[f] + row], pInd[newOffsets[f] + row], 1., INSERT_VALUES));
2714             }
2715           } else {
2716             PetscInt numRows = gDof, row;
2717             for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[row], pInd[row], 1., INSERT_VALUES));
2718           }
2719         } else { /* interpolate from all */
2720           if (numFields) {
2721             PetscInt f;
2722             for (f = 0; f < numFields; f++) {
2723               PetscInt numRows = offsets[f + 1] - offsets[f];
2724               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
2725               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], refPointFieldMats[childId - pRefStart][f], INSERT_VALUES));
2726             }
2727           } else {
2728             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, refPointFieldMats[childId - pRefStart][0], INSERT_VALUES));
2729           }
2730         }
2731       } else { /* interpolate from all */
2732         PetscInt     pMatOff;
2733         PetscScalar *pMat;
2734 
2735         PetscCall(PetscSectionGetOffset(leafMatricesSec, p, &pMatOff));
2736         pMat = &leafMatrices[pMatOff];
2737         if (childId < 0) { /* copy the incoming matrix */
2738           if (numFields) {
2739             PetscInt f, count;
2740             for (f = 0, count = 0; f < numFields; f++) {
2741               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2742               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2743               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2744               PetscScalar *inMat     = &pMat[count];
2745 
2746               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], inMat, INSERT_VALUES));
2747               count += numCols * numInRows;
2748             }
2749           } else {
2750             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, pMat, INSERT_VALUES));
2751           }
2752         } else { /* multiply the incoming matrix by the child interpolation */
2753           if (numFields) {
2754             PetscInt f, count;
2755             for (f = 0, count = 0; f < numFields; f++) {
2756               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2757               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2758               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2759               PetscScalar *inMat     = &pMat[count];
2760               PetscInt     i, j, k;
2761               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2762               for (i = 0; i < numRows; i++) {
2763                 for (j = 0; j < numCols; j++) {
2764                   PetscScalar val = 0.;
2765                   for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2766                   pointWork[i * numCols + j] = val;
2767                 }
2768               }
2769               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], pointWork, INSERT_VALUES));
2770               count += numCols * numInRows;
2771             }
2772           } else { /* every dof gets a full row */
2773             PetscInt numRows   = gDof;
2774             PetscInt numCols   = numColIndices;
2775             PetscInt numInRows = matSize / numColIndices;
2776             PetscInt i, j, k;
2777             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2778             for (i = 0; i < numRows; i++) {
2779               for (j = 0; j < numCols; j++) {
2780                 PetscScalar val = 0.;
2781                 for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2782                 pointWork[i * numCols + j] = val;
2783               }
2784             }
2785             PetscCall(MatSetValues(mat, numRows, rowIndices, numCols, pInd, pointWork, INSERT_VALUES));
2786           }
2787         }
2788       }
2789     }
2790     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
2791     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
2792     PetscCall(PetscFree(pointWork));
2793   }
2794   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
2795   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
2796   PetscCall(PetscSectionDestroy(&leafIndicesSec));
2797   PetscCall(PetscSectionDestroy(&leafMatricesSec));
2798   PetscCall(PetscFree2(leafIndices, leafMatrices));
2799   PetscCall(PetscFree2(*(PetscInt ****)&perms, *(PetscScalar ****)&flips));
2800   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
2801   PetscCall(ISRestoreIndices(aIS, &anchors));
2802   PetscFunctionReturn(PETSC_SUCCESS);
2803 }
2804 
2805 /*
2806  * Assuming a nodal basis (w.r.t. the dual basis) basis:
2807  *
2808  * for each coarse dof \phi^c_i:
2809  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
2810  *     for each fine dof \phi^f_j;
2811  *       a_{i,j} = 0;
2812  *       for each fine dof \phi^f_k:
2813  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
2814  *                    [^^^ this is = \phi^c_i ^^^]
2815  */
2816 PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
2817 {
2818   PetscDS      ds;
2819   PetscSection section, cSection;
2820   DMLabel      canonical, depth;
2821   Mat          cMat, mat;
2822   PetscInt    *nnz;
2823   PetscInt     f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
2824   PetscInt     m, n;
2825   PetscScalar *pointScalar;
2826   PetscReal   *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
2827 
2828   PetscFunctionBegin;
2829   PetscCall(DMGetLocalSection(refTree, &section));
2830   PetscCall(DMGetDimension(refTree, &dim));
2831   PetscCall(PetscMalloc6(dim, &v0, dim, &v0parent, dim, &vtmp, dim * dim, &J, dim * dim, &Jparent, dim * dim, &invJ));
2832   PetscCall(PetscMalloc2(dim, &pointScalar, dim, &pointRef));
2833   PetscCall(DMGetDS(refTree, &ds));
2834   PetscCall(PetscDSGetNumFields(ds, &numFields));
2835   PetscCall(PetscSectionGetNumFields(section, &numSecFields));
2836   PetscCall(DMGetLabel(refTree, "canonical", &canonical));
2837   PetscCall(DMGetLabel(refTree, "depth", &depth));
2838   PetscCall(DMGetDefaultConstraints(refTree, &cSection, &cMat, NULL));
2839   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
2840   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
2841   PetscCall(MatGetSize(cMat, &n, &m)); /* the injector has transpose sizes from the constraint matrix */
2842   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
2843   PetscCall(PetscCalloc1(m, &nnz));
2844   for (p = pStart; p < pEnd; p++) { /* a point will have non-zeros if it is canonical, it has dofs, and its children have dofs */
2845     const PetscInt *children;
2846     PetscInt        numChildren;
2847     PetscInt        i, numChildDof, numSelfDof;
2848 
2849     if (canonical) {
2850       PetscInt pCanonical;
2851       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
2852       if (p != pCanonical) continue;
2853     }
2854     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
2855     if (!numChildren) continue;
2856     for (i = 0, numChildDof = 0; i < numChildren; i++) {
2857       PetscInt child = children[i];
2858       PetscInt dof;
2859 
2860       PetscCall(PetscSectionGetDof(section, child, &dof));
2861       numChildDof += dof;
2862     }
2863     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
2864     if (!numChildDof || !numSelfDof) continue;
2865     for (f = 0; f < numFields; f++) {
2866       PetscInt selfOff;
2867 
2868       if (numSecFields) { /* count the dofs for just this field */
2869         for (i = 0, numChildDof = 0; i < numChildren; i++) {
2870           PetscInt child = children[i];
2871           PetscInt dof;
2872 
2873           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
2874           numChildDof += dof;
2875         }
2876         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
2877         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
2878       } else {
2879         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
2880       }
2881       for (i = 0; i < numSelfDof; i++) nnz[selfOff + i] = numChildDof;
2882     }
2883   }
2884   PetscCall(MatCreateAIJ(PETSC_COMM_SELF, m, n, m, n, -1, nnz, -1, NULL, &mat));
2885   PetscCall(PetscFree(nnz));
2886   /* Setp 2: compute entries */
2887   for (p = pStart; p < pEnd; p++) {
2888     const PetscInt *children;
2889     PetscInt        numChildren;
2890     PetscInt        i, numChildDof, numSelfDof;
2891 
2892     /* same conditions about when entries occur */
2893     if (canonical) {
2894       PetscInt pCanonical;
2895       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
2896       if (p != pCanonical) continue;
2897     }
2898     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
2899     if (!numChildren) continue;
2900     for (i = 0, numChildDof = 0; i < numChildren; i++) {
2901       PetscInt child = children[i];
2902       PetscInt dof;
2903 
2904       PetscCall(PetscSectionGetDof(section, child, &dof));
2905       numChildDof += dof;
2906     }
2907     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
2908     if (!numChildDof || !numSelfDof) continue;
2909 
2910     for (f = 0; f < numFields; f++) {
2911       PetscInt        pI = -1, cI = -1;
2912       PetscInt        selfOff, Nc, parentCell;
2913       PetscInt        cellShapeOff;
2914       PetscObject     disc;
2915       PetscDualSpace  dsp;
2916       PetscClassId    classId;
2917       PetscScalar    *pointMat;
2918       PetscInt       *matRows, *matCols;
2919       PetscInt        pO = PETSC_MIN_INT;
2920       const PetscInt *depthNumDof;
2921 
2922       if (numSecFields) {
2923         for (i = 0, numChildDof = 0; i < numChildren; i++) {
2924           PetscInt child = children[i];
2925           PetscInt dof;
2926 
2927           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
2928           numChildDof += dof;
2929         }
2930         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
2931         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
2932       } else {
2933         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
2934       }
2935 
2936       /* find a cell whose closure contains p */
2937       if (p >= cStart && p < cEnd) {
2938         parentCell = p;
2939       } else {
2940         PetscInt *star = NULL;
2941         PetscInt  numStar;
2942 
2943         parentCell = -1;
2944         PetscCall(DMPlexGetTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
2945         for (i = numStar - 1; i >= 0; i--) {
2946           PetscInt c = star[2 * i];
2947 
2948           if (c >= cStart && c < cEnd) {
2949             parentCell = c;
2950             break;
2951           }
2952         }
2953         PetscCall(DMPlexRestoreTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
2954       }
2955       /* determine the offset of p's shape functions within parentCell's shape functions */
2956       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
2957       PetscCall(PetscObjectGetClassId(disc, &classId));
2958       if (classId == PETSCFE_CLASSID) {
2959         PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
2960       } else if (classId == PETSCFV_CLASSID) {
2961         PetscCall(PetscFVGetDualSpace((PetscFV)disc, &dsp));
2962       } else {
2963         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported discretization object");
2964       }
2965       PetscCall(PetscDualSpaceGetNumDof(dsp, &depthNumDof));
2966       PetscCall(PetscDualSpaceGetNumComponents(dsp, &Nc));
2967       {
2968         PetscInt *closure = NULL;
2969         PetscInt  numClosure;
2970 
2971         PetscCall(DMPlexGetTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
2972         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
2973           PetscInt point = closure[2 * i], pointDepth;
2974 
2975           pO = closure[2 * i + 1];
2976           if (point == p) {
2977             pI = i;
2978             break;
2979           }
2980           PetscCall(DMLabelGetValue(depth, point, &pointDepth));
2981           cellShapeOff += depthNumDof[pointDepth];
2982         }
2983         PetscCall(DMPlexRestoreTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
2984       }
2985 
2986       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
2987       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
2988       matCols = matRows + numSelfDof;
2989       for (i = 0; i < numSelfDof; i++) matRows[i] = selfOff + i;
2990       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
2991       {
2992         PetscInt colOff = 0;
2993 
2994         for (i = 0; i < numChildren; i++) {
2995           PetscInt child = children[i];
2996           PetscInt dof, off, j;
2997 
2998           if (numSecFields) {
2999             PetscCall(PetscSectionGetFieldDof(cSection, child, f, &dof));
3000             PetscCall(PetscSectionGetFieldOffset(cSection, child, f, &off));
3001           } else {
3002             PetscCall(PetscSectionGetDof(cSection, child, &dof));
3003             PetscCall(PetscSectionGetOffset(cSection, child, &off));
3004           }
3005 
3006           for (j = 0; j < dof; j++) matCols[colOff++] = off + j;
3007         }
3008       }
3009       if (classId == PETSCFE_CLASSID) {
3010         PetscFE              fe = (PetscFE)disc;
3011         PetscInt             fSize;
3012         const PetscInt    ***perms;
3013         const PetscScalar ***flips;
3014         const PetscInt      *pperms;
3015 
3016         PetscCall(PetscFEGetDualSpace(fe, &dsp));
3017         PetscCall(PetscDualSpaceGetDimension(dsp, &fSize));
3018         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
3019         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
3020         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
3021           PetscQuadrature  q;
3022           PetscInt         dim, thisNc, numPoints, j, k;
3023           const PetscReal *points;
3024           const PetscReal *weights;
3025           PetscInt        *closure = NULL;
3026           PetscInt         numClosure;
3027           PetscInt         iCell              = pperms ? pperms[i] : i;
3028           PetscInt         parentCellShapeDof = cellShapeOff + iCell;
3029           PetscTabulation  Tparent;
3030 
3031           PetscCall(PetscDualSpaceGetFunctional(dsp, parentCellShapeDof, &q));
3032           PetscCall(PetscQuadratureGetData(q, &dim, &thisNc, &numPoints, &points, &weights));
3033           PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
3034           PetscCall(PetscFECreateTabulation(fe, 1, numPoints, points, 0, &Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
3035           for (j = 0; j < numPoints; j++) {
3036             PetscInt           childCell = -1;
3037             PetscReal         *parentValAtPoint;
3038             const PetscReal    xi0[3]    = {-1., -1., -1.};
3039             const PetscReal   *pointReal = &points[dim * j];
3040             const PetscScalar *point;
3041             PetscTabulation    Tchild;
3042             PetscInt           childCellShapeOff, pointMatOff;
3043 #if defined(PETSC_USE_COMPLEX)
3044             PetscInt d;
3045 
3046             for (d = 0; d < dim; d++) pointScalar[d] = points[dim * j + d];
3047             point = pointScalar;
3048 #else
3049             point = pointReal;
3050 #endif
3051 
3052             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
3053 
3054             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
3055               PetscInt  child = children[k];
3056               PetscInt *star  = NULL;
3057               PetscInt  numStar, s;
3058 
3059               PetscCall(DMPlexGetTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
3060               for (s = numStar - 1; s >= 0; s--) {
3061                 PetscInt c = star[2 * s];
3062 
3063                 if (c < cStart || c >= cEnd) continue;
3064                 PetscCall(DMPlexLocatePoint_Internal(refTree, dim, point, c, &childCell));
3065                 if (childCell >= 0) break;
3066               }
3067               PetscCall(DMPlexRestoreTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
3068               if (childCell >= 0) break;
3069             }
3070             PetscCheck(childCell >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not locate quadrature point");
3071             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
3072             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3073             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3074             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
3075 
3076             PetscCall(PetscFECreateTabulation(fe, 1, 1, pointRef, 0, &Tchild));
3077             PetscCall(DMPlexGetTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
3078             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3079               PetscInt        child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
3080               PetscInt        l;
3081               const PetscInt *cperms;
3082 
3083               PetscCall(DMLabelGetValue(depth, child, &childDepth));
3084               childDof = depthNumDof[childDepth];
3085               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
3086                 PetscInt point = closure[2 * l];
3087                 PetscInt pointDepth;
3088 
3089                 childO = closure[2 * l + 1];
3090                 if (point == child) {
3091                   cI = l;
3092                   break;
3093                 }
3094                 PetscCall(DMLabelGetValue(depth, point, &pointDepth));
3095                 childCellShapeOff += depthNumDof[pointDepth];
3096               }
3097               if (l == numClosure) {
3098                 pointMatOff += childDof;
3099                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
3100               }
3101               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
3102               for (l = 0; l < childDof; l++) {
3103                 PetscInt   lCell        = cperms ? cperms[l] : l;
3104                 PetscInt   childCellDof = childCellShapeOff + lCell;
3105                 PetscReal *childValAtPoint;
3106                 PetscReal  val = 0.;
3107 
3108                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
3109                 for (m = 0; m < Nc; m++) val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
3110 
3111                 pointMat[i * numChildDof + pointMatOff + l] += val;
3112               }
3113               pointMatOff += childDof;
3114             }
3115             PetscCall(DMPlexRestoreTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
3116             PetscCall(PetscTabulationDestroy(&Tchild));
3117           }
3118           PetscCall(PetscTabulationDestroy(&Tparent));
3119         }
3120       } else { /* just the volume-weighted averages of the children */
3121         PetscReal parentVol;
3122         PetscInt  childCell;
3123 
3124         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3125         for (i = 0, childCell = 0; i < numChildren; i++) {
3126           PetscInt  child = children[i], j;
3127           PetscReal childVol;
3128 
3129           if (child < cStart || child >= cEnd) continue;
3130           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
3131           for (j = 0; j < Nc; j++) pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
3132           childCell++;
3133         }
3134       }
3135       /* Insert pointMat into mat */
3136       PetscCall(MatSetValues(mat, numSelfDof, matRows, numChildDof, matCols, pointMat, INSERT_VALUES));
3137       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
3138       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
3139     }
3140   }
3141   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJ));
3142   PetscCall(PetscFree2(pointScalar, pointRef));
3143   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
3144   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
3145   *inj = mat;
3146   PetscFunctionReturn(PETSC_SUCCESS);
3147 }
3148 
3149 static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3150 {
3151   PetscDS        ds;
3152   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3153   PetscScalar ***refPointFieldMats;
3154   PetscSection   refConSec, refSection;
3155 
3156   PetscFunctionBegin;
3157   PetscCall(DMGetDS(refTree, &ds));
3158   PetscCall(PetscDSGetNumFields(ds, &numFields));
3159   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
3160   PetscCall(DMGetLocalSection(refTree, &refSection));
3161   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3162   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
3163   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
3164   PetscCall(PetscMalloc1(maxDof, &rows));
3165   PetscCall(PetscMalloc1(maxDof * maxDof, &cols));
3166   for (p = pRefStart; p < pRefEnd; p++) {
3167     PetscInt parent, pDof, parentDof;
3168 
3169     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
3170     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
3171     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3172     if (!pDof || !parentDof || parent == p) continue;
3173 
3174     PetscCall(PetscMalloc1(numFields, &refPointFieldMats[p - pRefStart]));
3175     for (f = 0; f < numFields; f++) {
3176       PetscInt cDof, cOff, numCols, r;
3177 
3178       if (numFields > 1) {
3179         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
3180         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
3181       } else {
3182         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3183         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
3184       }
3185 
3186       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
3187       numCols = 0;
3188       {
3189         PetscInt aDof, aOff, j;
3190 
3191         if (numFields > 1) {
3192           PetscCall(PetscSectionGetFieldDof(refSection, parent, f, &aDof));
3193           PetscCall(PetscSectionGetFieldOffset(refSection, parent, f, &aOff));
3194         } else {
3195           PetscCall(PetscSectionGetDof(refSection, parent, &aDof));
3196           PetscCall(PetscSectionGetOffset(refSection, parent, &aOff));
3197         }
3198 
3199         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + j;
3200       }
3201       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
3202       /* transpose of constraint matrix */
3203       PetscCall(MatGetValues(inj, numCols, cols, cDof, rows, refPointFieldMats[p - pRefStart][f]));
3204     }
3205   }
3206   *childrenMats = refPointFieldMats;
3207   PetscCall(PetscFree(rows));
3208   PetscCall(PetscFree(cols));
3209   PetscFunctionReturn(PETSC_SUCCESS);
3210 }
3211 
3212 static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3213 {
3214   PetscDS        ds;
3215   PetscScalar ***refPointFieldMats;
3216   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3217   PetscSection   refConSec, refSection;
3218 
3219   PetscFunctionBegin;
3220   refPointFieldMats = *childrenMats;
3221   *childrenMats     = NULL;
3222   PetscCall(DMGetDS(refTree, &ds));
3223   PetscCall(DMGetLocalSection(refTree, &refSection));
3224   PetscCall(PetscDSGetNumFields(ds, &numFields));
3225   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
3226   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3227   for (p = pRefStart; p < pRefEnd; p++) {
3228     PetscInt parent, pDof, parentDof;
3229 
3230     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
3231     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
3232     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3233     if (!pDof || !parentDof || parent == p) continue;
3234 
3235     for (f = 0; f < numFields; f++) {
3236       PetscInt cDof;
3237 
3238       if (numFields > 1) {
3239         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
3240       } else {
3241         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3242       }
3243 
3244       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3245     }
3246     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3247   }
3248   PetscCall(PetscFree(refPointFieldMats));
3249   PetscFunctionReturn(PETSC_SUCCESS);
3250 }
3251 
3252 static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree, Mat *injRef)
3253 {
3254   Mat         cMatRef;
3255   PetscObject injRefObj;
3256 
3257   PetscFunctionBegin;
3258   PetscCall(DMGetDefaultConstraints(refTree, NULL, &cMatRef, NULL));
3259   PetscCall(PetscObjectQuery((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", &injRefObj));
3260   *injRef = (Mat)injRefObj;
3261   if (!*injRef) {
3262     PetscCall(DMPlexComputeInjectorReferenceTree(refTree, injRef));
3263     PetscCall(PetscObjectCompose((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", (PetscObject)*injRef));
3264     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
3265     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3266   }
3267   PetscFunctionReturn(PETSC_SUCCESS);
3268 }
3269 
3270 static PetscErrorCode DMPlexTransferInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, const PetscInt *childIds, Vec fineVec, PetscInt numFields, PetscInt *offsets, PetscSection *rootMultiSec, PetscSection *multiLeafSec, PetscInt **gatheredIndices, PetscScalar **gatheredValues)
3271 {
3272   PetscInt        pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3273   PetscSection    globalCoarse, globalFine;
3274   PetscSection    localCoarse, localFine, leafIndicesSec;
3275   PetscSection    multiRootSec, rootIndicesSec;
3276   PetscInt       *leafInds, *rootInds = NULL;
3277   const PetscInt *rootDegrees;
3278   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3279   PetscSF         coarseToFineEmbedded;
3280 
3281   PetscFunctionBegin;
3282   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
3283   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
3284   PetscCall(DMGetLocalSection(fine, &localFine));
3285   PetscCall(DMGetGlobalSection(fine, &globalFine));
3286   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
3287   PetscCall(PetscSectionSetChart(leafIndicesSec, pStartF, pEndF));
3288   PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
3289   { /* winnow fine points that don't have global dofs out of the sf */
3290     PetscInt        l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
3291     const PetscInt *leaves;
3292 
3293     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
3294     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3295       p = leaves ? leaves[l] : l;
3296       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
3297       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3298       if ((dof - cdof) > 0) {
3299         numPointsWithDofs++;
3300 
3301         PetscCall(PetscSectionGetDof(localFine, p, &dof));
3302         PetscCall(PetscSectionSetDof(leafIndicesSec, p, dof + 1));
3303       }
3304     }
3305     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
3306     PetscCall(PetscSectionSetUp(leafIndicesSec));
3307     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numIndices));
3308     PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1), &leafInds));
3309     if (gatheredValues) PetscCall(PetscMalloc1(numIndices, &leafVals));
3310     for (l = 0, offset = 0; l < nleaves; l++) {
3311       p = leaves ? leaves[l] : l;
3312       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
3313       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3314       if ((dof - cdof) > 0) {
3315         PetscInt     off, gOff;
3316         PetscInt    *pInd;
3317         PetscScalar *pVal = NULL;
3318 
3319         pointsWithDofs[offset++] = l;
3320 
3321         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3322 
3323         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3324         if (gatheredValues) {
3325           PetscInt i;
3326 
3327           pVal = &leafVals[off + 1];
3328           for (i = 0; i < dof; i++) pVal[i] = 0.;
3329         }
3330         PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
3331 
3332         offsets[0] = 0;
3333         if (numFields) {
3334           PetscInt f;
3335 
3336           for (f = 0; f < numFields; f++) {
3337             PetscInt fDof;
3338             PetscCall(PetscSectionGetFieldDof(localFine, p, f, &fDof));
3339             offsets[f + 1] = fDof + offsets[f];
3340           }
3341           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
3342         } else {
3343           PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
3344         }
3345         if (gatheredValues) PetscCall(VecGetValues(fineVec, dof, pInd, pVal));
3346       }
3347     }
3348     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
3349     PetscCall(PetscFree(pointsWithDofs));
3350   }
3351 
3352   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
3353   PetscCall(DMGetLocalSection(coarse, &localCoarse));
3354   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3355 
3356   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
3357     MPI_Datatype threeInt;
3358     PetscMPIInt  rank;
3359     PetscInt(*parentNodeAndIdCoarse)[3];
3360     PetscInt(*parentNodeAndIdFine)[3];
3361     PetscInt           p, nleaves, nleavesToParents;
3362     PetscSF            pointSF, sfToParents;
3363     const PetscInt    *ilocal;
3364     const PetscSFNode *iremote;
3365     PetscSFNode       *iremoteToParents;
3366     PetscInt          *ilocalToParents;
3367 
3368     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse), &rank));
3369     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &threeInt));
3370     PetscCallMPI(MPI_Type_commit(&threeInt));
3371     PetscCall(PetscMalloc2(pEndC - pStartC, &parentNodeAndIdCoarse, pEndF - pStartF, &parentNodeAndIdFine));
3372     PetscCall(DMGetPointSF(coarse, &pointSF));
3373     PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, &iremote));
3374     for (p = pStartC; p < pEndC; p++) {
3375       PetscInt parent, childId;
3376       PetscCall(DMPlexGetTreeParent(coarse, p, &parent, &childId));
3377       parentNodeAndIdCoarse[p - pStartC][0] = rank;
3378       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
3379       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
3380       if (nleaves > 0) {
3381         PetscInt leaf = -1;
3382 
3383         if (ilocal) {
3384           PetscCall(PetscFindInt(parent, nleaves, ilocal, &leaf));
3385         } else {
3386           leaf = p - pStartC;
3387         }
3388         if (leaf >= 0) {
3389           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
3390           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
3391         }
3392       }
3393     }
3394     for (p = pStartF; p < pEndF; p++) {
3395       parentNodeAndIdFine[p - pStartF][0] = -1;
3396       parentNodeAndIdFine[p - pStartF][1] = -1;
3397       parentNodeAndIdFine[p - pStartF][2] = -1;
3398     }
3399     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
3400     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
3401     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3402       PetscInt dof;
3403 
3404       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &dof));
3405       if (dof) {
3406         PetscInt off;
3407 
3408         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3409         if (gatheredIndices) {
3410           leafInds[off] = PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3411         } else if (gatheredValues) {
3412           leafVals[off] = (PetscScalar)PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3413         }
3414       }
3415       if (parentNodeAndIdFine[p - pStartF][0] >= 0) nleavesToParents++;
3416     }
3417     PetscCall(PetscMalloc1(nleavesToParents, &ilocalToParents));
3418     PetscCall(PetscMalloc1(nleavesToParents, &iremoteToParents));
3419     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3420       if (parentNodeAndIdFine[p - pStartF][0] >= 0) {
3421         ilocalToParents[nleavesToParents]        = p - pStartF;
3422         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p - pStartF][0];
3423         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p - pStartF][1];
3424         nleavesToParents++;
3425       }
3426     }
3427     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse), &sfToParents));
3428     PetscCall(PetscSFSetGraph(sfToParents, pEndC - pStartC, nleavesToParents, ilocalToParents, PETSC_OWN_POINTER, iremoteToParents, PETSC_OWN_POINTER));
3429     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3430 
3431     coarseToFineEmbedded = sfToParents;
3432 
3433     PetscCall(PetscFree2(parentNodeAndIdCoarse, parentNodeAndIdFine));
3434     PetscCallMPI(MPI_Type_free(&threeInt));
3435   }
3436 
3437   { /* winnow out coarse points that don't have dofs */
3438     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
3439     PetscSF  sfDofsOnly;
3440 
3441     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
3442       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3443       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3444       if ((dof - cdof) > 0) numPointsWithDofs++;
3445     }
3446     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
3447     for (p = pStartC, offset = 0; p < pEndC; p++) {
3448       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3449       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3450       if ((dof - cdof) > 0) pointsWithDofs[offset++] = p - pStartC;
3451     }
3452     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
3453     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3454     PetscCall(PetscFree(pointsWithDofs));
3455     coarseToFineEmbedded = sfDofsOnly;
3456   }
3457 
3458   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
3459   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded, &rootDegrees));
3460   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded, &rootDegrees));
3461   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &multiRootSec));
3462   PetscCall(PetscSectionSetChart(multiRootSec, pStartC, pEndC));
3463   for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionSetDof(multiRootSec, p, rootDegrees[p - pStartC]));
3464   PetscCall(PetscSectionSetUp(multiRootSec));
3465   PetscCall(PetscSectionGetStorageSize(multiRootSec, &numMulti));
3466   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
3467   { /* distribute the leaf section */
3468     PetscSF   multi, multiInv, indicesSF;
3469     PetscInt *remoteOffsets, numRootIndices;
3470 
3471     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded, &multi));
3472     PetscCall(PetscSFCreateInverseSF(multi, &multiInv));
3473     PetscCall(PetscSFDistributeSection(multiInv, leafIndicesSec, &remoteOffsets, rootIndicesSec));
3474     PetscCall(PetscSFCreateSectionSF(multiInv, leafIndicesSec, remoteOffsets, rootIndicesSec, &indicesSF));
3475     PetscCall(PetscFree(remoteOffsets));
3476     PetscCall(PetscSFDestroy(&multiInv));
3477     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
3478     if (gatheredIndices) {
3479       PetscCall(PetscMalloc1(numRootIndices, &rootInds));
3480       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3481       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3482     }
3483     if (gatheredValues) {
3484       PetscCall(PetscMalloc1(numRootIndices, &rootVals));
3485       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3486       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3487     }
3488     PetscCall(PetscSFDestroy(&indicesSF));
3489   }
3490   PetscCall(PetscSectionDestroy(&leafIndicesSec));
3491   PetscCall(PetscFree(leafInds));
3492   PetscCall(PetscFree(leafVals));
3493   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3494   *rootMultiSec = multiRootSec;
3495   *multiLeafSec = rootIndicesSec;
3496   if (gatheredIndices) *gatheredIndices = rootInds;
3497   if (gatheredValues) *gatheredValues = rootVals;
3498   PetscFunctionReturn(PETSC_SUCCESS);
3499 }
3500 
3501 PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3502 {
3503   DM             refTree;
3504   PetscSection   multiRootSec, rootIndicesSec;
3505   PetscSection   globalCoarse, globalFine;
3506   PetscSection   localCoarse, localFine;
3507   PetscSection   cSecRef;
3508   PetscInt      *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3509   Mat            injRef;
3510   PetscInt       numFields, maxDof;
3511   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3512   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
3513   PetscLayout    rowMap, colMap;
3514   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3515   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3516 
3517   PetscFunctionBegin;
3518   /* get the templates for the fine-to-coarse injection from the reference tree */
3519   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
3520   PetscCall(DMCopyDisc(coarse, refTree));
3521   PetscCall(DMSetLocalSection(refTree, NULL));
3522   PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
3523   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
3524   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
3525   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
3526 
3527   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
3528   PetscCall(DMGetLocalSection(fine, &localFine));
3529   PetscCall(DMGetGlobalSection(fine, &globalFine));
3530   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
3531   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
3532   PetscCall(DMGetLocalSection(coarse, &localCoarse));
3533   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3534   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
3535   {
3536     PetscInt maxFields = PetscMax(1, numFields) + 1;
3537     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
3538   }
3539 
3540   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, childIds, NULL, numFields, offsets, &multiRootSec, &rootIndicesSec, &rootIndices, NULL));
3541 
3542   PetscCall(PetscMalloc1(maxDof, &parentIndices));
3543 
3544   /* count indices */
3545   PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
3546   PetscCall(PetscLayoutSetUp(rowMap));
3547   PetscCall(PetscLayoutSetUp(colMap));
3548   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
3549   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
3550   PetscCall(PetscCalloc2(rowEnd - rowStart, &nnzD, rowEnd - rowStart, &nnzO));
3551   for (p = pStartC; p < pEndC; p++) {
3552     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3553 
3554     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3555     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3556     if ((dof - cdof) <= 0) continue;
3557     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
3558 
3559     rowOffsets[0]  = 0;
3560     offsetsCopy[0] = 0;
3561     if (numFields) {
3562       PetscInt f;
3563 
3564       for (f = 0; f < numFields; f++) {
3565         PetscInt fDof;
3566         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3567         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3568       }
3569       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3570     } else {
3571       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3572       rowOffsets[1] = offsetsCopy[0];
3573     }
3574 
3575     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
3576     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3577     leafEnd = leafStart + numLeaves;
3578     for (l = leafStart; l < leafEnd; l++) {
3579       PetscInt        numIndices, childId, offset;
3580       const PetscInt *childIndices;
3581 
3582       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
3583       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3584       childId      = rootIndices[offset++];
3585       childIndices = &rootIndices[offset];
3586       numIndices--;
3587 
3588       if (childId == -1) { /* equivalent points: scatter */
3589         PetscInt i;
3590 
3591         for (i = 0; i < numIndices; i++) {
3592           PetscInt colIndex = childIndices[i];
3593           PetscInt rowIndex = parentIndices[i];
3594           if (rowIndex < 0) continue;
3595           PetscCheck(colIndex >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unconstrained fine and constrained coarse");
3596           if (colIndex >= colStart && colIndex < colEnd) {
3597             nnzD[rowIndex - rowStart] = 1;
3598           } else {
3599             nnzO[rowIndex - rowStart] = 1;
3600           }
3601         }
3602       } else {
3603         PetscInt parentId, f, lim;
3604 
3605         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3606 
3607         lim        = PetscMax(1, numFields);
3608         offsets[0] = 0;
3609         if (numFields) {
3610           PetscInt f;
3611 
3612           for (f = 0; f < numFields; f++) {
3613             PetscInt fDof;
3614             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3615 
3616             offsets[f + 1] = fDof + offsets[f];
3617           }
3618         } else {
3619           PetscInt cDof;
3620 
3621           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3622           offsets[1] = cDof;
3623         }
3624         for (f = 0; f < lim; f++) {
3625           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3626           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3627           PetscInt i, numD = 0, numO = 0;
3628 
3629           for (i = childStart; i < childEnd; i++) {
3630             PetscInt colIndex = childIndices[i];
3631 
3632             if (colIndex < 0) continue;
3633             if (colIndex >= colStart && colIndex < colEnd) {
3634               numD++;
3635             } else {
3636               numO++;
3637             }
3638           }
3639           for (i = parentStart; i < parentEnd; i++) {
3640             PetscInt rowIndex = parentIndices[i];
3641 
3642             if (rowIndex < 0) continue;
3643             nnzD[rowIndex - rowStart] += numD;
3644             nnzO[rowIndex - rowStart] += numO;
3645           }
3646         }
3647       }
3648     }
3649   }
3650   /* preallocate */
3651   PetscCall(MatXAIJSetPreallocation(mat, 1, nnzD, nnzO, NULL, NULL));
3652   PetscCall(PetscFree2(nnzD, nnzO));
3653   /* insert values */
3654   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3655   for (p = pStartC; p < pEndC; p++) {
3656     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3657 
3658     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3659     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3660     if ((dof - cdof) <= 0) continue;
3661     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
3662 
3663     rowOffsets[0]  = 0;
3664     offsetsCopy[0] = 0;
3665     if (numFields) {
3666       PetscInt f;
3667 
3668       for (f = 0; f < numFields; f++) {
3669         PetscInt fDof;
3670         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3671         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3672       }
3673       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3674     } else {
3675       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3676       rowOffsets[1] = offsetsCopy[0];
3677     }
3678 
3679     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
3680     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3681     leafEnd = leafStart + numLeaves;
3682     for (l = leafStart; l < leafEnd; l++) {
3683       PetscInt        numIndices, childId, offset;
3684       const PetscInt *childIndices;
3685 
3686       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
3687       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3688       childId      = rootIndices[offset++];
3689       childIndices = &rootIndices[offset];
3690       numIndices--;
3691 
3692       if (childId == -1) { /* equivalent points: scatter */
3693         PetscInt i;
3694 
3695         for (i = 0; i < numIndices; i++) PetscCall(MatSetValue(mat, parentIndices[i], childIndices[i], 1., INSERT_VALUES));
3696       } else {
3697         PetscInt parentId, f, lim;
3698 
3699         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3700 
3701         lim        = PetscMax(1, numFields);
3702         offsets[0] = 0;
3703         if (numFields) {
3704           PetscInt f;
3705 
3706           for (f = 0; f < numFields; f++) {
3707             PetscInt fDof;
3708             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3709 
3710             offsets[f + 1] = fDof + offsets[f];
3711           }
3712         } else {
3713           PetscInt cDof;
3714 
3715           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3716           offsets[1] = cDof;
3717         }
3718         for (f = 0; f < lim; f++) {
3719           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3720           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3721           const PetscInt *colIndices = &childIndices[offsets[f]];
3722 
3723           PetscCall(MatSetValues(mat, rowOffsets[f + 1] - rowOffsets[f], rowIndices, offsets[f + 1] - offsets[f], colIndices, childMat, INSERT_VALUES));
3724         }
3725       }
3726     }
3727   }
3728   PetscCall(PetscSectionDestroy(&multiRootSec));
3729   PetscCall(PetscSectionDestroy(&rootIndicesSec));
3730   PetscCall(PetscFree(parentIndices));
3731   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3732   PetscCall(PetscFree(rootIndices));
3733   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
3734 
3735   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
3736   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
3737   PetscFunctionReturn(PETSC_SUCCESS);
3738 }
3739 
3740 static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3741 {
3742   PetscSF            coarseToFineEmbedded;
3743   PetscSection       globalCoarse, globalFine;
3744   PetscSection       localCoarse, localFine;
3745   PetscSection       aSec, cSec;
3746   PetscSection       rootValuesSec;
3747   PetscSection       leafValuesSec;
3748   PetscScalar       *rootValues, *leafValues;
3749   IS                 aIS;
3750   const PetscInt    *anchors;
3751   Mat                cMat;
3752   PetscInt           numFields;
3753   PetscInt           pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
3754   PetscInt           aStart, aEnd, cStart, cEnd;
3755   PetscInt          *maxChildIds;
3756   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
3757   PetscFV            fv = NULL;
3758   PetscInt           dim, numFVcomps = -1, fvField = -1;
3759   DM                 cellDM = NULL, gradDM = NULL;
3760   const PetscScalar *cellGeomArray = NULL;
3761   const PetscScalar *gradArray     = NULL;
3762 
3763   PetscFunctionBegin;
3764   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
3765   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
3766   PetscCall(DMPlexGetSimplexOrBoxCells(coarse, 0, &cellStart, &cellEnd));
3767   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
3768   PetscCall(DMGetGlobalSection(fine, &globalFine));
3769   PetscCall(DMGetCoordinateDim(coarse, &dim));
3770   { /* winnow fine points that don't have global dofs out of the sf */
3771     PetscInt        nleaves, l;
3772     const PetscInt *leaves;
3773     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
3774 
3775     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
3776 
3777     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3778       PetscInt p = leaves ? leaves[l] : l;
3779 
3780       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
3781       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3782       if ((dof - cdof) > 0) numPointsWithDofs++;
3783     }
3784     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
3785     for (l = 0, offset = 0; l < nleaves; l++) {
3786       PetscInt p = leaves ? leaves[l] : l;
3787 
3788       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
3789       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3790       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
3791     }
3792     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
3793     PetscCall(PetscFree(pointsWithDofs));
3794   }
3795   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
3796   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
3797   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
3798   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
3799   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
3800 
3801   PetscCall(DMGetLocalSection(coarse, &localCoarse));
3802   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3803 
3804   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
3805   PetscCall(ISGetIndices(aIS, &anchors));
3806   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
3807 
3808   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
3809   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
3810 
3811   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
3812   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootValuesSec));
3813   PetscCall(PetscSectionSetChart(rootValuesSec, pStartC, pEndC));
3814   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
3815   {
3816     PetscInt maxFields = PetscMax(1, numFields) + 1;
3817     PetscCall(PetscMalloc7(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &newOffsets, maxFields, &newOffsetsCopy, maxFields, &rowOffsets, maxFields, &numD, maxFields, &numO));
3818   }
3819   if (grad) {
3820     PetscInt i;
3821 
3822     PetscCall(VecGetDM(cellGeom, &cellDM));
3823     PetscCall(VecGetArrayRead(cellGeom, &cellGeomArray));
3824     PetscCall(VecGetDM(grad, &gradDM));
3825     PetscCall(VecGetArrayRead(grad, &gradArray));
3826     for (i = 0; i < PetscMax(1, numFields); i++) {
3827       PetscObject  obj;
3828       PetscClassId id;
3829 
3830       PetscCall(DMGetField(coarse, i, NULL, &obj));
3831       PetscCall(PetscObjectGetClassId(obj, &id));
3832       if (id == PETSCFV_CLASSID) {
3833         fv = (PetscFV)obj;
3834         PetscCall(PetscFVGetNumComponents(fv, &numFVcomps));
3835         fvField = i;
3836         break;
3837       }
3838     }
3839   }
3840 
3841   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
3842     PetscInt dof;
3843     PetscInt maxChildId = maxChildIds[p - pStartC];
3844     PetscInt numValues  = 0;
3845 
3846     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3847     if (dof < 0) dof = -(dof + 1);
3848     offsets[0]    = 0;
3849     newOffsets[0] = 0;
3850     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
3851       PetscInt *closure = NULL, closureSize, cl;
3852 
3853       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
3854       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
3855         PetscInt c = closure[2 * cl], clDof;
3856 
3857         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
3858         numValues += clDof;
3859       }
3860       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
3861     } else if (maxChildId == -1) {
3862       PetscCall(PetscSectionGetDof(localCoarse, p, &numValues));
3863     }
3864     /* we will pack the column indices with the field offsets */
3865     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
3866       /* also send the centroid, and the gradient */
3867       numValues += dim * (1 + numFVcomps);
3868     }
3869     PetscCall(PetscSectionSetDof(rootValuesSec, p, numValues));
3870   }
3871   PetscCall(PetscSectionSetUp(rootValuesSec));
3872   {
3873     PetscInt           numRootValues;
3874     const PetscScalar *coarseArray;
3875 
3876     PetscCall(PetscSectionGetStorageSize(rootValuesSec, &numRootValues));
3877     PetscCall(PetscMalloc1(numRootValues, &rootValues));
3878     PetscCall(VecGetArrayRead(vecCoarseLocal, &coarseArray));
3879     for (p = pStartC; p < pEndC; p++) {
3880       PetscInt     numValues;
3881       PetscInt     pValOff;
3882       PetscScalar *pVal;
3883       PetscInt     maxChildId = maxChildIds[p - pStartC];
3884 
3885       PetscCall(PetscSectionGetDof(rootValuesSec, p, &numValues));
3886       if (!numValues) continue;
3887       PetscCall(PetscSectionGetOffset(rootValuesSec, p, &pValOff));
3888       pVal = &(rootValues[pValOff]);
3889       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
3890         PetscInt closureSize = numValues;
3891         PetscCall(DMPlexVecGetClosure(coarse, NULL, vecCoarseLocal, p, &closureSize, &pVal));
3892         if (grad && p >= cellStart && p < cellEnd) {
3893           PetscFVCellGeom *cg;
3894           PetscScalar     *gradVals = NULL;
3895           PetscInt         i;
3896 
3897           pVal += (numValues - dim * (1 + numFVcomps));
3898 
3899           PetscCall(DMPlexPointLocalRead(cellDM, p, cellGeomArray, (void *)&cg));
3900           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
3901           pVal += dim;
3902           PetscCall(DMPlexPointGlobalRead(gradDM, p, gradArray, (void *)&gradVals));
3903           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
3904         }
3905       } else if (maxChildId == -1) {
3906         PetscInt lDof, lOff, i;
3907 
3908         PetscCall(PetscSectionGetDof(localCoarse, p, &lDof));
3909         PetscCall(PetscSectionGetOffset(localCoarse, p, &lOff));
3910         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
3911       }
3912     }
3913     PetscCall(VecRestoreArrayRead(vecCoarseLocal, &coarseArray));
3914     PetscCall(PetscFree(maxChildIds));
3915   }
3916   {
3917     PetscSF   valuesSF;
3918     PetscInt *remoteOffsetsValues, numLeafValues;
3919 
3920     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafValuesSec));
3921     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootValuesSec, &remoteOffsetsValues, leafValuesSec));
3922     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootValuesSec, remoteOffsetsValues, leafValuesSec, &valuesSF));
3923     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3924     PetscCall(PetscFree(remoteOffsetsValues));
3925     PetscCall(PetscSectionGetStorageSize(leafValuesSec, &numLeafValues));
3926     PetscCall(PetscMalloc1(numLeafValues, &leafValues));
3927     PetscCall(PetscSFBcastBegin(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
3928     PetscCall(PetscSFBcastEnd(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
3929     PetscCall(PetscSFDestroy(&valuesSF));
3930     PetscCall(PetscFree(rootValues));
3931     PetscCall(PetscSectionDestroy(&rootValuesSec));
3932   }
3933   PetscCall(DMGetLocalSection(fine, &localFine));
3934   {
3935     PetscInt       maxDof;
3936     PetscInt      *rowIndices;
3937     DM             refTree;
3938     PetscInt     **refPointFieldN;
3939     PetscScalar ***refPointFieldMats;
3940     PetscSection   refConSec, refAnSec;
3941     PetscInt       pRefStart, pRefEnd, leafStart, leafEnd;
3942     PetscScalar   *pointWork;
3943 
3944     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
3945     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
3946     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
3947     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
3948     PetscCall(DMCopyDisc(fine, refTree));
3949     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
3950     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
3951     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
3952     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3953     PetscCall(PetscSectionGetChart(leafValuesSec, &leafStart, &leafEnd));
3954     PetscCall(DMPlexGetSimplexOrBoxCells(fine, 0, &cellStart, &cellEnd));
3955     for (p = leafStart; p < leafEnd; p++) {
3956       PetscInt           gDof, gcDof, gOff, lDof;
3957       PetscInt           numValues, pValOff;
3958       PetscInt           childId;
3959       const PetscScalar *pVal;
3960       const PetscScalar *fvGradData = NULL;
3961 
3962       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
3963       PetscCall(PetscSectionGetDof(localFine, p, &lDof));
3964       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
3965       if ((gDof - gcDof) <= 0) continue;
3966       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
3967       PetscCall(PetscSectionGetDof(leafValuesSec, p, &numValues));
3968       if (!numValues) continue;
3969       PetscCall(PetscSectionGetOffset(leafValuesSec, p, &pValOff));
3970       pVal              = &leafValues[pValOff];
3971       offsets[0]        = 0;
3972       offsetsCopy[0]    = 0;
3973       newOffsets[0]     = 0;
3974       newOffsetsCopy[0] = 0;
3975       childId           = cids[p - pStartF];
3976       if (numFields) {
3977         PetscInt f;
3978         for (f = 0; f < numFields; f++) {
3979           PetscInt rowDof;
3980 
3981           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
3982           offsets[f + 1]     = offsets[f] + rowDof;
3983           offsetsCopy[f + 1] = offsets[f + 1];
3984           /* TODO: closure indices */
3985           newOffsets[f + 1] = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
3986         }
3987         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
3988       } else {
3989         offsets[0]    = 0;
3990         offsets[1]    = lDof;
3991         newOffsets[0] = 0;
3992         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
3993         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
3994       }
3995       if (childId == -1) { /* no child interpolation: one nnz per */
3996         PetscCall(VecSetValues(vecFine, numValues, rowIndices, pVal, INSERT_VALUES));
3997       } else {
3998         PetscInt f;
3999 
4000         if (grad && p >= cellStart && p < cellEnd) {
4001           numValues -= (dim * (1 + numFVcomps));
4002           fvGradData = &pVal[numValues];
4003         }
4004         for (f = 0; f < PetscMax(1, numFields); f++) {
4005           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
4006           PetscInt           numRows  = offsets[f + 1] - offsets[f];
4007           PetscInt           numCols  = newOffsets[f + 1] - newOffsets[f];
4008           const PetscScalar *cVal     = &pVal[newOffsets[f]];
4009           PetscScalar       *rVal     = &pointWork[offsets[f]];
4010           PetscInt           i, j;
4011 
4012 #if 0
4013           PetscCall(PetscInfo(coarse,"childId %" PetscInt_FMT ", numRows %" PetscInt_FMT ", numCols %" PetscInt_FMT ", refPointFieldN %" PetscInt_FMT " maxDof %" PetscInt_FMT "\n",childId,numRows,numCols,refPointFieldN[childId - pRefStart][f], maxDof));
4014 #endif
4015           for (i = 0; i < numRows; i++) {
4016             PetscScalar val = 0.;
4017             for (j = 0; j < numCols; j++) val += childMat[i * numCols + j] * cVal[j];
4018             rVal[i] = val;
4019           }
4020           if (f == fvField && p >= cellStart && p < cellEnd) {
4021             PetscReal          centroid[3];
4022             PetscScalar        diff[3];
4023             const PetscScalar *parentCentroid = &fvGradData[0];
4024             const PetscScalar *gradient       = &fvGradData[dim];
4025 
4026             PetscCall(DMPlexComputeCellGeometryFVM(fine, p, NULL, centroid, NULL));
4027             for (i = 0; i < dim; i++) diff[i] = centroid[i] - parentCentroid[i];
4028             for (i = 0; i < numFVcomps; i++) {
4029               PetscScalar val = 0.;
4030 
4031               for (j = 0; j < dim; j++) val += gradient[dim * i + j] * diff[j];
4032               rVal[i] += val;
4033             }
4034           }
4035           PetscCall(VecSetValues(vecFine, numRows, &rowIndices[offsets[f]], rVal, INSERT_VALUES));
4036         }
4037       }
4038     }
4039     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
4040     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
4041     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
4042   }
4043   PetscCall(PetscFree(leafValues));
4044   PetscCall(PetscSectionDestroy(&leafValuesSec));
4045   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
4046   PetscCall(ISRestoreIndices(aIS, &anchors));
4047   PetscFunctionReturn(PETSC_SUCCESS);
4048 }
4049 
4050 static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4051 {
4052   DM             refTree;
4053   PetscSection   multiRootSec, rootIndicesSec;
4054   PetscSection   globalCoarse, globalFine;
4055   PetscSection   localCoarse, localFine;
4056   PetscSection   cSecRef;
4057   PetscInt      *parentIndices, pRefStart, pRefEnd;
4058   PetscScalar   *rootValues, *parentValues;
4059   Mat            injRef;
4060   PetscInt       numFields, maxDof;
4061   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4062   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
4063   PetscLayout    rowMap, colMap;
4064   PetscInt       rowStart, rowEnd, colStart, colEnd;
4065   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4066 
4067   PetscFunctionBegin;
4068   /* get the templates for the fine-to-coarse injection from the reference tree */
4069   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
4070   PetscCall(VecSetOption(vecCoarse, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
4071   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
4072   PetscCall(DMCopyDisc(coarse, refTree));
4073   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
4074   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
4075   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
4076 
4077   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
4078   PetscCall(DMGetLocalSection(fine, &localFine));
4079   PetscCall(DMGetGlobalSection(fine, &globalFine));
4080   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
4081   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
4082   PetscCall(DMGetLocalSection(coarse, &localCoarse));
4083   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
4084   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
4085   {
4086     PetscInt maxFields = PetscMax(1, numFields) + 1;
4087     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
4088   }
4089 
4090   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, cids, vecFine, numFields, offsets, &multiRootSec, &rootIndicesSec, NULL, &rootValues));
4091 
4092   PetscCall(PetscMalloc2(maxDof, &parentIndices, maxDof, &parentValues));
4093 
4094   /* count indices */
4095   PetscCall(VecGetLayout(vecFine, &colMap));
4096   PetscCall(VecGetLayout(vecCoarse, &rowMap));
4097   PetscCall(PetscLayoutSetUp(rowMap));
4098   PetscCall(PetscLayoutSetUp(colMap));
4099   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
4100   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
4101   /* insert values */
4102   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4103   for (p = pStartC; p < pEndC; p++) {
4104     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
4105     PetscBool contribute = PETSC_FALSE;
4106 
4107     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
4108     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
4109     if ((dof - cdof) <= 0) continue;
4110     PetscCall(PetscSectionGetDof(localCoarse, p, &dof));
4111     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
4112 
4113     rowOffsets[0]  = 0;
4114     offsetsCopy[0] = 0;
4115     if (numFields) {
4116       PetscInt f;
4117 
4118       for (f = 0; f < numFields; f++) {
4119         PetscInt fDof;
4120         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
4121         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4122       }
4123       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
4124     } else {
4125       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
4126       rowOffsets[1] = offsetsCopy[0];
4127     }
4128 
4129     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
4130     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
4131     leafEnd = leafStart + numLeaves;
4132     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4133     for (l = leafStart; l < leafEnd; l++) {
4134       PetscInt           numIndices, childId, offset;
4135       const PetscScalar *childValues;
4136 
4137       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
4138       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
4139       childId     = (PetscInt)PetscRealPart(rootValues[offset++]);
4140       childValues = &rootValues[offset];
4141       numIndices--;
4142 
4143       if (childId == -2) { /* skip */
4144         continue;
4145       } else if (childId == -1) { /* equivalent points: scatter */
4146         PetscInt m;
4147 
4148         contribute = PETSC_TRUE;
4149         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4150       } else { /* contributions from children: sum with injectors from reference tree */
4151         PetscInt parentId, f, lim;
4152 
4153         contribute = PETSC_TRUE;
4154         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
4155 
4156         lim        = PetscMax(1, numFields);
4157         offsets[0] = 0;
4158         if (numFields) {
4159           PetscInt f;
4160 
4161           for (f = 0; f < numFields; f++) {
4162             PetscInt fDof;
4163             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
4164 
4165             offsets[f + 1] = fDof + offsets[f];
4166           }
4167         } else {
4168           PetscInt cDof;
4169 
4170           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
4171           offsets[1] = cDof;
4172         }
4173         for (f = 0; f < lim; f++) {
4174           PetscScalar       *childMat = &childrenMats[childId - pRefStart][f][0];
4175           PetscInt           n        = offsets[f + 1] - offsets[f];
4176           PetscInt           m        = rowOffsets[f + 1] - rowOffsets[f];
4177           PetscInt           i, j;
4178           const PetscScalar *colValues = &childValues[offsets[f]];
4179 
4180           for (i = 0; i < m; i++) {
4181             PetscScalar val = 0.;
4182             for (j = 0; j < n; j++) val += childMat[n * i + j] * colValues[j];
4183             parentValues[rowOffsets[f] + i] += val;
4184           }
4185         }
4186       }
4187     }
4188     if (contribute) PetscCall(VecSetValues(vecCoarse, dof, parentIndices, parentValues, INSERT_VALUES));
4189   }
4190   PetscCall(PetscSectionDestroy(&multiRootSec));
4191   PetscCall(PetscSectionDestroy(&rootIndicesSec));
4192   PetscCall(PetscFree2(parentIndices, parentValues));
4193   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4194   PetscCall(PetscFree(rootValues));
4195   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
4196   PetscFunctionReturn(PETSC_SUCCESS);
4197 }
4198 
4199 /*@
4200   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4201   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4202   coarsening and refinement at the same time.
4203 
4204   Collective
4205 
4206   Input Parameters:
4207 + dmIn        - The `DMPLEX` mesh for the input vector
4208 . dmOut       - The second `DMPLEX` mesh
4209 . vecIn       - The input vector
4210 . sfRefine    - A star forest indicating points in the mesh `dmIn` (roots in the star forest) that are parents to points in
4211                 the mesh `dmOut` (leaves in the star forest), i.e. where `dmOut` is more refined than `dmIn`
4212 . sfCoarsen   - A star forest indicating points in the mesh `dmOut` (roots in the star forest) that are parents to points in
4213                 the mesh `dmIn` (leaves in the star forest), i.e. where `dmOut` is more coarsened than `dmIn`
4214 . cidsRefine  - The childIds of the points in `dmOut`.  These childIds relate back to the reference tree: childid[j] = k implies
4215                 that mesh point j of `dmOut` was refined from a point in `dmIn` just as the mesh point k in the reference
4216                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in `dmOut` is exactly
4217                 equivalent to its root in `dmIn`, so no interpolation is necessary.  childid[j] = -2 indicates that this
4218                 point j in `dmOut` is not a leaf of `sfRefine`.
4219 . cidsCoarsen - The childIds of the points in `dmIn`.  These childIds relate back to the reference tree: childid[j] = k implies
4220                 that mesh point j of dmIn coarsens to a point in `dmOut` just as the mesh point k in the reference
4221                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in `dmOut` is not a leaf in `sfCoarsen`.
4222 . useBCs      - `PETSC_TRUE` indicates that boundary values should be inserted into `vecIn` before transfer.
4223 - time        - Used if boundary values are time dependent.
4224 
4225   Output Parameter:
4226 . vecOut - Using interpolation and injection operators calculated on the reference tree, the transferred
4227                 projection of `vecIn` from `dmIn` to `dmOut`.  Note that any field discretized with a `PetscFV` finite volume
4228                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4229                 coarse points to fine points.
4230 
4231   Level: developer
4232 
4233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSF`, `Vec`, `PetscFV`, `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4234 @*/
4235 PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
4236 {
4237   PetscFunctionBegin;
4238   PetscCall(VecSet(vecOut, 0.0));
4239   if (sfRefine) {
4240     Vec vecInLocal;
4241     DM  dmGrad   = NULL;
4242     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4243 
4244     PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
4245     PetscCall(VecSet(vecInLocal, 0.0));
4246     {
4247       PetscInt numFields, i;
4248 
4249       PetscCall(DMGetNumFields(dmIn, &numFields));
4250       for (i = 0; i < numFields; i++) {
4251         PetscObject  obj;
4252         PetscClassId classid;
4253 
4254         PetscCall(DMGetField(dmIn, i, NULL, &obj));
4255         PetscCall(PetscObjectGetClassId(obj, &classid));
4256         if (classid == PETSCFV_CLASSID) {
4257           PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
4258           break;
4259         }
4260       }
4261     }
4262     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
4263     PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
4264     PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
4265     if (dmGrad) {
4266       PetscCall(DMGetGlobalVector(dmGrad, &grad));
4267       PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
4268     }
4269     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
4270     PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
4271     if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
4272   }
4273   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
4274   PetscCall(VecAssemblyBegin(vecOut));
4275   PetscCall(VecAssemblyEnd(vecOut));
4276   PetscFunctionReturn(PETSC_SUCCESS);
4277 }
4278