xref: /petsc/src/dm/impls/plex/plextree.c (revision 27f49a208b01d2e827ab9db411a2d16003fe9262) !
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 orientation 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
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
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
4197 
4198   Input Parameters:
4199 + dmIn        - The `DMPLEX` mesh for the input vector
4200 . dmOut        - The second `DMPLEX` mesh
4201 . vecIn       - The input vector
4202 . sfRefine    - A star forest indicating points in the mesh `dmIn` (roots in the star forest) that are parents to points in
4203                 the mesh `dmOut` (leaves in the star forest), i.e. where `dmOut` is more refined than `dmIn`
4204 . sfCoarsen   - A star forest indicating points in the mesh `dmOut` (roots in the star forest) that are parents to points in
4205                 the mesh `dmIn` (leaves in the star forest), i.e. where `dmOut` is more coarsened than `dmIn`
4206 . cidsRefine  - The childIds of the points in `dmOut`.  These childIds relate back to the reference tree: childid[j] = k implies
4207                 that mesh point j of `dmOut` was refined from a point in `dmIn` just as the mesh point k in the reference
4208                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in `dmOut` is exactly
4209                 equivalent to its root in `dmIn`, so no interpolation is necessary.  childid[j] = -2 indicates that this
4210                 point j in `dmOut` is not a leaf of `sfRefine`.
4211 . cidsCoarsen - The childIds of the points in `dmIn`.  These childIds relate back to the reference tree: childid[j] = k implies
4212                 that mesh point j of dmIn coarsens to a point in `dmOut` just as the mesh point k in the reference
4213                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in `dmOut` is not a leaf in `sfCoarsen`.
4214 . useBCs      - `PETSC_TRUE` indicates that boundary values should be inserted into `vecIn` before transfer.
4215 - time        - Used if boundary values are time dependent.
4216 
4217   Output Parameters:
4218 . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transferred
4219                 projection of `vecIn` from `dmIn` to `dmOut`.  Note that any field discretized with a `PetscFV` finite volume
4220                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4221                 coarse points to fine points.
4222 
4223   Level: developer
4224 
4225 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `Vec`, `PetscFV`, `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4226 @*/
4227 PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
4228 {
4229   PetscFunctionBegin;
4230   PetscCall(VecSet(vecOut, 0.0));
4231   if (sfRefine) {
4232     Vec vecInLocal;
4233     DM  dmGrad   = NULL;
4234     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4235 
4236     PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
4237     PetscCall(VecSet(vecInLocal, 0.0));
4238     {
4239       PetscInt numFields, i;
4240 
4241       PetscCall(DMGetNumFields(dmIn, &numFields));
4242       for (i = 0; i < numFields; i++) {
4243         PetscObject  obj;
4244         PetscClassId classid;
4245 
4246         PetscCall(DMGetField(dmIn, i, NULL, &obj));
4247         PetscCall(PetscObjectGetClassId(obj, &classid));
4248         if (classid == PETSCFV_CLASSID) {
4249           PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
4250           break;
4251         }
4252       }
4253     }
4254     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
4255     PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
4256     PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
4257     if (dmGrad) {
4258       PetscCall(DMGetGlobalVector(dmGrad, &grad));
4259       PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
4260     }
4261     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
4262     PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
4263     if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
4264   }
4265   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
4266   PetscCall(VecAssemblyBegin(vecOut));
4267   PetscCall(VecAssemblyEnd(vecOut));
4268   PetscFunctionReturn(PETSC_SUCCESS);
4269 }
4270