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