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