xref: /petsc/src/dm/impls/plex/plextree.c (revision cd6fc93e7ec9f98b27f7c0167d62aceaeb2bb536)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2af0996ceSBarry Smith #include <petsc/private/isimpl.h>
3af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
4d6a7ad0dSToby Isaac #include <petscsf.h>
50c37af3bSToby Isaac #include <petscds.h>
6d6a7ad0dSToby Isaac 
70e3d61c9SBarry Smith /* hierarchy routines */
8d6a7ad0dSToby Isaac 
9d6a7ad0dSToby Isaac /*@
10d6a7ad0dSToby Isaac   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
11d6a7ad0dSToby Isaac 
12d6a7ad0dSToby Isaac   Not collective
13d6a7ad0dSToby Isaac 
14d6a7ad0dSToby Isaac   Input Parameters:
15d6a7ad0dSToby Isaac + dm - The DMPlex object
16d6a7ad0dSToby Isaac - ref - The reference tree DMPlex object
17d6a7ad0dSToby Isaac 
180b7167a0SToby Isaac   Level: intermediate
19d6a7ad0dSToby Isaac 
20db781477SPatrick Sanan .seealso: `DMPlexGetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
21d6a7ad0dSToby Isaac @*/
229371c9d4SSatish Balay PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref) {
23d6a7ad0dSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
24d6a7ad0dSToby Isaac 
25d6a7ad0dSToby Isaac   PetscFunctionBegin;
26d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2747a1df27SMatthew G. Knepley   if (ref) { PetscValidHeaderSpecific(ref, DM_CLASSID, 2); }
289566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)ref));
299566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
30d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
31d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
32d6a7ad0dSToby Isaac }
33d6a7ad0dSToby Isaac 
34d6a7ad0dSToby Isaac /*@
35d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
36d6a7ad0dSToby Isaac 
37d6a7ad0dSToby Isaac   Not collective
38d6a7ad0dSToby Isaac 
39d6a7ad0dSToby Isaac   Input Parameters:
40d6a7ad0dSToby Isaac . dm - The DMPlex object
41d6a7ad0dSToby Isaac 
427a7aea1fSJed Brown   Output Parameters:
43d6a7ad0dSToby Isaac . ref - The reference tree DMPlex object
44d6a7ad0dSToby Isaac 
450b7167a0SToby Isaac   Level: intermediate
46d6a7ad0dSToby Isaac 
47db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
48d6a7ad0dSToby Isaac @*/
499371c9d4SSatish Balay PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref) {
50d6a7ad0dSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
51d6a7ad0dSToby Isaac 
52d6a7ad0dSToby Isaac   PetscFunctionBegin;
53d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
54d6a7ad0dSToby Isaac   PetscValidPointer(ref, 2);
55d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
56d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
57d6a7ad0dSToby Isaac }
58d6a7ad0dSToby Isaac 
599371c9d4SSatish Balay static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB) {
60dcbd3bf7SToby Isaac   PetscInt coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
61dcbd3bf7SToby Isaac 
62dcbd3bf7SToby Isaac   PetscFunctionBegin;
63dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
64dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
65dcbd3bf7SToby Isaac     if (childB) *childB = childA;
66dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
67dcbd3bf7SToby Isaac   }
68dcbd3bf7SToby Isaac   for (dim = 0; dim < 3; dim++) {
699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, dim, &dStart, &dEnd));
709371c9d4SSatish Balay     if (parent >= dStart && parent <= dEnd) { break; }
71dcbd3bf7SToby Isaac   }
7263a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot perform child symmetry for %" PetscInt_FMT "-cells", dim);
7328b400f6SJacob Faibussowitsch   PetscCheck(dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "A vertex has no children");
74dcbd3bf7SToby Isaac   if (childA < dStart || childA >= dEnd) {
75dcbd3bf7SToby Isaac     /* this is a lower-dimensional child: bootstrap */
76dcbd3bf7SToby Isaac     PetscInt        size, i, sA = -1, sB, sOrientB, sConeSize;
77dcbd3bf7SToby Isaac     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
78dcbd3bf7SToby Isaac 
799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, childA, &size));
809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, childA, &supp));
81dcbd3bf7SToby Isaac 
82dcbd3bf7SToby Isaac     /* find a point sA in supp(childA) that has the same parent */
83dcbd3bf7SToby Isaac     for (i = 0; i < size; i++) {
84dcbd3bf7SToby Isaac       PetscInt sParent;
85dcbd3bf7SToby Isaac 
86dcbd3bf7SToby Isaac       sA = supp[i];
87dcbd3bf7SToby Isaac       if (sA == parent) continue;
889566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, sA, &sParent, NULL));
899371c9d4SSatish Balay       if (sParent == parent) { break; }
90dcbd3bf7SToby Isaac     }
9108401ef6SPierre Jolivet     PetscCheck(i != size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "could not find support in children");
92dcbd3bf7SToby Isaac     /* find out which point sB is in an equivalent position to sA under
93dcbd3bf7SToby Isaac      * parentOrientB */
949566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildSymmetry_Default(dm, parent, parentOrientA, 0, sA, parentOrientB, &sOrientB, &sB));
959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, sA, &sConeSize));
969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sA, &coneA));
979566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sB, &coneB));
989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sA, &oA));
999566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sB, &oB));
100dcbd3bf7SToby Isaac     /* step through the cone of sA in natural order */
101dcbd3bf7SToby Isaac     for (i = 0; i < sConeSize; i++) {
102dcbd3bf7SToby Isaac       if (coneA[i] == childA) {
103dcbd3bf7SToby Isaac         /* if childA is at position i in coneA,
104dcbd3bf7SToby Isaac          * then we want the point that is at sOrientB*i in coneB */
105dcbd3bf7SToby Isaac         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize - (sOrientB + 1) - i) % sConeSize);
106dcbd3bf7SToby Isaac         if (childB) *childB = coneB[j];
107dcbd3bf7SToby Isaac         if (childOrientB) {
108b5a892a1SMatthew G. Knepley           DMPolytopeType ct;
109dcbd3bf7SToby Isaac           PetscInt       oBtrue;
110dcbd3bf7SToby Isaac 
1119566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, childA, &coneSize));
112dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
1131dca8a05SBarry Smith           PetscCheck(coneSize == 0 || coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected a vertex or an edge");
114b5a892a1SMatthew G. Knepley           ct            = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
115dcbd3bf7SToby Isaac           /* we may have to flip an edge */
116b5a892a1SMatthew G. Knepley           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientation(ct, -1, oB[j]);
117b5a892a1SMatthew G. Knepley           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
118b5a892a1SMatthew G. Knepley           ABswap        = DihedralSwap(coneSize, DMPolytopeConvertNewOrientation_Internal(ct, oA[i]), oBtrue);
119dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
120dcbd3bf7SToby Isaac         }
121dcbd3bf7SToby Isaac         break;
122dcbd3bf7SToby Isaac       }
123dcbd3bf7SToby Isaac     }
12408401ef6SPierre Jolivet     PetscCheck(i != sConeSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "support cone mismatch");
125dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
126dcbd3bf7SToby Isaac   }
127dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
1289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
129dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
130dcbd3bf7SToby Isaac   if (dim == 2) {
131dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
132dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
133dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
134dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
135dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
136dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
137947b95d8SBarry Smith   } else {
138dcbd3bf7SToby Isaac     ABswapVert = ABswap;
139dcbd3bf7SToby Isaac   }
140dcbd3bf7SToby Isaac   if (childB) {
141dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
142dcbd3bf7SToby Isaac     PetscInt        p, posA = -1, numChildren, i;
143dcbd3bf7SToby Isaac     const PetscInt *children;
144dcbd3bf7SToby Isaac 
145dcbd3bf7SToby Isaac     /* count which position the child is in */
1469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, parent, &numChildren, &children));
147dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
148dcbd3bf7SToby Isaac       p = children[i];
149dcbd3bf7SToby Isaac       if (p == childA) {
150dcbd3bf7SToby Isaac         posA = i;
151dcbd3bf7SToby Isaac         break;
152dcbd3bf7SToby Isaac       }
153dcbd3bf7SToby Isaac     }
154dcbd3bf7SToby Isaac     if (posA >= coneSize) {
155dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
156dcbd3bf7SToby Isaac        * is invariant */
1571dca8a05SBarry Smith       PetscCheck(dim == 2 && posA == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Expected a middle triangle, got something else");
158dcbd3bf7SToby Isaac       *childB = childA;
1599371c9d4SSatish Balay     } else {
160dcbd3bf7SToby Isaac       /* figure out position B by applying ABswapVert */
161dcbd3bf7SToby Isaac       PetscInt posB;
162dcbd3bf7SToby Isaac 
163dcbd3bf7SToby Isaac       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize - (ABswapVert + 1) - posA) % coneSize);
164dcbd3bf7SToby Isaac       if (childB) *childB = children[posB];
165dcbd3bf7SToby Isaac     }
166dcbd3bf7SToby Isaac   }
167dcbd3bf7SToby Isaac   if (childOrientB) *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
168dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
169dcbd3bf7SToby Isaac }
170dcbd3bf7SToby Isaac 
171dcbd3bf7SToby Isaac /*@
172dcbd3bf7SToby Isaac   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
173dcbd3bf7SToby Isaac 
174dcbd3bf7SToby Isaac   Input Parameters:
175dcbd3bf7SToby Isaac + dm - the reference tree DMPlex object
176dcbd3bf7SToby Isaac . parent - the parent point
177dcbd3bf7SToby Isaac . parentOrientA - the reference orientation for describing the parent
178dcbd3bf7SToby Isaac . childOrientA - the reference orientation for describing the child
179dcbd3bf7SToby Isaac . childA - the reference childID for describing the child
180dcbd3bf7SToby Isaac - parentOrientB - the new orientation for describing the parent
181dcbd3bf7SToby Isaac 
182dcbd3bf7SToby Isaac   Output Parameters:
183dcbd3bf7SToby Isaac + childOrientB - if not NULL, set to the new oreintation for describing the child
184ff1f73f7SToby Isaac - childB - if not NULL, the new childID for describing the child
185dcbd3bf7SToby Isaac 
186dcbd3bf7SToby Isaac   Level: developer
187dcbd3bf7SToby Isaac 
188db781477SPatrick Sanan .seealso: `DMPlexGetReferenceTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetTree()`
189dcbd3bf7SToby Isaac @*/
1909371c9d4SSatish Balay PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB) {
191dcbd3bf7SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
192dcbd3bf7SToby Isaac 
193dcbd3bf7SToby Isaac   PetscFunctionBegin;
194dcbd3bf7SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
19528b400f6SJacob Faibussowitsch   PetscCheck(mesh->getchildsymmetry, PETSC_COMM_SELF, PETSC_ERR_SUP, "DMPlexReferenceTreeGetChildSymmetry not implemented");
1969566063dSJacob Faibussowitsch   PetscCall(mesh->getchildsymmetry(dm, parent, parentOrientA, childOrientA, childA, parentOrientB, childOrientB, childB));
197dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
198dcbd3bf7SToby Isaac }
199dcbd3bf7SToby Isaac 
200776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM, PetscSection, PetscInt *, PetscInt *, PetscBool, PetscBool);
201f9f063d4SToby Isaac 
2029371c9d4SSatish Balay PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[]) {
203f2c1aa1dSLisandro Dalcin   PetscFunctionBegin;
2049566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_TRUE, PETSC_FALSE));
205f2c1aa1dSLisandro Dalcin   PetscFunctionReturn(0);
206f2c1aa1dSLisandro Dalcin }
207f2c1aa1dSLisandro Dalcin 
2089371c9d4SSatish Balay PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref) {
2090e2cc29aSToby Isaac   MPI_Comm     comm;
2100e2cc29aSToby Isaac   PetscInt     dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
211da43764aSToby Isaac   PetscInt    *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
212da43764aSToby Isaac   DMLabel      identity, identityRef;
21310f7e118SToby Isaac   PetscSection unionSection, unionConeSection, parentSection;
214da43764aSToby Isaac   PetscScalar *unionCoords;
215da43764aSToby Isaac   IS           perm;
216da43764aSToby Isaac 
217da43764aSToby Isaac   PetscFunctionBegin;
2180e2cc29aSToby Isaac   comm = PetscObjectComm((PetscObject)K);
2199566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(K, &dim));
2209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
2219566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, labelName, &identity));
2229566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(Kref, labelName, &identityRef));
2239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(Kref, &pRefStart, &pRefEnd));
2249566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionSection));
2259566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart)));
226da43764aSToby Isaac   /* count points that will go in the union */
2279371c9d4SSatish Balay   for (p = pStart; p < pEnd; p++) { PetscCall(PetscSectionSetDof(unionSection, p - pStart, 1)); }
228da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
229da43764aSToby Isaac     PetscInt q, qSize;
2309566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(identityRef, p, &q));
2319566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(identityRef, q, &qSize));
2329371c9d4SSatish Balay     if (qSize > 1) { PetscCall(PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1)); }
233da43764aSToby Isaac   }
2349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart, &permvals));
235da43764aSToby Isaac   offset = 0;
236da43764aSToby Isaac   /* stratify points in the union by topological dimension */
237da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
238da43764aSToby Isaac     PetscInt cStart, cEnd, c;
239da43764aSToby Isaac 
2409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, &cEnd));
2419371c9d4SSatish Balay     for (c = cStart; c < cEnd; c++) { permvals[offset++] = c; }
242da43764aSToby Isaac 
2439566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd));
2449371c9d4SSatish Balay     for (c = cStart; c < cEnd; c++) { permvals[offset++] = c + (pEnd - pStart); }
245da43764aSToby Isaac   }
2469566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm));
2479566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetPermutation(unionSection, perm));
2489566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionSection));
2499566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionSection, &numUnionPoints));
2509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numUnionPoints, &coneSizes, dim + 1, &numDimPoints));
251da43764aSToby Isaac   /* count dimension points */
252da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
253da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
2549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, NULL));
2559566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff));
256da43764aSToby Isaac     if (d < dim) {
2579566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d + 1, &cStart, NULL));
2589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff2));
2599371c9d4SSatish Balay     } else {
260da43764aSToby Isaac       cOff2 = numUnionPoints;
261da43764aSToby Isaac     }
262da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
263da43764aSToby Isaac   }
2649566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionConeSection));
2659566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(unionConeSection, 0, numUnionPoints));
266da43764aSToby Isaac   /* count the cones in the union */
267da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
268da43764aSToby Isaac     PetscInt dof, uOff;
269da43764aSToby Isaac 
2709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
2719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
2729566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
273da43764aSToby Isaac     coneSizes[uOff] = dof;
274da43764aSToby Isaac   }
275da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
276da43764aSToby Isaac     PetscInt dof, uDof, uOff;
277da43764aSToby Isaac 
2789566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
2799566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
2809566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
281da43764aSToby Isaac     if (uDof) {
2829566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
283da43764aSToby Isaac       coneSizes[uOff] = dof;
284da43764aSToby Isaac     }
285da43764aSToby Isaac   }
2869566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionConeSection));
2879566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionConeSection, &numCones));
2889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numCones, &unionCones, numCones, &unionOrientations));
289da43764aSToby Isaac   /* write the cones in the union */
290da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
291da43764aSToby Isaac     PetscInt        dof, uOff, c, cOff;
292da43764aSToby Isaac     const PetscInt *cone, *orientation;
293da43764aSToby Isaac 
2949566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
2959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(K, p, &cone));
2969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(K, p, &orientation));
2979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
2989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
299da43764aSToby Isaac     for (c = 0; c < dof; c++) {
300da43764aSToby Isaac       PetscInt e, eOff;
301da43764aSToby Isaac       e = cone[c];
3029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
303da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
304da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
305da43764aSToby Isaac     }
306da43764aSToby Isaac   }
307da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
308da43764aSToby Isaac     PetscInt        dof, uDof, uOff, c, cOff;
309da43764aSToby Isaac     const PetscInt *cone, *orientation;
310da43764aSToby Isaac 
3119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
3129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(Kref, p, &cone));
3139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(Kref, p, &orientation));
3149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
316da43764aSToby Isaac     if (uDof) {
3179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
318da43764aSToby Isaac       for (c = 0; c < dof; c++) {
319da43764aSToby Isaac         PetscInt e, eOff, eDof;
320da43764aSToby Isaac 
321da43764aSToby Isaac         e = cone[c];
3229566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart), &eDof));
323da43764aSToby Isaac         if (eDof) {
3249566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff));
3259371c9d4SSatish Balay         } else {
3269566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(identityRef, e, &e));
3279566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
328da43764aSToby Isaac         }
329da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
330da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
331da43764aSToby Isaac       }
332da43764aSToby Isaac     }
333da43764aSToby Isaac   }
334da43764aSToby Isaac   /* get the coordinates */
335da43764aSToby Isaac   {
336da43764aSToby Isaac     PetscInt     vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
337da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
338da43764aSToby Isaac     Vec          KcoordsVec, KrefCoordsVec;
339da43764aSToby Isaac     PetscScalar *Kcoords;
340da43764aSToby Isaac 
3419566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(K, &KcoordsSec));
3429566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(K, &KcoordsVec));
3439566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(Kref, &KrefCoordsSec));
3449566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(Kref, &KrefCoordsVec));
345da43764aSToby Isaac 
346da43764aSToby Isaac     numVerts = numDimPoints[0];
3479566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numVerts * dim, &unionCoords));
3489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(K, 0, &vStart, &vEnd));
349da43764aSToby Isaac 
350da43764aSToby Isaac     offset = 0;
351da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
3529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, v - pStart, &vOff));
3539566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords));
3549371c9d4SSatish Balay       for (d = 0; d < dim; d++) { unionCoords[offset * dim + d] = Kcoords[d]; }
355da43764aSToby Isaac       offset++;
356da43764aSToby Isaac     }
3579566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(Kref, 0, &vRefStart, &vRefEnd));
358da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
3599566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(unionSection, v - pRefStart + (pEnd - pStart), &vDof));
3609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, v - pRefStart + (pEnd - pStart), &vOff));
3619566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords));
362da43764aSToby Isaac       if (vDof) {
3639371c9d4SSatish Balay         for (d = 0; d < dim; d++) { unionCoords[offset * dim + d] = Kcoords[d]; }
364da43764aSToby Isaac         offset++;
365da43764aSToby Isaac       }
366da43764aSToby Isaac     }
367da43764aSToby Isaac   }
3689566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, ref));
3699566063dSJacob Faibussowitsch   PetscCall(DMSetType(*ref, DMPLEX));
3709566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ref, dim));
3719566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromDAG(*ref, dim, numDimPoints, coneSizes, unionCones, unionOrientations, unionCoords));
37210f7e118SToby Isaac   /* set the tree */
3739566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &parentSection));
3749566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(parentSection, 0, numUnionPoints));
37510f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
37610f7e118SToby Isaac     PetscInt uDof, uOff;
37710f7e118SToby Isaac 
3789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3799566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
3801baa6e33SBarry Smith     if (uDof) PetscCall(PetscSectionSetDof(parentSection, uOff, 1));
38110f7e118SToby Isaac   }
3829566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(parentSection));
3839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection, &parentSize));
3849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(parentSize, &parents, parentSize, &childIDs));
38510f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
38610f7e118SToby Isaac     PetscInt uDof, uOff;
38710f7e118SToby Isaac 
3889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
39010f7e118SToby Isaac     if (uDof) {
39110f7e118SToby Isaac       PetscInt pOff, parent, parentU;
3929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(parentSection, uOff, &pOff));
3939566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(identityRef, p, &parent));
3949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, parent - pStart, &parentU));
39510f7e118SToby Isaac       parents[pOff]  = parentU;
39610f7e118SToby Isaac       childIDs[pOff] = uOff;
39710f7e118SToby Isaac     }
39810f7e118SToby Isaac   }
3999566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_SetTree(*ref, parentSection, parents, childIDs));
4009566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
4019566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parents, childIDs));
40210f7e118SToby Isaac 
403da43764aSToby Isaac   /* clean up */
4049566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionSection));
4059566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionConeSection));
4069566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&perm));
4079566063dSJacob Faibussowitsch   PetscCall(PetscFree(unionCoords));
4089566063dSJacob Faibussowitsch   PetscCall(PetscFree2(unionCones, unionOrientations));
4099566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coneSizes, numDimPoints));
4100e2cc29aSToby Isaac   PetscFunctionReturn(0);
4110e2cc29aSToby Isaac }
4120e2cc29aSToby Isaac 
4130e2cc29aSToby Isaac /*@
4140e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4150e2cc29aSToby Isaac 
416d083f849SBarry Smith   Collective
4170e2cc29aSToby Isaac 
4180e2cc29aSToby Isaac   Input Parameters:
4190e2cc29aSToby Isaac + comm    - the MPI communicator
4200e2cc29aSToby Isaac . dim     - the spatial dimension
4210e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4220e2cc29aSToby Isaac 
4230e2cc29aSToby Isaac   Output Parameters:
4240e2cc29aSToby Isaac . ref     - the reference tree DMPlex object
4250e2cc29aSToby Isaac 
4260e2cc29aSToby Isaac   Level: intermediate
4270e2cc29aSToby Isaac 
428db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`
4290e2cc29aSToby Isaac @*/
4309371c9d4SSatish Balay PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref) {
4310e2cc29aSToby Isaac   DM_Plex *mesh;
4320e2cc29aSToby Isaac   DM       K, Kref;
4330e2cc29aSToby Isaac   PetscInt p, pStart, pEnd;
4340e2cc29aSToby Isaac   DMLabel  identity;
4350e2cc29aSToby Isaac 
4360e2cc29aSToby Isaac   PetscFunctionBegin;
4370e2cc29aSToby Isaac #if 1
4380e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4390e2cc29aSToby Isaac #endif
4400e2cc29aSToby Isaac   /* create a reference element */
4419566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K));
4429566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(K, "identity"));
4439566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, "identity", &identity));
4449566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
4459371c9d4SSatish Balay   for (p = pStart; p < pEnd; p++) { PetscCall(DMLabelSetValue(identity, p, p)); }
4460e2cc29aSToby Isaac   /* refine it */
4479566063dSJacob Faibussowitsch   PetscCall(DMRefine(K, comm, &Kref));
4480e2cc29aSToby Isaac 
4490e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4500e2cc29aSToby Isaac    * points that appear in both */
4519566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref));
4520e2cc29aSToby Isaac   mesh                   = (DM_Plex *)(*ref)->data;
4530e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
4549566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&K));
4559566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&Kref));
456da43764aSToby Isaac   PetscFunctionReturn(0);
457da43764aSToby Isaac }
458da43764aSToby Isaac 
4599371c9d4SSatish Balay static PetscErrorCode DMPlexTreeSymmetrize(DM dm) {
460878b19aaSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
461878b19aaSToby Isaac   PetscSection childSec, pSec;
462878b19aaSToby Isaac   PetscInt     p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
463878b19aaSToby Isaac   PetscInt    *offsets, *children, pStart, pEnd;
464878b19aaSToby Isaac 
465878b19aaSToby Isaac   PetscFunctionBegin;
466878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4679566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
4689566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
469878b19aaSToby Isaac   pSec = mesh->parentSection;
470878b19aaSToby Isaac   if (!pSec) PetscFunctionReturn(0);
4719566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(pSec, &pSize));
472878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
473878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
474878b19aaSToby Isaac 
475878b19aaSToby Isaac     parMax = PetscMax(parMax, par + 1);
476878b19aaSToby Isaac     parMin = PetscMin(parMin, par);
477878b19aaSToby Isaac   }
478878b19aaSToby Isaac   if (parMin > parMax) {
479878b19aaSToby Isaac     parMin = -1;
480878b19aaSToby Isaac     parMax = -1;
481878b19aaSToby Isaac   }
4829566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)pSec), &childSec));
4839566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(childSec, parMin, parMax));
484878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
485878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
486878b19aaSToby Isaac 
4879566063dSJacob Faibussowitsch     PetscCall(PetscSectionAddDof(childSec, par, 1));
488878b19aaSToby Isaac   }
4899566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(childSec));
4909566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(childSec, &cSize));
4919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cSize, &children));
4929566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(parMax - parMin, &offsets));
4939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(pSec, &pStart, &pEnd));
494878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
495878b19aaSToby Isaac     PetscInt dof, off, i;
496878b19aaSToby Isaac 
4979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pSec, p, &dof));
4989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(pSec, p, &off));
499878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
500878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
501878b19aaSToby Isaac 
5029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec, par, &cOff));
503878b19aaSToby Isaac       children[cOff + offsets[par - parMin]++] = p;
504878b19aaSToby Isaac     }
505878b19aaSToby Isaac   }
506878b19aaSToby Isaac   mesh->childSection = childSec;
507878b19aaSToby Isaac   mesh->children     = children;
5089566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
509878b19aaSToby Isaac   PetscFunctionReturn(0);
510878b19aaSToby Isaac }
511878b19aaSToby Isaac 
5129371c9d4SSatish Balay static PetscErrorCode AnchorsFlatten(PetscSection section, IS is, PetscSection *sectionNew, IS *isNew) {
5136dd5a8c8SToby Isaac   PetscInt        pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5146dd5a8c8SToby Isaac   const PetscInt *vals;
5156dd5a8c8SToby Isaac   PetscSection    secNew;
5166dd5a8c8SToby Isaac   PetscBool       anyNew, globalAnyNew;
5176dd5a8c8SToby Isaac   PetscBool       compress;
5186dd5a8c8SToby Isaac 
5196dd5a8c8SToby Isaac   PetscFunctionBegin;
5209566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
5219566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is, &size));
5229566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is, &vals));
5239566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secNew));
5249566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(secNew, pStart, pEnd));
5256dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5266dd5a8c8SToby Isaac     PetscInt dof;
5276dd5a8c8SToby Isaac 
5286dd5a8c8SToby Isaac     p = vals[i];
5296dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
5316dd5a8c8SToby Isaac     if (dof) break;
5326dd5a8c8SToby Isaac   }
5336dd5a8c8SToby Isaac   if (i == size) {
5349566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5356dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5366dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5376dd5a8c8SToby Isaac     sizeNew  = 0;
5389371c9d4SSatish Balay   } else {
5396dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5406dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5416dd5a8c8SToby Isaac       PetscInt dof, off;
5426dd5a8c8SToby Isaac 
5439566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5456dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5466dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5476dd5a8c8SToby Isaac 
5489371c9d4SSatish Balay         if (q >= pStart && q < pEnd) { PetscCall(PetscSectionGetDof(section, q, &qDof)); }
5491baa6e33SBarry Smith         if (qDof) PetscCall(PetscSectionAddDof(secNew, p, qDof));
5509371c9d4SSatish Balay         else { PetscCall(PetscSectionAddDof(secNew, p, 1)); }
5516dd5a8c8SToby Isaac       }
5526dd5a8c8SToby Isaac     }
5539566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(secNew, &sizeNew));
5559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sizeNew, &valsNew));
5566dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5576dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5586dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
5596dd5a8c8SToby Isaac 
5609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5619566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5629566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(secNew, p, &dofNew));
5639566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(secNew, p, &offNew));
5646dd5a8c8SToby Isaac       count = 0;
5656dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5666dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
5676dd5a8c8SToby Isaac 
5686dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5699566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, q, &qDof));
5709566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, q, &qOff));
5716dd5a8c8SToby Isaac         }
5726dd5a8c8SToby Isaac         if (qDof) {
5736dd5a8c8SToby Isaac           PetscInt oldCount = count;
5746dd5a8c8SToby Isaac 
5756dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
5766dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
5776dd5a8c8SToby Isaac 
5786dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
5799371c9d4SSatish Balay               if (valsNew[offNew + k] == r) { break; }
5806dd5a8c8SToby Isaac             }
5819371c9d4SSatish Balay             if (k == oldCount) { valsNew[offNew + count++] = r; }
5826dd5a8c8SToby Isaac           }
5839371c9d4SSatish Balay         } else {
5846dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
5856dd5a8c8SToby Isaac 
5866dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
5879371c9d4SSatish Balay             if (valsNew[offNew + k] == q) { break; }
5886dd5a8c8SToby Isaac           }
5899371c9d4SSatish Balay           if (k == oldCount) { valsNew[offNew + count++] = q; }
5906dd5a8c8SToby Isaac         }
5916dd5a8c8SToby Isaac       }
5926dd5a8c8SToby Isaac       if (count < dofNew) {
5939566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secNew, p, count));
5946dd5a8c8SToby Isaac         compress = PETSC_TRUE;
5956dd5a8c8SToby Isaac       }
5966dd5a8c8SToby Isaac     }
5976dd5a8c8SToby Isaac   }
5989566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is, &vals));
5991c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&anyNew, &globalAnyNew, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
6006dd5a8c8SToby Isaac   if (!globalAnyNew) {
6019566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secNew));
6026dd5a8c8SToby Isaac     *sectionNew = NULL;
6036dd5a8c8SToby Isaac     *isNew      = NULL;
6049371c9d4SSatish Balay   } else {
6056dd5a8c8SToby Isaac     PetscBool globalCompress;
6066dd5a8c8SToby Isaac 
6071c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&compress, &globalCompress, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
6086dd5a8c8SToby Isaac     if (compress) {
6096dd5a8c8SToby Isaac       PetscSection secComp;
6106dd5a8c8SToby Isaac       PetscInt    *valsComp = NULL;
6116dd5a8c8SToby Isaac 
6129566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secComp));
6139566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetChart(secComp, pStart, pEnd));
6146dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6156dd5a8c8SToby Isaac         PetscInt dof;
6166dd5a8c8SToby Isaac 
6179566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6189566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secComp, p, dof));
6196dd5a8c8SToby Isaac       }
6209566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetUp(secComp));
6219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(secComp, &sizeNew));
6229566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(sizeNew, &valsComp));
6236dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6246dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6256dd5a8c8SToby Isaac 
6269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6279566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secNew, p, &off));
6289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secComp, p, &offNew));
6299371c9d4SSatish Balay         for (j = 0; j < dof; j++) { valsComp[offNew + j] = valsNew[off + j]; }
6306dd5a8c8SToby Isaac       }
6319566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&secNew));
6326dd5a8c8SToby Isaac       secNew = secComp;
6339566063dSJacob Faibussowitsch       PetscCall(PetscFree(valsNew));
6346dd5a8c8SToby Isaac       valsNew = valsComp;
6356dd5a8c8SToby Isaac     }
6369566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), sizeNew, valsNew, PETSC_OWN_POINTER, isNew));
6376dd5a8c8SToby Isaac   }
6386dd5a8c8SToby Isaac   PetscFunctionReturn(0);
6396dd5a8c8SToby Isaac }
6406dd5a8c8SToby Isaac 
6419371c9d4SSatish Balay static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm) {
64266af876cSToby Isaac   PetscInt     p, pStart, pEnd, *anchors, size;
64366af876cSToby Isaac   PetscInt     aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
64466af876cSToby Isaac   PetscSection aSec;
645f9f063d4SToby Isaac   DMLabel      canonLabel;
64666af876cSToby Isaac   IS           aIS;
64766af876cSToby Isaac 
64866af876cSToby Isaac   PetscFunctionBegin;
64966af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
6519566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "canonical", &canonLabel));
65266af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
65366af876cSToby Isaac     PetscInt parent;
65466af876cSToby Isaac 
655f9f063d4SToby Isaac     if (canonLabel) {
656f9f063d4SToby Isaac       PetscInt canon;
657f9f063d4SToby Isaac 
6589566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
659f9f063d4SToby Isaac       if (p != canon) continue;
660f9f063d4SToby Isaac     }
6619566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
66266af876cSToby Isaac     if (parent != p) {
66366af876cSToby Isaac       aMin = PetscMin(aMin, p);
66466af876cSToby Isaac       aMax = PetscMax(aMax, p + 1);
66566af876cSToby Isaac     }
66666af876cSToby Isaac   }
66766af876cSToby Isaac   if (aMin > aMax) {
66866af876cSToby Isaac     aMin = -1;
66966af876cSToby Isaac     aMax = -1;
67066af876cSToby Isaac   }
6719566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &aSec));
6729566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(aSec, aMin, aMax));
67366af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
67466af876cSToby Isaac     PetscInt parent, ancestor = p;
67566af876cSToby Isaac 
676f9f063d4SToby Isaac     if (canonLabel) {
677f9f063d4SToby Isaac       PetscInt canon;
678f9f063d4SToby Isaac 
6799566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
680f9f063d4SToby Isaac       if (p != canon) continue;
681f9f063d4SToby Isaac     }
6829566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
68366af876cSToby Isaac     while (parent != ancestor) {
68466af876cSToby Isaac       ancestor = parent;
6859566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
68666af876cSToby Isaac     }
68766af876cSToby Isaac     if (ancestor != p) {
68866af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
68966af876cSToby Isaac 
6909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
6919566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(aSec, p, closureSize));
6929566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
69366af876cSToby Isaac     }
69466af876cSToby Isaac   }
6959566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(aSec));
6969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(aSec, &size));
6979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &anchors));
69866af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
69966af876cSToby Isaac     PetscInt parent, ancestor = p;
70066af876cSToby Isaac 
701f9f063d4SToby Isaac     if (canonLabel) {
702f9f063d4SToby Isaac       PetscInt canon;
703f9f063d4SToby Isaac 
7049566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
705f9f063d4SToby Isaac       if (p != canon) continue;
706f9f063d4SToby Isaac     }
7079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
70866af876cSToby Isaac     while (parent != ancestor) {
70966af876cSToby Isaac       ancestor = parent;
7109566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
71166af876cSToby Isaac     }
71266af876cSToby Isaac     if (ancestor != p) {
71366af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
71466af876cSToby Isaac 
7159566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
71666af876cSToby Isaac 
7179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
7189371c9d4SSatish Balay       for (j = 0; j < closureSize; j++) { anchors[aOff + j] = closure[2 * j]; }
7199566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
72066af876cSToby Isaac     }
72166af876cSToby Isaac   }
7229566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, anchors, PETSC_OWN_POINTER, &aIS));
7236dd5a8c8SToby Isaac   {
7246dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7256dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7266dd5a8c8SToby Isaac 
7279566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aSec));
7289566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aIS));
7296dd5a8c8SToby Isaac     while (aSecNew) {
7309566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&aSec));
7319566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&aIS));
7326dd5a8c8SToby Isaac       aSec    = aSecNew;
7336dd5a8c8SToby Isaac       aIS     = aISNew;
7346dd5a8c8SToby Isaac       aSecNew = NULL;
7356dd5a8c8SToby Isaac       aISNew  = NULL;
7369566063dSJacob Faibussowitsch       PetscCall(AnchorsFlatten(aSec, aIS, &aSecNew, &aISNew));
7376dd5a8c8SToby Isaac     }
7386dd5a8c8SToby Isaac   }
7399566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm, aSec, aIS));
7409566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&aSec));
7419566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&aIS));
74266af876cSToby Isaac   PetscFunctionReturn(0);
74366af876cSToby Isaac }
74466af876cSToby Isaac 
7459371c9d4SSatish Balay static PetscErrorCode DMPlexGetTrueSupportSize(DM dm, PetscInt p, PetscInt *dof, PetscInt *numTrueSupp) {
7466461c1adSToby Isaac   PetscFunctionBegin;
7476461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
7486461c1adSToby Isaac     PetscInt        i, alldof;
7496461c1adSToby Isaac     const PetscInt *supp;
7506461c1adSToby Isaac     PetscInt        count = 0;
7516461c1adSToby Isaac 
7529566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &alldof));
7539566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &supp));
7546461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
7556461c1adSToby Isaac       PetscInt        q = supp[i], numCones, j;
7566461c1adSToby Isaac       const PetscInt *cone;
7576461c1adSToby Isaac 
7589566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, q, &numCones));
7599566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, q, &cone));
7606461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
7616461c1adSToby Isaac         if (cone[j] == p) break;
7626461c1adSToby Isaac       }
7636461c1adSToby Isaac       if (j < numCones) count++;
7646461c1adSToby Isaac     }
7656461c1adSToby Isaac     numTrueSupp[p] = count;
7666461c1adSToby Isaac   }
7676461c1adSToby Isaac   *dof = numTrueSupp[p];
7686461c1adSToby Isaac   PetscFunctionReturn(0);
7696461c1adSToby Isaac }
7706461c1adSToby Isaac 
7719371c9d4SSatish Balay static PetscErrorCode DMPlexTreeExchangeSupports(DM dm) {
772776742edSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
773776742edSToby Isaac   PetscSection newSupportSection;
774776742edSToby Isaac   PetscInt     newSize, *newSupports, pStart, pEnd, p, d, depth;
7756461c1adSToby Isaac   PetscInt    *numTrueSupp;
776776742edSToby Isaac   PetscInt    *offsets;
777776742edSToby Isaac 
778776742edSToby Isaac   PetscFunctionBegin;
779776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
780776742edSToby Isaac   /* symmetrize the hierarchy */
7819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
7829566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)), &newSupportSection));
7839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7849566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSupportSection, pStart, pEnd));
7859566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd, &offsets));
7869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd, &numTrueSupp));
7876461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
7886461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
789776742edSToby Isaac    * parent(q) */
790776742edSToby Isaac   for (d = 0; d <= depth; d++) {
7919566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
792776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
793776742edSToby Isaac       PetscInt dof, q, qdof, parent;
794776742edSToby Isaac 
7959566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTrueSupportSize(dm, p, &dof, numTrueSupp));
7969566063dSJacob Faibussowitsch       PetscCall(PetscSectionAddDof(newSupportSection, p, dof));
797776742edSToby Isaac       q = p;
7989566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
799776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
800776742edSToby Isaac         q = parent;
801776742edSToby Isaac 
8029566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTrueSupportSize(dm, q, &qdof, numTrueSupp));
8039566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection, p, qdof));
8049566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection, q, dof));
8059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
806776742edSToby Isaac       }
807776742edSToby Isaac     }
808776742edSToby Isaac   }
8099566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSupportSection));
8109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSupportSection, &newSize));
8119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(newSize, &newSupports));
812776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
814776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
815776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
816776742edSToby Isaac 
8179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
8189566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
8199566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(newSupportSection, p, &newDof));
8209566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(newSupportSection, p, &newOff));
821776742edSToby Isaac       for (i = 0; i < dof; i++) {
8226461c1adSToby Isaac         PetscInt        numCones, j;
8236461c1adSToby Isaac         const PetscInt *cone;
8246461c1adSToby Isaac         PetscInt        q = mesh->supports[off + i];
8256461c1adSToby Isaac 
8269566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, q, &numCones));
8279566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, q, &cone));
8286461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8296461c1adSToby Isaac           if (cone[j] == p) break;
8306461c1adSToby Isaac         }
8316461c1adSToby Isaac         if (j < numCones) newSupports[newOff + offsets[p]++] = q;
832776742edSToby Isaac       }
833776742edSToby Isaac 
834776742edSToby Isaac       q = p;
8359566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
836776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
837776742edSToby Isaac         q = parent;
8389566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->supportSection, q, &qdof));
8399566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &qoff));
8409566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(newSupportSection, q, &newqOff));
841776742edSToby Isaac         for (i = 0; i < qdof; i++) {
8426461c1adSToby Isaac           PetscInt        numCones, j;
8436461c1adSToby Isaac           const PetscInt *cone;
8446461c1adSToby Isaac           PetscInt        r = mesh->supports[qoff + i];
8456461c1adSToby Isaac 
8469566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
8479566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, r, &cone));
8486461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
8496461c1adSToby Isaac             if (cone[j] == q) break;
8506461c1adSToby Isaac           }
8516461c1adSToby Isaac           if (j < numCones) newSupports[newOff + offsets[p]++] = r;
852776742edSToby Isaac         }
853776742edSToby Isaac         for (i = 0; i < dof; i++) {
8546461c1adSToby Isaac           PetscInt        numCones, j;
8556461c1adSToby Isaac           const PetscInt *cone;
8566461c1adSToby Isaac           PetscInt        r = mesh->supports[off + i];
8576461c1adSToby Isaac 
8589566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
8599566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, r, &cone));
8606461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
8616461c1adSToby Isaac             if (cone[j] == p) break;
8626461c1adSToby Isaac           }
8636461c1adSToby Isaac           if (j < numCones) newSupports[newqOff + offsets[q]++] = r;
864776742edSToby Isaac         }
8659566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
866776742edSToby Isaac       }
867776742edSToby Isaac     }
868776742edSToby Isaac   }
8699566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
870776742edSToby Isaac   mesh->supportSection = newSupportSection;
8719566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
872776742edSToby Isaac   mesh->supports = newSupports;
8739566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
8749566063dSJacob Faibussowitsch   PetscCall(PetscFree(numTrueSupp));
875776742edSToby Isaac 
876776742edSToby Isaac   PetscFunctionReturn(0);
877776742edSToby Isaac }
878776742edSToby Isaac 
879f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM, PetscSection, PetscSection, Mat);
880f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM, PetscSection, PetscSection, Mat);
881f7c74593SToby Isaac 
8829371c9d4SSatish Balay static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports) {
883f9f063d4SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
884f9f063d4SToby Isaac   DM       refTree;
885f9f063d4SToby Isaac   PetscInt size;
886f9f063d4SToby Isaac 
887f9f063d4SToby Isaac   PetscFunctionBegin;
888f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
889f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
8909566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)parentSection));
8919566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
892f9f063d4SToby Isaac   mesh->parentSection = parentSection;
8939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection, &size));
894f9f063d4SToby Isaac   if (parents != mesh->parents) {
8959566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->parents));
8969566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->parents));
8979566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->parents, parents, size));
898f9f063d4SToby Isaac   }
899f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
9009566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->childIDs));
9019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->childIDs));
9029566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->childIDs, childIDs, size));
903f9f063d4SToby Isaac   }
9049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
905f9f063d4SToby Isaac   if (refTree) {
906f9f063d4SToby Isaac     DMLabel canonLabel;
907f9f063d4SToby Isaac 
9089566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(refTree, "canonical", &canonLabel));
909f9f063d4SToby Isaac     if (canonLabel) {
910f9f063d4SToby Isaac       PetscInt i;
911f9f063d4SToby Isaac 
912f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
913f9f063d4SToby Isaac         PetscInt canon;
9149566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon));
9159371c9d4SSatish Balay         if (canon >= 0) { mesh->childIDs[i] = canon; }
916f9f063d4SToby Isaac       }
917f9f063d4SToby Isaac     }
918f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
9196e0288c8SStefano Zampini   } else {
920f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
921f9f063d4SToby Isaac   }
9229566063dSJacob Faibussowitsch   PetscCall(DMPlexTreeSymmetrize(dm));
923f9f063d4SToby Isaac   if (computeCanonical) {
924f9f063d4SToby Isaac     PetscInt d, dim;
925f9f063d4SToby Isaac 
926f9f063d4SToby Isaac     /* add the canonical label */
9279566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
9289566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "canonical"));
929f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
930f9f063d4SToby Isaac       PetscInt        p, dStart, dEnd, canon = -1, cNumChildren;
931f9f063d4SToby Isaac       const PetscInt *cChildren;
932f9f063d4SToby Isaac 
9339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
934f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
9359566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, p, &cNumChildren, &cChildren));
936f9f063d4SToby Isaac         if (cNumChildren) {
937f9f063d4SToby Isaac           canon = p;
938f9f063d4SToby Isaac           break;
939f9f063d4SToby Isaac         }
940f9f063d4SToby Isaac       }
941f9f063d4SToby Isaac       if (canon == -1) continue;
942f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
943f9f063d4SToby Isaac         PetscInt        numChildren, i;
944f9f063d4SToby Isaac         const PetscInt *children;
945f9f063d4SToby Isaac 
9469566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, p, &numChildren, &children));
947f9f063d4SToby Isaac         if (numChildren) {
94863a3b9bcSJacob Faibussowitsch           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);
9499566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "canonical", p, canon));
9509371c9d4SSatish Balay           for (i = 0; i < numChildren; i++) { PetscCall(DMSetLabelValue(dm, "canonical", children[i], cChildren[i])); }
951f9f063d4SToby Isaac         }
952f9f063d4SToby Isaac       }
953f9f063d4SToby Isaac     }
954f9f063d4SToby Isaac   }
9551baa6e33SBarry Smith   if (exchangeSupports) PetscCall(DMPlexTreeExchangeSupports(dm));
956f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
957f7c74593SToby Isaac   /* reset anchors */
9589566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm, NULL, NULL));
959f9f063d4SToby Isaac   PetscFunctionReturn(0);
960f9f063d4SToby Isaac }
961f9f063d4SToby Isaac 
9620b7167a0SToby Isaac /*@
9630b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
9640b7167a0SToby Isaac   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
9650b7167a0SToby Isaac   tree root.
9660b7167a0SToby Isaac 
9670b7167a0SToby Isaac   Collective on dm
9680b7167a0SToby Isaac 
9690b7167a0SToby Isaac   Input Parameters:
9700b7167a0SToby Isaac + dm - the DMPlex object
9710b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
9720b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
9730b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
9740b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
9750b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
9760b7167a0SToby Isaac 
9770b7167a0SToby Isaac   Level: intermediate
9780b7167a0SToby Isaac 
979db781477SPatrick Sanan .seealso: `DMPlexGetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
9800b7167a0SToby Isaac @*/
9819371c9d4SSatish Balay PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[]) {
9820b7167a0SToby Isaac   PetscFunctionBegin;
9839566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_FALSE, PETSC_TRUE));
9840b7167a0SToby Isaac   PetscFunctionReturn(0);
9850b7167a0SToby Isaac }
9860b7167a0SToby Isaac 
987b2f41788SToby Isaac /*@
988b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
989b2f41788SToby Isaac   Collective on dm
990b2f41788SToby Isaac 
991f899ff85SJose E. Roman   Input Parameter:
992b2f41788SToby Isaac . dm - the DMPlex object
993b2f41788SToby Isaac 
994b2f41788SToby Isaac   Output Parameters:
995b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
996b2f41788SToby Isaac                   offset indexes the parent and childID list
997b2f41788SToby Isaac . parents - a list of the point parents
998b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
999b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1000b2f41788SToby Isaac . childSection - the inverse of the parent section
1001b2f41788SToby Isaac - children - a list of the point children
1002b2f41788SToby Isaac 
1003b2f41788SToby Isaac   Level: intermediate
1004b2f41788SToby Isaac 
1005db781477SPatrick Sanan .seealso: `DMPlexSetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
1006b2f41788SToby Isaac @*/
10079371c9d4SSatish Balay PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[]) {
1008b2f41788SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
1009b2f41788SToby Isaac 
1010b2f41788SToby Isaac   PetscFunctionBegin;
1011b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1012b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1013b2f41788SToby Isaac   if (parents) *parents = mesh->parents;
1014b2f41788SToby Isaac   if (childIDs) *childIDs = mesh->childIDs;
1015b2f41788SToby Isaac   if (childSection) *childSection = mesh->childSection;
1016b2f41788SToby Isaac   if (children) *children = mesh->children;
1017b2f41788SToby Isaac   PetscFunctionReturn(0);
1018b2f41788SToby Isaac }
1019b2f41788SToby Isaac 
1020d961a43aSToby Isaac /*@
1021eaf898f9SPatrick Sanan   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)
1022d961a43aSToby Isaac 
1023d961a43aSToby Isaac   Input Parameters:
1024d961a43aSToby Isaac + dm - the DMPlex object
1025d961a43aSToby Isaac - point - the query point
1026d961a43aSToby Isaac 
1027d961a43aSToby Isaac   Output Parameters:
1028d961a43aSToby Isaac + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1029d961a43aSToby Isaac - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point
1030d961a43aSToby Isaac             does not have a parent
1031d961a43aSToby Isaac 
1032d961a43aSToby Isaac   Level: intermediate
1033d961a43aSToby Isaac 
1034db781477SPatrick Sanan .seealso: `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeChildren()`
1035d961a43aSToby Isaac @*/
10369371c9d4SSatish Balay PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID) {
1037d961a43aSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
1038d961a43aSToby Isaac   PetscSection pSec;
1039d961a43aSToby Isaac 
1040d961a43aSToby Isaac   PetscFunctionBegin;
1041d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1042d961a43aSToby Isaac   pSec = mesh->parentSection;
1043d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1044d961a43aSToby Isaac     PetscInt dof;
1045d961a43aSToby Isaac 
10469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pSec, point, &dof));
1047d961a43aSToby Isaac     if (dof) {
1048d961a43aSToby Isaac       PetscInt off;
1049d961a43aSToby Isaac 
10509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(pSec, point, &off));
1051d961a43aSToby Isaac       if (parent) *parent = mesh->parents[off];
1052d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
1053d961a43aSToby Isaac       PetscFunctionReturn(0);
1054d961a43aSToby Isaac     }
1055d961a43aSToby Isaac   }
10569371c9d4SSatish Balay   if (parent) { *parent = point; }
10579371c9d4SSatish Balay   if (childID) { *childID = 0; }
1058d961a43aSToby Isaac   PetscFunctionReturn(0);
1059d961a43aSToby Isaac }
1060d961a43aSToby Isaac 
1061d961a43aSToby Isaac /*@C
1062eaf898f9SPatrick Sanan   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)
1063d961a43aSToby Isaac 
1064d961a43aSToby Isaac   Input Parameters:
1065d961a43aSToby Isaac + dm - the DMPlex object
1066d961a43aSToby Isaac - point - the query point
1067d961a43aSToby Isaac 
1068d961a43aSToby Isaac   Output Parameters:
1069d961a43aSToby Isaac + numChildren - if not NULL, set to the number of children
1070d961a43aSToby Isaac - children - if not NULL, set to a list children, or set to NULL if the point has no children
1071d961a43aSToby Isaac 
1072d961a43aSToby Isaac   Level: intermediate
1073d961a43aSToby Isaac 
1074d961a43aSToby Isaac   Fortran Notes:
1075d961a43aSToby Isaac   Since it returns an array, this routine is only available in Fortran 90, and you must
1076d961a43aSToby Isaac   include petsc.h90 in your code.
1077d961a43aSToby Isaac 
1078db781477SPatrick Sanan .seealso: `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeParent()`
1079d961a43aSToby Isaac @*/
10809371c9d4SSatish Balay PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[]) {
1081d961a43aSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
1082d961a43aSToby Isaac   PetscSection childSec;
1083d961a43aSToby Isaac   PetscInt     dof = 0;
1084d961a43aSToby Isaac 
1085d961a43aSToby Isaac   PetscFunctionBegin;
1086d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1087d961a43aSToby Isaac   childSec = mesh->childSection;
10889371c9d4SSatish Balay   if (childSec && point >= childSec->pStart && point < childSec->pEnd) { PetscCall(PetscSectionGetDof(childSec, point, &dof)); }
1089d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1090d961a43aSToby Isaac   if (children) {
1091d961a43aSToby Isaac     if (dof) {
1092d961a43aSToby Isaac       PetscInt off;
1093d961a43aSToby Isaac 
10949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec, point, &off));
1095d961a43aSToby Isaac       *children = &mesh->children[off];
10969371c9d4SSatish Balay     } else {
1097d961a43aSToby Isaac       *children = NULL;
1098d961a43aSToby Isaac     }
1099d961a43aSToby Isaac   }
1100d961a43aSToby Isaac   PetscFunctionReturn(0);
1101d961a43aSToby Isaac }
11020c37af3bSToby Isaac 
11039371c9d4SSatish Balay 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) {
110452a3aeb4SToby Isaac   PetscInt f, b, p, c, offset, qPoints;
1105b3a4bf2aSToby Isaac 
1106b3a4bf2aSToby Isaac   PetscFunctionBegin;
11079566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(space, nPoints, points, work, NULL, NULL));
110852a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
110952a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
111052a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1111b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1112b3a4bf2aSToby Isaac 
111352a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
11149371c9d4SSatish Balay         for (c = 0; c < nComps; c++) { val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c]; }
111552a3aeb4SToby Isaac       }
11169566063dSJacob Faibussowitsch       PetscCall(MatSetValue(basisAtPoints, b, f, val, INSERT_VALUES));
1117b3a4bf2aSToby Isaac     }
1118b3a4bf2aSToby Isaac     offset += qPoints;
1119b3a4bf2aSToby Isaac   }
11209566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(basisAtPoints, MAT_FINAL_ASSEMBLY));
11219566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(basisAtPoints, MAT_FINAL_ASSEMBLY));
1122b3a4bf2aSToby Isaac   PetscFunctionReturn(0);
1123b3a4bf2aSToby Isaac }
1124b3a4bf2aSToby Isaac 
11259371c9d4SSatish Balay static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat) {
11260c37af3bSToby Isaac   PetscDS         ds;
11270c37af3bSToby Isaac   PetscInt        spdim;
11280c37af3bSToby Isaac   PetscInt        numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
11290c37af3bSToby Isaac   const PetscInt *anchors;
1130f7c74593SToby Isaac   PetscSection    aSec;
11310c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
11320c37af3bSToby Isaac   IS              aIS;
11330c37af3bSToby Isaac 
11340c37af3bSToby Isaac   PetscFunctionBegin;
11359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
11369566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
11379566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
11389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
11399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
11409566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
11419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &conStart, &conEnd));
11429566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &spdim));
11439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(spdim, &v0, spdim, &v0parent, spdim, &vtmp, spdim * spdim, &J, spdim * spdim, &Jparent, spdim * spdim, &invJparent));
11440c37af3bSToby Isaac 
11450c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
11460dd1b1feSToby Isaac     PetscObject          disc;
11470dd1b1feSToby Isaac     PetscClassId         id;
1148b3a4bf2aSToby Isaac     PetscSpace           bspace;
1149b3a4bf2aSToby Isaac     PetscDualSpace       dspace;
11509c3cf19fSMatthew G. Knepley     PetscInt             i, j, k, nPoints, Nc, offset;
115152a3aeb4SToby Isaac     PetscInt             fSize, maxDof;
1152b3a4bf2aSToby Isaac     PetscReal           *weights, *pointsRef, *pointsReal, *work;
11531683a169SBarry Smith     PetscScalar         *scwork;
11541683a169SBarry Smith     const PetscScalar   *X;
11552c44ad04SToby Isaac     PetscInt            *sizes, *workIndRow, *workIndCol;
11560c37af3bSToby Isaac     Mat                  Amat, Bmat, Xmat;
11572c44ad04SToby Isaac     const PetscInt      *numDof = NULL;
1158085f0adfSToby Isaac     const PetscInt    ***perms  = NULL;
1159085f0adfSToby Isaac     const PetscScalar ***flips  = NULL;
11600c37af3bSToby Isaac 
11619566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(ds, f, &disc));
11629566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(disc, &id));
11630dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1164b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE)disc;
1165b3a4bf2aSToby Isaac 
11669566063dSJacob Faibussowitsch       PetscCall(PetscFEGetBasisSpace(fe, &bspace));
11679566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(fe, &dspace));
11689566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
11699566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
11709371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
1171b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV)disc;
1172b3a4bf2aSToby Isaac 
11739566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
11749566063dSJacob Faibussowitsch       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)fv), &bspace));
11759566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetType(bspace, PETSCSPACEPOLYNOMIAL));
11769566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetDegree(bspace, 0, PETSC_DETERMINE));
11779566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumComponents(bspace, Nc));
11789566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumVariables(bspace, spdim));
11799566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(bspace));
11809566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &dspace));
11819566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
11829371c9d4SSatish Balay     } else SETERRQ(PetscObjectComm(disc), PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
11839566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetNumDof(dspace, &numDof));
11842c44ad04SToby Isaac     for (i = 0, maxDof = 0; i <= spdim; i++) { maxDof = PetscMax(maxDof, numDof[i]); }
11859566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSymmetries(dspace, &perms, &flips));
11860dd1b1feSToby Isaac 
11879566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &Amat));
11889566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Amat, fSize, fSize, fSize, fSize));
11899566063dSJacob Faibussowitsch     PetscCall(MatSetType(Amat, MATSEQDENSE));
11909566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Amat));
11919566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Bmat));
11929566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Xmat));
11930c37af3bSToby Isaac     nPoints = 0;
11940c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
119552a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
11960c37af3bSToby Isaac       PetscQuadrature quad;
11970c37af3bSToby Isaac 
11989566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
11999566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, &thisNc, &qPoints, NULL, NULL));
120063a3b9bcSJacob Faibussowitsch       PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
12010c37af3bSToby Isaac       nPoints += qPoints;
12020c37af3bSToby Isaac     }
12039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(fSize, &sizes, nPoints * Nc, &weights, spdim * nPoints, &pointsRef, spdim * nPoints, &pointsReal, nPoints * fSize * Nc, &work, maxDof, &workIndRow, maxDof, &workIndCol));
12049566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof * maxDof, &scwork));
12050c37af3bSToby Isaac     offset = 0;
12060c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12070c37af3bSToby Isaac       PetscInt         qPoints;
12080c37af3bSToby Isaac       const PetscReal *p, *w;
12090c37af3bSToby Isaac       PetscQuadrature  quad;
12100c37af3bSToby Isaac 
12119566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
12129566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &qPoints, &p, &w));
12139566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(weights + Nc * offset, w, Nc * qPoints));
12149566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pointsRef + spdim * offset, p, spdim * qPoints));
1215b3a4bf2aSToby Isaac       sizes[i] = qPoints;
12160c37af3bSToby Isaac       offset += qPoints;
12170c37af3bSToby Isaac     }
12189566063dSJacob Faibussowitsch     PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsRef, weights, work, Amat));
12199566063dSJacob Faibussowitsch     PetscCall(MatLUFactor(Amat, NULL, NULL, NULL));
12200c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
12210c37af3bSToby Isaac       PetscInt  parent;
12220c37af3bSToby Isaac       PetscInt  closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
12230c37af3bSToby Isaac       PetscInt *childOffsets, *parentOffsets;
12240c37af3bSToby Isaac 
12259566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, c, &parent, NULL));
12260c37af3bSToby Isaac       if (parent == c) continue;
12279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12280c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12290c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12300c37af3bSToby Isaac         PetscInt conDof;
12310c37af3bSToby Isaac 
12320c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1233085f0adfSToby Isaac         if (numFields) {
12349566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
12359371c9d4SSatish Balay         } else {
12369566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
12370c37af3bSToby Isaac         }
12380c37af3bSToby Isaac         if (conDof) break;
12390c37af3bSToby Isaac       }
12400c37af3bSToby Isaac       if (i == closureSize) {
12419566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12420c37af3bSToby Isaac         continue;
12430c37af3bSToby Isaac       }
12440c37af3bSToby Isaac 
12459566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ));
12469566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent));
12470c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1248c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
1249c330f8ffSToby Isaac 
1250c330f8ffSToby Isaac         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i * spdim], vtmp);
1251c330f8ffSToby Isaac         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i * spdim]);
12520c37af3bSToby Isaac       }
12539566063dSJacob Faibussowitsch       PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsReal, weights, work, Bmat));
12549566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(Amat, Bmat, Xmat));
12559566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Xmat, &X));
12569566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
12579566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(closureSize + 1, &childOffsets, closureSizeP + 1, &parentOffsets));
12580c37af3bSToby Isaac       childOffsets[0] = 0;
12590c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12600c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12610c37af3bSToby Isaac         PetscInt dof;
12620c37af3bSToby Isaac 
1263085f0adfSToby Isaac         if (numFields) {
12649566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12659371c9d4SSatish Balay         } else {
12669566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12670c37af3bSToby Isaac         }
126852a3aeb4SToby Isaac         childOffsets[i + 1] = childOffsets[i] + dof;
12690c37af3bSToby Isaac       }
12700c37af3bSToby Isaac       parentOffsets[0] = 0;
12710c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
12720c37af3bSToby Isaac         PetscInt p = closureP[2 * i];
12730c37af3bSToby Isaac         PetscInt dof;
12740c37af3bSToby Isaac 
1275085f0adfSToby Isaac         if (numFields) {
12769566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12779371c9d4SSatish Balay         } else {
12789566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12790c37af3bSToby Isaac         }
128052a3aeb4SToby Isaac         parentOffsets[i + 1] = parentOffsets[i] + dof;
12810c37af3bSToby Isaac       }
12820c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12832c44ad04SToby Isaac         PetscInt           conDof, conOff, aDof, aOff, nWork;
12840c37af3bSToby Isaac         PetscInt           p = closure[2 * i];
12850c37af3bSToby Isaac         PetscInt           o = closure[2 * i + 1];
1286085f0adfSToby Isaac         const PetscInt    *perm;
1287085f0adfSToby Isaac         const PetscScalar *flip;
12880c37af3bSToby Isaac 
12890c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1290085f0adfSToby Isaac         if (numFields) {
12919566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
12929566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &conOff));
12939371c9d4SSatish Balay         } else {
12949566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
12959566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(cSec, p, &conOff));
12960c37af3bSToby Isaac         }
12970c37af3bSToby Isaac         if (!conDof) continue;
1298085f0adfSToby Isaac         perm = (perms && perms[i]) ? perms[i][o] : NULL;
1299085f0adfSToby Isaac         flip = (flips && flips[i]) ? flips[i][o] : NULL;
13009566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
13019566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
13022c44ad04SToby Isaac         nWork = childOffsets[i + 1] - childOffsets[i];
13030c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
13040c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
13050c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
13060c37af3bSToby Isaac 
1307085f0adfSToby Isaac           if (numFields) {
13089566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aSecDof));
13099566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aSecOff));
13109371c9d4SSatish Balay           } else {
13119566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, a, &aSecDof));
13129566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, a, &aSecOff));
13130c37af3bSToby Isaac           }
13140c37af3bSToby Isaac           if (!aSecDof) continue;
13150c37af3bSToby Isaac 
13160c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
13170c37af3bSToby Isaac             PetscInt q  = closureP[2 * j];
13180c37af3bSToby Isaac             PetscInt oq = closureP[2 * j + 1];
13192c44ad04SToby Isaac 
13202c44ad04SToby Isaac             if (q == a) {
132152a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1322085f0adfSToby Isaac               const PetscInt    *permP;
1323085f0adfSToby Isaac               const PetscScalar *flipP;
1324085f0adfSToby Isaac 
1325085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1326085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
13272c44ad04SToby Isaac               nWorkP = parentOffsets[j + 1] - parentOffsets[j];
13282c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
13291683a169SBarry Smith                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
13302c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
13312c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
13329371c9d4SSatish Balay                 for (s = 0; s < nWorkP; s++) { scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])]; }
13332c44ad04SToby Isaac               }
133452a3aeb4SToby Isaac               for (r = 0; r < nWork; r++) { workIndRow[perm ? perm[r] : r] = conOff + r; }
133552a3aeb4SToby Isaac               for (s = 0; s < nWorkP; s++) { workIndCol[permP ? permP[s] : s] = aSecOff + s; }
13362c44ad04SToby Isaac               if (flip) {
13372c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
13389371c9d4SSatish Balay                   for (s = 0; s < nWorkP; s++) { scwork[r * nWorkP + s] *= flip[r]; }
13392c44ad04SToby Isaac                 }
13402c44ad04SToby Isaac               }
13412c44ad04SToby Isaac               if (flipP) {
13422c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
13439371c9d4SSatish Balay                   for (s = 0; s < nWorkP; s++) { scwork[r * nWorkP + s] *= flipP[s]; }
13442c44ad04SToby Isaac                 }
13452c44ad04SToby Isaac               }
13469566063dSJacob Faibussowitsch               PetscCall(MatSetValues(cMat, nWork, workIndRow, nWorkP, workIndCol, scwork, INSERT_VALUES));
13472c44ad04SToby Isaac               break;
13480c37af3bSToby Isaac             }
13490c37af3bSToby Isaac           }
13500c37af3bSToby Isaac         }
13510c37af3bSToby Isaac       }
13529566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Xmat, &X));
13539566063dSJacob Faibussowitsch       PetscCall(PetscFree2(childOffsets, parentOffsets));
13549566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
13559566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
13560c37af3bSToby Isaac     }
13579566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Amat));
13589566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Bmat));
13599566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Xmat));
13609566063dSJacob Faibussowitsch     PetscCall(PetscFree(scwork));
13619566063dSJacob Faibussowitsch     PetscCall(PetscFree7(sizes, weights, pointsRef, pointsReal, work, workIndRow, workIndCol));
13629371c9d4SSatish Balay     if (id == PETSCFV_CLASSID) { PetscCall(PetscSpaceDestroy(&bspace)); }
13630c37af3bSToby Isaac   }
13649566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
13659566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
13669566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJparent));
13679566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
13680c37af3bSToby Isaac 
13690c37af3bSToby Isaac   PetscFunctionReturn(0);
13700c37af3bSToby Isaac }
137195a0b26dSToby Isaac 
13729371c9d4SSatish Balay static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN) {
1373f7c74593SToby Isaac   Mat                 refCmat;
137421968bf8SToby Isaac   PetscDS             ds;
1375085f0adfSToby Isaac   PetscInt            numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
137621968bf8SToby Isaac   PetscScalar      ***refPointFieldMats;
137721968bf8SToby Isaac   PetscSection        refConSec, refAnSec, refSection;
137821968bf8SToby Isaac   IS                  refAnIS;
137921968bf8SToby Isaac   const PetscInt     *refAnchors;
1380085f0adfSToby Isaac   const PetscInt    **perms;
1381085f0adfSToby Isaac   const PetscScalar **flips;
138295a0b26dSToby Isaac 
138395a0b26dSToby Isaac   PetscFunctionBegin;
13849566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
13859566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1386085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
13879566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
13889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
13899566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(refAnIS, &refAnchors));
13909566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
13919566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
13929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
13939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldN));
13949566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
13959566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
13969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
13979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxAnDof, &cols));
139895a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
139995a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
140095a0b26dSToby Isaac 
14019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
14029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
140395a0b26dSToby Isaac     if (!pDof || parent == p) continue;
140495a0b26dSToby Isaac 
14059566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxFields, &refPointFieldMats[p - pRefStart]));
14069566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(maxFields, &refPointFieldN[p - pRefStart]));
14079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
1408085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1409085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
141095a0b26dSToby Isaac 
1411085f0adfSToby Isaac       if (f < numFields) {
14129566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
14139566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
14149566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1415085f0adfSToby Isaac       } else {
14169566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
14179566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
14189566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetPointSyms(refSection, closureSize, closure, &perms, &flips));
141995a0b26dSToby Isaac       }
142095a0b26dSToby Isaac 
14219371c9d4SSatish Balay       for (r = 0; r < cDof; r++) { rows[r] = cOff + r; }
142295a0b26dSToby Isaac       numCols = 0;
142395a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
142495a0b26dSToby Isaac         PetscInt        q = closure[2 * i];
142595a0b26dSToby Isaac         PetscInt        aDof, aOff, j;
1426085f0adfSToby Isaac         const PetscInt *perm = perms ? perms[i] : NULL;
142795a0b26dSToby Isaac 
1428085f0adfSToby Isaac         if (numFields) {
14299566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14309566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14319371c9d4SSatish Balay         } else {
14329566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14339566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
143495a0b26dSToby Isaac         }
143595a0b26dSToby Isaac 
14369371c9d4SSatish Balay         for (j = 0; j < aDof; j++) { cols[numCols++] = aOff + (perm ? perm[j] : j); }
143795a0b26dSToby Isaac       }
143895a0b26dSToby Isaac       refPointFieldN[p - pRefStart][f] = numCols;
14399566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
14409566063dSJacob Faibussowitsch       PetscCall(MatGetValues(refCmat, cDof, rows, numCols, cols, refPointFieldMats[p - pRefStart][f]));
1441085f0adfSToby Isaac       if (flips) {
1442085f0adfSToby Isaac         PetscInt colOff = 0;
1443085f0adfSToby Isaac 
1444085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1445085f0adfSToby Isaac           PetscInt           q = closure[2 * i];
1446085f0adfSToby Isaac           PetscInt           aDof, aOff, j;
1447085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1448085f0adfSToby Isaac 
1449085f0adfSToby Isaac           if (numFields) {
14509566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14519566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14529371c9d4SSatish Balay           } else {
14539566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14549566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
1455085f0adfSToby Isaac           }
1456085f0adfSToby Isaac           if (flip) {
1457085f0adfSToby Isaac             PetscInt k;
1458085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
14599371c9d4SSatish Balay               for (j = 0; j < aDof; j++) { refPointFieldMats[p - pRefStart][f][k * numCols + colOff + j] *= flip[j]; }
1460085f0adfSToby Isaac             }
1461085f0adfSToby Isaac           }
1462085f0adfSToby Isaac           colOff += aDof;
1463085f0adfSToby Isaac         }
1464085f0adfSToby Isaac       }
1465085f0adfSToby Isaac       if (numFields) {
14669566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestoreFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1467085f0adfSToby Isaac       } else {
14689566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestorePointSyms(refSection, closureSize, closure, &perms, &flips));
1469085f0adfSToby Isaac       }
147095a0b26dSToby Isaac     }
14719566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
147295a0b26dSToby Isaac   }
147321968bf8SToby Isaac   *childrenMats = refPointFieldMats;
147421968bf8SToby Isaac   *childrenN    = refPointFieldN;
14759566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(refAnIS, &refAnchors));
14769566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
14779566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
147821968bf8SToby Isaac   PetscFunctionReturn(0);
147921968bf8SToby Isaac }
148021968bf8SToby Isaac 
14819371c9d4SSatish Balay static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN) {
148221968bf8SToby Isaac   PetscDS        ds;
148321968bf8SToby Isaac   PetscInt     **refPointFieldN;
148421968bf8SToby Isaac   PetscScalar ***refPointFieldMats;
1485085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
148621968bf8SToby Isaac   PetscSection   refConSec;
148721968bf8SToby Isaac 
148821968bf8SToby Isaac   PetscFunctionBegin;
148921968bf8SToby Isaac   refPointFieldN    = *childrenN;
149021968bf8SToby Isaac   *childrenN        = NULL;
149121968bf8SToby Isaac   refPointFieldMats = *childrenMats;
149221968bf8SToby Isaac   *childrenMats     = NULL;
14939566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
14949566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1495367003a6SStefano Zampini   maxFields = PetscMax(1, numFields);
14969566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
14979566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
149821968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
149921968bf8SToby Isaac     PetscInt parent, pDof;
150021968bf8SToby Isaac 
15019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
15029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
150321968bf8SToby Isaac     if (!pDof || parent == p) continue;
150421968bf8SToby Isaac 
1505085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
150621968bf8SToby Isaac       PetscInt cDof;
150721968bf8SToby Isaac 
1508085f0adfSToby Isaac       if (numFields) {
15099566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
15109371c9d4SSatish Balay       } else {
15119566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
151221968bf8SToby Isaac       }
151321968bf8SToby Isaac 
15149566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
151521968bf8SToby Isaac     }
15169566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
15179566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldN[p - pRefStart]));
151821968bf8SToby Isaac   }
15199566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
15209566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldN));
152121968bf8SToby Isaac   PetscFunctionReturn(0);
152221968bf8SToby Isaac }
152321968bf8SToby Isaac 
15249371c9d4SSatish Balay static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat) {
152521968bf8SToby Isaac   DM              refTree;
152621968bf8SToby Isaac   PetscDS         ds;
152721968bf8SToby Isaac   Mat             refCmat;
1528085f0adfSToby Isaac   PetscInt        numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
152921968bf8SToby Isaac   PetscScalar  ***refPointFieldMats, *pointWork;
153021968bf8SToby Isaac   PetscSection    refConSec, refAnSec, anSec;
153121968bf8SToby Isaac   IS              refAnIS, anIS;
153221968bf8SToby Isaac   const PetscInt *anchors;
153321968bf8SToby Isaac 
153421968bf8SToby Isaac   PetscFunctionBegin;
153521968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
15369566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
15379566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1538085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
15399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
15409566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, refTree));
15419566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
15429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
15439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anSec, &anIS));
15449566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(anIS, &anchors));
15459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
15469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(conSec, &conStart, &conEnd));
15479566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
15489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
15499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof * maxAnDof, &pointWork));
155021968bf8SToby Isaac 
155121968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
15529566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
155395a0b26dSToby Isaac 
155495a0b26dSToby Isaac   /* step 2: compute the preorder */
15559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
15569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(pEnd - pStart, &perm, pEnd - pStart, &iperm));
155795a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
155895a0b26dSToby Isaac     perm[p - pStart]  = p;
155995a0b26dSToby Isaac     iperm[p - pStart] = p - pStart;
156095a0b26dSToby Isaac   }
156195a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
156295a0b26dSToby Isaac     PetscInt point = perm[p];
156395a0b26dSToby Isaac     PetscInt parent;
156495a0b26dSToby Isaac 
15659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
156695a0b26dSToby Isaac     if (parent == point) {
156795a0b26dSToby Isaac       p++;
15689371c9d4SSatish Balay     } else {
156995a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
157095a0b26dSToby Isaac 
15719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
157295a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
157395a0b26dSToby Isaac         PetscInt q = closure[2 * i];
157495a0b26dSToby Isaac         if (iperm[q - pStart] > iperm[point - pStart]) {
157595a0b26dSToby Isaac           /* swap */
157695a0b26dSToby Isaac           perm[p]                 = q;
157795a0b26dSToby Isaac           perm[iperm[q - pStart]] = point;
157895a0b26dSToby Isaac           iperm[point - pStart]   = iperm[q - pStart];
157995a0b26dSToby Isaac           iperm[q - pStart]       = p;
158095a0b26dSToby Isaac           break;
158195a0b26dSToby Isaac         }
158295a0b26dSToby Isaac       }
158395a0b26dSToby Isaac       size = closureSize;
15849566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
15859371c9d4SSatish Balay       if (i == size) { p++; }
158695a0b26dSToby Isaac     }
158795a0b26dSToby Isaac   }
158895a0b26dSToby Isaac 
158995a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
159095a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
159195a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
159295a0b26dSToby Isaac    * values outside of the Mat first.
159395a0b26dSToby Isaac    */
159495a0b26dSToby Isaac   {
159595a0b26dSToby Isaac     PetscInt        nRows, row, nnz;
159695a0b26dSToby Isaac     PetscBool       done;
1597*cd6fc93eSToby Isaac     PetscInt        secStart, secEnd;
159895a0b26dSToby Isaac     const PetscInt *ia, *ja;
159995a0b26dSToby Isaac     PetscScalar    *vals;
160095a0b26dSToby Isaac 
1601*cd6fc93eSToby Isaac     PetscCall(PetscSectionGetChart(section, &secStart, &secEnd));
16029566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
160328b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not get RowIJ of constraint matrix");
160495a0b26dSToby Isaac     nnz = ia[nRows];
160595a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
160695a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
16079566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vals));
160895a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
160995a0b26dSToby Isaac       PetscInt parent, childid, closureSize, *closure = NULL;
161095a0b26dSToby Isaac       PetscInt point = perm[p], pointDof;
161195a0b26dSToby Isaac 
16129566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, point, &parent, &childid));
161395a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
16149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(conSec, point, &pointDof));
161595a0b26dSToby Isaac       if (!pointDof) continue;
16169566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1617085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1618085f0adfSToby Isaac         PetscInt            cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
161995a0b26dSToby Isaac         PetscScalar        *pointMat;
1620085f0adfSToby Isaac         const PetscInt    **perms;
1621085f0adfSToby Isaac         const PetscScalar **flips;
162295a0b26dSToby Isaac 
1623085f0adfSToby Isaac         if (numFields) {
16249566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(conSec, point, f, &cDof));
16259566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(conSec, point, f, &cOff));
16269371c9d4SSatish Balay         } else {
16279566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(conSec, point, &cDof));
16289566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(conSec, point, &cOff));
162995a0b26dSToby Isaac         }
163095a0b26dSToby Isaac         if (!cDof) continue;
16319566063dSJacob Faibussowitsch         if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
16329566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetPointSyms(section, closureSize, closure, &perms, &flips));
163395a0b26dSToby Isaac 
163495a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
163576bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
163695a0b26dSToby Isaac           for (r = 0; r < cDof; r++) {
163795a0b26dSToby Isaac             if (cDof > 1 && r) {
163863a3b9bcSJacob Faibussowitsch               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]));
163995a0b26dSToby Isaac             }
164095a0b26dSToby Isaac           }
164176bd3646SJed Brown         }
164295a0b26dSToby Isaac         /* zero rows */
16439371c9d4SSatish Balay         for (i = ia[cOff]; i < ia[cOff + cDof]; i++) { vals[i] = 0.; }
164495a0b26dSToby Isaac         matOffset   = ia[cOff];
164595a0b26dSToby Isaac         numFillCols = ia[cOff + 1] - matOffset;
164695a0b26dSToby Isaac         pointMat    = refPointFieldMats[childid - pRefStart][f];
164795a0b26dSToby Isaac         numCols     = refPointFieldN[childid - pRefStart][f];
164895a0b26dSToby Isaac         offset      = 0;
164995a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
165095a0b26dSToby Isaac           PetscInt           q = closure[2 * i];
165195a0b26dSToby Isaac           PetscInt           aDof, aOff, j, k, qConDof, qConOff;
1652085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1653085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
165495a0b26dSToby Isaac 
165595a0b26dSToby Isaac           qConDof = qConOff = 0;
1656*cd6fc93eSToby Isaac           if (q < secStart || q >= secEnd) continue;
1657085f0adfSToby Isaac           if (numFields) {
16589566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, q, f, &aDof));
16599566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, q, f, &aOff));
166095a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16619566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(conSec, q, f, &qConDof));
16629566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldOffset(conSec, q, f, &qConOff));
166395a0b26dSToby Isaac             }
16649371c9d4SSatish Balay           } else {
16659566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, q, &aDof));
16669566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, q, &aOff));
166795a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16689566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(conSec, q, &qConDof));
16699566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(conSec, q, &qConOff));
167095a0b26dSToby Isaac             }
167195a0b26dSToby Isaac           }
167295a0b26dSToby Isaac           if (!aDof) continue;
167395a0b26dSToby Isaac           if (qConDof) {
167495a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
167595a0b26dSToby Isaac              * be filled, thanks to preordering */
167695a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
167795a0b26dSToby Isaac             PetscInt aMatOffset   = ia[qConOff];
167895a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
167995a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
168095a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
168195a0b26dSToby Isaac                 PetscScalar inVal = 0;
168295a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1683085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
168495a0b26dSToby Isaac 
1685085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
168695a0b26dSToby Isaac                 }
168795a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
168895a0b26dSToby Isaac               }
168995a0b26dSToby Isaac             }
169095a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
169195a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
169295a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
169395a0b26dSToby Isaac               for (; k < numFillCols; k++) {
16949371c9d4SSatish Balay                 if (ja[matOffset + k] == col) { break; }
169595a0b26dSToby Isaac               }
169663a3b9bcSJacob Faibussowitsch               PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, col);
16979371c9d4SSatish Balay               for (r = 0; r < cDof; r++) { vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j]; }
169895a0b26dSToby Isaac             }
16999371c9d4SSatish Balay           } else {
170095a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
170195a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
17029371c9d4SSatish Balay               if (ja[matOffset + k] == aOff) { break; }
170395a0b26dSToby Isaac             }
170463a3b9bcSJacob Faibussowitsch             PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, aOff);
170595a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1706085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1707085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1708085f0adfSToby Isaac 
1709085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
171095a0b26dSToby Isaac               }
171195a0b26dSToby Isaac             }
171295a0b26dSToby Isaac           }
171395a0b26dSToby Isaac           offset += aDof;
171495a0b26dSToby Isaac         }
1715085f0adfSToby Isaac         if (numFields) {
17169566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestoreFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
1717085f0adfSToby Isaac         } else {
17189566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestorePointSyms(section, closureSize, closure, &perms, &flips));
1719085f0adfSToby Isaac         }
172095a0b26dSToby Isaac       }
17219566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
172295a0b26dSToby Isaac     }
17239371c9d4SSatish Balay     for (row = 0; row < nRows; row++) { PetscCall(MatSetValues(cMat, 1, &row, ia[row + 1] - ia[row], &ja[ia[row]], &vals[ia[row]], INSERT_VALUES)); }
17249566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
172528b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not restore RowIJ of constraint matrix");
17269566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
17279566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
17289566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
172995a0b26dSToby Isaac   }
173095a0b26dSToby Isaac 
173195a0b26dSToby Isaac   /* clean up */
17329566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(anIS, &anchors));
17339566063dSJacob Faibussowitsch   PetscCall(PetscFree2(perm, iperm));
17349566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointWork));
17359566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
173695a0b26dSToby Isaac   PetscFunctionReturn(0);
173795a0b26dSToby Isaac }
173895a0b26dSToby Isaac 
17396f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
17406f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
17419371c9d4SSatish Balay PetscErrorCode DMPlexTreeRefineCell(DM dm, PetscInt cell, DM *ncdm) {
17426f5f1567SToby Isaac   DM           K;
1743420f55faSMatthew G. Knepley   PetscMPIInt  rank;
17446f5f1567SToby Isaac   PetscInt     dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
17456f5f1567SToby Isaac   PetscInt     numNewCones, *newConeSizes, *newCones, *newOrientations;
17466f5f1567SToby Isaac   PetscInt    *Kembedding;
17476f5f1567SToby Isaac   PetscInt    *cellClosure = NULL, nc;
17486f5f1567SToby Isaac   PetscScalar *newVertexCoords;
17496f5f1567SToby Isaac   PetscInt     numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
17506f5f1567SToby Isaac   PetscSection parentSection;
17516f5f1567SToby Isaac 
17526f5f1567SToby Isaac   PetscFunctionBegin;
17539566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
17549566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
17559566063dSJacob Faibussowitsch   PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
17569566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ncdm, dim));
17576f5f1567SToby Isaac 
17589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
17599566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &parentSection));
17609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &K));
17616858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
1762dd400576SPatrick Sanan   if (rank == 0) {
17636f5f1567SToby Isaac     /* compute the new charts */
17649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc5(dim + 1, &pNewCount, dim + 1, &pNewStart, dim + 1, &pNewEnd, dim + 1, &pOldStart, dim + 1, &pOldEnd));
17656f5f1567SToby Isaac     offset = 0;
17666f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
17676f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
17686f5f1567SToby Isaac 
17696f5f1567SToby Isaac       pNewStart[d] = offset;
17709566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, d, &pOldStart[d], &pOldEnd[d]));
17719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
17726f5f1567SToby Isaac       pOldCount    = pOldEnd[d] - pOldStart[d];
17736f5f1567SToby Isaac       /* adding the new points */
17746f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
17756f5f1567SToby Isaac       if (!d) {
17766f5f1567SToby Isaac         /* removing the cell */
17776f5f1567SToby Isaac         pNewCount[d]--;
17786f5f1567SToby Isaac       }
17796f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
17806f5f1567SToby Isaac         PetscInt parent;
17819566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &parent, NULL));
17826f5f1567SToby Isaac         if (parent == k) {
17836f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
17846f5f1567SToby Isaac           pNewCount[d]--;
17856f5f1567SToby Isaac         }
17866f5f1567SToby Isaac       }
17876f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
17886f5f1567SToby Isaac       offset     = pNewEnd[d];
17896f5f1567SToby Isaac     }
17901dca8a05SBarry Smith     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]);
17916f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
17929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
17936f5f1567SToby Isaac 
17949566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pNewEnd[dim], &newConeSizes));
17956f5f1567SToby Isaac     {
1796b5a892a1SMatthew G. Knepley       DMPolytopeType pct, qct;
17976f5f1567SToby Isaac       PetscInt       kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
17986f5f1567SToby Isaac 
17999566063dSJacob Faibussowitsch       PetscCall(DMPlexGetChart(K, &kStart, &kEnd));
18009566063dSJacob Faibussowitsch       PetscCall(PetscMalloc4(kEnd - kStart, &Kembedding, kEnd - kStart, &perm, kEnd - kStart, &iperm, kEnd - kStart, &preOrient));
18016f5f1567SToby Isaac 
18026f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18036f5f1567SToby Isaac         perm[k - kStart]      = k;
18046f5f1567SToby Isaac         iperm[k - kStart]     = k - kStart;
18056f5f1567SToby Isaac         preOrient[k - kStart] = 0;
18066f5f1567SToby Isaac       }
18076f5f1567SToby Isaac 
18089566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18096f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
18106f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2 * j + 1];
18116f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2 * j + 1];
18126f5f1567SToby Isaac         PetscInt p, q;
18136f5f1567SToby Isaac 
18146f5f1567SToby Isaac         p = closureK[2 * j];
18156f5f1567SToby Isaac         q = cellClosure[2 * j];
18169566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(K, p, &pct));
18179566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, q, &qct));
18186f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
18199371c9d4SSatish Balay           if (q >= pOldStart[d] && q < pOldEnd[d]) { Kembedding[p] = (q - pOldStart[d]) + pNewStart[d]; }
18206f5f1567SToby Isaac         }
1821b5a892a1SMatthew G. Knepley         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1822b5a892a1SMatthew G. Knepley         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
18236f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
18246f5f1567SToby Isaac           PetscInt        numChildren, i;
18256f5f1567SToby Isaac           const PetscInt *children;
18266f5f1567SToby Isaac 
18279566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(K, p, &numChildren, &children));
18286f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
18296f5f1567SToby Isaac             PetscInt kPerm, oPerm;
18306f5f1567SToby Isaac 
18316f5f1567SToby Isaac             k = children[i];
18329566063dSJacob Faibussowitsch             PetscCall(DMPlexReferenceTreeGetChildSymmetry(K, p, parentOrientA, 0, k, parentOrientB, &oPerm, &kPerm));
18336f5f1567SToby Isaac             /* perm = what refTree position I'm in */
18346f5f1567SToby Isaac             perm[kPerm - kStart]      = k;
18356f5f1567SToby Isaac             /* iperm = who is at this position */
18366f5f1567SToby Isaac             iperm[k - kStart]         = kPerm - kStart;
18376f5f1567SToby Isaac             preOrient[kPerm - kStart] = oPerm;
18386f5f1567SToby Isaac           }
18396f5f1567SToby Isaac         }
18406f5f1567SToby Isaac       }
18419566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18426f5f1567SToby Isaac     }
18439566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, 0, pNewEnd[dim]));
18446f5f1567SToby Isaac     offset      = 0;
18456f5f1567SToby Isaac     numNewCones = 0;
18466f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18476f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
18486f5f1567SToby Isaac       PetscInt p;
18496f5f1567SToby Isaac       PetscInt size;
18506f5f1567SToby Isaac 
18516f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
18526f5f1567SToby Isaac         /* skip cell 0 */
18536f5f1567SToby Isaac         if (p == cell) continue;
18546f5f1567SToby Isaac         /* old cones to new cones */
18559566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
18566f5f1567SToby Isaac         newConeSizes[offset++] = size;
18576f5f1567SToby Isaac         numNewCones += size;
18586f5f1567SToby Isaac       }
18596f5f1567SToby Isaac 
18609566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
18616f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18626f5f1567SToby Isaac         PetscInt kParent;
18636f5f1567SToby Isaac 
18649566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
18656f5f1567SToby Isaac         if (kParent != k) {
18666f5f1567SToby Isaac           Kembedding[k] = offset;
18679566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
18686f5f1567SToby Isaac           newConeSizes[offset++] = size;
18696f5f1567SToby Isaac           numNewCones += size;
18709371c9d4SSatish Balay           if (kParent != 0) { PetscCall(PetscSectionSetDof(parentSection, Kembedding[k], 1)); }
18716f5f1567SToby Isaac         }
18726f5f1567SToby Isaac       }
18736f5f1567SToby Isaac     }
18746f5f1567SToby Isaac 
18759566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
18769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(parentSection, &numPointsWithParents));
18779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numNewCones, &newCones, numNewCones, &newOrientations));
18789566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPointsWithParents, &parents, numPointsWithParents, &childIDs));
18796f5f1567SToby Isaac 
18806f5f1567SToby Isaac     /* fill new cones */
18816f5f1567SToby Isaac     offset = 0;
18826f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18836f5f1567SToby Isaac       PetscInt        kStart, kEnd, k, l;
18846f5f1567SToby Isaac       PetscInt        p;
18856f5f1567SToby Isaac       PetscInt        size;
18866f5f1567SToby Isaac       const PetscInt *cone, *orientation;
18876f5f1567SToby Isaac 
18886f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
18896f5f1567SToby Isaac         /* skip cell 0 */
18906f5f1567SToby Isaac         if (p == cell) continue;
18916f5f1567SToby Isaac         /* old cones to new cones */
18929566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
18939566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
18949566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeOrientation(dm, p, &orientation));
18956f5f1567SToby Isaac         for (l = 0; l < size; l++) {
18966f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
18976f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
18986f5f1567SToby Isaac         }
18996f5f1567SToby Isaac       }
19006f5f1567SToby Isaac 
19019566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
19026f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19036f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
19046f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
19056f5f1567SToby Isaac 
19069566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
19076f5f1567SToby Isaac         if (kParent != k) {
19086f5f1567SToby Isaac           /* embed new cones */
19099566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
19109566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(K, kPerm, &cone));
19119566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeOrientation(K, kPerm, &orientation));
19126f5f1567SToby Isaac           for (l = 0; l < size; l++) {
19136f5f1567SToby Isaac             PetscInt       q, m = (preO >= 0) ? ((preO + l) % size) : ((size - (preO + 1) - l) % size);
19146f5f1567SToby Isaac             PetscInt       newO, lSize, oTrue;
1915b5a892a1SMatthew G. Knepley             DMPolytopeType ct = DM_NUM_POLYTOPES;
19166f5f1567SToby Isaac 
19176f5f1567SToby Isaac             q                = iperm[cone[m]];
19186f5f1567SToby Isaac             newCones[offset] = Kembedding[q];
19199566063dSJacob Faibussowitsch             PetscCall(DMPlexGetConeSize(K, q, &lSize));
1920b5a892a1SMatthew G. Knepley             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
1921b5a892a1SMatthew G. Knepley             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
1922b5a892a1SMatthew G. Knepley             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
19236f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
19246f5f1567SToby Isaac             newO                      = DihedralCompose(lSize, oTrue, preOrient[q]);
1925b5a892a1SMatthew G. Knepley             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
19266f5f1567SToby Isaac           }
19276f5f1567SToby Isaac           if (kParent != 0) {
19286f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
19299566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(parentSection, Kembedding[k], &pOffset));
19306f5f1567SToby Isaac             parents[pOffset]  = newPoint;
19316f5f1567SToby Isaac             childIDs[pOffset] = k;
19326f5f1567SToby Isaac           }
19336f5f1567SToby Isaac         }
19346f5f1567SToby Isaac       }
19356f5f1567SToby Isaac     }
19366f5f1567SToby Isaac 
19379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(dim * (pNewEnd[dim] - pNewStart[dim]), &newVertexCoords));
19386f5f1567SToby Isaac 
19396f5f1567SToby Isaac     /* fill coordinates */
19406f5f1567SToby Isaac     offset = 0;
19416f5f1567SToby Isaac     {
1942d90620a3SMatthew G. Knepley       PetscInt     kStart, kEnd, l;
19436f5f1567SToby Isaac       PetscSection vSection;
19446f5f1567SToby Isaac       PetscInt     v;
19456f5f1567SToby Isaac       Vec          coords;
19466f5f1567SToby Isaac       PetscScalar *coordvals;
19476f5f1567SToby Isaac       PetscInt     dof, off;
1948c111c6b7SMatthew G. Knepley       PetscReal    v0[3], J[9], detJ;
19496f5f1567SToby Isaac 
195076bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
1951d90620a3SMatthew G. Knepley         PetscInt k;
19529566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(K, 0, &kStart, &kEnd));
19536f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
19549566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
195563a3b9bcSJacob Faibussowitsch           PetscCheck(detJ > 0., PETSC_COMM_SELF, PETSC_ERR_PLIB, "reference tree cell %" PetscInt_FMT " has bad determinant", k);
19566f5f1567SToby Isaac         }
1957d90620a3SMatthew G. Knepley       }
19589566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
19599566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &vSection));
19609566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coords));
19619566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19626f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
19639566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(vSection, v, &dof));
19649566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(vSection, v, &off));
19659371c9d4SSatish Balay         for (l = 0; l < dof; l++) { newVertexCoords[offset++] = coordvals[off + l]; }
19666f5f1567SToby Isaac       }
19679566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
19686f5f1567SToby Isaac 
19699566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(K, &vSection));
19709566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(K, &coords));
19719566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19729566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(K, 0, &kStart, &kEnd));
19736f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
19749bc368c7SMatthew G. Knepley         PetscReal       coord[3], newCoord[3];
19756f5f1567SToby Isaac         PetscInt        vPerm = perm[v];
19766f5f1567SToby Isaac         PetscInt        kParent;
1977c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
19786f5f1567SToby Isaac 
19799566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, v, &kParent, NULL));
19806f5f1567SToby Isaac         if (kParent != v) {
19816f5f1567SToby Isaac           /* this is a new vertex */
19829566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(vSection, vPerm, &off));
19839bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off + l]);
1984367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
19859bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset + l] = newCoord[l];
19866f5f1567SToby Isaac           offset += dim;
19876f5f1567SToby Isaac         }
19886f5f1567SToby Isaac       }
19899566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
19906f5f1567SToby Isaac     }
19916f5f1567SToby Isaac 
19926f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
19936f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
19946f5f1567SToby Isaac       PetscInt tmp;
19956f5f1567SToby Isaac 
19966f5f1567SToby Isaac       tmp                = pNewCount[d];
19976f5f1567SToby Isaac       pNewCount[d]       = pNewCount[dim - d];
19986f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
19996f5f1567SToby Isaac     }
20006f5f1567SToby Isaac 
20019566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, pNewCount, newConeSizes, newCones, newOrientations, newVertexCoords));
20029566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20039566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, parents, childIDs));
20046f5f1567SToby Isaac 
20056f5f1567SToby Isaac     /* clean up */
20069566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
20079566063dSJacob Faibussowitsch     PetscCall(PetscFree5(pNewCount, pNewStart, pNewEnd, pOldStart, pOldEnd));
20089566063dSJacob Faibussowitsch     PetscCall(PetscFree(newConeSizes));
20099566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCones, newOrientations));
20109566063dSJacob Faibussowitsch     PetscCall(PetscFree(newVertexCoords));
20119566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parents, childIDs));
20129566063dSJacob Faibussowitsch     PetscCall(PetscFree4(Kembedding, perm, iperm, preOrient));
20139371c9d4SSatish Balay   } else {
20146f5f1567SToby Isaac     PetscInt     p, counts[4];
20156f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
20166f5f1567SToby Isaac     Vec          coordVec;
20176f5f1567SToby Isaac     PetscScalar *coords;
20186f5f1567SToby Isaac 
20196f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20206f5f1567SToby Isaac       PetscInt dStart, dEnd;
20216f5f1567SToby Isaac 
20229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
20236f5f1567SToby Isaac       counts[d] = dEnd - dStart;
20246f5f1567SToby Isaac     }
20259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEnd - pStart, &coneSizes));
20269371c9d4SSatish Balay     for (p = pStart; p < pEnd; p++) { PetscCall(DMPlexGetConeSize(dm, p, &coneSizes[p - pStart])); }
20279566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCones(dm, &cones));
20289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientations(dm, &orientations));
20299566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordVec));
20309566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordVec, &coords));
20316f5f1567SToby Isaac 
20329566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
20339566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
20349566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, counts, coneSizes, cones, orientations, NULL));
20359566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20369566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, NULL, NULL));
20379566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordVec, &coords));
20386f5f1567SToby Isaac   }
20399566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
20406f5f1567SToby Isaac 
20416f5f1567SToby Isaac   PetscFunctionReturn(0);
20426f5f1567SToby Isaac }
20436ecaa68aSToby Isaac 
20449371c9d4SSatish Balay PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat) {
20456ecaa68aSToby Isaac   PetscSF              coarseToFineEmbedded;
20466ecaa68aSToby Isaac   PetscSection         globalCoarse, globalFine;
20476ecaa68aSToby Isaac   PetscSection         localCoarse, localFine;
20486ecaa68aSToby Isaac   PetscSection         aSec, cSec;
20496ecaa68aSToby Isaac   PetscSection         rootIndicesSec, rootMatricesSec;
205046bdb399SToby Isaac   PetscSection         leafIndicesSec, leafMatricesSec;
205146bdb399SToby Isaac   PetscInt            *rootIndices, *leafIndices;
205246bdb399SToby Isaac   PetscScalar         *rootMatrices, *leafMatrices;
20536ecaa68aSToby Isaac   IS                   aIS;
20546ecaa68aSToby Isaac   const PetscInt      *anchors;
20556ecaa68aSToby Isaac   Mat                  cMat;
20564acb8e1eSToby Isaac   PetscInt             numFields, maxFields;
20576ecaa68aSToby Isaac   PetscInt             pStartC, pEndC, pStartF, pEndF, p;
20586ecaa68aSToby Isaac   PetscInt             aStart, aEnd, cStart, cEnd;
20591c58ffc4SToby Isaac   PetscInt            *maxChildIds;
2060e44e4e7fSToby Isaac   PetscInt            *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
20614acb8e1eSToby Isaac   const PetscInt    ***perms;
20624acb8e1eSToby Isaac   const PetscScalar ***flips;
20636ecaa68aSToby Isaac 
20646ecaa68aSToby Isaac   PetscFunctionBegin;
20659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
20669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
20679566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
20686ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
206989698031SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
207089698031SToby Isaac     const PetscInt *leaves;
20716ecaa68aSToby Isaac 
20729566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
207389698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
207489698031SToby Isaac       p = leaves ? leaves[l] : l;
20759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
20769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
20779371c9d4SSatish Balay       if ((dof - cdof) > 0) { numPointsWithDofs++; }
20786ecaa68aSToby Isaac     }
20799566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
20807cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
208189698031SToby Isaac       p = leaves ? leaves[l] : l;
20829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
20839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
20849371c9d4SSatish Balay       if ((dof - cdof) > 0) { pointsWithDofs[offset++] = l; }
20856ecaa68aSToby Isaac     }
20869566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
20879566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
20886ecaa68aSToby Isaac   }
20896ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
20909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
20919371c9d4SSatish Balay   for (p = pStartC; p < pEndC; p++) { maxChildIds[p - pStartC] = -2; }
209257168dbeSPierre Jolivet   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
209357168dbeSPierre Jolivet   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
209446bdb399SToby Isaac 
20959566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
20969566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
209746bdb399SToby Isaac 
20989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
20999566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
21009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
210146bdb399SToby Isaac 
21029566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
21039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
210446bdb399SToby Isaac 
210546bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
21069566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
21079566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootMatricesSec));
21089566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootIndicesSec, pStartC, pEndC));
21099566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootMatricesSec, pStartC, pEndC));
21109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
2111713c1c5dSToby Isaac   maxFields = PetscMax(1, numFields);
21129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc7(maxFields + 1, &offsets, maxFields + 1, &offsetsCopy, maxFields + 1, &newOffsets, maxFields + 1, &newOffsetsCopy, maxFields + 1, &rowOffsets, maxFields + 1, &numD, maxFields + 1, &numO));
21139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxFields + 1, (PetscInt ****)&perms, maxFields + 1, (PetscScalar ****)&flips));
21149566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)perms, (maxFields + 1) * sizeof(const PetscInt **)));
21159566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)flips, (maxFields + 1) * sizeof(const PetscScalar **)));
211646bdb399SToby Isaac 
211746bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
21188d2f55e7SToby Isaac     PetscInt dof, matSize = 0;
21196ecaa68aSToby Isaac     PetscInt aDof          = 0;
21206ecaa68aSToby Isaac     PetscInt cDof          = 0;
21216ecaa68aSToby Isaac     PetscInt maxChildId    = maxChildIds[p - pStartC];
21226ecaa68aSToby Isaac     PetscInt numRowIndices = 0;
21236ecaa68aSToby Isaac     PetscInt numColIndices = 0;
2124f13f9184SToby Isaac     PetscInt f;
21256ecaa68aSToby Isaac 
21269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
21279371c9d4SSatish Balay     if (dof < 0) { dof = -(dof + 1); }
21289371c9d4SSatish Balay     if (p >= aStart && p < aEnd) { PetscCall(PetscSectionGetDof(aSec, p, &aDof)); }
21299371c9d4SSatish Balay     if (p >= cStart && p < cEnd) { PetscCall(PetscSectionGetDof(cSec, p, &cDof)); }
2130f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2131f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
21326ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2133f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
21346ecaa68aSToby Isaac 
21359566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
213646bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
21376ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
21386ecaa68aSToby Isaac 
21399566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
21406ecaa68aSToby Isaac         numRowIndices += clDof;
21416ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21429566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &clDof));
21436ecaa68aSToby Isaac           offsets[f + 1] += clDof;
21446ecaa68aSToby Isaac         }
21456ecaa68aSToby Isaac       }
21466ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
21476ecaa68aSToby Isaac         offsets[f + 1] += offsets[f];
21486ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
21496ecaa68aSToby Isaac       }
215046bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
21519566063dSJacob Faibussowitsch       PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, NULL, NULL, NULL, &numColIndices, NULL, NULL, newOffsets, PETSC_FALSE));
21529566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
21536ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
21546ecaa68aSToby Isaac         numColIndices = numRowIndices;
21556ecaa68aSToby Isaac         matSize       = 0;
21569371c9d4SSatish Balay       } else if (numFields) { /* we send one submat for each field: sum their sizes */
21576ecaa68aSToby Isaac         matSize = 0;
21586ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21596ecaa68aSToby Isaac           PetscInt numRow, numCol;
21606ecaa68aSToby Isaac 
21616ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2162f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
21636ecaa68aSToby Isaac           matSize += numRow * numCol;
21646ecaa68aSToby Isaac         }
21659371c9d4SSatish Balay       } else {
21666ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
21676ecaa68aSToby Isaac       }
2168f13f9184SToby Isaac     } else if (maxChildId == -1) {
21698d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2170f13f9184SToby Isaac         PetscInt aOff, a;
21716ecaa68aSToby Isaac 
21729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
21736ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21746ecaa68aSToby Isaac           PetscInt fDof;
21756ecaa68aSToby Isaac 
21769566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
217721968bf8SToby Isaac           offsets[f + 1] = fDof;
21786ecaa68aSToby Isaac         }
21796ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
21806ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
21816ecaa68aSToby Isaac 
21829566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(localCoarse, anchor, &aLocalDof));
21836ecaa68aSToby Isaac           numColIndices += aLocalDof;
21846ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
21856ecaa68aSToby Isaac             PetscInt fDof;
21866ecaa68aSToby Isaac 
21879566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
218821968bf8SToby Isaac             newOffsets[f + 1] += fDof;
21896ecaa68aSToby Isaac           }
21906ecaa68aSToby Isaac         }
21916ecaa68aSToby Isaac         if (numFields) {
21926ecaa68aSToby Isaac           matSize = 0;
21939371c9d4SSatish Balay           for (f = 0; f < numFields; f++) { matSize += offsets[f + 1] * newOffsets[f + 1]; }
21949371c9d4SSatish Balay         } else {
21956ecaa68aSToby Isaac           matSize = numColIndices * dof;
21966ecaa68aSToby Isaac         }
21979371c9d4SSatish Balay       } else { /* no children, and no constraints on dofs: just get the global indices */
21986ecaa68aSToby Isaac         numColIndices = dof;
21996ecaa68aSToby Isaac         matSize       = 0;
22006ecaa68aSToby Isaac       }
22018d2f55e7SToby Isaac     }
220246bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
22039566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootIndicesSec, p, numColIndices ? numColIndices + 2 * numFields : 0));
22049566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootMatricesSec, p, matSize));
22056ecaa68aSToby Isaac   }
22069566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootIndicesSec));
22079566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootMatricesSec));
22086ecaa68aSToby Isaac   {
22096ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
22106ecaa68aSToby Isaac 
22119566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
22129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootMatricesSec, &numRootMatrices));
22139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numRootIndices, &rootIndices, numRootMatrices, &rootMatrices));
22146ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
22156ecaa68aSToby Isaac       PetscInt     numRowIndices, numColIndices, matSize, dof;
2216f13f9184SToby Isaac       PetscInt     pIndOff, pMatOff, f;
22176ecaa68aSToby Isaac       PetscInt    *pInd;
22186ecaa68aSToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
22196ecaa68aSToby Isaac       PetscScalar *pMat       = NULL;
22206ecaa68aSToby Isaac 
22219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, p, &numColIndices));
22229371c9d4SSatish Balay       if (!numColIndices) { continue; }
2223f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2224f13f9184SToby Isaac         offsets[f]        = 0;
2225f13f9184SToby Isaac         newOffsets[f]     = 0;
2226f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2227f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2228f13f9184SToby Isaac       }
22296ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
22309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, p, &pIndOff));
22316ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
22329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootMatricesSec, p, &matSize));
22336ecaa68aSToby Isaac       if (matSize) {
22349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootMatricesSec, p, &pMatOff));
22356ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
22366ecaa68aSToby Isaac       }
22379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
22389371c9d4SSatish Balay       if (dof < 0) { dof = -(dof + 1); }
22396ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
22406ecaa68aSToby Isaac         PetscInt i, j;
22416ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
22426ecaa68aSToby Isaac 
22436ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
22446ecaa68aSToby Isaac           PetscInt numIndices, *indices;
22459566063dSJacob Faibussowitsch           PetscCall(DMPlexGetClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
224608401ef6SPierre Jolivet           PetscCheck(numIndices == numColIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "mismatching constraint indices calculations");
22479371c9d4SSatish Balay           for (i = 0; i < numColIndices; i++) { pInd[i] = indices[i]; }
22486ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
224946bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i + 1];
225046bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i + 1];
22516ecaa68aSToby Isaac           }
22529566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
22539371c9d4SSatish Balay         } else {
22546ecaa68aSToby Isaac           PetscInt     closureSize, *closure = NULL, cl;
22556ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
22566ecaa68aSToby Isaac           PetscInt     numPoints, *points;
22576ecaa68aSToby Isaac 
22589566063dSJacob Faibussowitsch           PetscCall(DMGetWorkArray(coarse, numRowIndices * numRowIndices, MPIU_SCALAR, &pMatIn));
22596ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
22609371c9d4SSatish Balay             for (j = 0; j < numRowIndices; j++) { pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.; }
22616ecaa68aSToby Isaac           }
22629566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22634acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
22649566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
22659566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
22664acb8e1eSToby Isaac           }
22676ecaa68aSToby Isaac           if (numFields) {
22686ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
22696ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
22706ecaa68aSToby Isaac 
22716ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
22726ecaa68aSToby Isaac                 PetscInt fDof;
22736ecaa68aSToby Isaac 
22749566063dSJacob Faibussowitsch                 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &fDof));
22756ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
22766ecaa68aSToby Isaac               }
22776ecaa68aSToby Isaac             }
22786ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
22796ecaa68aSToby Isaac               offsets[f + 1] += offsets[f];
22806ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
22816ecaa68aSToby Isaac             }
22826ecaa68aSToby Isaac           }
22834acb8e1eSToby Isaac           /* TODO : flips here ? */
22846ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
22859566063dSJacob Faibussowitsch           PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, perms, pMatIn, &numPoints, NULL, &points, &pMatModified, newOffsets, PETSC_FALSE));
22864acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
22879566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
22889566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
22894acb8e1eSToby Isaac           }
22904acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
22919566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
22929566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
22934acb8e1eSToby Isaac           }
22946ecaa68aSToby Isaac           if (!numFields) {
22959371c9d4SSatish Balay             for (i = 0; i < numRowIndices * numColIndices; i++) { pMat[i] = pMatModified[i]; }
22969371c9d4SSatish Balay           } else {
2297f13f9184SToby Isaac             PetscInt i, j, count;
22986ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
22996ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f + 1]; i++) {
23009371c9d4SSatish Balay                 for (j = newOffsets[f]; j < newOffsets[f + 1]; j++, count++) { pMat[count] = pMatModified[i * numColIndices + j]; }
23016ecaa68aSToby Isaac               }
23026ecaa68aSToby Isaac             }
23036ecaa68aSToby Isaac           }
23049566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatModified));
23059566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
23069566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatIn));
23076ecaa68aSToby Isaac           if (numFields) {
230846bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
230946bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f + 1];
231046bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f + 1];
23116ecaa68aSToby Isaac             }
23124acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23134acb8e1eSToby Isaac               PetscInt globalOff, c = points[2 * cl];
23149566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23159566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
23166ecaa68aSToby Isaac             }
23176ecaa68aSToby Isaac           } else {
23184acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23194acb8e1eSToby Isaac               PetscInt        c    = points[2 * cl], globalOff;
23204acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
23214acb8e1eSToby Isaac 
23229566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23239566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
23246ecaa68aSToby Isaac             }
23256ecaa68aSToby Isaac           }
23264acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23279566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23289566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23294acb8e1eSToby Isaac           }
23309566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numPoints, MPIU_SCALAR, &points));
23316ecaa68aSToby Isaac         }
23329371c9d4SSatish Balay       } else if (matSize) {
23336ecaa68aSToby Isaac         PetscInt  cOff;
23346ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
23356ecaa68aSToby Isaac 
23366ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
233708401ef6SPierre Jolivet         PetscCheck(numRowIndices == dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Miscounted dofs");
23389566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
23399566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
23409566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, p, &cOff));
23419566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
23429566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
23436ecaa68aSToby Isaac         if (numFields) {
23446ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23456ecaa68aSToby Isaac             PetscInt fDof;
2346f13f9184SToby Isaac 
23479566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSec, p, f, &fDof));
23486ecaa68aSToby Isaac             offsets[f + 1] = fDof;
23496ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
23506ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
23519566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
23526ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
23536ecaa68aSToby Isaac             }
23546ecaa68aSToby Isaac           }
23556ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23566ecaa68aSToby Isaac             offsets[f + 1] += offsets[f];
23576ecaa68aSToby Isaac             offsetsCopy[f + 1] = offsets[f + 1];
23586ecaa68aSToby Isaac             newOffsets[f + 1] += newOffsets[f];
23596ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
23606ecaa68aSToby Isaac           }
23619566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, -1, NULL, rowIndices));
23626ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23636ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23649566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23659566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, -1, NULL, colIndices));
23666ecaa68aSToby Isaac           }
23679371c9d4SSatish Balay         } else {
23689566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, NULL, rowIndices));
23696ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23706ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23719566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23729566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, NULL, colIndices));
23736ecaa68aSToby Isaac           }
23746ecaa68aSToby Isaac         }
23756ecaa68aSToby Isaac         if (numFields) {
2376f13f9184SToby Isaac           PetscInt count, a;
2377f13f9184SToby Isaac 
23786ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
23796ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
23806ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
23819566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat, iSize, &rowIndices[offsets[f]], jSize, &colIndices[newOffsets[f]], &pMat[count]));
23826ecaa68aSToby Isaac             count += iSize * jSize;
238346bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
238446bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f + 1];
23856ecaa68aSToby Isaac           }
23866ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23876ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
23886ecaa68aSToby Isaac             PetscInt gOff;
23899566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
23909566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, -1, NULL, pInd));
23916ecaa68aSToby Isaac           }
23929371c9d4SSatish Balay         } else {
23936ecaa68aSToby Isaac           PetscInt a;
23949566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat, numRowIndices, rowIndices, numColIndices, colIndices, pMat));
23956ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23966ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
23976ecaa68aSToby Isaac             PetscInt gOff;
23989566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
23999566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, NULL, pInd));
24006ecaa68aSToby Isaac           }
24016ecaa68aSToby Isaac         }
24029566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
24039566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
24049371c9d4SSatish Balay       } else {
24056ecaa68aSToby Isaac         PetscInt gOff;
24066ecaa68aSToby Isaac 
24079566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
24086ecaa68aSToby Isaac         if (numFields) {
24096ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
24106ecaa68aSToby Isaac             PetscInt fDof;
24119566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
24126ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
24136ecaa68aSToby Isaac           }
24146ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
241546bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
241646bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f + 1];
24176ecaa68aSToby Isaac           }
24189566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2419367003a6SStefano Zampini         } else {
24209566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
24216ecaa68aSToby Isaac         }
24226ecaa68aSToby Isaac       }
24236ecaa68aSToby Isaac     }
24249566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
24256ecaa68aSToby Isaac   }
242646bdb399SToby Isaac   {
242746bdb399SToby Isaac     PetscSF   indicesSF, matricesSF;
242846bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
242946bdb399SToby Isaac 
24309566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
24319566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafMatricesSec));
24329566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootIndicesSec, &remoteOffsetsIndices, leafIndicesSec));
24339566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootMatricesSec, &remoteOffsetsMatrices, leafMatricesSec));
24349566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootIndicesSec, remoteOffsetsIndices, leafIndicesSec, &indicesSF));
24359566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootMatricesSec, remoteOffsetsMatrices, leafMatricesSec, &matricesSF));
24369566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
24379566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsIndices));
24389566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsMatrices));
24399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numLeafIndices));
24409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafMatricesSec, &numLeafMatrices));
24419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numLeafIndices, &leafIndices, numLeafMatrices, &leafMatrices));
24429566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24439566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24449566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24459566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24469566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&matricesSF));
24479566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
24489566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rootIndices, rootMatrices));
24499566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootIndicesSec));
24509566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootMatricesSec));
245146bdb399SToby Isaac   }
245246bdb399SToby Isaac   /* count to preallocate */
24539566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
245446bdb399SToby Isaac   {
245546bdb399SToby Isaac     PetscInt       nGlobal;
245646bdb399SToby Isaac     PetscInt      *dnnz, *onnz;
2457b9a5774bSToby Isaac     PetscLayout    rowMap, colMap;
2458b9a5774bSToby Isaac     PetscInt       rowStart, rowEnd, colStart, colEnd;
24591c58ffc4SToby Isaac     PetscInt       maxDof;
24601c58ffc4SToby Isaac     PetscInt      *rowIndices;
24611c58ffc4SToby Isaac     DM             refTree;
24621c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
24631c58ffc4SToby Isaac     PetscScalar ***refPointFieldMats;
24641c58ffc4SToby Isaac     PetscSection   refConSec, refAnSec;
24650eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, maxConDof, maxColumns, leafStart, leafEnd;
24661c58ffc4SToby Isaac     PetscScalar   *pointWork;
246746bdb399SToby Isaac 
24689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine, &nGlobal));
24699566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nGlobal, &dnnz, nGlobal, &onnz));
24709566063dSJacob Faibussowitsch     PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
24719566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rowMap));
24729566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(colMap));
24739566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
24749566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
24759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
24769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafIndicesSec, &leafStart, &leafEnd));
24779566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
24780eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
247946bdb399SToby Isaac       PetscInt gDof, gcDof, gOff;
248046bdb399SToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
248146bdb399SToby Isaac       PetscInt matSize;
248221968bf8SToby Isaac       PetscInt i;
248346bdb399SToby Isaac 
24849566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
24859566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
24869371c9d4SSatish Balay       if ((gDof - gcDof) <= 0) { continue; }
24879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
248808401ef6SPierre Jolivet       PetscCheck(gOff >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I though having global dofs meant a non-negative offset");
24891dca8a05SBarry Smith       PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I thought the row map would constrain the global dofs");
24909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
24919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
249246bdb399SToby Isaac       numColIndices -= 2 * numFields;
249308401ef6SPierre Jolivet       PetscCheck(numColIndices > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "global fine dof with no dofs to interpolate from");
249446bdb399SToby Isaac       pInd              = &leafIndices[pIndOff];
249521968bf8SToby Isaac       offsets[0]        = 0;
249621968bf8SToby Isaac       offsetsCopy[0]    = 0;
249721968bf8SToby Isaac       newOffsets[0]     = 0;
249821968bf8SToby Isaac       newOffsetsCopy[0] = 0;
249946bdb399SToby Isaac       if (numFields) {
250021968bf8SToby Isaac         PetscInt f;
250146bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
250246bdb399SToby Isaac           PetscInt rowDof;
250346bdb399SToby Isaac 
25049566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
250521968bf8SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
250621968bf8SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
250721968bf8SToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
250821968bf8SToby Isaac           numD[f]            = 0;
250921968bf8SToby Isaac           numO[f]            = 0;
251046bdb399SToby Isaac         }
25119566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
251246bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
251321968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
251421968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
251546bdb399SToby Isaac 
251646bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
251746bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
251846bdb399SToby Isaac 
251946bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
252021968bf8SToby Isaac               numD[f]++;
25219371c9d4SSatish Balay             } else if (gInd >= 0) { /* negative means non-entry */
252221968bf8SToby Isaac               numO[f]++;
252346bdb399SToby Isaac             }
252446bdb399SToby Isaac           }
252546bdb399SToby Isaac         }
25269371c9d4SSatish Balay       } else {
25279566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
252821968bf8SToby Isaac         numD[0] = 0;
252921968bf8SToby Isaac         numO[0] = 0;
253046bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
253146bdb399SToby Isaac           PetscInt gInd = pInd[i];
253246bdb399SToby Isaac 
253346bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
253421968bf8SToby Isaac             numD[0]++;
25359371c9d4SSatish Balay           } else if (gInd >= 0) { /* negative means non-entry */
253621968bf8SToby Isaac             numO[0]++;
253746bdb399SToby Isaac           }
253846bdb399SToby Isaac         }
253946bdb399SToby Isaac       }
25409566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
254146bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
254246bdb399SToby Isaac         PetscInt childId;
254346bdb399SToby Isaac 
254446bdb399SToby Isaac         childId = childIds[p - pStartF];
254521968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
254646bdb399SToby Isaac           if (numFields) {
2547b9a5774bSToby Isaac             PetscInt f;
2548b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
254921968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
255046bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
255121968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
255221968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
255346bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25541dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2555b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
25569371c9d4SSatish Balay                 } else if (gIndCoarse >= 0) { /* remote */
25571dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2558b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
25599371c9d4SSatish Balay                 } else { /* constrained */
256008401ef6SPierre Jolivet                   PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
256146bdb399SToby Isaac                 }
256246bdb399SToby Isaac               }
256346bdb399SToby Isaac             }
25649371c9d4SSatish Balay           } else {
2565b9a5774bSToby Isaac             PetscInt i;
2566b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
256746bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
256846bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
256946bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25701dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2571b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
25729371c9d4SSatish Balay               } else if (gIndCoarse >= 0) { /* remote */
25731dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2574b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
25759371c9d4SSatish Balay               } else { /* constrained */
257608401ef6SPierre Jolivet                 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
257746bdb399SToby Isaac               }
257846bdb399SToby Isaac             }
257946bdb399SToby Isaac           }
25809371c9d4SSatish Balay         } else { /* interpolate from all */
258146bdb399SToby Isaac           if (numFields) {
2582b9a5774bSToby Isaac             PetscInt f;
2583b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
258421968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
258546bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
258621968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
258746bdb399SToby Isaac                 if (gIndFine >= 0) {
25881dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2589b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2590b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
259146bdb399SToby Isaac                 }
259246bdb399SToby Isaac               }
259346bdb399SToby Isaac             }
25949371c9d4SSatish Balay           } else {
2595b9a5774bSToby Isaac             PetscInt i;
2596b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
259746bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
259846bdb399SToby Isaac               if (gIndFine >= 0) {
25991dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2600b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2601b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
260246bdb399SToby Isaac               }
260346bdb399SToby Isaac             }
260446bdb399SToby Isaac           }
260546bdb399SToby Isaac         }
26069371c9d4SSatish Balay       } else { /* interpolate from all */
260746bdb399SToby Isaac         if (numFields) {
2608b9a5774bSToby Isaac           PetscInt f;
2609b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
261021968bf8SToby Isaac             PetscInt numRows = offsets[f + 1] - offsets[f], row;
261146bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
261221968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
261346bdb399SToby Isaac               if (gIndFine >= 0) {
26141dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2615b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2616b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
261746bdb399SToby Isaac               }
261846bdb399SToby Isaac             }
261946bdb399SToby Isaac           }
26209371c9d4SSatish Balay         } else { /* every dof get a full row */
2621b9a5774bSToby Isaac           PetscInt i;
2622b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
262346bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
262446bdb399SToby Isaac             if (gIndFine >= 0) {
26251dca8a05SBarry Smith               PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2626b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2627b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
262846bdb399SToby Isaac             }
262946bdb399SToby Isaac           }
263046bdb399SToby Isaac         }
263146bdb399SToby Isaac       }
263246bdb399SToby Isaac     }
26339566063dSJacob Faibussowitsch     PetscCall(MatXAIJSetPreallocation(mat, 1, dnnz, onnz, NULL, NULL));
26349566063dSJacob Faibussowitsch     PetscCall(PetscFree2(dnnz, onnz));
263521968bf8SToby Isaac 
26369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
26379566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
26389566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
26399566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
26409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
26419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(refConSec, &maxConDof));
26429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(leafIndicesSec, &maxColumns));
26439566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxConDof * maxColumns, &pointWork));
26440eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2645e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2646e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2647e44e4e7fSToby Isaac       PetscInt matSize;
2648e44e4e7fSToby Isaac       PetscInt childId;
2649e44e4e7fSToby Isaac 
26509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
26519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
26529371c9d4SSatish Balay       if ((gDof - gcDof) <= 0) { continue; }
2653e44e4e7fSToby Isaac       childId = childIds[p - pStartF];
26549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
26559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
26569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2657e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2658e44e4e7fSToby Isaac       pInd              = &leafIndices[pIndOff];
2659e44e4e7fSToby Isaac       offsets[0]        = 0;
2660e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2661e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2662e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2663e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2664e44e4e7fSToby Isaac       if (numFields) {
2665e44e4e7fSToby Isaac         PetscInt f;
2666e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2667e44e4e7fSToby Isaac           PetscInt rowDof;
2668e44e4e7fSToby Isaac 
26699566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2670e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2671e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2672e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2673e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2674e44e4e7fSToby Isaac         }
26759566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
26769371c9d4SSatish Balay       } else {
26779566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
26781c58ffc4SToby Isaac       }
26799566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2680e44e4e7fSToby Isaac       if (!matSize) {      /* incoming matrix is identity */
2681e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2682e44e4e7fSToby Isaac           if (numFields) {
2683e44e4e7fSToby Isaac             PetscInt f;
2684e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2685e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
26869371c9d4SSatish Balay               for (row = 0; row < numRows; row++) { PetscCall(MatSetValue(mat, rowIndices[offsets[f] + row], pInd[newOffsets[f] + row], 1., INSERT_VALUES)); }
268721968bf8SToby Isaac             }
26889371c9d4SSatish Balay           } else {
2689e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
26909371c9d4SSatish Balay             for (row = 0; row < numRows; row++) { PetscCall(MatSetValue(mat, rowIndices[row], pInd[row], 1., INSERT_VALUES)); }
2691e44e4e7fSToby Isaac           }
26929371c9d4SSatish Balay         } else { /* interpolate from all */
2693e44e4e7fSToby Isaac           if (numFields) {
2694e44e4e7fSToby Isaac             PetscInt f;
2695e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2696e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f];
2697e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
26989566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], refPointFieldMats[childId - pRefStart][f], INSERT_VALUES));
2699e44e4e7fSToby Isaac             }
27009371c9d4SSatish Balay           } else {
27019566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, refPointFieldMats[childId - pRefStart][0], INSERT_VALUES));
2702e44e4e7fSToby Isaac           }
2703e44e4e7fSToby Isaac         }
27049371c9d4SSatish Balay       } else { /* interpolate from all */
2705e44e4e7fSToby Isaac         PetscInt     pMatOff;
2706e44e4e7fSToby Isaac         PetscScalar *pMat;
2707e44e4e7fSToby Isaac 
27089566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafMatricesSec, p, &pMatOff));
2709e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2710e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2711e44e4e7fSToby Isaac           if (numFields) {
2712e44e4e7fSToby Isaac             PetscInt f, count;
2713e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2714e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2715e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2716e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2717e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2718e44e4e7fSToby Isaac 
27199566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], inMat, INSERT_VALUES));
2720e44e4e7fSToby Isaac               count += numCols * numInRows;
2721e44e4e7fSToby Isaac             }
27229371c9d4SSatish Balay           } else {
27239566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, pMat, INSERT_VALUES));
2724e44e4e7fSToby Isaac           }
27259371c9d4SSatish Balay         } else { /* multiply the incoming matrix by the child interpolation */
2726e44e4e7fSToby Isaac           if (numFields) {
2727e44e4e7fSToby Isaac             PetscInt f, count;
2728e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2729e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2730e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2731e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2732e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2733e44e4e7fSToby Isaac               PetscInt     i, j, k;
273408401ef6SPierre Jolivet               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2735e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2736e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2737e44e4e7fSToby Isaac                   PetscScalar val = 0.;
27389371c9d4SSatish Balay                   for (k = 0; k < numInRows; k++) { val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j]; }
2739e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2740e44e4e7fSToby Isaac                 }
2741e44e4e7fSToby Isaac               }
27429566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], pointWork, INSERT_VALUES));
2743e44e4e7fSToby Isaac               count += numCols * numInRows;
2744e44e4e7fSToby Isaac             }
27459371c9d4SSatish Balay           } else { /* every dof gets a full row */
2746e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2747e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2748e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2749e44e4e7fSToby Isaac             PetscInt i, j, k;
275008401ef6SPierre Jolivet             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2751e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2752e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2753e44e4e7fSToby Isaac                 PetscScalar val = 0.;
27549371c9d4SSatish Balay                 for (k = 0; k < numInRows; k++) { val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j]; }
2755e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2756e44e4e7fSToby Isaac               }
2757e44e4e7fSToby Isaac             }
27589566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, numRows, rowIndices, numCols, pInd, pointWork, INSERT_VALUES));
2759e44e4e7fSToby Isaac           }
2760e44e4e7fSToby Isaac         }
2761e44e4e7fSToby Isaac       }
2762e44e4e7fSToby Isaac     }
27639566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
27649566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
27659566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointWork));
2766e44e4e7fSToby Isaac   }
27679566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
27689566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
27699566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
27709566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafMatricesSec));
27719566063dSJacob Faibussowitsch   PetscCall(PetscFree2(leafIndices, leafMatrices));
27729566063dSJacob Faibussowitsch   PetscCall(PetscFree2(*(PetscInt ****)&perms, *(PetscScalar ****)&flips));
27739566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
27749566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
27756ecaa68aSToby Isaac   PetscFunctionReturn(0);
27766ecaa68aSToby Isaac }
2777154bca37SToby Isaac 
27788d2f55e7SToby Isaac /*
27798d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
27808d2f55e7SToby Isaac  *
27818d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
27828d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
27838d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
27848d2f55e7SToby Isaac  *       a_{i,j} = 0;
27858d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
27868d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
27878d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
27888d2f55e7SToby Isaac  */
27899371c9d4SSatish Balay PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj) {
27908d2f55e7SToby Isaac   PetscDS      ds;
27918d2f55e7SToby Isaac   PetscSection section, cSection;
27928d2f55e7SToby Isaac   DMLabel      canonical, depth;
27938d2f55e7SToby Isaac   Mat          cMat, mat;
27948d2f55e7SToby Isaac   PetscInt    *nnz;
27958d2f55e7SToby Isaac   PetscInt     f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
27968d2f55e7SToby Isaac   PetscInt     m, n;
27978d2f55e7SToby Isaac   PetscScalar *pointScalar;
27988d2f55e7SToby Isaac   PetscReal   *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
27998d2f55e7SToby Isaac 
28008d2f55e7SToby Isaac   PetscFunctionBegin;
28019566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &section));
28029566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(refTree, &dim));
28039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(dim, &v0, dim, &v0parent, dim, &vtmp, dim * dim, &J, dim * dim, &Jparent, dim * dim, &invJ));
28049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(dim, &pointScalar, dim, &pointRef));
28059566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
28069566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
28079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numSecFields));
28089566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "canonical", &canonical));
28099566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "depth", &depth));
28109566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSection, &cMat, NULL));
28119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
28129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
28139566063dSJacob Faibussowitsch   PetscCall(MatGetSize(cMat, &n, &m)); /* the injector has transpose sizes from the constraint matrix */
28148d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
28159566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(m, &nnz));
28168d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) { /* a point will have non-zeros if it is canonical, it has dofs, and its children have dofs */
28178d2f55e7SToby Isaac     const PetscInt *children;
28188d2f55e7SToby Isaac     PetscInt        numChildren;
28198d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28208d2f55e7SToby Isaac 
28218d2f55e7SToby Isaac     if (canonical) {
28228d2f55e7SToby Isaac       PetscInt pCanonical;
28239566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28248d2f55e7SToby Isaac       if (p != pCanonical) continue;
28258d2f55e7SToby Isaac     }
28269566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28278d2f55e7SToby Isaac     if (!numChildren) continue;
28288d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28298d2f55e7SToby Isaac       PetscInt child = children[i];
28308d2f55e7SToby Isaac       PetscInt dof;
28318d2f55e7SToby Isaac 
28329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
28338d2f55e7SToby Isaac       numChildDof += dof;
28348d2f55e7SToby Isaac     }
28359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
28368d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
28378d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
28388d2f55e7SToby Isaac       PetscInt selfOff;
28398d2f55e7SToby Isaac 
28408d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
28418d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
28428d2f55e7SToby Isaac           PetscInt child = children[i];
28438d2f55e7SToby Isaac           PetscInt dof;
28448d2f55e7SToby Isaac 
28459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
28468d2f55e7SToby Isaac           numChildDof += dof;
28478d2f55e7SToby Isaac         }
28489566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
28499566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
28509371c9d4SSatish Balay       } else {
28519566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
28528d2f55e7SToby Isaac       }
28539371c9d4SSatish Balay       for (i = 0; i < numSelfDof; i++) { nnz[selfOff + i] = numChildDof; }
28548d2f55e7SToby Isaac     }
28558d2f55e7SToby Isaac   }
28569566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(PETSC_COMM_SELF, m, n, m, n, -1, nnz, -1, NULL, &mat));
28579566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
28588d2f55e7SToby Isaac   /* Setp 2: compute entries */
28598d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
28608d2f55e7SToby Isaac     const PetscInt *children;
28618d2f55e7SToby Isaac     PetscInt        numChildren;
28628d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28638d2f55e7SToby Isaac 
28648d2f55e7SToby Isaac     /* same conditions about when entries occur */
28658d2f55e7SToby Isaac     if (canonical) {
28668d2f55e7SToby Isaac       PetscInt pCanonical;
28679566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28688d2f55e7SToby Isaac       if (p != pCanonical) continue;
28698d2f55e7SToby Isaac     }
28709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28718d2f55e7SToby Isaac     if (!numChildren) continue;
28728d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28738d2f55e7SToby Isaac       PetscInt child = children[i];
28748d2f55e7SToby Isaac       PetscInt dof;
28758d2f55e7SToby Isaac 
28769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
28778d2f55e7SToby Isaac       numChildDof += dof;
28788d2f55e7SToby Isaac     }
28799566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
28808d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
28818d2f55e7SToby Isaac 
28828d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
288359fc6756SToby Isaac       PetscInt        pI = -1, cI = -1;
288452a3aeb4SToby Isaac       PetscInt        selfOff, Nc, parentCell;
28858d2f55e7SToby Isaac       PetscInt        cellShapeOff;
28868d2f55e7SToby Isaac       PetscObject     disc;
28878d2f55e7SToby Isaac       PetscDualSpace  dsp;
28888d2f55e7SToby Isaac       PetscClassId    classId;
28898d2f55e7SToby Isaac       PetscScalar    *pointMat;
28903b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
28918d2f55e7SToby Isaac       PetscInt        pO = PETSC_MIN_INT;
28928d2f55e7SToby Isaac       const PetscInt *depthNumDof;
28938d2f55e7SToby Isaac 
28948d2f55e7SToby Isaac       if (numSecFields) {
28958d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
28968d2f55e7SToby Isaac           PetscInt child = children[i];
28978d2f55e7SToby Isaac           PetscInt dof;
28988d2f55e7SToby Isaac 
28999566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
29008d2f55e7SToby Isaac           numChildDof += dof;
29018d2f55e7SToby Isaac         }
29029566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
29039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
29049371c9d4SSatish Balay       } else {
29059566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
29068d2f55e7SToby Isaac       }
29078d2f55e7SToby Isaac 
29083b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
29098d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
29108d2f55e7SToby Isaac         parentCell = p;
29119371c9d4SSatish Balay       } else {
29128d2f55e7SToby Isaac         PetscInt *star = NULL;
29138d2f55e7SToby Isaac         PetscInt  numStar;
29148d2f55e7SToby Isaac 
29158d2f55e7SToby Isaac         parentCell = -1;
29169566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29178d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
29188d2f55e7SToby Isaac           PetscInt c = star[2 * i];
29198d2f55e7SToby Isaac 
29208d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
29218d2f55e7SToby Isaac             parentCell = c;
29228d2f55e7SToby Isaac             break;
29238d2f55e7SToby Isaac           }
29248d2f55e7SToby Isaac         }
29259566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29268d2f55e7SToby Isaac       }
2927a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
29289566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
29299566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc, &classId));
2930c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
29319566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
29329371c9d4SSatish Balay       } else if (classId == PETSCFV_CLASSID) {
29339566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace((PetscFV)disc, &dsp));
29349371c9d4SSatish Balay       } else {
29359b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported discretization object");
2936c5356c36SToby Isaac       }
29379566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumDof(dsp, &depthNumDof));
29389566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumComponents(dsp, &Nc));
29398d2f55e7SToby Isaac       {
29408d2f55e7SToby Isaac         PetscInt *closure = NULL;
29418d2f55e7SToby Isaac         PetscInt  numClosure;
29428d2f55e7SToby Isaac 
29439566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
294459fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
29458d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
29468d2f55e7SToby Isaac 
29478d2f55e7SToby Isaac           pO = closure[2 * i + 1];
294859fc6756SToby Isaac           if (point == p) {
294959fc6756SToby Isaac             pI = i;
295059fc6756SToby Isaac             break;
295159fc6756SToby Isaac           }
29529566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(depth, point, &pointDepth));
29538d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
29548d2f55e7SToby Isaac         }
29559566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
29568d2f55e7SToby Isaac       }
29578d2f55e7SToby Isaac 
29589566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
29599566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
296052a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
29619371c9d4SSatish Balay       for (i = 0; i < numSelfDof; i++) { matRows[i] = selfOff + i; }
296252a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
29633b1c2a6aSToby Isaac       {
29643b1c2a6aSToby Isaac         PetscInt colOff = 0;
29653b1c2a6aSToby Isaac 
29663b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
29673b1c2a6aSToby Isaac           PetscInt child = children[i];
29683b1c2a6aSToby Isaac           PetscInt dof, off, j;
29693b1c2a6aSToby Isaac 
29703b1c2a6aSToby Isaac           if (numSecFields) {
29719566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSection, child, f, &dof));
29729566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(cSection, child, f, &off));
29739371c9d4SSatish Balay           } else {
29749566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(cSection, child, &dof));
29759566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(cSection, child, &off));
29763b1c2a6aSToby Isaac           }
29773b1c2a6aSToby Isaac 
29789371c9d4SSatish Balay           for (j = 0; j < dof; j++) { matCols[colOff++] = off + j; }
29793b1c2a6aSToby Isaac         }
29803b1c2a6aSToby Isaac       }
29818d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
29828d2f55e7SToby Isaac         PetscFE              fe = (PetscFE)disc;
29838d2f55e7SToby Isaac         PetscInt             fSize;
298459fc6756SToby Isaac         const PetscInt    ***perms;
298559fc6756SToby Isaac         const PetscScalar ***flips;
298659fc6756SToby Isaac         const PetscInt      *pperms;
298759fc6756SToby Isaac 
29889566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &dsp));
29899566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetDimension(dsp, &fSize));
29909566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
299159fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
299252a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
29938d2f55e7SToby Isaac           PetscQuadrature  q;
299452a3aeb4SToby Isaac           PetscInt         dim, thisNc, numPoints, j, k;
29958d2f55e7SToby Isaac           const PetscReal *points;
29968d2f55e7SToby Isaac           const PetscReal *weights;
29978d2f55e7SToby Isaac           PetscInt        *closure = NULL;
29988d2f55e7SToby Isaac           PetscInt         numClosure;
299959fc6756SToby Isaac           PetscInt         iCell              = pperms ? pperms[i] : i;
300059fc6756SToby Isaac           PetscInt         parentCellShapeDof = cellShapeOff + iCell;
3001ef0bb6c7SMatthew G. Knepley           PetscTabulation  Tparent;
30028d2f55e7SToby Isaac 
30039566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(dsp, parentCellShapeDof, &q));
30049566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(q, &dim, &thisNc, &numPoints, &points, &weights));
300563a3b9bcSJacob Faibussowitsch           PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
30069566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe, 1, numPoints, points, 0, &Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
30073b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
30088d2f55e7SToby Isaac             PetscInt           childCell = -1;
300952a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3010c330f8ffSToby Isaac             const PetscReal    xi0[3]    = {-1., -1., -1.};
30118d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
30128d2f55e7SToby Isaac             const PetscScalar *point;
3013ef0bb6c7SMatthew G. Knepley             PetscTabulation    Tchild;
30148d2f55e7SToby Isaac             PetscInt           childCellShapeOff, pointMatOff;
30158d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
30168d2f55e7SToby Isaac             PetscInt d;
30178d2f55e7SToby Isaac 
30189371c9d4SSatish Balay             for (d = 0; d < dim; d++) { pointScalar[d] = points[dim * j + d]; }
30198d2f55e7SToby Isaac             point = pointScalar;
30208d2f55e7SToby Isaac #else
30218d2f55e7SToby Isaac             point = pointReal;
30228d2f55e7SToby Isaac #endif
30238d2f55e7SToby Isaac 
3024ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
30253b1c2a6aSToby Isaac 
30263b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
30278d2f55e7SToby Isaac               PetscInt  child = children[k];
30288d2f55e7SToby Isaac               PetscInt *star  = NULL;
30298d2f55e7SToby Isaac               PetscInt  numStar, s;
30308d2f55e7SToby Isaac 
30319566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30328d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
30338d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
30348d2f55e7SToby Isaac 
30358d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
30369566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(refTree, dim, point, c, &childCell));
30378d2f55e7SToby Isaac                 if (childCell >= 0) break;
30388d2f55e7SToby Isaac               }
30399566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30408d2f55e7SToby Isaac               if (childCell >= 0) break;
30418d2f55e7SToby Isaac             }
304208401ef6SPierre Jolivet             PetscCheck(childCell >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not locate quadrature point");
30439566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
30449566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3045c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3046c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
30478d2f55e7SToby Isaac 
30489566063dSJacob Faibussowitsch             PetscCall(PetscFECreateTabulation(fe, 1, 1, pointRef, 0, &Tchild));
30499566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
30503b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3051c5356c36SToby Isaac               PetscInt        child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
30528d2f55e7SToby Isaac               PetscInt        l;
305359fc6756SToby Isaac               const PetscInt *cperms;
30548d2f55e7SToby Isaac 
30559566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(depth, child, &childDepth));
30568d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
305759fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
30588d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
30598d2f55e7SToby Isaac                 PetscInt pointDepth;
30608d2f55e7SToby Isaac 
30618d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
306259fc6756SToby Isaac                 if (point == child) {
306359fc6756SToby Isaac                   cI = l;
306459fc6756SToby Isaac                   break;
306559fc6756SToby Isaac                 }
30669566063dSJacob Faibussowitsch                 PetscCall(DMLabelGetValue(depth, point, &pointDepth));
30678d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
30688d2f55e7SToby Isaac               }
30698d2f55e7SToby Isaac               if (l == numClosure) {
30708d2f55e7SToby Isaac                 pointMatOff += childDof;
30718d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
30728d2f55e7SToby Isaac               }
307359fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
30748d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
307559fc6756SToby Isaac                 PetscInt   lCell        = cperms ? cperms[l] : l;
307659fc6756SToby Isaac                 PetscInt   childCellDof = childCellShapeOff + lCell;
307752a3aeb4SToby Isaac                 PetscReal *childValAtPoint;
307852a3aeb4SToby Isaac                 PetscReal  val = 0.;
30798d2f55e7SToby Isaac 
3080ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
30819371c9d4SSatish Balay                 for (m = 0; m < Nc; m++) { val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m]; }
308252a3aeb4SToby Isaac 
308352a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
30848d2f55e7SToby Isaac               }
30858d2f55e7SToby Isaac               pointMatOff += childDof;
30868d2f55e7SToby Isaac             }
30879566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
30889566063dSJacob Faibussowitsch             PetscCall(PetscTabulationDestroy(&Tchild));
30898d2f55e7SToby Isaac           }
30909566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&Tparent));
30918d2f55e7SToby Isaac         }
30929371c9d4SSatish Balay       } else { /* just the volume-weighted averages of the children */
30933b1c2a6aSToby Isaac         PetscReal parentVol;
3094bfaa5bdcSToby Isaac         PetscInt  childCell;
30953b1c2a6aSToby Isaac 
30969566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3097bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
309852a3aeb4SToby Isaac           PetscInt  child = children[i], j;
30993b1c2a6aSToby Isaac           PetscReal childVol;
31003b1c2a6aSToby Isaac 
31013b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
31029566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
31039371c9d4SSatish Balay           for (j = 0; j < Nc; j++) { pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol; }
3104bfaa5bdcSToby Isaac           childCell++;
31053b1c2a6aSToby Isaac         }
31068d2f55e7SToby Isaac       }
31073b1c2a6aSToby Isaac       /* Insert pointMat into mat */
31089566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, numSelfDof, matRows, numChildDof, matCols, pointMat, INSERT_VALUES));
31099566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
31109566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
31118d2f55e7SToby Isaac     }
31128d2f55e7SToby Isaac   }
31139566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJ));
31149566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointScalar, pointRef));
31159566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
31169566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
31178d2f55e7SToby Isaac   *inj = mat;
31188d2f55e7SToby Isaac   PetscFunctionReturn(0);
31198d2f55e7SToby Isaac }
31208d2f55e7SToby Isaac 
31219371c9d4SSatish Balay static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats) {
3122f30e825dSToby Isaac   PetscDS        ds;
3123f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3124f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3125f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3126f30e825dSToby Isaac 
3127f30e825dSToby Isaac   PetscFunctionBegin;
31289566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
31299566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
31309566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
31319566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
31329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
31339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
31349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
31359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
31369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof, &cols));
3137f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3138f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3139f30e825dSToby Isaac 
31409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
31419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
31429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3143f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3144f30e825dSToby Isaac 
31459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFields, &refPointFieldMats[p - pRefStart]));
3146f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
314752a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3148f30e825dSToby Isaac 
3149f30e825dSToby Isaac       if (numFields > 1) {
31509566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
31519566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
31529371c9d4SSatish Balay       } else {
31539566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
31549566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
3155f30e825dSToby Isaac       }
3156f30e825dSToby Isaac 
31579371c9d4SSatish Balay       for (r = 0; r < cDof; r++) { rows[r] = cOff + r; }
3158f30e825dSToby Isaac       numCols = 0;
3159f30e825dSToby Isaac       {
3160f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3161f30e825dSToby Isaac 
3162f30e825dSToby Isaac         if (numFields > 1) {
31639566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, parent, f, &aDof));
31649566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, parent, f, &aOff));
31659371c9d4SSatish Balay         } else {
31669566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, parent, &aDof));
31679566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, parent, &aOff));
3168f30e825dSToby Isaac         }
3169f30e825dSToby Isaac 
31709371c9d4SSatish Balay         for (j = 0; j < aDof; j++) { cols[numCols++] = aOff + j; }
3171f30e825dSToby Isaac       }
31729566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
3173f30e825dSToby Isaac       /* transpose of constraint matrix */
31749566063dSJacob Faibussowitsch       PetscCall(MatGetValues(inj, numCols, cols, cDof, rows, refPointFieldMats[p - pRefStart][f]));
3175f30e825dSToby Isaac     }
3176f30e825dSToby Isaac   }
3177f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
31789566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
31799566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
3180f30e825dSToby Isaac   PetscFunctionReturn(0);
3181f30e825dSToby Isaac }
3182f30e825dSToby Isaac 
31839371c9d4SSatish Balay static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats) {
3184f30e825dSToby Isaac   PetscDS        ds;
3185f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3186f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3187c6154584SToby Isaac   PetscSection   refConSec, refSection;
3188f30e825dSToby Isaac 
3189f30e825dSToby Isaac   PetscFunctionBegin;
3190f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3191f30e825dSToby Isaac   *childrenMats     = NULL;
31929566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
31939566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
31949566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
31959566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
31969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3197f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3198f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3199f30e825dSToby Isaac 
32009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
32019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
32029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3203f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3204f30e825dSToby Isaac 
3205f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3206f30e825dSToby Isaac       PetscInt cDof;
3207f30e825dSToby Isaac 
3208f30e825dSToby Isaac       if (numFields > 1) {
32099566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
32109371c9d4SSatish Balay       } else {
32119566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3212f30e825dSToby Isaac       }
3213f30e825dSToby Isaac 
32149566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3215f30e825dSToby Isaac     }
32169566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3217f30e825dSToby Isaac   }
32189566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
3219f30e825dSToby Isaac   PetscFunctionReturn(0);
3220f30e825dSToby Isaac }
3221f30e825dSToby Isaac 
32229371c9d4SSatish Balay static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree, Mat *injRef) {
3223ebf164c7SToby Isaac   Mat         cMatRef;
32246148253fSToby Isaac   PetscObject injRefObj;
32258d2f55e7SToby Isaac 
3226154bca37SToby Isaac   PetscFunctionBegin;
32279566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, NULL, &cMatRef, NULL));
32289566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", &injRefObj));
3229ebf164c7SToby Isaac   *injRef = (Mat)injRefObj;
3230ebf164c7SToby Isaac   if (!*injRef) {
32319566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorReferenceTree(refTree, injRef));
32329566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", (PetscObject)*injRef));
3233ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
32349566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3235ebf164c7SToby Isaac   }
3236ebf164c7SToby Isaac   PetscFunctionReturn(0);
32376148253fSToby Isaac }
3238f30e825dSToby Isaac 
32399371c9d4SSatish Balay 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) {
3240c921d74cSToby Isaac   PetscInt        pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3241ebf164c7SToby Isaac   PetscSection    globalCoarse, globalFine;
3242ebf164c7SToby Isaac   PetscSection    localCoarse, localFine, leafIndicesSec;
3243c921d74cSToby Isaac   PetscSection    multiRootSec, rootIndicesSec;
3244c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3245c921d74cSToby Isaac   const PetscInt *rootDegrees;
3246c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3247ebf164c7SToby Isaac   PetscSF         coarseToFineEmbedded;
3248ebf164c7SToby Isaac 
3249ebf164c7SToby Isaac   PetscFunctionBegin;
32509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
32519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
32529566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
32539566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
32549566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
32559566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafIndicesSec, pStartF, pEndF));
32569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
32578d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
32587e96bdafSToby Isaac     PetscInt        l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
32597e96bdafSToby Isaac     const PetscInt *leaves;
32608d2f55e7SToby Isaac 
32619566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
32627e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
32637e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
32649566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
32659566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
32668d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
32678d2f55e7SToby Isaac         numPointsWithDofs++;
3268f30e825dSToby Isaac 
32699566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localFine, p, &dof));
32709566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafIndicesSec, p, dof + 1));
32718d2f55e7SToby Isaac       }
32728d2f55e7SToby Isaac     }
32739566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
32749566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafIndicesSec));
32759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numIndices));
32769566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1), &leafInds));
32779566063dSJacob Faibussowitsch     if (gatheredValues) PetscCall(PetscMalloc1(numIndices, &leafVals));
32787e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
32797e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
32809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
32819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
32828d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3283f30e825dSToby Isaac         PetscInt     off, gOff;
3284f30e825dSToby Isaac         PetscInt    *pInd;
3285c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3286f30e825dSToby Isaac 
32877e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3288f30e825dSToby Isaac 
32899566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3290f30e825dSToby Isaac 
3291c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3292c921d74cSToby Isaac         if (gatheredValues) {
3293c921d74cSToby Isaac           PetscInt i;
3294c921d74cSToby Isaac 
3295c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3296c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3297c921d74cSToby Isaac         }
32989566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
3299f30e825dSToby Isaac 
3300f30e825dSToby Isaac         offsets[0] = 0;
3301f30e825dSToby Isaac         if (numFields) {
3302f30e825dSToby Isaac           PetscInt f;
3303f30e825dSToby Isaac 
3304f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3305f30e825dSToby Isaac             PetscInt fDof;
33069566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localFine, p, f, &fDof));
3307f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3308f30e825dSToby Isaac           }
33099566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
3310367003a6SStefano Zampini         } else {
33119566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
3312f30e825dSToby Isaac         }
33139566063dSJacob Faibussowitsch         if (gatheredValues) PetscCall(VecGetValues(fineVec, dof, pInd, pVal));
33148d2f55e7SToby Isaac       }
33158d2f55e7SToby Isaac     }
33169566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
33179566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
33188d2f55e7SToby Isaac   }
3319f30e825dSToby Isaac 
33209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
33219566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
33229566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3323f30e825dSToby Isaac 
33246148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
33256148253fSToby Isaac     MPI_Datatype threeInt;
33266148253fSToby Isaac     PetscMPIInt  rank;
33276148253fSToby Isaac     PetscInt(*parentNodeAndIdCoarse)[3];
33286148253fSToby Isaac     PetscInt(*parentNodeAndIdFine)[3];
33296148253fSToby Isaac     PetscInt           p, nleaves, nleavesToParents;
33306148253fSToby Isaac     PetscSF            pointSF, sfToParents;
33316148253fSToby Isaac     const PetscInt    *ilocal;
33326148253fSToby Isaac     const PetscSFNode *iremote;
33336148253fSToby Isaac     PetscSFNode       *iremoteToParents;
33346148253fSToby Isaac     PetscInt          *ilocalToParents;
33356148253fSToby Isaac 
33369566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse), &rank));
33379566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &threeInt));
33389566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&threeInt));
33399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEndC - pStartC, &parentNodeAndIdCoarse, pEndF - pStartF, &parentNodeAndIdFine));
33409566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(coarse, &pointSF));
33419566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, &iremote));
33426148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
33436148253fSToby Isaac       PetscInt parent, childId;
33449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(coarse, p, &parent, &childId));
33456148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
33466148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
33476148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
33486148253fSToby Isaac       if (nleaves > 0) {
33496148253fSToby Isaac         PetscInt leaf = -1;
33506148253fSToby Isaac 
33516148253fSToby Isaac         if (ilocal) {
33529566063dSJacob Faibussowitsch           PetscCall(PetscFindInt(parent, nleaves, ilocal, &leaf));
33539371c9d4SSatish Balay         } else {
33546148253fSToby Isaac           leaf = p - pStartC;
33556148253fSToby Isaac         }
33566148253fSToby Isaac         if (leaf >= 0) {
33576148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
33586148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
33596148253fSToby Isaac         }
33606148253fSToby Isaac       }
33616148253fSToby Isaac     }
33626148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
33636148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
33646148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
33656148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
33666148253fSToby Isaac     }
33679566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
33689566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
33696148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3370f30e825dSToby Isaac       PetscInt dof;
3371f30e825dSToby Isaac 
33729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &dof));
3373f30e825dSToby Isaac       if (dof) {
3374f30e825dSToby Isaac         PetscInt off;
3375f30e825dSToby Isaac 
33769566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3377c921d74cSToby Isaac         if (gatheredIndices) {
3378c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3379c921d74cSToby Isaac         } else if (gatheredValues) {
3380c921d74cSToby Isaac           leafVals[off] = (PetscScalar)PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3381c921d74cSToby Isaac         }
3382f30e825dSToby Isaac       }
33839371c9d4SSatish Balay       if (parentNodeAndIdFine[p - pStartF][0] >= 0) { nleavesToParents++; }
33846148253fSToby Isaac     }
33859566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &ilocalToParents));
33869566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &iremoteToParents));
33876148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
33886148253fSToby Isaac       if (parentNodeAndIdFine[p - pStartF][0] >= 0) {
33896148253fSToby Isaac         ilocalToParents[nleavesToParents]        = p - pStartF;
33906148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p - pStartF][0];
33916148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p - pStartF][1];
33926148253fSToby Isaac         nleavesToParents++;
33936148253fSToby Isaac       }
33946148253fSToby Isaac     }
33959566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse), &sfToParents));
33969566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(sfToParents, pEndC - pStartC, nleavesToParents, ilocalToParents, PETSC_OWN_POINTER, iremoteToParents, PETSC_OWN_POINTER));
33979566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
33986148253fSToby Isaac 
33996148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
34006148253fSToby Isaac 
34019566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parentNodeAndIdCoarse, parentNodeAndIdFine));
34029566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&threeInt));
34036148253fSToby Isaac   }
3404f30e825dSToby Isaac 
34056148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
34066148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
34076148253fSToby Isaac     PetscSF  sfDofsOnly;
34086148253fSToby Isaac 
34096148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
34109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
34129371c9d4SSatish Balay       if ((dof - cdof) > 0) { numPointsWithDofs++; }
34136148253fSToby Isaac     }
34149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
34156148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
34169566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
34189371c9d4SSatish Balay       if ((dof - cdof) > 0) { pointsWithDofs[offset++] = p - pStartC; }
34196148253fSToby Isaac     }
34209566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
34219566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34229566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
34236148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
34246148253fSToby Isaac   }
3425f30e825dSToby Isaac 
34266148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
34279566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded, &rootDegrees));
34289566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded, &rootDegrees));
34299566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &multiRootSec));
34309566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(multiRootSec, pStartC, pEndC));
34319371c9d4SSatish Balay   for (p = pStartC; p < pEndC; p++) { PetscCall(PetscSectionSetDof(multiRootSec, p, rootDegrees[p - pStartC])); }
34329566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(multiRootSec));
34339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(multiRootSec, &numMulti));
34349566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
3435f30e825dSToby Isaac   { /* distribute the leaf section */
3436f30e825dSToby Isaac     PetscSF   multi, multiInv, indicesSF;
3437f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
34388d2f55e7SToby Isaac 
34399566063dSJacob Faibussowitsch     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded, &multi));
34409566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF(multi, &multiInv));
34419566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(multiInv, leafIndicesSec, &remoteOffsets, rootIndicesSec));
34429566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(multiInv, leafIndicesSec, remoteOffsets, rootIndicesSec, &indicesSF));
34439566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
34449566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&multiInv));
34459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
3446c921d74cSToby Isaac     if (gatheredIndices) {
34479566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootInds));
34489566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
34499566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3450c921d74cSToby Isaac     }
3451c921d74cSToby Isaac     if (gatheredValues) {
34529566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootVals));
34539566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
34549566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3455c921d74cSToby Isaac     }
34569566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
34578d2f55e7SToby Isaac   }
34589566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
34599566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafInds));
34609566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafVals));
34619566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3462c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3463c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3464c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3465c921d74cSToby Isaac   if (gatheredValues) *gatheredValues = rootVals;
3466ebf164c7SToby Isaac   PetscFunctionReturn(0);
3467ebf164c7SToby Isaac }
3468ebf164c7SToby Isaac 
34699371c9d4SSatish Balay PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat) {
3470ebf164c7SToby Isaac   DM             refTree;
3471c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3472ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3473ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3474ebf164c7SToby Isaac   PetscSection   cSecRef;
3475277f51e8SBarry Smith   PetscInt      *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3476ebf164c7SToby Isaac   Mat            injRef;
3477c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3478ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3479ebf164c7SToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
3480ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3481ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3482ebf164c7SToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3483ebf164c7SToby Isaac 
3484ebf164c7SToby Isaac   PetscFunctionBegin;
3485ebf164c7SToby Isaac 
3486ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
34879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
34889566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
34899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
34909566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
3491ebf164c7SToby Isaac 
34929566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
34939566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
34949566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
34959566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
34969566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
34979566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
34989566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
34999566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
3500ebf164c7SToby Isaac   {
3501ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
35029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
3503ebf164c7SToby Isaac   }
3504ebf164c7SToby Isaac 
35059566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, childIds, NULL, numFields, offsets, &multiRootSec, &rootIndicesSec, &rootIndices, NULL));
35068d2f55e7SToby Isaac 
35079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &parentIndices));
3508f30e825dSToby Isaac 
3509f30e825dSToby Isaac   /* count indices */
35109566063dSJacob Faibussowitsch   PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
35119566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
35129566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
35139566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
35149566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
35159566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(rowEnd - rowStart, &nnzD, rowEnd - rowStart, &nnzO));
3516f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3517f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
35188d2f55e7SToby Isaac 
35199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
35209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3521f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
35229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
35238d2f55e7SToby Isaac 
35248d2f55e7SToby Isaac     rowOffsets[0]  = 0;
3525f30e825dSToby Isaac     offsetsCopy[0] = 0;
35268d2f55e7SToby Isaac     if (numFields) {
35278d2f55e7SToby Isaac       PetscInt f;
35288d2f55e7SToby Isaac 
3529f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3530f30e825dSToby Isaac         PetscInt fDof;
35319566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3532f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
35338d2f55e7SToby Isaac       }
35349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3535367003a6SStefano Zampini     } else {
35369566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3537f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
35388d2f55e7SToby Isaac     }
3539f30e825dSToby Isaac 
35409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
35419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3542f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3543f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3544f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3545f30e825dSToby Isaac       const PetscInt *childIndices;
3546f30e825dSToby Isaac 
35479566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
35489566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3549f30e825dSToby Isaac       childId      = rootIndices[offset++];
3550f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3551f30e825dSToby Isaac       numIndices--;
3552f30e825dSToby Isaac 
3553f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3554f30e825dSToby Isaac         PetscInt i;
3555f30e825dSToby Isaac 
3556f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3557f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3558f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3559f30e825dSToby Isaac           if (rowIndex < 0) continue;
356008401ef6SPierre Jolivet           PetscCheck(colIndex >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unconstrained fine and constrained coarse");
3561a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3562f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
35639371c9d4SSatish Balay           } else {
3564f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3565f30e825dSToby Isaac           }
3566f30e825dSToby Isaac         }
35679371c9d4SSatish Balay       } else {
3568f30e825dSToby Isaac         PetscInt parentId, f, lim;
3569f30e825dSToby Isaac 
35709566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3571f30e825dSToby Isaac 
3572f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3573f30e825dSToby Isaac         offsets[0] = 0;
35748d2f55e7SToby Isaac         if (numFields) {
35758d2f55e7SToby Isaac           PetscInt f;
3576f30e825dSToby Isaac 
35778d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3578f30e825dSToby Isaac             PetscInt fDof;
35799566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3580f30e825dSToby Isaac 
3581f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
35828d2f55e7SToby Isaac           }
35839371c9d4SSatish Balay         } else {
3584f30e825dSToby Isaac           PetscInt cDof;
3585f30e825dSToby Isaac 
35869566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3587f30e825dSToby Isaac           offsets[1] = cDof;
3588f30e825dSToby Isaac         }
3589f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3590f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3591f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3592f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3593f30e825dSToby Isaac 
3594f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3595f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3596f30e825dSToby Isaac 
3597f30e825dSToby Isaac             if (colIndex < 0) continue;
3598f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3599f30e825dSToby Isaac               numD++;
36009371c9d4SSatish Balay             } else {
3601f30e825dSToby Isaac               numO++;
3602f30e825dSToby Isaac             }
3603f30e825dSToby Isaac           }
3604f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3605f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3606f30e825dSToby Isaac 
3607f30e825dSToby Isaac             if (rowIndex < 0) continue;
3608f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3609f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
36108d2f55e7SToby Isaac           }
36118d2f55e7SToby Isaac         }
36128d2f55e7SToby Isaac       }
3613f30e825dSToby Isaac     }
3614f30e825dSToby Isaac   }
3615f30e825dSToby Isaac   /* preallocate */
36169566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mat, 1, nnzD, nnzO, NULL, NULL));
36179566063dSJacob Faibussowitsch   PetscCall(PetscFree2(nnzD, nnzO));
3618f30e825dSToby Isaac   /* insert values */
36199566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3620f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3621f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3622f30e825dSToby Isaac 
36239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
36249566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3625f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
36269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
3627f30e825dSToby Isaac 
3628f30e825dSToby Isaac     rowOffsets[0]  = 0;
3629f30e825dSToby Isaac     offsetsCopy[0] = 0;
36308d2f55e7SToby Isaac     if (numFields) {
36318d2f55e7SToby Isaac       PetscInt f;
3632f30e825dSToby Isaac 
36338d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3634f30e825dSToby Isaac         PetscInt fDof;
36359566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3636f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3637f30e825dSToby Isaac       }
36389566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3639367003a6SStefano Zampini     } else {
36409566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3641f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3642f30e825dSToby Isaac     }
3643f30e825dSToby Isaac 
36449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
36459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3646f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3647f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3648f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3649f30e825dSToby Isaac       const PetscInt *childIndices;
3650f30e825dSToby Isaac 
36519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
36529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3653f30e825dSToby Isaac       childId      = rootIndices[offset++];
3654f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3655f30e825dSToby Isaac       numIndices--;
3656f30e825dSToby Isaac 
3657f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3658f30e825dSToby Isaac         PetscInt i;
3659f30e825dSToby Isaac 
36609371c9d4SSatish Balay         for (i = 0; i < numIndices; i++) { PetscCall(MatSetValue(mat, parentIndices[i], childIndices[i], 1., INSERT_VALUES)); }
36619371c9d4SSatish Balay       } else {
3662f30e825dSToby Isaac         PetscInt parentId, f, lim;
36638d2f55e7SToby Isaac 
36649566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3665f30e825dSToby Isaac 
3666f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3667f30e825dSToby Isaac         offsets[0] = 0;
36688d2f55e7SToby Isaac         if (numFields) {
3669f30e825dSToby Isaac           PetscInt f;
36708d2f55e7SToby Isaac 
3671f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3672f30e825dSToby Isaac             PetscInt fDof;
36739566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3674f30e825dSToby Isaac 
3675f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
36768d2f55e7SToby Isaac           }
36779371c9d4SSatish Balay         } else {
3678f30e825dSToby Isaac           PetscInt cDof;
3679f30e825dSToby Isaac 
36809566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3681f30e825dSToby Isaac           offsets[1] = cDof;
36828d2f55e7SToby Isaac         }
3683f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3684f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3685f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3686f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3687f30e825dSToby Isaac 
36889566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat, rowOffsets[f + 1] - rowOffsets[f], rowIndices, offsets[f + 1] - offsets[f], colIndices, childMat, INSERT_VALUES));
36898d2f55e7SToby Isaac         }
36908d2f55e7SToby Isaac       }
36918d2f55e7SToby Isaac     }
36928d2f55e7SToby Isaac   }
36939566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
36949566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
36959566063dSJacob Faibussowitsch   PetscCall(PetscFree(parentIndices));
36969566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
36979566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootIndices));
36989566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
3699f30e825dSToby Isaac 
37009566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
37019566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
3702154bca37SToby Isaac   PetscFunctionReturn(0);
3703154bca37SToby Isaac }
370438fc2455SToby Isaac 
37059371c9d4SSatish Balay static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom) {
370662095d54SToby Isaac   PetscSF            coarseToFineEmbedded;
370762095d54SToby Isaac   PetscSection       globalCoarse, globalFine;
370862095d54SToby Isaac   PetscSection       localCoarse, localFine;
370962095d54SToby Isaac   PetscSection       aSec, cSec;
371062095d54SToby Isaac   PetscSection       rootValuesSec;
371162095d54SToby Isaac   PetscSection       leafValuesSec;
371262095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
371362095d54SToby Isaac   IS                 aIS;
371462095d54SToby Isaac   const PetscInt    *anchors;
371562095d54SToby Isaac   Mat                cMat;
371662095d54SToby Isaac   PetscInt           numFields;
3717412e9a14SMatthew G. Knepley   PetscInt           pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
371862095d54SToby Isaac   PetscInt           aStart, aEnd, cStart, cEnd;
371962095d54SToby Isaac   PetscInt          *maxChildIds;
372062095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
37210eb7e1eaSToby Isaac   PetscFV            fv = NULL;
37220eb7e1eaSToby Isaac   PetscInt           dim, numFVcomps = -1, fvField = -1;
37230eb7e1eaSToby Isaac   DM                 cellDM = NULL, gradDM = NULL;
37240eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
37250eb7e1eaSToby Isaac   const PetscScalar *gradArray     = NULL;
372662095d54SToby Isaac 
3727ebf164c7SToby Isaac   PetscFunctionBegin;
37289566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
37299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
37309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(coarse, 0, &cellStart, &cellEnd));
37319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
37329566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
37339566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(coarse, &dim));
373462095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3735e4a60869SToby Isaac     PetscInt        nleaves, l;
3736e4a60869SToby Isaac     const PetscInt *leaves;
373762095d54SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
373862095d54SToby Isaac 
37399566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
3740e4a60869SToby Isaac 
3741e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3742e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3743e4a60869SToby Isaac 
37449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
37469371c9d4SSatish Balay       if ((dof - cdof) > 0) { numPointsWithDofs++; }
374762095d54SToby Isaac     }
37489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
37494833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
3750e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3751e4a60869SToby Isaac 
37529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
37549371c9d4SSatish Balay       if ((dof - cdof) > 0) { pointsWithDofs[offset++] = l; }
375562095d54SToby Isaac     }
37569566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
37579566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
375862095d54SToby Isaac   }
375962095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
37609566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
37619371c9d4SSatish Balay   for (p = pStartC; p < pEndC; p++) { maxChildIds[p - pStartC] = -2; }
37629566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
37639566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
376462095d54SToby Isaac 
37659566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
37669566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
376762095d54SToby Isaac 
37689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
37699566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
37709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
377162095d54SToby Isaac 
37729566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
37739566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
377462095d54SToby Isaac 
377562095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
37769566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootValuesSec));
37779566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootValuesSec, pStartC, pEndC));
37789566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
377962095d54SToby Isaac   {
378062095d54SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
37819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &newOffsets, maxFields, &newOffsetsCopy, maxFields, &rowOffsets, maxFields, &numD, maxFields, &numO));
378262095d54SToby Isaac   }
37830eb7e1eaSToby Isaac   if (grad) {
37840eb7e1eaSToby Isaac     PetscInt i;
37850eb7e1eaSToby Isaac 
37869566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeom, &cellDM));
37879566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeom, &cellGeomArray));
37889566063dSJacob Faibussowitsch     PetscCall(VecGetDM(grad, &gradDM));
37899566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(grad, &gradArray));
37900eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1, numFields); i++) {
37910eb7e1eaSToby Isaac       PetscObject  obj;
37920eb7e1eaSToby Isaac       PetscClassId id;
37930eb7e1eaSToby Isaac 
37949566063dSJacob Faibussowitsch       PetscCall(DMGetField(coarse, i, NULL, &obj));
37959566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
37960eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
37970eb7e1eaSToby Isaac         fv = (PetscFV)obj;
37989566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &numFVcomps));
37990eb7e1eaSToby Isaac         fvField = i;
38000eb7e1eaSToby Isaac         break;
38010eb7e1eaSToby Isaac       }
38020eb7e1eaSToby Isaac     }
38030eb7e1eaSToby Isaac   }
380462095d54SToby Isaac 
380562095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
380662095d54SToby Isaac     PetscInt dof;
380762095d54SToby Isaac     PetscInt maxChildId = maxChildIds[p - pStartC];
380862095d54SToby Isaac     PetscInt numValues  = 0;
380962095d54SToby Isaac 
38109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
38119371c9d4SSatish Balay     if (dof < 0) { dof = -(dof + 1); }
381262095d54SToby Isaac     offsets[0]    = 0;
381362095d54SToby Isaac     newOffsets[0] = 0;
381462095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
381562095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
381662095d54SToby Isaac 
38179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
381862095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
381962095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
382062095d54SToby Isaac 
38219566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
382262095d54SToby Isaac         numValues += clDof;
382362095d54SToby Isaac       }
38249566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
38259371c9d4SSatish Balay     } else if (maxChildId == -1) {
38269566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localCoarse, p, &numValues));
382762095d54SToby Isaac     }
382862095d54SToby Isaac     /* we will pack the column indices with the field offsets */
382978b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
38300eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
38310eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
38320eb7e1eaSToby Isaac     }
38339566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootValuesSec, p, numValues));
383462095d54SToby Isaac   }
38359566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootValuesSec));
383662095d54SToby Isaac   {
383762095d54SToby Isaac     PetscInt           numRootValues;
383862095d54SToby Isaac     const PetscScalar *coarseArray;
383962095d54SToby Isaac 
38409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootValuesSec, &numRootValues));
38419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRootValues, &rootValues));
38429566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecCoarseLocal, &coarseArray));
384362095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
384462095d54SToby Isaac       PetscInt     numValues;
384562095d54SToby Isaac       PetscInt     pValOff;
384662095d54SToby Isaac       PetscScalar *pVal;
384762095d54SToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
384862095d54SToby Isaac 
38499566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootValuesSec, p, &numValues));
38509371c9d4SSatish Balay       if (!numValues) { continue; }
38519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootValuesSec, p, &pValOff));
385262095d54SToby Isaac       pVal = &(rootValues[pValOff]);
385362095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
38540eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
38559566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(coarse, NULL, vecCoarseLocal, p, &closureSize, &pVal));
38560eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
3857193eb951SToby Isaac           PetscFVCellGeom *cg;
38586dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
38590eb7e1eaSToby Isaac           PetscInt         i;
38600eb7e1eaSToby Isaac 
38610eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
38620eb7e1eaSToby Isaac 
38639566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(cellDM, p, cellGeomArray, (void *)&cg));
38640eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
38650eb7e1eaSToby Isaac           pVal += dim;
38669566063dSJacob Faibussowitsch           PetscCall(DMPlexPointGlobalRead(gradDM, p, gradArray, (void *)&gradVals));
38670eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
38680eb7e1eaSToby Isaac         }
38699371c9d4SSatish Balay       } else if (maxChildId == -1) {
387078b7adb5SToby Isaac         PetscInt lDof, lOff, i;
387178b7adb5SToby Isaac 
38729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, p, &lDof));
38739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(localCoarse, p, &lOff));
387478b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
387578b7adb5SToby Isaac       }
387678b7adb5SToby Isaac     }
38779566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecCoarseLocal, &coarseArray));
38789566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
387962095d54SToby Isaac   }
388062095d54SToby Isaac   {
388162095d54SToby Isaac     PetscSF   valuesSF;
388262095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
388362095d54SToby Isaac 
38849566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafValuesSec));
38859566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootValuesSec, &remoteOffsetsValues, leafValuesSec));
38869566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootValuesSec, remoteOffsetsValues, leafValuesSec, &valuesSF));
38879566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
38889566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsValues));
38899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafValuesSec, &numLeafValues));
38909566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafValues, &leafValues));
38919566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
38929566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
38939566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&valuesSF));
38949566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootValues));
38959566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootValuesSec));
389662095d54SToby Isaac   }
38979566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
389862095d54SToby Isaac   {
389962095d54SToby Isaac     PetscInt       maxDof;
390062095d54SToby Isaac     PetscInt      *rowIndices;
390162095d54SToby Isaac     DM             refTree;
390262095d54SToby Isaac     PetscInt     **refPointFieldN;
390362095d54SToby Isaac     PetscScalar ***refPointFieldMats;
390462095d54SToby Isaac     PetscSection   refConSec, refAnSec;
39050eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, leafStart, leafEnd;
390662095d54SToby Isaac     PetscScalar   *pointWork;
390762095d54SToby Isaac 
39089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
39099566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
39109566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
39119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
39129566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(fine, refTree));
39139566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
39149566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
39159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
39169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
39179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafValuesSec, &leafStart, &leafEnd));
39189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSimplexOrBoxCells(fine, 0, &cellStart, &cellEnd));
39190eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
392062095d54SToby Isaac       PetscInt           gDof, gcDof, gOff, lDof;
392162095d54SToby Isaac       PetscInt           numValues, pValOff;
392262095d54SToby Isaac       PetscInt           childId;
392362095d54SToby Isaac       const PetscScalar *pVal;
39240eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
392562095d54SToby Isaac 
39269566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
39279566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localFine, p, &lDof));
39289566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
39299371c9d4SSatish Balay       if ((gDof - gcDof) <= 0) { continue; }
39309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
39319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafValuesSec, p, &numValues));
393262095d54SToby Isaac       if (!numValues) continue;
39339566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafValuesSec, p, &pValOff));
393462095d54SToby Isaac       pVal              = &leafValues[pValOff];
393562095d54SToby Isaac       offsets[0]        = 0;
393662095d54SToby Isaac       offsetsCopy[0]    = 0;
393762095d54SToby Isaac       newOffsets[0]     = 0;
393862095d54SToby Isaac       newOffsetsCopy[0] = 0;
39394833aeb0SToby Isaac       childId           = cids[p - pStartF];
394062095d54SToby Isaac       if (numFields) {
394162095d54SToby Isaac         PetscInt f;
394262095d54SToby Isaac         for (f = 0; f < numFields; f++) {
394362095d54SToby Isaac           PetscInt rowDof;
394462095d54SToby Isaac 
39459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
394662095d54SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
394762095d54SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
394862095d54SToby Isaac           /* TODO: closure indices */
39499f4e70e1SToby Isaac           newOffsets[f + 1]  = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
395062095d54SToby Isaac         }
39519566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
39529371c9d4SSatish Balay       } else {
39534833aeb0SToby Isaac         offsets[0]    = 0;
39544833aeb0SToby Isaac         offsets[1]    = lDof;
39554833aeb0SToby Isaac         newOffsets[0] = 0;
39564833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
39579566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
395862095d54SToby Isaac       }
395962095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
39609566063dSJacob Faibussowitsch         PetscCall(VecSetValues(vecFine, numValues, rowIndices, pVal, INSERT_VALUES));
396162095d54SToby Isaac       } else {
396262095d54SToby Isaac         PetscInt f;
396362095d54SToby Isaac 
396478b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
396578b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
396678b7adb5SToby Isaac           fvGradData = &pVal[numValues];
396778b7adb5SToby Isaac         }
396862095d54SToby Isaac         for (f = 0; f < PetscMax(1, numFields); f++) {
396962095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
397062095d54SToby Isaac           PetscInt           numRows  = offsets[f + 1] - offsets[f];
397162095d54SToby Isaac           PetscInt           numCols  = newOffsets[f + 1] - newOffsets[f];
397262095d54SToby Isaac           const PetscScalar *cVal     = &pVal[newOffsets[f]];
397362095d54SToby Isaac           PetscScalar       *rVal     = &pointWork[offsets[f]];
397462095d54SToby Isaac           PetscInt           i, j;
397562095d54SToby Isaac 
3976708c7f19SToby Isaac #if 0
397763a3b9bcSJacob Faibussowitsch           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));
3978708c7f19SToby Isaac #endif
397962095d54SToby Isaac           for (i = 0; i < numRows; i++) {
398062095d54SToby Isaac             PetscScalar val = 0.;
39819371c9d4SSatish Balay             for (j = 0; j < numCols; j++) { val += childMat[i * numCols + j] * cVal[j]; }
398262095d54SToby Isaac             rVal[i] = val;
398362095d54SToby Isaac           }
39840eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
39850eb7e1eaSToby Isaac             PetscReal          centroid[3];
39860eb7e1eaSToby Isaac             PetscScalar        diff[3];
39870eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
39880eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
39890eb7e1eaSToby Isaac 
39909566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFVM(fine, p, NULL, centroid, NULL));
39919371c9d4SSatish Balay             for (i = 0; i < dim; i++) { diff[i] = centroid[i] - parentCentroid[i]; }
39920eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
39930eb7e1eaSToby Isaac               PetscScalar val = 0.;
39940eb7e1eaSToby Isaac 
39959371c9d4SSatish Balay               for (j = 0; j < dim; j++) { val += gradient[dim * i + j] * diff[j]; }
39960eb7e1eaSToby Isaac               rVal[i] += val;
39970eb7e1eaSToby Isaac             }
39980eb7e1eaSToby Isaac           }
39999566063dSJacob Faibussowitsch           PetscCall(VecSetValues(vecFine, numRows, &rowIndices[offsets[f]], rVal, INSERT_VALUES));
400062095d54SToby Isaac         }
400162095d54SToby Isaac       }
400262095d54SToby Isaac     }
40039566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
40049566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
40059566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
400662095d54SToby Isaac   }
40079566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafValues));
40089566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafValuesSec));
40099566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
40109566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
4011ebf164c7SToby Isaac   PetscFunctionReturn(0);
4012ebf164c7SToby Isaac }
4013ebf164c7SToby Isaac 
40149371c9d4SSatish Balay static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids) {
4015c921d74cSToby Isaac   DM             refTree;
4016c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4017c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4018c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4019c921d74cSToby Isaac   PetscSection   cSecRef;
4020c921d74cSToby Isaac   PetscInt      *parentIndices, pRefStart, pRefEnd;
4021d3bc4906SToby Isaac   PetscScalar   *rootValues, *parentValues;
4022c921d74cSToby Isaac   Mat            injRef;
4023c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4024c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4025c921d74cSToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
4026c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4027c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4028c921d74cSToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4029c921d74cSToby Isaac 
4030ebf164c7SToby Isaac   PetscFunctionBegin;
4031c921d74cSToby Isaac 
4032c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
40339566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40349566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecCoarse, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
40369566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(coarse, refTree));
40379566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
40389566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
40399566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
4040c921d74cSToby Isaac 
40419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
40429566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
40439566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
40449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
40459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
40469566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
40479566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
40489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
4049c921d74cSToby Isaac   {
4050c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
40519566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
4052c921d74cSToby Isaac   }
4053c921d74cSToby Isaac 
40549566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, cids, vecFine, numFields, offsets, &multiRootSec, &rootIndicesSec, NULL, &rootValues));
4055c921d74cSToby Isaac 
40569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxDof, &parentIndices, maxDof, &parentValues));
4057c921d74cSToby Isaac 
4058c921d74cSToby Isaac   /* count indices */
40599566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecFine, &colMap));
40609566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecCoarse, &rowMap));
40619566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
40629566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
40639566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
40649566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
4065c921d74cSToby Isaac   /* insert values */
40669566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4067c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4068c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
406978b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4070c921d74cSToby Isaac 
40719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
40729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
4073c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
40749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localCoarse, p, &dof));
40759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
4076c921d74cSToby Isaac 
4077c921d74cSToby Isaac     rowOffsets[0]  = 0;
4078c921d74cSToby Isaac     offsetsCopy[0] = 0;
4079c921d74cSToby Isaac     if (numFields) {
4080c921d74cSToby Isaac       PetscInt f;
4081c921d74cSToby Isaac 
4082c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4083c921d74cSToby Isaac         PetscInt fDof;
40849566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
4085c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4086c921d74cSToby Isaac       }
40879566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
4088367003a6SStefano Zampini     } else {
40899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
4090c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4091c921d74cSToby Isaac     }
4092c921d74cSToby Isaac 
40939566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
40949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
4095c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
40962f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4097c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4098c921d74cSToby Isaac       PetscInt           numIndices, childId, offset;
4099c921d74cSToby Isaac       const PetscScalar *childValues;
4100c921d74cSToby Isaac 
41019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
41029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
4103c921d74cSToby Isaac       childId     = (PetscInt)PetscRealPart(rootValues[offset++]);
4104c921d74cSToby Isaac       childValues = &rootValues[offset];
4105c921d74cSToby Isaac       numIndices--;
4106c921d74cSToby Isaac 
4107c921d74cSToby Isaac       if (childId == -2) { /* skip */
4108c921d74cSToby Isaac         continue;
4109c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
41102f65e181SToby Isaac         PetscInt m;
41112f65e181SToby Isaac 
411278b7adb5SToby Isaac         contribute = PETSC_TRUE;
41132f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4114beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4115d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4116d3bc4906SToby Isaac 
411778b7adb5SToby Isaac         contribute = PETSC_TRUE;
41189566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
4119d3bc4906SToby Isaac 
4120d3bc4906SToby Isaac         lim        = PetscMax(1, numFields);
4121d3bc4906SToby Isaac         offsets[0] = 0;
4122d3bc4906SToby Isaac         if (numFields) {
4123d3bc4906SToby Isaac           PetscInt f;
4124d3bc4906SToby Isaac 
4125d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4126d3bc4906SToby Isaac             PetscInt fDof;
41279566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
4128d3bc4906SToby Isaac 
4129d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4130d3bc4906SToby Isaac           }
41319371c9d4SSatish Balay         } else {
4132d3bc4906SToby Isaac           PetscInt cDof;
4133d3bc4906SToby Isaac 
41349566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
4135d3bc4906SToby Isaac           offsets[1] = cDof;
4136d3bc4906SToby Isaac         }
4137d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4138d3bc4906SToby Isaac           PetscScalar       *childMat = &childrenMats[childId - pRefStart][f][0];
4139d3bc4906SToby Isaac           PetscInt           n        = offsets[f + 1] - offsets[f];
4140e328ff09SToby Isaac           PetscInt           m        = rowOffsets[f + 1] - rowOffsets[f];
4141d3bc4906SToby Isaac           PetscInt           i, j;
4142d3bc4906SToby Isaac           const PetscScalar *colValues = &childValues[offsets[f]];
4143d3bc4906SToby Isaac 
4144e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4145d3bc4906SToby Isaac             PetscScalar val = 0.;
41469371c9d4SSatish Balay             for (j = 0; j < n; j++) { val += childMat[n * i + j] * colValues[j]; }
4147e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4148d3bc4906SToby Isaac           }
4149d3bc4906SToby Isaac         }
4150c921d74cSToby Isaac       }
4151c921d74cSToby Isaac     }
41529566063dSJacob Faibussowitsch     if (contribute) PetscCall(VecSetValues(vecCoarse, dof, parentIndices, parentValues, INSERT_VALUES));
4153c921d74cSToby Isaac   }
41549566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
41559566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
41569566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parentIndices, parentValues));
41579566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
41589566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootValues));
41599566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
4160ebf164c7SToby Isaac   PetscFunctionReturn(0);
4161ebf164c7SToby Isaac }
4162ebf164c7SToby Isaac 
4163ff1f73f7SToby Isaac /*@
4164ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4165ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4166ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4167ff1f73f7SToby Isaac 
4168ff1f73f7SToby Isaac   collective
4169ff1f73f7SToby Isaac 
4170ff1f73f7SToby Isaac   Input Parameters:
4171ff1f73f7SToby Isaac + dmIn        - The DMPlex mesh for the input vector
4172ff1f73f7SToby Isaac . vecIn       - The input vector
4173ff1f73f7SToby Isaac . sfRefine    - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4174ff1f73f7SToby Isaac                 the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4175ff1f73f7SToby Isaac . sfCoarsen   - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4176ff1f73f7SToby Isaac                 the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4177ff1f73f7SToby Isaac . cidsRefine  - The childIds of the points in dmOut.  These childIds relate back to the reference tree: childid[j] = k implies
4178ff1f73f7SToby Isaac                 that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4179ff1f73f7SToby Isaac                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in dmOut is exactly
4180ff1f73f7SToby Isaac                 equivalent to its root in dmIn, so no interpolation is necessary.  childid[j] = -2 indicates that this
4181ff1f73f7SToby Isaac                 point j in dmOut is not a leaf of sfRefine.
4182ff1f73f7SToby Isaac . cidsCoarsen - The childIds of the points in dmIn.  These childIds relate back to the reference tree: childid[j] = k implies
4183ff1f73f7SToby Isaac                 that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4184ff1f73f7SToby Isaac                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4185ff1f73f7SToby Isaac . useBCs      - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4186ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4187ff1f73f7SToby Isaac 
4188ff1f73f7SToby Isaac   Output Parameters:
41898966356dSPierre Jolivet . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transferred
4190ff1f73f7SToby Isaac                 projection of vecIn from dmIn to dmOut.  Note that any field discretized with a PetscFV finite volume
4191ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4192ff1f73f7SToby Isaac                 coarse points to fine points.
4193ff1f73f7SToby Isaac 
4194ff1f73f7SToby Isaac   Level: developer
4195ff1f73f7SToby Isaac 
4196db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4197ff1f73f7SToby Isaac @*/
41989371c9d4SSatish Balay PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time) {
419938fc2455SToby Isaac   PetscFunctionBegin;
42009566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
4201ff1f73f7SToby Isaac   if (sfRefine) {
4202fbfa57b9SToby Isaac     Vec vecInLocal;
42030eb7e1eaSToby Isaac     DM  dmGrad   = NULL;
42040eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4205fbfa57b9SToby Isaac 
42069566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
42079566063dSJacob Faibussowitsch     PetscCall(VecSet(vecInLocal, 0.0));
42080eb7e1eaSToby Isaac     {
42090eb7e1eaSToby Isaac       PetscInt numFields, i;
42100eb7e1eaSToby Isaac 
42119566063dSJacob Faibussowitsch       PetscCall(DMGetNumFields(dmIn, &numFields));
42120eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
42130eb7e1eaSToby Isaac         PetscObject  obj;
42140eb7e1eaSToby Isaac         PetscClassId classid;
42150eb7e1eaSToby Isaac 
42169566063dSJacob Faibussowitsch         PetscCall(DMGetField(dmIn, i, NULL, &obj));
42179566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &classid));
42180eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
42199566063dSJacob Faibussowitsch           PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
42200eb7e1eaSToby Isaac           break;
42210eb7e1eaSToby Isaac         }
42220eb7e1eaSToby Isaac       }
42230eb7e1eaSToby Isaac     }
42241baa6e33SBarry Smith     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
42259566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42269566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42270eb7e1eaSToby Isaac     if (dmGrad) {
42289566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad, &grad));
42299566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
42300eb7e1eaSToby Isaac     }
42319566063dSJacob Faibussowitsch     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
42329566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
42339371c9d4SSatish Balay     if (dmGrad) { PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); }
4234ebf164c7SToby Isaac   }
42351baa6e33SBarry Smith   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
42369566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(vecOut));
42379566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(vecOut));
423838fc2455SToby Isaac   PetscFunctionReturn(0);
423938fc2455SToby Isaac }
4240