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