xref: /petsc/src/dm/impls/plex/plextree.c (revision c77c71ff2d9eaa2c74538bf9bf94eff01b512dbf)
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 
1220f4b53cSBarry Smith   Not Collective
13d6a7ad0dSToby Isaac 
14d6a7ad0dSToby Isaac   Input Parameters:
15a1cb98faSBarry Smith + dm - The `DMPLEX` object
16a1cb98faSBarry Smith - ref - The reference tree `DMPLEX` object
17d6a7ad0dSToby Isaac 
180b7167a0SToby Isaac   Level: intermediate
19d6a7ad0dSToby Isaac 
20a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`,`DMPlexGetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
21d6a7ad0dSToby Isaac @*/
22d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
23d71ae5a4SJacob Faibussowitsch {
24d6a7ad0dSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
25d6a7ad0dSToby Isaac 
26d6a7ad0dSToby Isaac   PetscFunctionBegin;
27d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28ad540459SPierre Jolivet   if (ref) PetscValidHeaderSpecific(ref, DM_CLASSID, 2);
299566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)ref));
309566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
31d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33d6a7ad0dSToby Isaac }
34d6a7ad0dSToby Isaac 
35d6a7ad0dSToby Isaac /*@
36d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
37d6a7ad0dSToby Isaac 
3820f4b53cSBarry Smith   Not Collective
39d6a7ad0dSToby Isaac 
402fe279fdSBarry Smith   Input Parameter:
41a1cb98faSBarry Smith . dm - The `DMPLEX` object
42d6a7ad0dSToby Isaac 
432fe279fdSBarry Smith   Output Parameter:
44a1cb98faSBarry Smith . ref - The reference tree `DMPLEX` object
45d6a7ad0dSToby Isaac 
460b7167a0SToby Isaac   Level: intermediate
47d6a7ad0dSToby Isaac 
48a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
49d6a7ad0dSToby Isaac @*/
50d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
51d71ae5a4SJacob Faibussowitsch {
52d6a7ad0dSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
53d6a7ad0dSToby Isaac 
54d6a7ad0dSToby Isaac   PetscFunctionBegin;
55d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
56d6a7ad0dSToby Isaac   PetscValidPointer(ref, 2);
57d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
59d6a7ad0dSToby Isaac }
60d6a7ad0dSToby Isaac 
61d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
62d71ae5a4SJacob Faibussowitsch {
63dcbd3bf7SToby Isaac   PetscInt coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
64dcbd3bf7SToby Isaac 
65dcbd3bf7SToby Isaac   PetscFunctionBegin;
66dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
67dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
68dcbd3bf7SToby Isaac     if (childB) *childB = childA;
693ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
70dcbd3bf7SToby Isaac   }
71dcbd3bf7SToby Isaac   for (dim = 0; dim < 3; dim++) {
729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, dim, &dStart, &dEnd));
73ad540459SPierre Jolivet     if (parent >= dStart && parent <= dEnd) break;
74dcbd3bf7SToby Isaac   }
7563a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot perform child symmetry for %" PetscInt_FMT "-cells", dim);
7628b400f6SJacob Faibussowitsch   PetscCheck(dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "A vertex has no children");
77dcbd3bf7SToby Isaac   if (childA < dStart || childA >= dEnd) {
78dcbd3bf7SToby Isaac     /* this is a lower-dimensional child: bootstrap */
79dcbd3bf7SToby Isaac     PetscInt        size, i, sA = -1, sB, sOrientB, sConeSize;
80dcbd3bf7SToby Isaac     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
81dcbd3bf7SToby Isaac 
829566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, childA, &size));
839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, childA, &supp));
84dcbd3bf7SToby Isaac 
85dcbd3bf7SToby Isaac     /* find a point sA in supp(childA) that has the same parent */
86dcbd3bf7SToby Isaac     for (i = 0; i < size; i++) {
87dcbd3bf7SToby Isaac       PetscInt sParent;
88dcbd3bf7SToby Isaac 
89dcbd3bf7SToby Isaac       sA = supp[i];
90dcbd3bf7SToby Isaac       if (sA == parent) continue;
919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, sA, &sParent, NULL));
92ad540459SPierre Jolivet       if (sParent == parent) break;
93dcbd3bf7SToby Isaac     }
9408401ef6SPierre Jolivet     PetscCheck(i != size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "could not find support in children");
95dcbd3bf7SToby Isaac     /* find out which point sB is in an equivalent position to sA under
96dcbd3bf7SToby Isaac      * parentOrientB */
979566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildSymmetry_Default(dm, parent, parentOrientA, 0, sA, parentOrientB, &sOrientB, &sB));
989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, sA, &sConeSize));
999566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sA, &coneA));
1009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sB, &coneB));
1019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sA, &oA));
1029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sB, &oB));
103dcbd3bf7SToby Isaac     /* step through the cone of sA in natural order */
104dcbd3bf7SToby Isaac     for (i = 0; i < sConeSize; i++) {
105dcbd3bf7SToby Isaac       if (coneA[i] == childA) {
106dcbd3bf7SToby Isaac         /* if childA is at position i in coneA,
107dcbd3bf7SToby Isaac          * then we want the point that is at sOrientB*i in coneB */
108dcbd3bf7SToby Isaac         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize - (sOrientB + 1) - i) % sConeSize);
109dcbd3bf7SToby Isaac         if (childB) *childB = coneB[j];
110dcbd3bf7SToby Isaac         if (childOrientB) {
111b5a892a1SMatthew G. Knepley           DMPolytopeType ct;
112dcbd3bf7SToby Isaac           PetscInt       oBtrue;
113dcbd3bf7SToby Isaac 
1149566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, childA, &coneSize));
115dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
1161dca8a05SBarry Smith           PetscCheck(coneSize == 0 || coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected a vertex or an edge");
117b5a892a1SMatthew G. Knepley           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
118dcbd3bf7SToby Isaac           /* we may have to flip an edge */
119b5a892a1SMatthew G. Knepley           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientation(ct, -1, oB[j]);
120b5a892a1SMatthew G. Knepley           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
121b5a892a1SMatthew G. Knepley           ABswap        = DihedralSwap(coneSize, DMPolytopeConvertNewOrientation_Internal(ct, oA[i]), oBtrue);
122dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
123dcbd3bf7SToby Isaac         }
124dcbd3bf7SToby Isaac         break;
125dcbd3bf7SToby Isaac       }
126dcbd3bf7SToby Isaac     }
12708401ef6SPierre Jolivet     PetscCheck(i != sConeSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "support cone mismatch");
1283ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
129dcbd3bf7SToby Isaac   }
130dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
1319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
132dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
133dcbd3bf7SToby Isaac   if (dim == 2) {
134dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
135dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
136dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
137dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
138dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
139dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
140947b95d8SBarry Smith   } else {
141dcbd3bf7SToby Isaac     ABswapVert = ABswap;
142dcbd3bf7SToby Isaac   }
143dcbd3bf7SToby Isaac   if (childB) {
144dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
145dcbd3bf7SToby Isaac     PetscInt        p, posA = -1, numChildren, i;
146dcbd3bf7SToby Isaac     const PetscInt *children;
147dcbd3bf7SToby Isaac 
148dcbd3bf7SToby Isaac     /* count which position the child is in */
1499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, parent, &numChildren, &children));
150dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
151dcbd3bf7SToby Isaac       p = children[i];
152dcbd3bf7SToby Isaac       if (p == childA) {
153dcbd3bf7SToby Isaac         posA = i;
154dcbd3bf7SToby Isaac         break;
155dcbd3bf7SToby Isaac       }
156dcbd3bf7SToby Isaac     }
157dcbd3bf7SToby Isaac     if (posA >= coneSize) {
158dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
159dcbd3bf7SToby Isaac        * is invariant */
1601dca8a05SBarry Smith       PetscCheck(dim == 2 && posA == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Expected a middle triangle, got something else");
161dcbd3bf7SToby Isaac       *childB = childA;
1629371c9d4SSatish Balay     } else {
163dcbd3bf7SToby Isaac       /* figure out position B by applying ABswapVert */
164dcbd3bf7SToby Isaac       PetscInt posB;
165dcbd3bf7SToby Isaac 
166dcbd3bf7SToby Isaac       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize - (ABswapVert + 1) - posA) % coneSize);
167dcbd3bf7SToby Isaac       if (childB) *childB = children[posB];
168dcbd3bf7SToby Isaac     }
169dcbd3bf7SToby Isaac   }
170dcbd3bf7SToby Isaac   if (childOrientB) *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
1713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
172dcbd3bf7SToby Isaac }
173dcbd3bf7SToby Isaac 
174dcbd3bf7SToby Isaac /*@
175dcbd3bf7SToby Isaac   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
176dcbd3bf7SToby Isaac 
177dcbd3bf7SToby Isaac   Input Parameters:
178a1cb98faSBarry Smith + dm - the reference tree `DMPLEX` object
179dcbd3bf7SToby Isaac . parent - the parent point
180dcbd3bf7SToby Isaac . parentOrientA - the reference orientation for describing the parent
181dcbd3bf7SToby Isaac . childOrientA - the reference orientation for describing the child
182dcbd3bf7SToby Isaac . childA - the reference childID for describing the child
183dcbd3bf7SToby Isaac - parentOrientB - the new orientation for describing the parent
184dcbd3bf7SToby Isaac 
185dcbd3bf7SToby Isaac   Output Parameters:
18620f4b53cSBarry Smith + childOrientB - if not `NULL`, set to the new orientation for describing the child
18720f4b53cSBarry Smith - childB - if not `NULL`, the new childID for describing the child
188dcbd3bf7SToby Isaac 
189dcbd3bf7SToby Isaac   Level: developer
190dcbd3bf7SToby Isaac 
191a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetReferenceTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetTree()`
192dcbd3bf7SToby Isaac @*/
193d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
194d71ae5a4SJacob Faibussowitsch {
195dcbd3bf7SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
196dcbd3bf7SToby Isaac 
197dcbd3bf7SToby Isaac   PetscFunctionBegin;
198dcbd3bf7SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
19928b400f6SJacob Faibussowitsch   PetscCheck(mesh->getchildsymmetry, PETSC_COMM_SELF, PETSC_ERR_SUP, "DMPlexReferenceTreeGetChildSymmetry not implemented");
2009566063dSJacob Faibussowitsch   PetscCall(mesh->getchildsymmetry(dm, parent, parentOrientA, childOrientA, childA, parentOrientB, childOrientB, childB));
2013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
202dcbd3bf7SToby Isaac }
203dcbd3bf7SToby Isaac 
204776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM, PetscSection, PetscInt *, PetscInt *, PetscBool, PetscBool);
205f9f063d4SToby Isaac 
206d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
207d71ae5a4SJacob Faibussowitsch {
208f2c1aa1dSLisandro Dalcin   PetscFunctionBegin;
2099566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_TRUE, PETSC_FALSE));
2103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
211f2c1aa1dSLisandro Dalcin }
212f2c1aa1dSLisandro Dalcin 
213d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
214d71ae5a4SJacob Faibussowitsch {
2150e2cc29aSToby Isaac   MPI_Comm     comm;
2160e2cc29aSToby Isaac   PetscInt     dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
217da43764aSToby Isaac   PetscInt    *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
218da43764aSToby Isaac   DMLabel      identity, identityRef;
21910f7e118SToby Isaac   PetscSection unionSection, unionConeSection, parentSection;
220da43764aSToby Isaac   PetscScalar *unionCoords;
221da43764aSToby Isaac   IS           perm;
222da43764aSToby Isaac 
223da43764aSToby Isaac   PetscFunctionBegin;
2240e2cc29aSToby Isaac   comm = PetscObjectComm((PetscObject)K);
2259566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(K, &dim));
2269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
2279566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, labelName, &identity));
2289566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(Kref, labelName, &identityRef));
2299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(Kref, &pRefStart, &pRefEnd));
2309566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionSection));
2319566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart)));
232da43764aSToby Isaac   /* count points that will go in the union */
23348a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; p++) PetscCall(PetscSectionSetDof(unionSection, p - pStart, 1));
234da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
235da43764aSToby Isaac     PetscInt q, qSize;
2369566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(identityRef, p, &q));
2379566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(identityRef, q, &qSize));
23848a46eb9SPierre Jolivet     if (qSize > 1) PetscCall(PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1));
239da43764aSToby Isaac   }
2409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart, &permvals));
241da43764aSToby Isaac   offset = 0;
242da43764aSToby Isaac   /* stratify points in the union by topological dimension */
243da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
244da43764aSToby Isaac     PetscInt cStart, cEnd, c;
245da43764aSToby Isaac 
2469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, &cEnd));
247ad540459SPierre Jolivet     for (c = cStart; c < cEnd; c++) permvals[offset++] = c;
248da43764aSToby Isaac 
2499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd));
250ad540459SPierre Jolivet     for (c = cStart; c < cEnd; c++) permvals[offset++] = c + (pEnd - pStart);
251da43764aSToby Isaac   }
2529566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm));
2539566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetPermutation(unionSection, perm));
2549566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionSection));
2559566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionSection, &numUnionPoints));
2569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numUnionPoints, &coneSizes, dim + 1, &numDimPoints));
257da43764aSToby Isaac   /* count dimension points */
258da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
259da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
2609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, NULL));
2619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff));
262da43764aSToby Isaac     if (d < dim) {
2639566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d + 1, &cStart, NULL));
2649566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff2));
2659371c9d4SSatish Balay     } else {
266da43764aSToby Isaac       cOff2 = numUnionPoints;
267da43764aSToby Isaac     }
268da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
269da43764aSToby Isaac   }
2709566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionConeSection));
2719566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(unionConeSection, 0, numUnionPoints));
272da43764aSToby Isaac   /* count the cones in the union */
273da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
274da43764aSToby Isaac     PetscInt dof, uOff;
275da43764aSToby Isaac 
2769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
2779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
2789566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
279da43764aSToby Isaac     coneSizes[uOff] = dof;
280da43764aSToby Isaac   }
281da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
282da43764aSToby Isaac     PetscInt dof, uDof, uOff;
283da43764aSToby Isaac 
2849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
2859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
2869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
287da43764aSToby Isaac     if (uDof) {
2889566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
289da43764aSToby Isaac       coneSizes[uOff] = dof;
290da43764aSToby Isaac     }
291da43764aSToby Isaac   }
2929566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionConeSection));
2939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionConeSection, &numCones));
2949566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numCones, &unionCones, numCones, &unionOrientations));
295da43764aSToby Isaac   /* write the cones in the union */
296da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
297da43764aSToby Isaac     PetscInt        dof, uOff, c, cOff;
298da43764aSToby Isaac     const PetscInt *cone, *orientation;
299da43764aSToby Isaac 
3009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
3019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(K, p, &cone));
3029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(K, p, &orientation));
3039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
3049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
305da43764aSToby Isaac     for (c = 0; c < dof; c++) {
306da43764aSToby Isaac       PetscInt e, eOff;
307da43764aSToby Isaac       e = cone[c];
3089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
309da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
310da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
311da43764aSToby Isaac     }
312da43764aSToby Isaac   }
313da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
314da43764aSToby Isaac     PetscInt        dof, uDof, uOff, c, cOff;
315da43764aSToby Isaac     const PetscInt *cone, *orientation;
316da43764aSToby Isaac 
3179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
3189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(Kref, p, &cone));
3199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(Kref, p, &orientation));
3209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
322da43764aSToby Isaac     if (uDof) {
3239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
324da43764aSToby Isaac       for (c = 0; c < dof; c++) {
325da43764aSToby Isaac         PetscInt e, eOff, eDof;
326da43764aSToby Isaac 
327da43764aSToby Isaac         e = cone[c];
3289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart), &eDof));
329da43764aSToby Isaac         if (eDof) {
3309566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff));
3319371c9d4SSatish Balay         } else {
3329566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(identityRef, e, &e));
3339566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
334da43764aSToby Isaac         }
335da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
336da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
337da43764aSToby Isaac       }
338da43764aSToby Isaac     }
339da43764aSToby Isaac   }
340da43764aSToby Isaac   /* get the coordinates */
341da43764aSToby Isaac   {
342da43764aSToby Isaac     PetscInt     vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
343da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
344da43764aSToby Isaac     Vec          KcoordsVec, KrefCoordsVec;
345da43764aSToby Isaac     PetscScalar *Kcoords;
346da43764aSToby Isaac 
3479566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(K, &KcoordsSec));
3489566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(K, &KcoordsVec));
3499566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(Kref, &KrefCoordsSec));
3509566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(Kref, &KrefCoordsVec));
351da43764aSToby Isaac 
352da43764aSToby Isaac     numVerts = numDimPoints[0];
3539566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numVerts * dim, &unionCoords));
3549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(K, 0, &vStart, &vEnd));
355da43764aSToby Isaac 
356da43764aSToby Isaac     offset = 0;
357da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
3589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, v - pStart, &vOff));
3599566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords));
360ad540459SPierre Jolivet       for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
361da43764aSToby Isaac       offset++;
362da43764aSToby Isaac     }
3639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(Kref, 0, &vRefStart, &vRefEnd));
364da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
3659566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(unionSection, v - pRefStart + (pEnd - pStart), &vDof));
3669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, v - pRefStart + (pEnd - pStart), &vOff));
3679566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords));
368da43764aSToby Isaac       if (vDof) {
369ad540459SPierre Jolivet         for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
370da43764aSToby Isaac         offset++;
371da43764aSToby Isaac       }
372da43764aSToby Isaac     }
373da43764aSToby Isaac   }
3749566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, ref));
3759566063dSJacob Faibussowitsch   PetscCall(DMSetType(*ref, DMPLEX));
3769566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ref, dim));
3779566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromDAG(*ref, dim, numDimPoints, coneSizes, unionCones, unionOrientations, unionCoords));
37810f7e118SToby Isaac   /* set the tree */
3799566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &parentSection));
3809566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(parentSection, 0, numUnionPoints));
38110f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
38210f7e118SToby Isaac     PetscInt uDof, uOff;
38310f7e118SToby Isaac 
3849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
3861baa6e33SBarry Smith     if (uDof) PetscCall(PetscSectionSetDof(parentSection, uOff, 1));
38710f7e118SToby Isaac   }
3889566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(parentSection));
3899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection, &parentSize));
3909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(parentSize, &parents, parentSize, &childIDs));
39110f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
39210f7e118SToby Isaac     PetscInt uDof, uOff;
39310f7e118SToby Isaac 
3949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
39610f7e118SToby Isaac     if (uDof) {
39710f7e118SToby Isaac       PetscInt pOff, parent, parentU;
3989566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(parentSection, uOff, &pOff));
3999566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(identityRef, p, &parent));
4009566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, parent - pStart, &parentU));
40110f7e118SToby Isaac       parents[pOff]  = parentU;
40210f7e118SToby Isaac       childIDs[pOff] = uOff;
40310f7e118SToby Isaac     }
40410f7e118SToby Isaac   }
4059566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_SetTree(*ref, parentSection, parents, childIDs));
4069566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
4079566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parents, childIDs));
40810f7e118SToby Isaac 
409da43764aSToby Isaac   /* clean up */
4109566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionSection));
4119566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionConeSection));
4129566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&perm));
4139566063dSJacob Faibussowitsch   PetscCall(PetscFree(unionCoords));
4149566063dSJacob Faibussowitsch   PetscCall(PetscFree2(unionCones, unionOrientations));
4159566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coneSizes, numDimPoints));
4163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4170e2cc29aSToby Isaac }
4180e2cc29aSToby Isaac 
4190e2cc29aSToby Isaac /*@
4200e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4210e2cc29aSToby Isaac 
422d083f849SBarry Smith   Collective
4230e2cc29aSToby Isaac 
4240e2cc29aSToby Isaac   Input Parameters:
4250e2cc29aSToby Isaac + comm    - the MPI communicator
4260e2cc29aSToby Isaac . dim     - the spatial dimension
4270e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4280e2cc29aSToby Isaac 
4292fe279fdSBarry Smith   Output Parameter:
430a1cb98faSBarry Smith . ref     - the reference tree `DMPLEX` object
4310e2cc29aSToby Isaac 
4320e2cc29aSToby Isaac   Level: intermediate
4330e2cc29aSToby Isaac 
434db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`
4350e2cc29aSToby Isaac @*/
436d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
437d71ae5a4SJacob Faibussowitsch {
4380e2cc29aSToby Isaac   DM_Plex *mesh;
4390e2cc29aSToby Isaac   DM       K, Kref;
4400e2cc29aSToby Isaac   PetscInt p, pStart, pEnd;
4410e2cc29aSToby Isaac   DMLabel  identity;
4420e2cc29aSToby Isaac 
4430e2cc29aSToby Isaac   PetscFunctionBegin;
4440e2cc29aSToby Isaac #if 1
4450e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4460e2cc29aSToby Isaac #endif
4470e2cc29aSToby Isaac   /* create a reference element */
4489566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K));
4499566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(K, "identity"));
4509566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, "identity", &identity));
4519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
45248a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; p++) PetscCall(DMLabelSetValue(identity, p, p));
4530e2cc29aSToby Isaac   /* refine it */
4549566063dSJacob Faibussowitsch   PetscCall(DMRefine(K, comm, &Kref));
4550e2cc29aSToby Isaac 
4560e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4570e2cc29aSToby Isaac    * points that appear in both */
4589566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref));
4590e2cc29aSToby Isaac   mesh                   = (DM_Plex *)(*ref)->data;
4600e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
4619566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&K));
4629566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&Kref));
4633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
464da43764aSToby Isaac }
465da43764aSToby Isaac 
466d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
467d71ae5a4SJacob Faibussowitsch {
468878b19aaSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
469878b19aaSToby Isaac   PetscSection childSec, pSec;
470878b19aaSToby Isaac   PetscInt     p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
471878b19aaSToby Isaac   PetscInt    *offsets, *children, pStart, pEnd;
472878b19aaSToby Isaac 
473878b19aaSToby Isaac   PetscFunctionBegin;
474878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4759566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
4769566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
477878b19aaSToby Isaac   pSec = mesh->parentSection;
4783ba16761SJacob Faibussowitsch   if (!pSec) PetscFunctionReturn(PETSC_SUCCESS);
4799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(pSec, &pSize));
480878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
481878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
482878b19aaSToby Isaac 
483878b19aaSToby Isaac     parMax = PetscMax(parMax, par + 1);
484878b19aaSToby Isaac     parMin = PetscMin(parMin, par);
485878b19aaSToby Isaac   }
486878b19aaSToby Isaac   if (parMin > parMax) {
487878b19aaSToby Isaac     parMin = -1;
488878b19aaSToby Isaac     parMax = -1;
489878b19aaSToby Isaac   }
4909566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)pSec), &childSec));
4919566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(childSec, parMin, parMax));
492878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
493878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
494878b19aaSToby Isaac 
4959566063dSJacob Faibussowitsch     PetscCall(PetscSectionAddDof(childSec, par, 1));
496878b19aaSToby Isaac   }
4979566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(childSec));
4989566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(childSec, &cSize));
4999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cSize, &children));
5009566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(parMax - parMin, &offsets));
5019566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(pSec, &pStart, &pEnd));
502878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
503878b19aaSToby Isaac     PetscInt dof, off, i;
504878b19aaSToby Isaac 
5059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pSec, p, &dof));
5069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(pSec, p, &off));
507878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
508878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
509878b19aaSToby Isaac 
5109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec, par, &cOff));
511878b19aaSToby Isaac       children[cOff + offsets[par - parMin]++] = p;
512878b19aaSToby Isaac     }
513878b19aaSToby Isaac   }
514878b19aaSToby Isaac   mesh->childSection = childSec;
515878b19aaSToby Isaac   mesh->children     = children;
5169566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
5173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
518878b19aaSToby Isaac }
519878b19aaSToby Isaac 
520d71ae5a4SJacob Faibussowitsch static PetscErrorCode AnchorsFlatten(PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
521d71ae5a4SJacob Faibussowitsch {
5226dd5a8c8SToby Isaac   PetscInt        pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5236dd5a8c8SToby Isaac   const PetscInt *vals;
5246dd5a8c8SToby Isaac   PetscSection    secNew;
5256dd5a8c8SToby Isaac   PetscBool       anyNew, globalAnyNew;
5266dd5a8c8SToby Isaac   PetscBool       compress;
5276dd5a8c8SToby Isaac 
5286dd5a8c8SToby Isaac   PetscFunctionBegin;
5299566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
5309566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is, &size));
5319566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is, &vals));
5329566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secNew));
5339566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(secNew, pStart, pEnd));
5346dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5356dd5a8c8SToby Isaac     PetscInt dof;
5366dd5a8c8SToby Isaac 
5376dd5a8c8SToby Isaac     p = vals[i];
5386dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
5406dd5a8c8SToby Isaac     if (dof) break;
5416dd5a8c8SToby Isaac   }
5426dd5a8c8SToby Isaac   if (i == size) {
5439566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5446dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5456dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5466dd5a8c8SToby Isaac     sizeNew  = 0;
5479371c9d4SSatish Balay   } else {
5486dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5496dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5506dd5a8c8SToby Isaac       PetscInt dof, off;
5516dd5a8c8SToby Isaac 
5529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5546dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5556dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5566dd5a8c8SToby Isaac 
55748a46eb9SPierre Jolivet         if (q >= pStart && q < pEnd) PetscCall(PetscSectionGetDof(section, q, &qDof));
5581baa6e33SBarry Smith         if (qDof) PetscCall(PetscSectionAddDof(secNew, p, qDof));
55948a46eb9SPierre Jolivet         else PetscCall(PetscSectionAddDof(secNew, p, 1));
5606dd5a8c8SToby Isaac       }
5616dd5a8c8SToby Isaac     }
5629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(secNew, &sizeNew));
5649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sizeNew, &valsNew));
5656dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5666dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5676dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
5686dd5a8c8SToby Isaac 
5699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(secNew, p, &dofNew));
5729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(secNew, p, &offNew));
5736dd5a8c8SToby Isaac       count = 0;
5746dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5756dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
5766dd5a8c8SToby Isaac 
5776dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5789566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, q, &qDof));
5799566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, q, &qOff));
5806dd5a8c8SToby Isaac         }
5816dd5a8c8SToby Isaac         if (qDof) {
5826dd5a8c8SToby Isaac           PetscInt oldCount = count;
5836dd5a8c8SToby Isaac 
5846dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
5856dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
5866dd5a8c8SToby Isaac 
5876dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
588ad540459SPierre Jolivet               if (valsNew[offNew + k] == r) break;
5896dd5a8c8SToby Isaac             }
590ad540459SPierre Jolivet             if (k == oldCount) valsNew[offNew + count++] = r;
5916dd5a8c8SToby Isaac           }
5929371c9d4SSatish Balay         } else {
5936dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
5946dd5a8c8SToby Isaac 
5956dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
596ad540459SPierre Jolivet             if (valsNew[offNew + k] == q) break;
5976dd5a8c8SToby Isaac           }
598ad540459SPierre Jolivet           if (k == oldCount) valsNew[offNew + count++] = q;
5996dd5a8c8SToby Isaac         }
6006dd5a8c8SToby Isaac       }
6016dd5a8c8SToby Isaac       if (count < dofNew) {
6029566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secNew, p, count));
6036dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6046dd5a8c8SToby Isaac       }
6056dd5a8c8SToby Isaac     }
6066dd5a8c8SToby Isaac   }
6079566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is, &vals));
6081c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&anyNew, &globalAnyNew, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
6096dd5a8c8SToby Isaac   if (!globalAnyNew) {
6109566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secNew));
6116dd5a8c8SToby Isaac     *sectionNew = NULL;
6126dd5a8c8SToby Isaac     *isNew      = NULL;
6139371c9d4SSatish Balay   } else {
6146dd5a8c8SToby Isaac     PetscBool globalCompress;
6156dd5a8c8SToby Isaac 
6161c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&compress, &globalCompress, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
6176dd5a8c8SToby Isaac     if (compress) {
6186dd5a8c8SToby Isaac       PetscSection secComp;
6196dd5a8c8SToby Isaac       PetscInt    *valsComp = NULL;
6206dd5a8c8SToby Isaac 
6219566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secComp));
6229566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetChart(secComp, pStart, pEnd));
6236dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6246dd5a8c8SToby Isaac         PetscInt dof;
6256dd5a8c8SToby Isaac 
6269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6279566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secComp, p, dof));
6286dd5a8c8SToby Isaac       }
6299566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetUp(secComp));
6309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(secComp, &sizeNew));
6319566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(sizeNew, &valsComp));
6326dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6336dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6346dd5a8c8SToby Isaac 
6359566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6369566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secNew, p, &off));
6379566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secComp, p, &offNew));
638ad540459SPierre Jolivet         for (j = 0; j < dof; j++) valsComp[offNew + j] = valsNew[off + j];
6396dd5a8c8SToby Isaac       }
6409566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&secNew));
6416dd5a8c8SToby Isaac       secNew = secComp;
6429566063dSJacob Faibussowitsch       PetscCall(PetscFree(valsNew));
6436dd5a8c8SToby Isaac       valsNew = valsComp;
6446dd5a8c8SToby Isaac     }
6459566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), sizeNew, valsNew, PETSC_OWN_POINTER, isNew));
6466dd5a8c8SToby Isaac   }
6473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6486dd5a8c8SToby Isaac }
6496dd5a8c8SToby Isaac 
650d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
651d71ae5a4SJacob Faibussowitsch {
65266af876cSToby Isaac   PetscInt     p, pStart, pEnd, *anchors, size;
65366af876cSToby Isaac   PetscInt     aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
65466af876cSToby Isaac   PetscSection aSec;
655f9f063d4SToby Isaac   DMLabel      canonLabel;
65666af876cSToby Isaac   IS           aIS;
65766af876cSToby Isaac 
65866af876cSToby Isaac   PetscFunctionBegin;
65966af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
6619566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "canonical", &canonLabel));
66266af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
66366af876cSToby Isaac     PetscInt parent;
66466af876cSToby Isaac 
665f9f063d4SToby Isaac     if (canonLabel) {
666f9f063d4SToby Isaac       PetscInt canon;
667f9f063d4SToby Isaac 
6689566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
669f9f063d4SToby Isaac       if (p != canon) continue;
670f9f063d4SToby Isaac     }
6719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
67266af876cSToby Isaac     if (parent != p) {
67366af876cSToby Isaac       aMin = PetscMin(aMin, p);
67466af876cSToby Isaac       aMax = PetscMax(aMax, p + 1);
67566af876cSToby Isaac     }
67666af876cSToby Isaac   }
67766af876cSToby Isaac   if (aMin > aMax) {
67866af876cSToby Isaac     aMin = -1;
67966af876cSToby Isaac     aMax = -1;
68066af876cSToby Isaac   }
6819566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &aSec));
6829566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(aSec, aMin, aMax));
68366af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
68466af876cSToby Isaac     PetscInt parent, ancestor = p;
68566af876cSToby Isaac 
686f9f063d4SToby Isaac     if (canonLabel) {
687f9f063d4SToby Isaac       PetscInt canon;
688f9f063d4SToby Isaac 
6899566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
690f9f063d4SToby Isaac       if (p != canon) continue;
691f9f063d4SToby Isaac     }
6929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
69366af876cSToby Isaac     while (parent != ancestor) {
69466af876cSToby Isaac       ancestor = parent;
6959566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
69666af876cSToby Isaac     }
69766af876cSToby Isaac     if (ancestor != p) {
69866af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
69966af876cSToby Isaac 
7009566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
7019566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(aSec, p, closureSize));
7029566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
70366af876cSToby Isaac     }
70466af876cSToby Isaac   }
7059566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(aSec));
7069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(aSec, &size));
7079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &anchors));
70866af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
70966af876cSToby Isaac     PetscInt parent, ancestor = p;
71066af876cSToby Isaac 
711f9f063d4SToby Isaac     if (canonLabel) {
712f9f063d4SToby Isaac       PetscInt canon;
713f9f063d4SToby Isaac 
7149566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
715f9f063d4SToby Isaac       if (p != canon) continue;
716f9f063d4SToby Isaac     }
7179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
71866af876cSToby Isaac     while (parent != ancestor) {
71966af876cSToby Isaac       ancestor = parent;
7209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
72166af876cSToby Isaac     }
72266af876cSToby Isaac     if (ancestor != p) {
72366af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
72466af876cSToby Isaac 
7259566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
72666af876cSToby Isaac 
7279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
728ad540459SPierre Jolivet       for (j = 0; j < closureSize; j++) anchors[aOff + j] = closure[2 * j];
7299566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
73066af876cSToby Isaac     }
73166af876cSToby Isaac   }
7329566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, anchors, PETSC_OWN_POINTER, &aIS));
7336dd5a8c8SToby Isaac   {
7346dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7356dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7366dd5a8c8SToby Isaac 
7379566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aSec));
7389566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aIS));
7396dd5a8c8SToby Isaac     while (aSecNew) {
7409566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&aSec));
7419566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&aIS));
7426dd5a8c8SToby Isaac       aSec    = aSecNew;
7436dd5a8c8SToby Isaac       aIS     = aISNew;
7446dd5a8c8SToby Isaac       aSecNew = NULL;
7456dd5a8c8SToby Isaac       aISNew  = NULL;
7469566063dSJacob Faibussowitsch       PetscCall(AnchorsFlatten(aSec, aIS, &aSecNew, &aISNew));
7476dd5a8c8SToby Isaac     }
7486dd5a8c8SToby Isaac   }
7499566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm, aSec, aIS));
7509566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&aSec));
7519566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&aIS));
7523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
75366af876cSToby Isaac }
75466af876cSToby Isaac 
755d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTrueSupportSize(DM dm, PetscInt p, PetscInt *dof, PetscInt *numTrueSupp)
756d71ae5a4SJacob Faibussowitsch {
7576461c1adSToby Isaac   PetscFunctionBegin;
7586461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
7596461c1adSToby Isaac     PetscInt        i, alldof;
7606461c1adSToby Isaac     const PetscInt *supp;
7616461c1adSToby Isaac     PetscInt        count = 0;
7626461c1adSToby Isaac 
7639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &alldof));
7649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &supp));
7656461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
7666461c1adSToby Isaac       PetscInt        q = supp[i], numCones, j;
7676461c1adSToby Isaac       const PetscInt *cone;
7686461c1adSToby Isaac 
7699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, q, &numCones));
7709566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, q, &cone));
7716461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
7726461c1adSToby Isaac         if (cone[j] == p) break;
7736461c1adSToby Isaac       }
7746461c1adSToby Isaac       if (j < numCones) count++;
7756461c1adSToby Isaac     }
7766461c1adSToby Isaac     numTrueSupp[p] = count;
7776461c1adSToby Isaac   }
7786461c1adSToby Isaac   *dof = numTrueSupp[p];
7793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7806461c1adSToby Isaac }
7816461c1adSToby Isaac 
782d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
783d71ae5a4SJacob Faibussowitsch {
784776742edSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
785776742edSToby Isaac   PetscSection newSupportSection;
786776742edSToby Isaac   PetscInt     newSize, *newSupports, pStart, pEnd, p, d, depth;
7876461c1adSToby Isaac   PetscInt    *numTrueSupp;
788776742edSToby Isaac   PetscInt    *offsets;
789776742edSToby Isaac 
790776742edSToby Isaac   PetscFunctionBegin;
791776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
792776742edSToby Isaac   /* symmetrize the hierarchy */
7939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
7949566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)), &newSupportSection));
7959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7969566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSupportSection, pStart, pEnd));
7979566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd, &offsets));
7989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd, &numTrueSupp));
7996461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8006461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
801776742edSToby Isaac    * parent(q) */
802776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
804776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
805776742edSToby Isaac       PetscInt dof, q, qdof, parent;
806776742edSToby Isaac 
8079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTrueSupportSize(dm, p, &dof, numTrueSupp));
8089566063dSJacob Faibussowitsch       PetscCall(PetscSectionAddDof(newSupportSection, p, dof));
809776742edSToby Isaac       q = p;
8109566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
811776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
812776742edSToby Isaac         q = parent;
813776742edSToby Isaac 
8149566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTrueSupportSize(dm, q, &qdof, numTrueSupp));
8159566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection, p, qdof));
8169566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection, q, dof));
8179566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
818776742edSToby Isaac       }
819776742edSToby Isaac     }
820776742edSToby Isaac   }
8219566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSupportSection));
8229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSupportSection, &newSize));
8239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(newSize, &newSupports));
824776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
826776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
827776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
828776742edSToby Isaac 
8299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
8309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
8319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(newSupportSection, p, &newDof));
8329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(newSupportSection, p, &newOff));
833776742edSToby Isaac       for (i = 0; i < dof; i++) {
8346461c1adSToby Isaac         PetscInt        numCones, j;
8356461c1adSToby Isaac         const PetscInt *cone;
8366461c1adSToby Isaac         PetscInt        q = mesh->supports[off + i];
8376461c1adSToby Isaac 
8389566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, q, &numCones));
8399566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, q, &cone));
8406461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8416461c1adSToby Isaac           if (cone[j] == p) break;
8426461c1adSToby Isaac         }
8436461c1adSToby Isaac         if (j < numCones) newSupports[newOff + offsets[p]++] = q;
844776742edSToby Isaac       }
845776742edSToby Isaac 
846776742edSToby Isaac       q = p;
8479566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
848776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
849776742edSToby Isaac         q = parent;
8509566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->supportSection, q, &qdof));
8519566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &qoff));
8529566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(newSupportSection, q, &newqOff));
853776742edSToby Isaac         for (i = 0; i < qdof; i++) {
8546461c1adSToby Isaac           PetscInt        numCones, j;
8556461c1adSToby Isaac           const PetscInt *cone;
8566461c1adSToby Isaac           PetscInt        r = mesh->supports[qoff + 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] == q) break;
8626461c1adSToby Isaac           }
8636461c1adSToby Isaac           if (j < numCones) newSupports[newOff + offsets[p]++] = r;
864776742edSToby Isaac         }
865776742edSToby Isaac         for (i = 0; i < dof; i++) {
8666461c1adSToby Isaac           PetscInt        numCones, j;
8676461c1adSToby Isaac           const PetscInt *cone;
8686461c1adSToby Isaac           PetscInt        r = mesh->supports[off + i];
8696461c1adSToby Isaac 
8709566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
8719566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, r, &cone));
8726461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
8736461c1adSToby Isaac             if (cone[j] == p) break;
8746461c1adSToby Isaac           }
8756461c1adSToby Isaac           if (j < numCones) newSupports[newqOff + offsets[q]++] = r;
876776742edSToby Isaac         }
8779566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
878776742edSToby Isaac       }
879776742edSToby Isaac     }
880776742edSToby Isaac   }
8819566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
882776742edSToby Isaac   mesh->supportSection = newSupportSection;
8839566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
884776742edSToby Isaac   mesh->supports = newSupports;
8859566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
8869566063dSJacob Faibussowitsch   PetscCall(PetscFree(numTrueSupp));
887776742edSToby Isaac 
8883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
889776742edSToby Isaac }
890776742edSToby Isaac 
891f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM, PetscSection, PetscSection, Mat);
892f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM, PetscSection, PetscSection, Mat);
893f7c74593SToby Isaac 
894d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
895d71ae5a4SJacob Faibussowitsch {
896f9f063d4SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
897f9f063d4SToby Isaac   DM       refTree;
898f9f063d4SToby Isaac   PetscInt size;
899f9f063d4SToby Isaac 
900f9f063d4SToby Isaac   PetscFunctionBegin;
901f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
902f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
9039566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)parentSection));
9049566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
905f9f063d4SToby Isaac   mesh->parentSection = parentSection;
9069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection, &size));
907f9f063d4SToby Isaac   if (parents != mesh->parents) {
9089566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->parents));
9099566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->parents));
9109566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->parents, parents, size));
911f9f063d4SToby Isaac   }
912f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
9139566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->childIDs));
9149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->childIDs));
9159566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->childIDs, childIDs, size));
916f9f063d4SToby Isaac   }
9179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
918f9f063d4SToby Isaac   if (refTree) {
919f9f063d4SToby Isaac     DMLabel canonLabel;
920f9f063d4SToby Isaac 
9219566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(refTree, "canonical", &canonLabel));
922f9f063d4SToby Isaac     if (canonLabel) {
923f9f063d4SToby Isaac       PetscInt i;
924f9f063d4SToby Isaac 
925f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
926f9f063d4SToby Isaac         PetscInt canon;
9279566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon));
928ad540459SPierre Jolivet         if (canon >= 0) mesh->childIDs[i] = canon;
929f9f063d4SToby Isaac       }
930f9f063d4SToby Isaac     }
931f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
9326e0288c8SStefano Zampini   } else {
933f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
934f9f063d4SToby Isaac   }
9359566063dSJacob Faibussowitsch   PetscCall(DMPlexTreeSymmetrize(dm));
936f9f063d4SToby Isaac   if (computeCanonical) {
937f9f063d4SToby Isaac     PetscInt d, dim;
938f9f063d4SToby Isaac 
939f9f063d4SToby Isaac     /* add the canonical label */
9409566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
9419566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "canonical"));
942f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
943f9f063d4SToby Isaac       PetscInt        p, dStart, dEnd, canon = -1, cNumChildren;
944f9f063d4SToby Isaac       const PetscInt *cChildren;
945f9f063d4SToby Isaac 
9469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
947f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
9489566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, p, &cNumChildren, &cChildren));
949f9f063d4SToby Isaac         if (cNumChildren) {
950f9f063d4SToby Isaac           canon = p;
951f9f063d4SToby Isaac           break;
952f9f063d4SToby Isaac         }
953f9f063d4SToby Isaac       }
954f9f063d4SToby Isaac       if (canon == -1) continue;
955f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
956f9f063d4SToby Isaac         PetscInt        numChildren, i;
957f9f063d4SToby Isaac         const PetscInt *children;
958f9f063d4SToby Isaac 
9599566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, p, &numChildren, &children));
960f9f063d4SToby Isaac         if (numChildren) {
96163a3b9bcSJacob 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);
9629566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "canonical", p, canon));
96348a46eb9SPierre Jolivet           for (i = 0; i < numChildren; i++) PetscCall(DMSetLabelValue(dm, "canonical", children[i], cChildren[i]));
964f9f063d4SToby Isaac         }
965f9f063d4SToby Isaac       }
966f9f063d4SToby Isaac     }
967f9f063d4SToby Isaac   }
9681baa6e33SBarry Smith   if (exchangeSupports) PetscCall(DMPlexTreeExchangeSupports(dm));
969f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
970f7c74593SToby Isaac   /* reset anchors */
9719566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm, NULL, NULL));
9723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
973f9f063d4SToby Isaac }
974f9f063d4SToby Isaac 
9750b7167a0SToby Isaac /*@
9760b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
977aaa8cc7dSPierre Jolivet   the point-to-point constraints determined by the tree: a point is constrained to the points in the closure of its
9780b7167a0SToby Isaac   tree root.
9790b7167a0SToby Isaac 
98020f4b53cSBarry Smith   Collective
9810b7167a0SToby Isaac 
9820b7167a0SToby Isaac   Input Parameters:
983a1cb98faSBarry Smith + dm - the `DMPLEX` object
9840b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
9850b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
9860b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
9870b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
9880b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
9890b7167a0SToby Isaac 
9900b7167a0SToby Isaac   Level: intermediate
9910b7167a0SToby Isaac 
992a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
9930b7167a0SToby Isaac @*/
994d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
995d71ae5a4SJacob Faibussowitsch {
9960b7167a0SToby Isaac   PetscFunctionBegin;
9979566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_FALSE, PETSC_TRUE));
9983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9990b7167a0SToby Isaac }
10000b7167a0SToby Isaac 
1001b2f41788SToby Isaac /*@
1002b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
100320f4b53cSBarry Smith   Collective
1004b2f41788SToby Isaac 
1005f899ff85SJose E. Roman   Input Parameter:
1006a1cb98faSBarry Smith . dm - the `DMPLEX` object
1007b2f41788SToby Isaac 
1008b2f41788SToby Isaac   Output Parameters:
1009b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1010b2f41788SToby Isaac                   offset indexes the parent and childID list
1011b2f41788SToby Isaac . parents - a list of the point parents
1012b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1013b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1014b2f41788SToby Isaac . childSection - the inverse of the parent section
1015b2f41788SToby Isaac - children - a list of the point children
1016b2f41788SToby Isaac 
1017b2f41788SToby Isaac   Level: intermediate
1018b2f41788SToby Isaac 
1019a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`,`DMPlexSetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
1020b2f41788SToby Isaac @*/
1021d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1022d71ae5a4SJacob Faibussowitsch {
1023b2f41788SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
1024b2f41788SToby Isaac 
1025b2f41788SToby Isaac   PetscFunctionBegin;
1026b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1027b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1028b2f41788SToby Isaac   if (parents) *parents = mesh->parents;
1029b2f41788SToby Isaac   if (childIDs) *childIDs = mesh->childIDs;
1030b2f41788SToby Isaac   if (childSection) *childSection = mesh->childSection;
1031b2f41788SToby Isaac   if (children) *children = mesh->children;
10323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1033b2f41788SToby Isaac }
1034b2f41788SToby Isaac 
1035d961a43aSToby Isaac /*@
1036eaf898f9SPatrick Sanan   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)
1037d961a43aSToby Isaac 
1038d961a43aSToby Isaac   Input Parameters:
1039a1cb98faSBarry Smith + dm - the `DMPLEX` object
1040d961a43aSToby Isaac - point - the query point
1041d961a43aSToby Isaac 
1042d961a43aSToby Isaac   Output Parameters:
104320f4b53cSBarry Smith + parent - if not `NULL`, set to the parent of the point, or the point itself if the point does not have a parent
104420f4b53cSBarry Smith - childID - if not `NULL`, set to the child ID of the point with respect to its parent, or 0 if the point
1045d961a43aSToby Isaac             does not have a parent
1046d961a43aSToby Isaac 
1047d961a43aSToby Isaac   Level: intermediate
1048d961a43aSToby Isaac 
1049a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeChildren()`
1050d961a43aSToby Isaac @*/
1051d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1052d71ae5a4SJacob Faibussowitsch {
1053d961a43aSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
1054d961a43aSToby Isaac   PetscSection pSec;
1055d961a43aSToby Isaac 
1056d961a43aSToby Isaac   PetscFunctionBegin;
1057d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1058d961a43aSToby Isaac   pSec = mesh->parentSection;
1059d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1060d961a43aSToby Isaac     PetscInt dof;
1061d961a43aSToby Isaac 
10629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pSec, point, &dof));
1063d961a43aSToby Isaac     if (dof) {
1064d961a43aSToby Isaac       PetscInt off;
1065d961a43aSToby Isaac 
10669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(pSec, point, &off));
1067d961a43aSToby Isaac       if (parent) *parent = mesh->parents[off];
1068d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
10693ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
1070d961a43aSToby Isaac     }
1071d961a43aSToby Isaac   }
1072ad540459SPierre Jolivet   if (parent) *parent = point;
1073ad540459SPierre Jolivet   if (childID) *childID = 0;
10743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1075d961a43aSToby Isaac }
1076d961a43aSToby Isaac 
1077d961a43aSToby Isaac /*@C
1078eaf898f9SPatrick Sanan   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)
1079d961a43aSToby Isaac 
1080d961a43aSToby Isaac   Input Parameters:
1081a1cb98faSBarry Smith + dm - the `DMPLEX` object
1082d961a43aSToby Isaac - point - the query point
1083d961a43aSToby Isaac 
1084d961a43aSToby Isaac   Output Parameters:
108520f4b53cSBarry Smith + numChildren - if not `NULL`, set to the number of children
108620f4b53cSBarry Smith - children - if not `NULL`, set to a list children, or set to `NULL` if the point has no children
1087d961a43aSToby Isaac 
1088d961a43aSToby Isaac   Level: intermediate
1089d961a43aSToby Isaac 
1090a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeParent()`
1091d961a43aSToby Isaac @*/
1092d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1093d71ae5a4SJacob Faibussowitsch {
1094d961a43aSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
1095d961a43aSToby Isaac   PetscSection childSec;
1096d961a43aSToby Isaac   PetscInt     dof = 0;
1097d961a43aSToby Isaac 
1098d961a43aSToby Isaac   PetscFunctionBegin;
1099d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1100d961a43aSToby Isaac   childSec = mesh->childSection;
110148a46eb9SPierre Jolivet   if (childSec && point >= childSec->pStart && point < childSec->pEnd) PetscCall(PetscSectionGetDof(childSec, point, &dof));
1102d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1103d961a43aSToby Isaac   if (children) {
1104d961a43aSToby Isaac     if (dof) {
1105d961a43aSToby Isaac       PetscInt off;
1106d961a43aSToby Isaac 
11079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec, point, &off));
1108d961a43aSToby Isaac       *children = &mesh->children[off];
11099371c9d4SSatish Balay     } else {
1110d961a43aSToby Isaac       *children = NULL;
1111d961a43aSToby Isaac     }
1112d961a43aSToby Isaac   }
11133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1114d961a43aSToby Isaac }
11150c37af3bSToby Isaac 
1116d71ae5a4SJacob Faibussowitsch 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)
1117d71ae5a4SJacob Faibussowitsch {
111852a3aeb4SToby Isaac   PetscInt f, b, p, c, offset, qPoints;
1119b3a4bf2aSToby Isaac 
1120b3a4bf2aSToby Isaac   PetscFunctionBegin;
11219566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(space, nPoints, points, work, NULL, NULL));
112252a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
112352a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
112452a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1125b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1126b3a4bf2aSToby Isaac 
112752a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
1128ad540459SPierre Jolivet         for (c = 0; c < nComps; c++) val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
112952a3aeb4SToby Isaac       }
11309566063dSJacob Faibussowitsch       PetscCall(MatSetValue(basisAtPoints, b, f, val, INSERT_VALUES));
1131b3a4bf2aSToby Isaac     }
1132b3a4bf2aSToby Isaac     offset += qPoints;
1133b3a4bf2aSToby Isaac   }
11349566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(basisAtPoints, MAT_FINAL_ASSEMBLY));
11359566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(basisAtPoints, MAT_FINAL_ASSEMBLY));
11363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1137b3a4bf2aSToby Isaac }
1138b3a4bf2aSToby Isaac 
1139d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
1140d71ae5a4SJacob Faibussowitsch {
11410c37af3bSToby Isaac   PetscDS         ds;
11420c37af3bSToby Isaac   PetscInt        spdim;
11430c37af3bSToby Isaac   PetscInt        numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
11440c37af3bSToby Isaac   const PetscInt *anchors;
1145f7c74593SToby Isaac   PetscSection    aSec;
11460c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
11470c37af3bSToby Isaac   IS              aIS;
11480c37af3bSToby Isaac 
11490c37af3bSToby Isaac   PetscFunctionBegin;
11509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
11519566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
11529566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
11539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
11549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
11559566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
11569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &conStart, &conEnd));
11579566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &spdim));
11589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(spdim, &v0, spdim, &v0parent, spdim, &vtmp, spdim * spdim, &J, spdim * spdim, &Jparent, spdim * spdim, &invJparent));
11590c37af3bSToby Isaac 
11600c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
11610dd1b1feSToby Isaac     PetscObject          disc;
11620dd1b1feSToby Isaac     PetscClassId         id;
1163b3a4bf2aSToby Isaac     PetscSpace           bspace;
1164b3a4bf2aSToby Isaac     PetscDualSpace       dspace;
11659c3cf19fSMatthew G. Knepley     PetscInt             i, j, k, nPoints, Nc, offset;
116652a3aeb4SToby Isaac     PetscInt             fSize, maxDof;
1167b3a4bf2aSToby Isaac     PetscReal           *weights, *pointsRef, *pointsReal, *work;
11681683a169SBarry Smith     PetscScalar         *scwork;
11691683a169SBarry Smith     const PetscScalar   *X;
11702c44ad04SToby Isaac     PetscInt            *sizes, *workIndRow, *workIndCol;
11710c37af3bSToby Isaac     Mat                  Amat, Bmat, Xmat;
11722c44ad04SToby Isaac     const PetscInt      *numDof = NULL;
1173085f0adfSToby Isaac     const PetscInt    ***perms  = NULL;
1174085f0adfSToby Isaac     const PetscScalar ***flips  = NULL;
11750c37af3bSToby Isaac 
11769566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(ds, f, &disc));
11779566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(disc, &id));
11780dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1179b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE)disc;
1180b3a4bf2aSToby Isaac 
11819566063dSJacob Faibussowitsch       PetscCall(PetscFEGetBasisSpace(fe, &bspace));
11829566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(fe, &dspace));
11839566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
11849566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
11859371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
1186b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV)disc;
1187b3a4bf2aSToby Isaac 
11889566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
11899566063dSJacob Faibussowitsch       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)fv), &bspace));
11909566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetType(bspace, PETSCSPACEPOLYNOMIAL));
11919566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetDegree(bspace, 0, PETSC_DETERMINE));
11929566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumComponents(bspace, Nc));
11939566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumVariables(bspace, spdim));
11949566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(bspace));
11959566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &dspace));
11969566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
11979371c9d4SSatish Balay     } else SETERRQ(PetscObjectComm(disc), PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
11989566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetNumDof(dspace, &numDof));
1199ad540459SPierre Jolivet     for (i = 0, maxDof = 0; i <= spdim; i++) maxDof = PetscMax(maxDof, numDof[i]);
12009566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSymmetries(dspace, &perms, &flips));
12010dd1b1feSToby Isaac 
12029566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &Amat));
12039566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Amat, fSize, fSize, fSize, fSize));
12049566063dSJacob Faibussowitsch     PetscCall(MatSetType(Amat, MATSEQDENSE));
12059566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Amat));
12069566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Bmat));
12079566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Xmat));
12080c37af3bSToby Isaac     nPoints = 0;
12090c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
121052a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
12110c37af3bSToby Isaac       PetscQuadrature quad;
12120c37af3bSToby Isaac 
12139566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
12149566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, &thisNc, &qPoints, NULL, NULL));
121563a3b9bcSJacob Faibussowitsch       PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
12160c37af3bSToby Isaac       nPoints += qPoints;
12170c37af3bSToby Isaac     }
12189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(fSize, &sizes, nPoints * Nc, &weights, spdim * nPoints, &pointsRef, spdim * nPoints, &pointsReal, nPoints * fSize * Nc, &work, maxDof, &workIndRow, maxDof, &workIndCol));
12199566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof * maxDof, &scwork));
12200c37af3bSToby Isaac     offset = 0;
12210c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12220c37af3bSToby Isaac       PetscInt         qPoints;
12230c37af3bSToby Isaac       const PetscReal *p, *w;
12240c37af3bSToby Isaac       PetscQuadrature  quad;
12250c37af3bSToby Isaac 
12269566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
12279566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &qPoints, &p, &w));
12289566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(weights + Nc * offset, w, Nc * qPoints));
12299566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pointsRef + spdim * offset, p, spdim * qPoints));
1230b3a4bf2aSToby Isaac       sizes[i] = qPoints;
12310c37af3bSToby Isaac       offset += qPoints;
12320c37af3bSToby Isaac     }
12339566063dSJacob Faibussowitsch     PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsRef, weights, work, Amat));
12349566063dSJacob Faibussowitsch     PetscCall(MatLUFactor(Amat, NULL, NULL, NULL));
12350c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
12360c37af3bSToby Isaac       PetscInt  parent;
12370c37af3bSToby Isaac       PetscInt  closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
12380c37af3bSToby Isaac       PetscInt *childOffsets, *parentOffsets;
12390c37af3bSToby Isaac 
12409566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, c, &parent, NULL));
12410c37af3bSToby Isaac       if (parent == c) continue;
12429566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12430c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12440c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12450c37af3bSToby Isaac         PetscInt conDof;
12460c37af3bSToby Isaac 
12470c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1248085f0adfSToby Isaac         if (numFields) {
12499566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
12509371c9d4SSatish Balay         } else {
12519566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
12520c37af3bSToby Isaac         }
12530c37af3bSToby Isaac         if (conDof) break;
12540c37af3bSToby Isaac       }
12550c37af3bSToby Isaac       if (i == closureSize) {
12569566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12570c37af3bSToby Isaac         continue;
12580c37af3bSToby Isaac       }
12590c37af3bSToby Isaac 
12609566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ));
12619566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent));
12620c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1263c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
1264c330f8ffSToby Isaac 
1265c330f8ffSToby Isaac         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i * spdim], vtmp);
1266c330f8ffSToby Isaac         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i * spdim]);
12670c37af3bSToby Isaac       }
12689566063dSJacob Faibussowitsch       PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsReal, weights, work, Bmat));
12699566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(Amat, Bmat, Xmat));
12709566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Xmat, &X));
12719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
12729566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(closureSize + 1, &childOffsets, closureSizeP + 1, &parentOffsets));
12730c37af3bSToby Isaac       childOffsets[0] = 0;
12740c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12750c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12760c37af3bSToby Isaac         PetscInt dof;
12770c37af3bSToby Isaac 
1278085f0adfSToby Isaac         if (numFields) {
12799566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12809371c9d4SSatish Balay         } else {
12819566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12820c37af3bSToby Isaac         }
128352a3aeb4SToby Isaac         childOffsets[i + 1] = childOffsets[i] + dof;
12840c37af3bSToby Isaac       }
12850c37af3bSToby Isaac       parentOffsets[0] = 0;
12860c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
12870c37af3bSToby Isaac         PetscInt p = closureP[2 * i];
12880c37af3bSToby Isaac         PetscInt dof;
12890c37af3bSToby Isaac 
1290085f0adfSToby Isaac         if (numFields) {
12919566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12929371c9d4SSatish Balay         } else {
12939566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12940c37af3bSToby Isaac         }
129552a3aeb4SToby Isaac         parentOffsets[i + 1] = parentOffsets[i] + dof;
12960c37af3bSToby Isaac       }
12970c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12982c44ad04SToby Isaac         PetscInt           conDof, conOff, aDof, aOff, nWork;
12990c37af3bSToby Isaac         PetscInt           p = closure[2 * i];
13000c37af3bSToby Isaac         PetscInt           o = closure[2 * i + 1];
1301085f0adfSToby Isaac         const PetscInt    *perm;
1302085f0adfSToby Isaac         const PetscScalar *flip;
13030c37af3bSToby Isaac 
13040c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1305085f0adfSToby Isaac         if (numFields) {
13069566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
13079566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &conOff));
13089371c9d4SSatish Balay         } else {
13099566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
13109566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(cSec, p, &conOff));
13110c37af3bSToby Isaac         }
13120c37af3bSToby Isaac         if (!conDof) continue;
1313085f0adfSToby Isaac         perm = (perms && perms[i]) ? perms[i][o] : NULL;
1314085f0adfSToby Isaac         flip = (flips && flips[i]) ? flips[i][o] : NULL;
13159566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
13169566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
13172c44ad04SToby Isaac         nWork = childOffsets[i + 1] - childOffsets[i];
13180c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
13190c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
13200c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
13210c37af3bSToby Isaac 
1322085f0adfSToby Isaac           if (numFields) {
13239566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aSecDof));
13249566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aSecOff));
13259371c9d4SSatish Balay           } else {
13269566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, a, &aSecDof));
13279566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, a, &aSecOff));
13280c37af3bSToby Isaac           }
13290c37af3bSToby Isaac           if (!aSecDof) continue;
13300c37af3bSToby Isaac 
13310c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
13320c37af3bSToby Isaac             PetscInt q  = closureP[2 * j];
13330c37af3bSToby Isaac             PetscInt oq = closureP[2 * j + 1];
13342c44ad04SToby Isaac 
13352c44ad04SToby Isaac             if (q == a) {
133652a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1337085f0adfSToby Isaac               const PetscInt    *permP;
1338085f0adfSToby Isaac               const PetscScalar *flipP;
1339085f0adfSToby Isaac 
1340085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1341085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
13422c44ad04SToby Isaac               nWorkP = parentOffsets[j + 1] - parentOffsets[j];
13432c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
13441683a169SBarry Smith                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
13452c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
13462c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
1347ad540459SPierre Jolivet                 for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
13482c44ad04SToby Isaac               }
1349ad540459SPierre Jolivet               for (r = 0; r < nWork; r++) workIndRow[perm ? perm[r] : r] = conOff + r;
1350ad540459SPierre Jolivet               for (s = 0; s < nWorkP; s++) workIndCol[permP ? permP[s] : s] = aSecOff + s;
13512c44ad04SToby Isaac               if (flip) {
13522c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1353ad540459SPierre Jolivet                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flip[r];
13542c44ad04SToby Isaac                 }
13552c44ad04SToby Isaac               }
13562c44ad04SToby Isaac               if (flipP) {
13572c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1358ad540459SPierre Jolivet                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flipP[s];
13592c44ad04SToby Isaac                 }
13602c44ad04SToby Isaac               }
13619566063dSJacob Faibussowitsch               PetscCall(MatSetValues(cMat, nWork, workIndRow, nWorkP, workIndCol, scwork, INSERT_VALUES));
13622c44ad04SToby Isaac               break;
13630c37af3bSToby Isaac             }
13640c37af3bSToby Isaac           }
13650c37af3bSToby Isaac         }
13660c37af3bSToby Isaac       }
13679566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Xmat, &X));
13689566063dSJacob Faibussowitsch       PetscCall(PetscFree2(childOffsets, parentOffsets));
13699566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
13709566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
13710c37af3bSToby Isaac     }
13729566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Amat));
13739566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Bmat));
13749566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Xmat));
13759566063dSJacob Faibussowitsch     PetscCall(PetscFree(scwork));
13769566063dSJacob Faibussowitsch     PetscCall(PetscFree7(sizes, weights, pointsRef, pointsReal, work, workIndRow, workIndCol));
137748a46eb9SPierre Jolivet     if (id == PETSCFV_CLASSID) PetscCall(PetscSpaceDestroy(&bspace));
13780c37af3bSToby Isaac   }
13799566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
13809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
13819566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJparent));
13829566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
13830c37af3bSToby Isaac 
13843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13850c37af3bSToby Isaac }
138695a0b26dSToby Isaac 
1387d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1388d71ae5a4SJacob Faibussowitsch {
1389f7c74593SToby Isaac   Mat                 refCmat;
139021968bf8SToby Isaac   PetscDS             ds;
1391085f0adfSToby Isaac   PetscInt            numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
139221968bf8SToby Isaac   PetscScalar      ***refPointFieldMats;
139321968bf8SToby Isaac   PetscSection        refConSec, refAnSec, refSection;
139421968bf8SToby Isaac   IS                  refAnIS;
139521968bf8SToby Isaac   const PetscInt     *refAnchors;
1396085f0adfSToby Isaac   const PetscInt    **perms;
1397085f0adfSToby Isaac   const PetscScalar **flips;
139895a0b26dSToby Isaac 
139995a0b26dSToby Isaac   PetscFunctionBegin;
14009566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
14019566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1402085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
14039566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
14049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
14059566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(refAnIS, &refAnchors));
14069566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
14079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
14089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
14099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldN));
14109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
14119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
14129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
14139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxAnDof, &cols));
141495a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
141595a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
141695a0b26dSToby Isaac 
14179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
14189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
141995a0b26dSToby Isaac     if (!pDof || parent == p) continue;
142095a0b26dSToby Isaac 
14219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxFields, &refPointFieldMats[p - pRefStart]));
14229566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(maxFields, &refPointFieldN[p - pRefStart]));
14239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
1424085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1425085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
142695a0b26dSToby Isaac 
1427085f0adfSToby Isaac       if (f < numFields) {
14289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
14299566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
14309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1431085f0adfSToby Isaac       } else {
14329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
14339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
14349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetPointSyms(refSection, closureSize, closure, &perms, &flips));
143595a0b26dSToby Isaac       }
143695a0b26dSToby Isaac 
1437ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
143895a0b26dSToby Isaac       numCols = 0;
143995a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
144095a0b26dSToby Isaac         PetscInt        q = closure[2 * i];
144195a0b26dSToby Isaac         PetscInt        aDof, aOff, j;
1442085f0adfSToby Isaac         const PetscInt *perm = perms ? perms[i] : NULL;
144395a0b26dSToby Isaac 
1444085f0adfSToby Isaac         if (numFields) {
14459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14469566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14479371c9d4SSatish Balay         } else {
14489566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14499566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
145095a0b26dSToby Isaac         }
145195a0b26dSToby Isaac 
1452ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + (perm ? perm[j] : j);
145395a0b26dSToby Isaac       }
145495a0b26dSToby Isaac       refPointFieldN[p - pRefStart][f] = numCols;
14559566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
14569566063dSJacob Faibussowitsch       PetscCall(MatGetValues(refCmat, cDof, rows, numCols, cols, refPointFieldMats[p - pRefStart][f]));
1457085f0adfSToby Isaac       if (flips) {
1458085f0adfSToby Isaac         PetscInt colOff = 0;
1459085f0adfSToby Isaac 
1460085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1461085f0adfSToby Isaac           PetscInt           q = closure[2 * i];
1462085f0adfSToby Isaac           PetscInt           aDof, aOff, j;
1463085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1464085f0adfSToby Isaac 
1465085f0adfSToby Isaac           if (numFields) {
14669566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14679566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14689371c9d4SSatish Balay           } else {
14699566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14709566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
1471085f0adfSToby Isaac           }
1472085f0adfSToby Isaac           if (flip) {
1473085f0adfSToby Isaac             PetscInt k;
1474085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1475ad540459SPierre Jolivet               for (j = 0; j < aDof; j++) refPointFieldMats[p - pRefStart][f][k * numCols + colOff + j] *= flip[j];
1476085f0adfSToby Isaac             }
1477085f0adfSToby Isaac           }
1478085f0adfSToby Isaac           colOff += aDof;
1479085f0adfSToby Isaac         }
1480085f0adfSToby Isaac       }
1481085f0adfSToby Isaac       if (numFields) {
14829566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestoreFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1483085f0adfSToby Isaac       } else {
14849566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestorePointSyms(refSection, closureSize, closure, &perms, &flips));
1485085f0adfSToby Isaac       }
148695a0b26dSToby Isaac     }
14879566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
148895a0b26dSToby Isaac   }
148921968bf8SToby Isaac   *childrenMats = refPointFieldMats;
149021968bf8SToby Isaac   *childrenN    = refPointFieldN;
14919566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(refAnIS, &refAnchors));
14929566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
14939566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
14943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
149521968bf8SToby Isaac }
149621968bf8SToby Isaac 
1497d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1498d71ae5a4SJacob Faibussowitsch {
149921968bf8SToby Isaac   PetscDS        ds;
150021968bf8SToby Isaac   PetscInt     **refPointFieldN;
150121968bf8SToby Isaac   PetscScalar ***refPointFieldMats;
1502085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
150321968bf8SToby Isaac   PetscSection   refConSec;
150421968bf8SToby Isaac 
150521968bf8SToby Isaac   PetscFunctionBegin;
150621968bf8SToby Isaac   refPointFieldN    = *childrenN;
150721968bf8SToby Isaac   *childrenN        = NULL;
150821968bf8SToby Isaac   refPointFieldMats = *childrenMats;
150921968bf8SToby Isaac   *childrenMats     = NULL;
15109566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
15119566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1512367003a6SStefano Zampini   maxFields = PetscMax(1, numFields);
15139566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
15149566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
151521968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
151621968bf8SToby Isaac     PetscInt parent, pDof;
151721968bf8SToby Isaac 
15189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
15199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
152021968bf8SToby Isaac     if (!pDof || parent == p) continue;
152121968bf8SToby Isaac 
1522085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
152321968bf8SToby Isaac       PetscInt cDof;
152421968bf8SToby Isaac 
1525085f0adfSToby Isaac       if (numFields) {
15269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
15279371c9d4SSatish Balay       } else {
15289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
152921968bf8SToby Isaac       }
153021968bf8SToby Isaac 
15319566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
153221968bf8SToby Isaac     }
15339566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
15349566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldN[p - pRefStart]));
153521968bf8SToby Isaac   }
15369566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
15379566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldN));
15383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153921968bf8SToby Isaac }
154021968bf8SToby Isaac 
1541d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
1542d71ae5a4SJacob Faibussowitsch {
154321968bf8SToby Isaac   DM              refTree;
154421968bf8SToby Isaac   PetscDS         ds;
154521968bf8SToby Isaac   Mat             refCmat;
1546085f0adfSToby Isaac   PetscInt        numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
154721968bf8SToby Isaac   PetscScalar  ***refPointFieldMats, *pointWork;
154821968bf8SToby Isaac   PetscSection    refConSec, refAnSec, anSec;
154921968bf8SToby Isaac   IS              refAnIS, anIS;
155021968bf8SToby Isaac   const PetscInt *anchors;
155121968bf8SToby Isaac 
155221968bf8SToby Isaac   PetscFunctionBegin;
155321968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
15549566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
15559566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1556085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
15579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
15589566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, refTree));
1559*c77c71ffSToby Isaac   PetscCall(DMSetLocalSection(refTree, NULL));
1560*c77c71ffSToby Isaac   PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
15619566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
15629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
15639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anSec, &anIS));
15649566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(anIS, &anchors));
15659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
15669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(conSec, &conStart, &conEnd));
15679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
15689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
15699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof * maxAnDof, &pointWork));
157021968bf8SToby Isaac 
157121968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
15729566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
157395a0b26dSToby Isaac 
157495a0b26dSToby Isaac   /* step 2: compute the preorder */
15759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
15769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(pEnd - pStart, &perm, pEnd - pStart, &iperm));
157795a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
157895a0b26dSToby Isaac     perm[p - pStart]  = p;
157995a0b26dSToby Isaac     iperm[p - pStart] = p - pStart;
158095a0b26dSToby Isaac   }
158195a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
158295a0b26dSToby Isaac     PetscInt point = perm[p];
158395a0b26dSToby Isaac     PetscInt parent;
158495a0b26dSToby Isaac 
15859566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
158695a0b26dSToby Isaac     if (parent == point) {
158795a0b26dSToby Isaac       p++;
15889371c9d4SSatish Balay     } else {
158995a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
159095a0b26dSToby Isaac 
15919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
159295a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
159395a0b26dSToby Isaac         PetscInt q = closure[2 * i];
159495a0b26dSToby Isaac         if (iperm[q - pStart] > iperm[point - pStart]) {
159595a0b26dSToby Isaac           /* swap */
159695a0b26dSToby Isaac           perm[p]                 = q;
159795a0b26dSToby Isaac           perm[iperm[q - pStart]] = point;
159895a0b26dSToby Isaac           iperm[point - pStart]   = iperm[q - pStart];
159995a0b26dSToby Isaac           iperm[q - pStart]       = p;
160095a0b26dSToby Isaac           break;
160195a0b26dSToby Isaac         }
160295a0b26dSToby Isaac       }
160395a0b26dSToby Isaac       size = closureSize;
16049566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1605ad540459SPierre Jolivet       if (i == size) p++;
160695a0b26dSToby Isaac     }
160795a0b26dSToby Isaac   }
160895a0b26dSToby Isaac 
160995a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
161095a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
161195a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
161295a0b26dSToby Isaac    * values outside of the Mat first.
161395a0b26dSToby Isaac    */
161495a0b26dSToby Isaac   {
161595a0b26dSToby Isaac     PetscInt        nRows, row, nnz;
161695a0b26dSToby Isaac     PetscBool       done;
1617cd6fc93eSToby Isaac     PetscInt        secStart, secEnd;
161895a0b26dSToby Isaac     const PetscInt *ia, *ja;
161995a0b26dSToby Isaac     PetscScalar    *vals;
162095a0b26dSToby Isaac 
1621cd6fc93eSToby Isaac     PetscCall(PetscSectionGetChart(section, &secStart, &secEnd));
16229566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
162328b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not get RowIJ of constraint matrix");
162495a0b26dSToby Isaac     nnz = ia[nRows];
162595a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
162695a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
16279566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vals));
162895a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
162995a0b26dSToby Isaac       PetscInt parent, childid, closureSize, *closure = NULL;
163095a0b26dSToby Isaac       PetscInt point = perm[p], pointDof;
163195a0b26dSToby Isaac 
16329566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, point, &parent, &childid));
163395a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
16349566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(conSec, point, &pointDof));
163595a0b26dSToby Isaac       if (!pointDof) continue;
16369566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1637085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1638085f0adfSToby Isaac         PetscInt            cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
163995a0b26dSToby Isaac         PetscScalar        *pointMat;
1640085f0adfSToby Isaac         const PetscInt    **perms;
1641085f0adfSToby Isaac         const PetscScalar **flips;
164295a0b26dSToby Isaac 
1643085f0adfSToby Isaac         if (numFields) {
16449566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(conSec, point, f, &cDof));
16459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(conSec, point, f, &cOff));
16469371c9d4SSatish Balay         } else {
16479566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(conSec, point, &cDof));
16489566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(conSec, point, &cOff));
164995a0b26dSToby Isaac         }
165095a0b26dSToby Isaac         if (!cDof) continue;
16519566063dSJacob Faibussowitsch         if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
16529566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetPointSyms(section, closureSize, closure, &perms, &flips));
165395a0b26dSToby Isaac 
165495a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
165576bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
165695a0b26dSToby Isaac           for (r = 0; r < cDof; r++) {
165795a0b26dSToby Isaac             if (cDof > 1 && r) {
165863a3b9bcSJacob 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]));
165995a0b26dSToby Isaac             }
166095a0b26dSToby Isaac           }
166176bd3646SJed Brown         }
166295a0b26dSToby Isaac         /* zero rows */
1663ad540459SPierre Jolivet         for (i = ia[cOff]; i < ia[cOff + cDof]; i++) vals[i] = 0.;
166495a0b26dSToby Isaac         matOffset   = ia[cOff];
166595a0b26dSToby Isaac         numFillCols = ia[cOff + 1] - matOffset;
166695a0b26dSToby Isaac         pointMat    = refPointFieldMats[childid - pRefStart][f];
166795a0b26dSToby Isaac         numCols     = refPointFieldN[childid - pRefStart][f];
166895a0b26dSToby Isaac         offset      = 0;
166995a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
167095a0b26dSToby Isaac           PetscInt           q = closure[2 * i];
167195a0b26dSToby Isaac           PetscInt           aDof, aOff, j, k, qConDof, qConOff;
1672085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1673085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
167495a0b26dSToby Isaac 
167595a0b26dSToby Isaac           qConDof = qConOff = 0;
1676cd6fc93eSToby Isaac           if (q < secStart || q >= secEnd) continue;
1677085f0adfSToby Isaac           if (numFields) {
16789566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, q, f, &aDof));
16799566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, q, f, &aOff));
168095a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16819566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(conSec, q, f, &qConDof));
16829566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldOffset(conSec, q, f, &qConOff));
168395a0b26dSToby Isaac             }
16849371c9d4SSatish Balay           } else {
16859566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, q, &aDof));
16869566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, q, &aOff));
168795a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16889566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(conSec, q, &qConDof));
16899566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(conSec, q, &qConOff));
169095a0b26dSToby Isaac             }
169195a0b26dSToby Isaac           }
169295a0b26dSToby Isaac           if (!aDof) continue;
169395a0b26dSToby Isaac           if (qConDof) {
169495a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
169595a0b26dSToby Isaac              * be filled, thanks to preordering */
169695a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
169795a0b26dSToby Isaac             PetscInt aMatOffset   = ia[qConOff];
169895a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
169995a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
170095a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
170195a0b26dSToby Isaac                 PetscScalar inVal = 0;
170295a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1703085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
170495a0b26dSToby Isaac 
1705085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
170695a0b26dSToby Isaac                 }
170795a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
170895a0b26dSToby Isaac               }
170995a0b26dSToby Isaac             }
171095a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
171195a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
171295a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
171395a0b26dSToby Isaac               for (; k < numFillCols; k++) {
1714ad540459SPierre Jolivet                 if (ja[matOffset + k] == col) break;
171595a0b26dSToby Isaac               }
171663a3b9bcSJacob Faibussowitsch               PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, col);
1717ad540459SPierre Jolivet               for (r = 0; r < cDof; r++) vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
171895a0b26dSToby Isaac             }
17199371c9d4SSatish Balay           } else {
172095a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
172195a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
1722ad540459SPierre Jolivet               if (ja[matOffset + k] == aOff) break;
172395a0b26dSToby Isaac             }
172463a3b9bcSJacob Faibussowitsch             PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, aOff);
172595a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1726085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1727085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1728085f0adfSToby Isaac 
1729085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
173095a0b26dSToby Isaac               }
173195a0b26dSToby Isaac             }
173295a0b26dSToby Isaac           }
173395a0b26dSToby Isaac           offset += aDof;
173495a0b26dSToby Isaac         }
1735085f0adfSToby Isaac         if (numFields) {
17369566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestoreFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
1737085f0adfSToby Isaac         } else {
17389566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestorePointSyms(section, closureSize, closure, &perms, &flips));
1739085f0adfSToby Isaac         }
174095a0b26dSToby Isaac       }
17419566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
174295a0b26dSToby Isaac     }
174348a46eb9SPierre Jolivet     for (row = 0; row < nRows; row++) PetscCall(MatSetValues(cMat, 1, &row, ia[row + 1] - ia[row], &ja[ia[row]], &vals[ia[row]], INSERT_VALUES));
17449566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
174528b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not restore RowIJ of constraint matrix");
17469566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
17479566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
17489566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
174995a0b26dSToby Isaac   }
175095a0b26dSToby Isaac 
175195a0b26dSToby Isaac   /* clean up */
17529566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(anIS, &anchors));
17539566063dSJacob Faibussowitsch   PetscCall(PetscFree2(perm, iperm));
17549566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointWork));
17559566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
17563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
175795a0b26dSToby Isaac }
175895a0b26dSToby Isaac 
17596f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
17606f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
1761d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTreeRefineCell(DM dm, PetscInt cell, DM *ncdm)
1762d71ae5a4SJacob Faibussowitsch {
17636f5f1567SToby Isaac   DM           K;
1764420f55faSMatthew G. Knepley   PetscMPIInt  rank;
17656f5f1567SToby Isaac   PetscInt     dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
17666f5f1567SToby Isaac   PetscInt     numNewCones, *newConeSizes, *newCones, *newOrientations;
17676f5f1567SToby Isaac   PetscInt    *Kembedding;
17686f5f1567SToby Isaac   PetscInt    *cellClosure = NULL, nc;
17696f5f1567SToby Isaac   PetscScalar *newVertexCoords;
17706f5f1567SToby Isaac   PetscInt     numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
17716f5f1567SToby Isaac   PetscSection parentSection;
17726f5f1567SToby Isaac 
17736f5f1567SToby Isaac   PetscFunctionBegin;
17749566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
17759566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
17769566063dSJacob Faibussowitsch   PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
17779566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ncdm, dim));
17786f5f1567SToby Isaac 
17799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
17809566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &parentSection));
17819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &K));
17826858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
1783dd400576SPatrick Sanan   if (rank == 0) {
17846f5f1567SToby Isaac     /* compute the new charts */
17859566063dSJacob Faibussowitsch     PetscCall(PetscMalloc5(dim + 1, &pNewCount, dim + 1, &pNewStart, dim + 1, &pNewEnd, dim + 1, &pOldStart, dim + 1, &pOldEnd));
17866f5f1567SToby Isaac     offset = 0;
17876f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
17886f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
17896f5f1567SToby Isaac 
17906f5f1567SToby Isaac       pNewStart[d] = offset;
17919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, d, &pOldStart[d], &pOldEnd[d]));
17929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
17936f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
17946f5f1567SToby Isaac       /* adding the new points */
17956f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
17966f5f1567SToby Isaac       if (!d) {
17976f5f1567SToby Isaac         /* removing the cell */
17986f5f1567SToby Isaac         pNewCount[d]--;
17996f5f1567SToby Isaac       }
18006f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18016f5f1567SToby Isaac         PetscInt parent;
18029566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &parent, NULL));
18036f5f1567SToby Isaac         if (parent == k) {
18046f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
18056f5f1567SToby Isaac           pNewCount[d]--;
18066f5f1567SToby Isaac         }
18076f5f1567SToby Isaac       }
18086f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
18096f5f1567SToby Isaac       offset     = pNewEnd[d];
18106f5f1567SToby Isaac     }
18111dca8a05SBarry 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]);
18126f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
18139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
18146f5f1567SToby Isaac 
18159566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pNewEnd[dim], &newConeSizes));
18166f5f1567SToby Isaac     {
1817b5a892a1SMatthew G. Knepley       DMPolytopeType pct, qct;
18186f5f1567SToby Isaac       PetscInt       kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
18196f5f1567SToby Isaac 
18209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetChart(K, &kStart, &kEnd));
18219566063dSJacob Faibussowitsch       PetscCall(PetscMalloc4(kEnd - kStart, &Kembedding, kEnd - kStart, &perm, kEnd - kStart, &iperm, kEnd - kStart, &preOrient));
18226f5f1567SToby Isaac 
18236f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18246f5f1567SToby Isaac         perm[k - kStart]      = k;
18256f5f1567SToby Isaac         iperm[k - kStart]     = k - kStart;
18266f5f1567SToby Isaac         preOrient[k - kStart] = 0;
18276f5f1567SToby Isaac       }
18286f5f1567SToby Isaac 
18299566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18306f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
18316f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2 * j + 1];
18326f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2 * j + 1];
18336f5f1567SToby Isaac         PetscInt p, q;
18346f5f1567SToby Isaac 
18356f5f1567SToby Isaac         p = closureK[2 * j];
18366f5f1567SToby Isaac         q = cellClosure[2 * j];
18379566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(K, p, &pct));
18389566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, q, &qct));
18396f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
1840ad540459SPierre Jolivet           if (q >= pOldStart[d] && q < pOldEnd[d]) Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
18416f5f1567SToby Isaac         }
1842b5a892a1SMatthew G. Knepley         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1843b5a892a1SMatthew G. Knepley         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
18446f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
18456f5f1567SToby Isaac           PetscInt        numChildren, i;
18466f5f1567SToby Isaac           const PetscInt *children;
18476f5f1567SToby Isaac 
18489566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(K, p, &numChildren, &children));
18496f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
18506f5f1567SToby Isaac             PetscInt kPerm, oPerm;
18516f5f1567SToby Isaac 
18526f5f1567SToby Isaac             k = children[i];
18539566063dSJacob Faibussowitsch             PetscCall(DMPlexReferenceTreeGetChildSymmetry(K, p, parentOrientA, 0, k, parentOrientB, &oPerm, &kPerm));
18546f5f1567SToby Isaac             /* perm = what refTree position I'm in */
18556f5f1567SToby Isaac             perm[kPerm - kStart] = k;
18566f5f1567SToby Isaac             /* iperm = who is at this position */
18576f5f1567SToby Isaac             iperm[k - kStart]         = kPerm - kStart;
18586f5f1567SToby Isaac             preOrient[kPerm - kStart] = oPerm;
18596f5f1567SToby Isaac           }
18606f5f1567SToby Isaac         }
18616f5f1567SToby Isaac       }
18629566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18636f5f1567SToby Isaac     }
18649566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, 0, pNewEnd[dim]));
18656f5f1567SToby Isaac     offset      = 0;
18666f5f1567SToby Isaac     numNewCones = 0;
18676f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18686f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
18696f5f1567SToby Isaac       PetscInt p;
18706f5f1567SToby Isaac       PetscInt size;
18716f5f1567SToby Isaac 
18726f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
18736f5f1567SToby Isaac         /* skip cell 0 */
18746f5f1567SToby Isaac         if (p == cell) continue;
18756f5f1567SToby Isaac         /* old cones to new cones */
18769566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
18776f5f1567SToby Isaac         newConeSizes[offset++] = size;
18786f5f1567SToby Isaac         numNewCones += size;
18796f5f1567SToby Isaac       }
18806f5f1567SToby Isaac 
18819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
18826f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18836f5f1567SToby Isaac         PetscInt kParent;
18846f5f1567SToby Isaac 
18859566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
18866f5f1567SToby Isaac         if (kParent != k) {
18876f5f1567SToby Isaac           Kembedding[k] = offset;
18889566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
18896f5f1567SToby Isaac           newConeSizes[offset++] = size;
18906f5f1567SToby Isaac           numNewCones += size;
189148a46eb9SPierre Jolivet           if (kParent != 0) PetscCall(PetscSectionSetDof(parentSection, Kembedding[k], 1));
18926f5f1567SToby Isaac         }
18936f5f1567SToby Isaac       }
18946f5f1567SToby Isaac     }
18956f5f1567SToby Isaac 
18969566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
18979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(parentSection, &numPointsWithParents));
18989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numNewCones, &newCones, numNewCones, &newOrientations));
18999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPointsWithParents, &parents, numPointsWithParents, &childIDs));
19006f5f1567SToby Isaac 
19016f5f1567SToby Isaac     /* fill new cones */
19026f5f1567SToby Isaac     offset = 0;
19036f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19046f5f1567SToby Isaac       PetscInt        kStart, kEnd, k, l;
19056f5f1567SToby Isaac       PetscInt        p;
19066f5f1567SToby Isaac       PetscInt        size;
19076f5f1567SToby Isaac       const PetscInt *cone, *orientation;
19086f5f1567SToby Isaac 
19096f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19106f5f1567SToby Isaac         /* skip cell 0 */
19116f5f1567SToby Isaac         if (p == cell) continue;
19126f5f1567SToby Isaac         /* old cones to new cones */
19139566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
19149566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
19159566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeOrientation(dm, p, &orientation));
19166f5f1567SToby Isaac         for (l = 0; l < size; l++) {
19176f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
19186f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
19196f5f1567SToby Isaac         }
19206f5f1567SToby Isaac       }
19216f5f1567SToby Isaac 
19229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
19236f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19246f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
19256f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
19266f5f1567SToby Isaac 
19279566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
19286f5f1567SToby Isaac         if (kParent != k) {
19296f5f1567SToby Isaac           /* embed new cones */
19309566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
19319566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(K, kPerm, &cone));
19329566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeOrientation(K, kPerm, &orientation));
19336f5f1567SToby Isaac           for (l = 0; l < size; l++) {
19346f5f1567SToby Isaac             PetscInt       q, m = (preO >= 0) ? ((preO + l) % size) : ((size - (preO + 1) - l) % size);
19356f5f1567SToby Isaac             PetscInt       newO, lSize, oTrue;
1936b5a892a1SMatthew G. Knepley             DMPolytopeType ct = DM_NUM_POLYTOPES;
19376f5f1567SToby Isaac 
19386f5f1567SToby Isaac             q                = iperm[cone[m]];
19396f5f1567SToby Isaac             newCones[offset] = Kembedding[q];
19409566063dSJacob Faibussowitsch             PetscCall(DMPlexGetConeSize(K, q, &lSize));
1941b5a892a1SMatthew G. Knepley             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
1942b5a892a1SMatthew G. Knepley             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
1943b5a892a1SMatthew G. Knepley             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
19446f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
19456f5f1567SToby Isaac             newO                      = DihedralCompose(lSize, oTrue, preOrient[q]);
1946b5a892a1SMatthew G. Knepley             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
19476f5f1567SToby Isaac           }
19486f5f1567SToby Isaac           if (kParent != 0) {
19496f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
19509566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(parentSection, Kembedding[k], &pOffset));
19516f5f1567SToby Isaac             parents[pOffset]  = newPoint;
19526f5f1567SToby Isaac             childIDs[pOffset] = k;
19536f5f1567SToby Isaac           }
19546f5f1567SToby Isaac         }
19556f5f1567SToby Isaac       }
19566f5f1567SToby Isaac     }
19576f5f1567SToby Isaac 
19589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(dim * (pNewEnd[dim] - pNewStart[dim]), &newVertexCoords));
19596f5f1567SToby Isaac 
19606f5f1567SToby Isaac     /* fill coordinates */
19616f5f1567SToby Isaac     offset = 0;
19626f5f1567SToby Isaac     {
1963d90620a3SMatthew G. Knepley       PetscInt     kStart, kEnd, l;
19646f5f1567SToby Isaac       PetscSection vSection;
19656f5f1567SToby Isaac       PetscInt     v;
19666f5f1567SToby Isaac       Vec          coords;
19676f5f1567SToby Isaac       PetscScalar *coordvals;
19686f5f1567SToby Isaac       PetscInt     dof, off;
1969c111c6b7SMatthew G. Knepley       PetscReal    v0[3], J[9], detJ;
19706f5f1567SToby Isaac 
197176bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
1972d90620a3SMatthew G. Knepley         PetscInt k;
19739566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(K, 0, &kStart, &kEnd));
19746f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
19759566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
197663a3b9bcSJacob Faibussowitsch           PetscCheck(detJ > 0., PETSC_COMM_SELF, PETSC_ERR_PLIB, "reference tree cell %" PetscInt_FMT " has bad determinant", k);
19776f5f1567SToby Isaac         }
1978d90620a3SMatthew G. Knepley       }
19799566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
19809566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &vSection));
19819566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coords));
19829566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19836f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
19849566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(vSection, v, &dof));
19859566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(vSection, v, &off));
1986ad540459SPierre Jolivet         for (l = 0; l < dof; l++) newVertexCoords[offset++] = coordvals[off + l];
19876f5f1567SToby Isaac       }
19889566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
19896f5f1567SToby Isaac 
19909566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(K, &vSection));
19919566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(K, &coords));
19929566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(K, 0, &kStart, &kEnd));
19946f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
19959bc368c7SMatthew G. Knepley         PetscReal       coord[3], newCoord[3];
19966f5f1567SToby Isaac         PetscInt        vPerm = perm[v];
19976f5f1567SToby Isaac         PetscInt        kParent;
1998c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
19996f5f1567SToby Isaac 
20009566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, v, &kParent, NULL));
20016f5f1567SToby Isaac         if (kParent != v) {
20026f5f1567SToby Isaac           /* this is a new vertex */
20039566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(vSection, vPerm, &off));
20049bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off + l]);
2005367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
20069bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset + l] = newCoord[l];
20076f5f1567SToby Isaac           offset += dim;
20086f5f1567SToby Isaac         }
20096f5f1567SToby Isaac       }
20109566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
20116f5f1567SToby Isaac     }
20126f5f1567SToby Isaac 
20136f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
20146f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
20156f5f1567SToby Isaac       PetscInt tmp;
20166f5f1567SToby Isaac 
20176f5f1567SToby Isaac       tmp                = pNewCount[d];
20186f5f1567SToby Isaac       pNewCount[d]       = pNewCount[dim - d];
20196f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
20206f5f1567SToby Isaac     }
20216f5f1567SToby Isaac 
20229566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, pNewCount, newConeSizes, newCones, newOrientations, newVertexCoords));
20239566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20249566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, parents, childIDs));
20256f5f1567SToby Isaac 
20266f5f1567SToby Isaac     /* clean up */
20279566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
20289566063dSJacob Faibussowitsch     PetscCall(PetscFree5(pNewCount, pNewStart, pNewEnd, pOldStart, pOldEnd));
20299566063dSJacob Faibussowitsch     PetscCall(PetscFree(newConeSizes));
20309566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCones, newOrientations));
20319566063dSJacob Faibussowitsch     PetscCall(PetscFree(newVertexCoords));
20329566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parents, childIDs));
20339566063dSJacob Faibussowitsch     PetscCall(PetscFree4(Kembedding, perm, iperm, preOrient));
20349371c9d4SSatish Balay   } else {
20356f5f1567SToby Isaac     PetscInt     p, counts[4];
20366f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
20376f5f1567SToby Isaac     Vec          coordVec;
20386f5f1567SToby Isaac     PetscScalar *coords;
20396f5f1567SToby Isaac 
20406f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20416f5f1567SToby Isaac       PetscInt dStart, dEnd;
20426f5f1567SToby Isaac 
20439566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
20446f5f1567SToby Isaac       counts[d] = dEnd - dStart;
20456f5f1567SToby Isaac     }
20469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEnd - pStart, &coneSizes));
204748a46eb9SPierre Jolivet     for (p = pStart; p < pEnd; p++) PetscCall(DMPlexGetConeSize(dm, p, &coneSizes[p - pStart]));
20489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCones(dm, &cones));
20499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientations(dm, &orientations));
20509566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordVec));
20519566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordVec, &coords));
20526f5f1567SToby Isaac 
20539566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
20549566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
20559566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, counts, coneSizes, cones, orientations, NULL));
20569566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20579566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, NULL, NULL));
20589566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordVec, &coords));
20596f5f1567SToby Isaac   }
20609566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
20616f5f1567SToby Isaac 
20623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20636f5f1567SToby Isaac }
20646ecaa68aSToby Isaac 
2065d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
2066d71ae5a4SJacob Faibussowitsch {
20676ecaa68aSToby Isaac   PetscSF              coarseToFineEmbedded;
20686ecaa68aSToby Isaac   PetscSection         globalCoarse, globalFine;
20696ecaa68aSToby Isaac   PetscSection         localCoarse, localFine;
20706ecaa68aSToby Isaac   PetscSection         aSec, cSec;
20716ecaa68aSToby Isaac   PetscSection         rootIndicesSec, rootMatricesSec;
207246bdb399SToby Isaac   PetscSection         leafIndicesSec, leafMatricesSec;
207346bdb399SToby Isaac   PetscInt            *rootIndices, *leafIndices;
207446bdb399SToby Isaac   PetscScalar         *rootMatrices, *leafMatrices;
20756ecaa68aSToby Isaac   IS                   aIS;
20766ecaa68aSToby Isaac   const PetscInt      *anchors;
20776ecaa68aSToby Isaac   Mat                  cMat;
20784acb8e1eSToby Isaac   PetscInt             numFields, maxFields;
20796ecaa68aSToby Isaac   PetscInt             pStartC, pEndC, pStartF, pEndF, p;
20806ecaa68aSToby Isaac   PetscInt             aStart, aEnd, cStart, cEnd;
20811c58ffc4SToby Isaac   PetscInt            *maxChildIds;
2082e44e4e7fSToby Isaac   PetscInt            *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
20834acb8e1eSToby Isaac   const PetscInt    ***perms;
20844acb8e1eSToby Isaac   const PetscScalar ***flips;
20856ecaa68aSToby Isaac 
20866ecaa68aSToby Isaac   PetscFunctionBegin;
20879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
20889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
20899566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
20906ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
209189698031SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
209289698031SToby Isaac     const PetscInt *leaves;
20936ecaa68aSToby Isaac 
20949566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
209589698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
209689698031SToby Isaac       p = leaves ? leaves[l] : l;
20979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
20989566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2099ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
21006ecaa68aSToby Isaac     }
21019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
21027cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
210389698031SToby Isaac       p = leaves ? leaves[l] : l;
21049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
21059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2106ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
21076ecaa68aSToby Isaac     }
21089566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
21099566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
21106ecaa68aSToby Isaac   }
21116ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
21129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
2113ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
211457168dbeSPierre Jolivet   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211557168dbeSPierre Jolivet   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211646bdb399SToby Isaac 
21179566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
21189566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
211946bdb399SToby Isaac 
21209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
21219566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
21229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
212346bdb399SToby Isaac 
21249566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
21259566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
212646bdb399SToby Isaac 
212746bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
21289566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
21299566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootMatricesSec));
21309566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootIndicesSec, pStartC, pEndC));
21319566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootMatricesSec, pStartC, pEndC));
21329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
2133713c1c5dSToby Isaac   maxFields = PetscMax(1, numFields);
21349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc7(maxFields + 1, &offsets, maxFields + 1, &offsetsCopy, maxFields + 1, &newOffsets, maxFields + 1, &newOffsetsCopy, maxFields + 1, &rowOffsets, maxFields + 1, &numD, maxFields + 1, &numO));
21359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxFields + 1, (PetscInt ****)&perms, maxFields + 1, (PetscScalar ****)&flips));
21369566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)perms, (maxFields + 1) * sizeof(const PetscInt **)));
21379566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)flips, (maxFields + 1) * sizeof(const PetscScalar **)));
213846bdb399SToby Isaac 
213946bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
21408d2f55e7SToby Isaac     PetscInt dof, matSize = 0;
21416ecaa68aSToby Isaac     PetscInt aDof          = 0;
21426ecaa68aSToby Isaac     PetscInt cDof          = 0;
21436ecaa68aSToby Isaac     PetscInt maxChildId    = maxChildIds[p - pStartC];
21446ecaa68aSToby Isaac     PetscInt numRowIndices = 0;
21456ecaa68aSToby Isaac     PetscInt numColIndices = 0;
2146f13f9184SToby Isaac     PetscInt f;
21476ecaa68aSToby Isaac 
21489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2149ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
215048a46eb9SPierre Jolivet     if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof));
215148a46eb9SPierre Jolivet     if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(cSec, p, &cDof));
2152f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2153f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
21546ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2155f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
21566ecaa68aSToby Isaac 
21579566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
215846bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
21596ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
21606ecaa68aSToby Isaac 
21619566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
21626ecaa68aSToby Isaac         numRowIndices += clDof;
21636ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21649566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &clDof));
21656ecaa68aSToby Isaac           offsets[f + 1] += clDof;
21666ecaa68aSToby Isaac         }
21676ecaa68aSToby Isaac       }
21686ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
21696ecaa68aSToby Isaac         offsets[f + 1] += offsets[f];
21706ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
21716ecaa68aSToby Isaac       }
217246bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
21739566063dSJacob Faibussowitsch       PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, NULL, NULL, NULL, &numColIndices, NULL, NULL, newOffsets, PETSC_FALSE));
21749566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
21756ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
21766ecaa68aSToby Isaac         numColIndices = numRowIndices;
21776ecaa68aSToby Isaac         matSize       = 0;
21789371c9d4SSatish Balay       } else if (numFields) { /* we send one submat for each field: sum their sizes */
21796ecaa68aSToby Isaac         matSize = 0;
21806ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21816ecaa68aSToby Isaac           PetscInt numRow, numCol;
21826ecaa68aSToby Isaac 
21836ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2184f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
21856ecaa68aSToby Isaac           matSize += numRow * numCol;
21866ecaa68aSToby Isaac         }
21879371c9d4SSatish Balay       } else {
21886ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
21896ecaa68aSToby Isaac       }
2190f13f9184SToby Isaac     } else if (maxChildId == -1) {
21918d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2192f13f9184SToby Isaac         PetscInt aOff, a;
21936ecaa68aSToby Isaac 
21949566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
21956ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21966ecaa68aSToby Isaac           PetscInt fDof;
21976ecaa68aSToby Isaac 
21989566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
219921968bf8SToby Isaac           offsets[f + 1] = fDof;
22006ecaa68aSToby Isaac         }
22016ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
22026ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
22036ecaa68aSToby Isaac 
22049566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(localCoarse, anchor, &aLocalDof));
22056ecaa68aSToby Isaac           numColIndices += aLocalDof;
22066ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
22076ecaa68aSToby Isaac             PetscInt fDof;
22086ecaa68aSToby Isaac 
22099566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
221021968bf8SToby Isaac             newOffsets[f + 1] += fDof;
22116ecaa68aSToby Isaac           }
22126ecaa68aSToby Isaac         }
22136ecaa68aSToby Isaac         if (numFields) {
22146ecaa68aSToby Isaac           matSize = 0;
2215ad540459SPierre Jolivet           for (f = 0; f < numFields; f++) matSize += offsets[f + 1] * newOffsets[f + 1];
22169371c9d4SSatish Balay         } else {
22176ecaa68aSToby Isaac           matSize = numColIndices * dof;
22186ecaa68aSToby Isaac         }
22199371c9d4SSatish Balay       } else { /* no children, and no constraints on dofs: just get the global indices */
22206ecaa68aSToby Isaac         numColIndices = dof;
22216ecaa68aSToby Isaac         matSize       = 0;
22226ecaa68aSToby Isaac       }
22238d2f55e7SToby Isaac     }
222446bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
22259566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootIndicesSec, p, numColIndices ? numColIndices + 2 * numFields : 0));
22269566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootMatricesSec, p, matSize));
22276ecaa68aSToby Isaac   }
22289566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootIndicesSec));
22299566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootMatricesSec));
22306ecaa68aSToby Isaac   {
22316ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
22326ecaa68aSToby Isaac 
22339566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
22349566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootMatricesSec, &numRootMatrices));
22359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numRootIndices, &rootIndices, numRootMatrices, &rootMatrices));
22366ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
22376ecaa68aSToby Isaac       PetscInt     numRowIndices, numColIndices, matSize, dof;
2238f13f9184SToby Isaac       PetscInt     pIndOff, pMatOff, f;
22396ecaa68aSToby Isaac       PetscInt    *pInd;
22406ecaa68aSToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
22416ecaa68aSToby Isaac       PetscScalar *pMat       = NULL;
22426ecaa68aSToby Isaac 
22439566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, p, &numColIndices));
2244ad540459SPierre Jolivet       if (!numColIndices) continue;
2245f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2246f13f9184SToby Isaac         offsets[f]        = 0;
2247f13f9184SToby Isaac         newOffsets[f]     = 0;
2248f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2249f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2250f13f9184SToby Isaac       }
22516ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
22529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, p, &pIndOff));
22536ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
22549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootMatricesSec, p, &matSize));
22556ecaa68aSToby Isaac       if (matSize) {
22569566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootMatricesSec, p, &pMatOff));
22576ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
22586ecaa68aSToby Isaac       }
22599566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2260ad540459SPierre Jolivet       if (dof < 0) dof = -(dof + 1);
22616ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
22626ecaa68aSToby Isaac         PetscInt i, j;
22636ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
22646ecaa68aSToby Isaac 
22656ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
22666ecaa68aSToby Isaac           PetscInt numIndices, *indices;
22679566063dSJacob Faibussowitsch           PetscCall(DMPlexGetClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
226808401ef6SPierre Jolivet           PetscCheck(numIndices == numColIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "mismatching constraint indices calculations");
2269ad540459SPierre Jolivet           for (i = 0; i < numColIndices; i++) pInd[i] = indices[i];
22706ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
227146bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i + 1];
227246bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i + 1];
22736ecaa68aSToby Isaac           }
22749566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
22759371c9d4SSatish Balay         } else {
22766ecaa68aSToby Isaac           PetscInt     closureSize, *closure = NULL, cl;
22776ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
22786ecaa68aSToby Isaac           PetscInt     numPoints, *points;
22796ecaa68aSToby Isaac 
22809566063dSJacob Faibussowitsch           PetscCall(DMGetWorkArray(coarse, numRowIndices * numRowIndices, MPIU_SCALAR, &pMatIn));
22816ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
2282ad540459SPierre Jolivet             for (j = 0; j < numRowIndices; j++) pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
22836ecaa68aSToby Isaac           }
22849566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22854acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
22869566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
22879566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
22884acb8e1eSToby Isaac           }
22896ecaa68aSToby Isaac           if (numFields) {
22906ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
22916ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
22926ecaa68aSToby Isaac 
22936ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
22946ecaa68aSToby Isaac                 PetscInt fDof;
22956ecaa68aSToby Isaac 
22969566063dSJacob Faibussowitsch                 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &fDof));
22976ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
22986ecaa68aSToby Isaac               }
22996ecaa68aSToby Isaac             }
23006ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
23016ecaa68aSToby Isaac               offsets[f + 1] += offsets[f];
23026ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
23036ecaa68aSToby Isaac             }
23046ecaa68aSToby Isaac           }
23054acb8e1eSToby Isaac           /* TODO : flips here ? */
23066ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
23079566063dSJacob Faibussowitsch           PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, perms, pMatIn, &numPoints, NULL, &points, &pMatModified, newOffsets, PETSC_FALSE));
23084acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23099566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
23109566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
23114acb8e1eSToby Isaac           }
23124acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23139566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23149566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23154acb8e1eSToby Isaac           }
23166ecaa68aSToby Isaac           if (!numFields) {
2317ad540459SPierre Jolivet             for (i = 0; i < numRowIndices * numColIndices; i++) pMat[i] = pMatModified[i];
23189371c9d4SSatish Balay           } else {
2319f13f9184SToby Isaac             PetscInt i, j, count;
23206ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
23216ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f + 1]; i++) {
2322ad540459SPierre Jolivet                 for (j = newOffsets[f]; j < newOffsets[f + 1]; j++, count++) pMat[count] = pMatModified[i * numColIndices + j];
23236ecaa68aSToby Isaac               }
23246ecaa68aSToby Isaac             }
23256ecaa68aSToby Isaac           }
23269566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatModified));
23279566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
23289566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatIn));
23296ecaa68aSToby Isaac           if (numFields) {
233046bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
233146bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f + 1];
233246bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f + 1];
23336ecaa68aSToby Isaac             }
23344acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23354acb8e1eSToby Isaac               PetscInt globalOff, c = points[2 * cl];
23369566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23379566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
23386ecaa68aSToby Isaac             }
23396ecaa68aSToby Isaac           } else {
23404acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23414acb8e1eSToby Isaac               PetscInt        c    = points[2 * cl], globalOff;
23424acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
23434acb8e1eSToby Isaac 
23449566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23459566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
23466ecaa68aSToby Isaac             }
23476ecaa68aSToby Isaac           }
23484acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23499566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23509566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23514acb8e1eSToby Isaac           }
23529566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numPoints, MPIU_SCALAR, &points));
23536ecaa68aSToby Isaac         }
23549371c9d4SSatish Balay       } else if (matSize) {
23556ecaa68aSToby Isaac         PetscInt  cOff;
23566ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
23576ecaa68aSToby Isaac 
23586ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
235908401ef6SPierre Jolivet         PetscCheck(numRowIndices == dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Miscounted dofs");
23609566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
23619566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
23629566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, p, &cOff));
23639566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
23649566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
23656ecaa68aSToby Isaac         if (numFields) {
23666ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23676ecaa68aSToby Isaac             PetscInt fDof;
2368f13f9184SToby Isaac 
23699566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSec, p, f, &fDof));
23706ecaa68aSToby Isaac             offsets[f + 1] = fDof;
23716ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
23726ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
23739566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
23746ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
23756ecaa68aSToby Isaac             }
23766ecaa68aSToby Isaac           }
23776ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23786ecaa68aSToby Isaac             offsets[f + 1] += offsets[f];
23796ecaa68aSToby Isaac             offsetsCopy[f + 1] = offsets[f + 1];
23806ecaa68aSToby Isaac             newOffsets[f + 1] += newOffsets[f];
23816ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
23826ecaa68aSToby Isaac           }
23839566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, -1, NULL, rowIndices));
23846ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23856ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23869566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23879566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, -1, NULL, colIndices));
23886ecaa68aSToby Isaac           }
23899371c9d4SSatish Balay         } else {
23909566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, NULL, rowIndices));
23916ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23926ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23939566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23949566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, NULL, colIndices));
23956ecaa68aSToby Isaac           }
23966ecaa68aSToby Isaac         }
23976ecaa68aSToby Isaac         if (numFields) {
2398f13f9184SToby Isaac           PetscInt count, a;
2399f13f9184SToby Isaac 
24006ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
24016ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
24026ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
24039566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat, iSize, &rowIndices[offsets[f]], jSize, &colIndices[newOffsets[f]], &pMat[count]));
24046ecaa68aSToby Isaac             count += iSize * jSize;
240546bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
240646bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f + 1];
24076ecaa68aSToby Isaac           }
24086ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24096ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24106ecaa68aSToby Isaac             PetscInt gOff;
24119566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24129566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, -1, NULL, pInd));
24136ecaa68aSToby Isaac           }
24149371c9d4SSatish Balay         } else {
24156ecaa68aSToby Isaac           PetscInt a;
24169566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat, numRowIndices, rowIndices, numColIndices, colIndices, pMat));
24176ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24186ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24196ecaa68aSToby Isaac             PetscInt gOff;
24209566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24219566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, NULL, pInd));
24226ecaa68aSToby Isaac           }
24236ecaa68aSToby Isaac         }
24249566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
24259566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
24269371c9d4SSatish Balay       } else {
24276ecaa68aSToby Isaac         PetscInt gOff;
24286ecaa68aSToby Isaac 
24299566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
24306ecaa68aSToby Isaac         if (numFields) {
24316ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
24326ecaa68aSToby Isaac             PetscInt fDof;
24339566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
24346ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
24356ecaa68aSToby Isaac           }
24366ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
243746bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
243846bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f + 1];
24396ecaa68aSToby Isaac           }
24409566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2441367003a6SStefano Zampini         } else {
24429566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
24436ecaa68aSToby Isaac         }
24446ecaa68aSToby Isaac       }
24456ecaa68aSToby Isaac     }
24469566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
24476ecaa68aSToby Isaac   }
244846bdb399SToby Isaac   {
244946bdb399SToby Isaac     PetscSF   indicesSF, matricesSF;
245046bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
245146bdb399SToby Isaac 
24529566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
24539566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafMatricesSec));
24549566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootIndicesSec, &remoteOffsetsIndices, leafIndicesSec));
24559566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootMatricesSec, &remoteOffsetsMatrices, leafMatricesSec));
24569566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootIndicesSec, remoteOffsetsIndices, leafIndicesSec, &indicesSF));
24579566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootMatricesSec, remoteOffsetsMatrices, leafMatricesSec, &matricesSF));
24589566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
24599566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsIndices));
24609566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsMatrices));
24619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numLeafIndices));
24629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafMatricesSec, &numLeafMatrices));
24639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numLeafIndices, &leafIndices, numLeafMatrices, &leafMatrices));
24649566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24659566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24669566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24679566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24689566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&matricesSF));
24699566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
24709566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rootIndices, rootMatrices));
24719566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootIndicesSec));
24729566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootMatricesSec));
247346bdb399SToby Isaac   }
247446bdb399SToby Isaac   /* count to preallocate */
24759566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
247646bdb399SToby Isaac   {
247746bdb399SToby Isaac     PetscInt       nGlobal;
247846bdb399SToby Isaac     PetscInt      *dnnz, *onnz;
2479b9a5774bSToby Isaac     PetscLayout    rowMap, colMap;
2480b9a5774bSToby Isaac     PetscInt       rowStart, rowEnd, colStart, colEnd;
24811c58ffc4SToby Isaac     PetscInt       maxDof;
24821c58ffc4SToby Isaac     PetscInt      *rowIndices;
24831c58ffc4SToby Isaac     DM             refTree;
24841c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
24851c58ffc4SToby Isaac     PetscScalar ***refPointFieldMats;
24861c58ffc4SToby Isaac     PetscSection   refConSec, refAnSec;
24870eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, maxConDof, maxColumns, leafStart, leafEnd;
24881c58ffc4SToby Isaac     PetscScalar   *pointWork;
248946bdb399SToby Isaac 
24909566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine, &nGlobal));
24919566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nGlobal, &dnnz, nGlobal, &onnz));
24929566063dSJacob Faibussowitsch     PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
24939566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rowMap));
24949566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(colMap));
24959566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
24969566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
24979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
24989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafIndicesSec, &leafStart, &leafEnd));
24999566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
25000eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
250146bdb399SToby Isaac       PetscInt gDof, gcDof, gOff;
250246bdb399SToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
250346bdb399SToby Isaac       PetscInt matSize;
250421968bf8SToby Isaac       PetscInt i;
250546bdb399SToby Isaac 
25069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
25079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2508ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
25099566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
251008401ef6SPierre Jolivet       PetscCheck(gOff >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I though having global dofs meant a non-negative offset");
25111dca8a05SBarry Smith       PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I thought the row map would constrain the global dofs");
25129566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
25139566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
251446bdb399SToby Isaac       numColIndices -= 2 * numFields;
251508401ef6SPierre Jolivet       PetscCheck(numColIndices > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "global fine dof with no dofs to interpolate from");
251646bdb399SToby Isaac       pInd              = &leafIndices[pIndOff];
251721968bf8SToby Isaac       offsets[0]        = 0;
251821968bf8SToby Isaac       offsetsCopy[0]    = 0;
251921968bf8SToby Isaac       newOffsets[0]     = 0;
252021968bf8SToby Isaac       newOffsetsCopy[0] = 0;
252146bdb399SToby Isaac       if (numFields) {
252221968bf8SToby Isaac         PetscInt f;
252346bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
252446bdb399SToby Isaac           PetscInt rowDof;
252546bdb399SToby Isaac 
25269566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
252721968bf8SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
252821968bf8SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
252921968bf8SToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
253021968bf8SToby Isaac           numD[f]            = 0;
253121968bf8SToby Isaac           numO[f]            = 0;
253246bdb399SToby Isaac         }
25339566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
253446bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
253521968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
253621968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
253746bdb399SToby Isaac 
253846bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
253946bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
254046bdb399SToby Isaac 
254146bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
254221968bf8SToby Isaac               numD[f]++;
25439371c9d4SSatish Balay             } else if (gInd >= 0) { /* negative means non-entry */
254421968bf8SToby Isaac               numO[f]++;
254546bdb399SToby Isaac             }
254646bdb399SToby Isaac           }
254746bdb399SToby Isaac         }
25489371c9d4SSatish Balay       } else {
25499566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
255021968bf8SToby Isaac         numD[0] = 0;
255121968bf8SToby Isaac         numO[0] = 0;
255246bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
255346bdb399SToby Isaac           PetscInt gInd = pInd[i];
255446bdb399SToby Isaac 
255546bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
255621968bf8SToby Isaac             numD[0]++;
25579371c9d4SSatish Balay           } else if (gInd >= 0) { /* negative means non-entry */
255821968bf8SToby Isaac             numO[0]++;
255946bdb399SToby Isaac           }
256046bdb399SToby Isaac         }
256146bdb399SToby Isaac       }
25629566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
256346bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
256446bdb399SToby Isaac         PetscInt childId;
256546bdb399SToby Isaac 
256646bdb399SToby Isaac         childId = childIds[p - pStartF];
256721968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
256846bdb399SToby Isaac           if (numFields) {
2569b9a5774bSToby Isaac             PetscInt f;
2570b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
257121968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
257246bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
257321968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
257421968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
257546bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25761dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2577b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
25789371c9d4SSatish Balay                 } else if (gIndCoarse >= 0) { /* remote */
25791dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2580b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
25819371c9d4SSatish Balay                 } else { /* constrained */
258208401ef6SPierre Jolivet                   PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
258346bdb399SToby Isaac                 }
258446bdb399SToby Isaac               }
258546bdb399SToby Isaac             }
25869371c9d4SSatish Balay           } else {
2587b9a5774bSToby Isaac             PetscInt i;
2588b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
258946bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
259046bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
259146bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25921dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2593b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
25949371c9d4SSatish Balay               } else if (gIndCoarse >= 0) { /* remote */
25951dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2596b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
25979371c9d4SSatish Balay               } else { /* constrained */
259808401ef6SPierre Jolivet                 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
259946bdb399SToby Isaac               }
260046bdb399SToby Isaac             }
260146bdb399SToby Isaac           }
26029371c9d4SSatish Balay         } else { /* interpolate from all */
260346bdb399SToby Isaac           if (numFields) {
2604b9a5774bSToby Isaac             PetscInt f;
2605b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
260621968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
260746bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
260821968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
260946bdb399SToby Isaac                 if (gIndFine >= 0) {
26101dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2611b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2612b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
261346bdb399SToby Isaac                 }
261446bdb399SToby Isaac               }
261546bdb399SToby Isaac             }
26169371c9d4SSatish Balay           } else {
2617b9a5774bSToby Isaac             PetscInt i;
2618b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
261946bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
262046bdb399SToby Isaac               if (gIndFine >= 0) {
26211dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2622b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2623b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
262446bdb399SToby Isaac               }
262546bdb399SToby Isaac             }
262646bdb399SToby Isaac           }
262746bdb399SToby Isaac         }
26289371c9d4SSatish Balay       } else { /* interpolate from all */
262946bdb399SToby Isaac         if (numFields) {
2630b9a5774bSToby Isaac           PetscInt f;
2631b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
263221968bf8SToby Isaac             PetscInt numRows = offsets[f + 1] - offsets[f], row;
263346bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
263421968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
263546bdb399SToby Isaac               if (gIndFine >= 0) {
26361dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2637b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2638b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
263946bdb399SToby Isaac               }
264046bdb399SToby Isaac             }
264146bdb399SToby Isaac           }
26429371c9d4SSatish Balay         } else { /* every dof get a full row */
2643b9a5774bSToby Isaac           PetscInt i;
2644b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
264546bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
264646bdb399SToby Isaac             if (gIndFine >= 0) {
26471dca8a05SBarry Smith               PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2648b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2649b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
265046bdb399SToby Isaac             }
265146bdb399SToby Isaac           }
265246bdb399SToby Isaac         }
265346bdb399SToby Isaac       }
265446bdb399SToby Isaac     }
26559566063dSJacob Faibussowitsch     PetscCall(MatXAIJSetPreallocation(mat, 1, dnnz, onnz, NULL, NULL));
26569566063dSJacob Faibussowitsch     PetscCall(PetscFree2(dnnz, onnz));
265721968bf8SToby Isaac 
26589566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
26599566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
26609566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
26619566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
26629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
26639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(refConSec, &maxConDof));
26649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(leafIndicesSec, &maxColumns));
26659566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxConDof * maxColumns, &pointWork));
26660eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2667e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2668e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2669e44e4e7fSToby Isaac       PetscInt matSize;
2670e44e4e7fSToby Isaac       PetscInt childId;
2671e44e4e7fSToby Isaac 
26729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
26739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2674ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
2675e44e4e7fSToby Isaac       childId = childIds[p - pStartF];
26769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
26779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
26789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2679e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2680e44e4e7fSToby Isaac       pInd              = &leafIndices[pIndOff];
2681e44e4e7fSToby Isaac       offsets[0]        = 0;
2682e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2683e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2684e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2685e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2686e44e4e7fSToby Isaac       if (numFields) {
2687e44e4e7fSToby Isaac         PetscInt f;
2688e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2689e44e4e7fSToby Isaac           PetscInt rowDof;
2690e44e4e7fSToby Isaac 
26919566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2692e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2693e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2694e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2695e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2696e44e4e7fSToby Isaac         }
26979566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
26989371c9d4SSatish Balay       } else {
26999566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
27001c58ffc4SToby Isaac       }
27019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2702e44e4e7fSToby Isaac       if (!matSize) {      /* incoming matrix is identity */
2703e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2704e44e4e7fSToby Isaac           if (numFields) {
2705e44e4e7fSToby Isaac             PetscInt f;
2706e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2707e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
270848a46eb9SPierre Jolivet               for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[offsets[f] + row], pInd[newOffsets[f] + row], 1., INSERT_VALUES));
270921968bf8SToby Isaac             }
27109371c9d4SSatish Balay           } else {
2711e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
271248a46eb9SPierre Jolivet             for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[row], pInd[row], 1., INSERT_VALUES));
2713e44e4e7fSToby Isaac           }
27149371c9d4SSatish Balay         } else { /* interpolate from all */
2715e44e4e7fSToby Isaac           if (numFields) {
2716e44e4e7fSToby Isaac             PetscInt f;
2717e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2718e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f];
2719e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
27209566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], refPointFieldMats[childId - pRefStart][f], INSERT_VALUES));
2721e44e4e7fSToby Isaac             }
27229371c9d4SSatish Balay           } else {
27239566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, refPointFieldMats[childId - pRefStart][0], INSERT_VALUES));
2724e44e4e7fSToby Isaac           }
2725e44e4e7fSToby Isaac         }
27269371c9d4SSatish Balay       } else { /* interpolate from all */
2727e44e4e7fSToby Isaac         PetscInt     pMatOff;
2728e44e4e7fSToby Isaac         PetscScalar *pMat;
2729e44e4e7fSToby Isaac 
27309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafMatricesSec, p, &pMatOff));
2731e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2732e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2733e44e4e7fSToby Isaac           if (numFields) {
2734e44e4e7fSToby Isaac             PetscInt f, count;
2735e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2736e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2737e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2738e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2739e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2740e44e4e7fSToby Isaac 
27419566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], inMat, INSERT_VALUES));
2742e44e4e7fSToby Isaac               count += numCols * numInRows;
2743e44e4e7fSToby Isaac             }
27449371c9d4SSatish Balay           } else {
27459566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, pMat, INSERT_VALUES));
2746e44e4e7fSToby Isaac           }
27479371c9d4SSatish Balay         } else { /* multiply the incoming matrix by the child interpolation */
2748e44e4e7fSToby Isaac           if (numFields) {
2749e44e4e7fSToby Isaac             PetscInt f, count;
2750e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2751e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2752e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2753e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2754e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2755e44e4e7fSToby Isaac               PetscInt     i, j, k;
275608401ef6SPierre Jolivet               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2757e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2758e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2759e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2760ad540459SPierre Jolivet                   for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2761e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2762e44e4e7fSToby Isaac                 }
2763e44e4e7fSToby Isaac               }
27649566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], pointWork, INSERT_VALUES));
2765e44e4e7fSToby Isaac               count += numCols * numInRows;
2766e44e4e7fSToby Isaac             }
27679371c9d4SSatish Balay           } else { /* every dof gets a full row */
2768e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2769e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2770e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2771e44e4e7fSToby Isaac             PetscInt i, j, k;
277208401ef6SPierre Jolivet             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2773e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2774e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2775e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2776ad540459SPierre Jolivet                 for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2777e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2778e44e4e7fSToby Isaac               }
2779e44e4e7fSToby Isaac             }
27809566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, numRows, rowIndices, numCols, pInd, pointWork, INSERT_VALUES));
2781e44e4e7fSToby Isaac           }
2782e44e4e7fSToby Isaac         }
2783e44e4e7fSToby Isaac       }
2784e44e4e7fSToby Isaac     }
27859566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
27869566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
27879566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointWork));
2788e44e4e7fSToby Isaac   }
27899566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
27909566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
27919566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
27929566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafMatricesSec));
27939566063dSJacob Faibussowitsch   PetscCall(PetscFree2(leafIndices, leafMatrices));
27949566063dSJacob Faibussowitsch   PetscCall(PetscFree2(*(PetscInt ****)&perms, *(PetscScalar ****)&flips));
27959566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
27969566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
27973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27986ecaa68aSToby Isaac }
2799154bca37SToby Isaac 
28008d2f55e7SToby Isaac /*
28018d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
28028d2f55e7SToby Isaac  *
28038d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
28048d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
28058d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
28068d2f55e7SToby Isaac  *       a_{i,j} = 0;
28078d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
28088d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
28098d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
28108d2f55e7SToby Isaac  */
2811d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
2812d71ae5a4SJacob Faibussowitsch {
28138d2f55e7SToby Isaac   PetscDS      ds;
28148d2f55e7SToby Isaac   PetscSection section, cSection;
28158d2f55e7SToby Isaac   DMLabel      canonical, depth;
28168d2f55e7SToby Isaac   Mat          cMat, mat;
28178d2f55e7SToby Isaac   PetscInt    *nnz;
28188d2f55e7SToby Isaac   PetscInt     f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
28198d2f55e7SToby Isaac   PetscInt     m, n;
28208d2f55e7SToby Isaac   PetscScalar *pointScalar;
28218d2f55e7SToby Isaac   PetscReal   *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
28228d2f55e7SToby Isaac 
28238d2f55e7SToby Isaac   PetscFunctionBegin;
28249566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &section));
28259566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(refTree, &dim));
28269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(dim, &v0, dim, &v0parent, dim, &vtmp, dim * dim, &J, dim * dim, &Jparent, dim * dim, &invJ));
28279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(dim, &pointScalar, dim, &pointRef));
28289566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
28299566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
28309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numSecFields));
28319566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "canonical", &canonical));
28329566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "depth", &depth));
28339566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSection, &cMat, NULL));
28349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
28359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
28369566063dSJacob Faibussowitsch   PetscCall(MatGetSize(cMat, &n, &m)); /* the injector has transpose sizes from the constraint matrix */
28378d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
28389566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(m, &nnz));
28398d2f55e7SToby 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 */
28408d2f55e7SToby Isaac     const PetscInt *children;
28418d2f55e7SToby Isaac     PetscInt        numChildren;
28428d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28438d2f55e7SToby Isaac 
28448d2f55e7SToby Isaac     if (canonical) {
28458d2f55e7SToby Isaac       PetscInt pCanonical;
28469566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28478d2f55e7SToby Isaac       if (p != pCanonical) continue;
28488d2f55e7SToby Isaac     }
28499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28508d2f55e7SToby Isaac     if (!numChildren) continue;
28518d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28528d2f55e7SToby Isaac       PetscInt child = children[i];
28538d2f55e7SToby Isaac       PetscInt dof;
28548d2f55e7SToby Isaac 
28559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
28568d2f55e7SToby Isaac       numChildDof += dof;
28578d2f55e7SToby Isaac     }
28589566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
28598d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
28608d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
28618d2f55e7SToby Isaac       PetscInt selfOff;
28628d2f55e7SToby Isaac 
28638d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
28648d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
28658d2f55e7SToby Isaac           PetscInt child = children[i];
28668d2f55e7SToby Isaac           PetscInt dof;
28678d2f55e7SToby Isaac 
28689566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
28698d2f55e7SToby Isaac           numChildDof += dof;
28708d2f55e7SToby Isaac         }
28719566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
28729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
28739371c9d4SSatish Balay       } else {
28749566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
28758d2f55e7SToby Isaac       }
2876ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) nnz[selfOff + i] = numChildDof;
28778d2f55e7SToby Isaac     }
28788d2f55e7SToby Isaac   }
28799566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(PETSC_COMM_SELF, m, n, m, n, -1, nnz, -1, NULL, &mat));
28809566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
28818d2f55e7SToby Isaac   /* Setp 2: compute entries */
28828d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
28838d2f55e7SToby Isaac     const PetscInt *children;
28848d2f55e7SToby Isaac     PetscInt        numChildren;
28858d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28868d2f55e7SToby Isaac 
28878d2f55e7SToby Isaac     /* same conditions about when entries occur */
28888d2f55e7SToby Isaac     if (canonical) {
28898d2f55e7SToby Isaac       PetscInt pCanonical;
28909566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28918d2f55e7SToby Isaac       if (p != pCanonical) continue;
28928d2f55e7SToby Isaac     }
28939566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28948d2f55e7SToby Isaac     if (!numChildren) continue;
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(PetscSectionGetDof(section, child, &dof));
29008d2f55e7SToby Isaac       numChildDof += dof;
29018d2f55e7SToby Isaac     }
29029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
29038d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
29048d2f55e7SToby Isaac 
29058d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
290659fc6756SToby Isaac       PetscInt        pI = -1, cI = -1;
290752a3aeb4SToby Isaac       PetscInt        selfOff, Nc, parentCell;
29088d2f55e7SToby Isaac       PetscInt        cellShapeOff;
29098d2f55e7SToby Isaac       PetscObject     disc;
29108d2f55e7SToby Isaac       PetscDualSpace  dsp;
29118d2f55e7SToby Isaac       PetscClassId    classId;
29128d2f55e7SToby Isaac       PetscScalar    *pointMat;
29133b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
29148d2f55e7SToby Isaac       PetscInt        pO = PETSC_MIN_INT;
29158d2f55e7SToby Isaac       const PetscInt *depthNumDof;
29168d2f55e7SToby Isaac 
29178d2f55e7SToby Isaac       if (numSecFields) {
29188d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
29198d2f55e7SToby Isaac           PetscInt child = children[i];
29208d2f55e7SToby Isaac           PetscInt dof;
29218d2f55e7SToby Isaac 
29229566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
29238d2f55e7SToby Isaac           numChildDof += dof;
29248d2f55e7SToby Isaac         }
29259566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
29269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
29279371c9d4SSatish Balay       } else {
29289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
29298d2f55e7SToby Isaac       }
29308d2f55e7SToby Isaac 
29313b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
29328d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
29338d2f55e7SToby Isaac         parentCell = p;
29349371c9d4SSatish Balay       } else {
29358d2f55e7SToby Isaac         PetscInt *star = NULL;
29368d2f55e7SToby Isaac         PetscInt  numStar;
29378d2f55e7SToby Isaac 
29388d2f55e7SToby Isaac         parentCell = -1;
29399566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29408d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
29418d2f55e7SToby Isaac           PetscInt c = star[2 * i];
29428d2f55e7SToby Isaac 
29438d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
29448d2f55e7SToby Isaac             parentCell = c;
29458d2f55e7SToby Isaac             break;
29468d2f55e7SToby Isaac           }
29478d2f55e7SToby Isaac         }
29489566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29498d2f55e7SToby Isaac       }
2950a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
29519566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
29529566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc, &classId));
2953c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
29549566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
29559371c9d4SSatish Balay       } else if (classId == PETSCFV_CLASSID) {
29569566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace((PetscFV)disc, &dsp));
29579371c9d4SSatish Balay       } else {
29589b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported discretization object");
2959c5356c36SToby Isaac       }
29609566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumDof(dsp, &depthNumDof));
29619566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumComponents(dsp, &Nc));
29628d2f55e7SToby Isaac       {
29638d2f55e7SToby Isaac         PetscInt *closure = NULL;
29648d2f55e7SToby Isaac         PetscInt  numClosure;
29658d2f55e7SToby Isaac 
29669566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
296759fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
29688d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
29698d2f55e7SToby Isaac 
29708d2f55e7SToby Isaac           pO = closure[2 * i + 1];
297159fc6756SToby Isaac           if (point == p) {
297259fc6756SToby Isaac             pI = i;
297359fc6756SToby Isaac             break;
297459fc6756SToby Isaac           }
29759566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(depth, point, &pointDepth));
29768d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
29778d2f55e7SToby Isaac         }
29789566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
29798d2f55e7SToby Isaac       }
29808d2f55e7SToby Isaac 
29819566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
29829566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
298352a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
2984ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) matRows[i] = selfOff + i;
298552a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
29863b1c2a6aSToby Isaac       {
29873b1c2a6aSToby Isaac         PetscInt colOff = 0;
29883b1c2a6aSToby Isaac 
29893b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
29903b1c2a6aSToby Isaac           PetscInt child = children[i];
29913b1c2a6aSToby Isaac           PetscInt dof, off, j;
29923b1c2a6aSToby Isaac 
29933b1c2a6aSToby Isaac           if (numSecFields) {
29949566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSection, child, f, &dof));
29959566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(cSection, child, f, &off));
29969371c9d4SSatish Balay           } else {
29979566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(cSection, child, &dof));
29989566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(cSection, child, &off));
29993b1c2a6aSToby Isaac           }
30003b1c2a6aSToby Isaac 
3001ad540459SPierre Jolivet           for (j = 0; j < dof; j++) matCols[colOff++] = off + j;
30023b1c2a6aSToby Isaac         }
30033b1c2a6aSToby Isaac       }
30048d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
30058d2f55e7SToby Isaac         PetscFE              fe = (PetscFE)disc;
30068d2f55e7SToby Isaac         PetscInt             fSize;
300759fc6756SToby Isaac         const PetscInt    ***perms;
300859fc6756SToby Isaac         const PetscScalar ***flips;
300959fc6756SToby Isaac         const PetscInt      *pperms;
301059fc6756SToby Isaac 
30119566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &dsp));
30129566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetDimension(dsp, &fSize));
30139566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
301459fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
301552a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
30168d2f55e7SToby Isaac           PetscQuadrature  q;
301752a3aeb4SToby Isaac           PetscInt         dim, thisNc, numPoints, j, k;
30188d2f55e7SToby Isaac           const PetscReal *points;
30198d2f55e7SToby Isaac           const PetscReal *weights;
30208d2f55e7SToby Isaac           PetscInt        *closure = NULL;
30218d2f55e7SToby Isaac           PetscInt         numClosure;
302259fc6756SToby Isaac           PetscInt         iCell              = pperms ? pperms[i] : i;
302359fc6756SToby Isaac           PetscInt         parentCellShapeDof = cellShapeOff + iCell;
3024ef0bb6c7SMatthew G. Knepley           PetscTabulation  Tparent;
30258d2f55e7SToby Isaac 
30269566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(dsp, parentCellShapeDof, &q));
30279566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(q, &dim, &thisNc, &numPoints, &points, &weights));
302863a3b9bcSJacob Faibussowitsch           PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
30299566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe, 1, numPoints, points, 0, &Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
30303b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
30318d2f55e7SToby Isaac             PetscInt           childCell = -1;
303252a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3033c330f8ffSToby Isaac             const PetscReal    xi0[3]    = {-1., -1., -1.};
30348d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
30358d2f55e7SToby Isaac             const PetscScalar *point;
3036ef0bb6c7SMatthew G. Knepley             PetscTabulation    Tchild;
30378d2f55e7SToby Isaac             PetscInt           childCellShapeOff, pointMatOff;
30388d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
30398d2f55e7SToby Isaac             PetscInt d;
30408d2f55e7SToby Isaac 
3041ad540459SPierre Jolivet             for (d = 0; d < dim; d++) pointScalar[d] = points[dim * j + d];
30428d2f55e7SToby Isaac             point = pointScalar;
30438d2f55e7SToby Isaac #else
30448d2f55e7SToby Isaac             point = pointReal;
30458d2f55e7SToby Isaac #endif
30468d2f55e7SToby Isaac 
3047ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
30483b1c2a6aSToby Isaac 
30493b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
30508d2f55e7SToby Isaac               PetscInt  child = children[k];
30518d2f55e7SToby Isaac               PetscInt *star  = NULL;
30528d2f55e7SToby Isaac               PetscInt  numStar, s;
30538d2f55e7SToby Isaac 
30549566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30558d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
30568d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
30578d2f55e7SToby Isaac 
30588d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
30599566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(refTree, dim, point, c, &childCell));
30608d2f55e7SToby Isaac                 if (childCell >= 0) break;
30618d2f55e7SToby Isaac               }
30629566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30638d2f55e7SToby Isaac               if (childCell >= 0) break;
30648d2f55e7SToby Isaac             }
306508401ef6SPierre Jolivet             PetscCheck(childCell >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not locate quadrature point");
30669566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
30679566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3068c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3069c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
30708d2f55e7SToby Isaac 
30719566063dSJacob Faibussowitsch             PetscCall(PetscFECreateTabulation(fe, 1, 1, pointRef, 0, &Tchild));
30729566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
30733b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3074c5356c36SToby Isaac               PetscInt        child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
30758d2f55e7SToby Isaac               PetscInt        l;
307659fc6756SToby Isaac               const PetscInt *cperms;
30778d2f55e7SToby Isaac 
30789566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(depth, child, &childDepth));
30798d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
308059fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
30818d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
30828d2f55e7SToby Isaac                 PetscInt pointDepth;
30838d2f55e7SToby Isaac 
30848d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
308559fc6756SToby Isaac                 if (point == child) {
308659fc6756SToby Isaac                   cI = l;
308759fc6756SToby Isaac                   break;
308859fc6756SToby Isaac                 }
30899566063dSJacob Faibussowitsch                 PetscCall(DMLabelGetValue(depth, point, &pointDepth));
30908d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
30918d2f55e7SToby Isaac               }
30928d2f55e7SToby Isaac               if (l == numClosure) {
30938d2f55e7SToby Isaac                 pointMatOff += childDof;
30948d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
30958d2f55e7SToby Isaac               }
309659fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
30978d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
309859fc6756SToby Isaac                 PetscInt   lCell        = cperms ? cperms[l] : l;
309959fc6756SToby Isaac                 PetscInt   childCellDof = childCellShapeOff + lCell;
310052a3aeb4SToby Isaac                 PetscReal *childValAtPoint;
310152a3aeb4SToby Isaac                 PetscReal  val = 0.;
31028d2f55e7SToby Isaac 
3103ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
3104ad540459SPierre Jolivet                 for (m = 0; m < Nc; m++) val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
310552a3aeb4SToby Isaac 
310652a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
31078d2f55e7SToby Isaac               }
31088d2f55e7SToby Isaac               pointMatOff += childDof;
31098d2f55e7SToby Isaac             }
31109566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
31119566063dSJacob Faibussowitsch             PetscCall(PetscTabulationDestroy(&Tchild));
31128d2f55e7SToby Isaac           }
31139566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&Tparent));
31148d2f55e7SToby Isaac         }
31159371c9d4SSatish Balay       } else { /* just the volume-weighted averages of the children */
31163b1c2a6aSToby Isaac         PetscReal parentVol;
3117bfaa5bdcSToby Isaac         PetscInt  childCell;
31183b1c2a6aSToby Isaac 
31199566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3120bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
312152a3aeb4SToby Isaac           PetscInt  child = children[i], j;
31223b1c2a6aSToby Isaac           PetscReal childVol;
31233b1c2a6aSToby Isaac 
31243b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
31259566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
3126ad540459SPierre Jolivet           for (j = 0; j < Nc; j++) pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
3127bfaa5bdcSToby Isaac           childCell++;
31283b1c2a6aSToby Isaac         }
31298d2f55e7SToby Isaac       }
31303b1c2a6aSToby Isaac       /* Insert pointMat into mat */
31319566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, numSelfDof, matRows, numChildDof, matCols, pointMat, INSERT_VALUES));
31329566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
31339566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
31348d2f55e7SToby Isaac     }
31358d2f55e7SToby Isaac   }
31369566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJ));
31379566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointScalar, pointRef));
31389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
31399566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
31408d2f55e7SToby Isaac   *inj = mat;
31413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31428d2f55e7SToby Isaac }
31438d2f55e7SToby Isaac 
3144d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3145d71ae5a4SJacob Faibussowitsch {
3146f30e825dSToby Isaac   PetscDS        ds;
3147f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3148f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3149f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3150f30e825dSToby Isaac 
3151f30e825dSToby Isaac   PetscFunctionBegin;
31529566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
31539566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
31549566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
31559566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
31569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
31579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
31589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
31599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
31609566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof, &cols));
3161f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3162f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3163f30e825dSToby Isaac 
31649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
31659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
31669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3167f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3168f30e825dSToby Isaac 
31699566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFields, &refPointFieldMats[p - pRefStart]));
3170f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
317152a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3172f30e825dSToby Isaac 
3173f30e825dSToby Isaac       if (numFields > 1) {
31749566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
31759566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
31769371c9d4SSatish Balay       } else {
31779566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
31789566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
3179f30e825dSToby Isaac       }
3180f30e825dSToby Isaac 
3181ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
3182f30e825dSToby Isaac       numCols = 0;
3183f30e825dSToby Isaac       {
3184f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3185f30e825dSToby Isaac 
3186f30e825dSToby Isaac         if (numFields > 1) {
31879566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, parent, f, &aDof));
31889566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, parent, f, &aOff));
31899371c9d4SSatish Balay         } else {
31909566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, parent, &aDof));
31919566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, parent, &aOff));
3192f30e825dSToby Isaac         }
3193f30e825dSToby Isaac 
3194ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + j;
3195f30e825dSToby Isaac       }
31969566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
3197f30e825dSToby Isaac       /* transpose of constraint matrix */
31989566063dSJacob Faibussowitsch       PetscCall(MatGetValues(inj, numCols, cols, cDof, rows, refPointFieldMats[p - pRefStart][f]));
3199f30e825dSToby Isaac     }
3200f30e825dSToby Isaac   }
3201f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
32029566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
32039566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
32043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3205f30e825dSToby Isaac }
3206f30e825dSToby Isaac 
3207d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3208d71ae5a4SJacob Faibussowitsch {
3209f30e825dSToby Isaac   PetscDS        ds;
3210f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3211f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3212c6154584SToby Isaac   PetscSection   refConSec, refSection;
3213f30e825dSToby Isaac 
3214f30e825dSToby Isaac   PetscFunctionBegin;
3215f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3216f30e825dSToby Isaac   *childrenMats     = NULL;
32179566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
32189566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
32199566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
32209566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
32219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3222f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3223f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3224f30e825dSToby Isaac 
32259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
32269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
32279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3228f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3229f30e825dSToby Isaac 
3230f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3231f30e825dSToby Isaac       PetscInt cDof;
3232f30e825dSToby Isaac 
3233f30e825dSToby Isaac       if (numFields > 1) {
32349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
32359371c9d4SSatish Balay       } else {
32369566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3237f30e825dSToby Isaac       }
3238f30e825dSToby Isaac 
32399566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3240f30e825dSToby Isaac     }
32419566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3242f30e825dSToby Isaac   }
32439566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
32443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3245f30e825dSToby Isaac }
3246f30e825dSToby Isaac 
3247d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree, Mat *injRef)
3248d71ae5a4SJacob Faibussowitsch {
3249ebf164c7SToby Isaac   Mat         cMatRef;
32506148253fSToby Isaac   PetscObject injRefObj;
32518d2f55e7SToby Isaac 
3252154bca37SToby Isaac   PetscFunctionBegin;
32539566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, NULL, &cMatRef, NULL));
32549566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", &injRefObj));
3255ebf164c7SToby Isaac   *injRef = (Mat)injRefObj;
3256ebf164c7SToby Isaac   if (!*injRef) {
32579566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorReferenceTree(refTree, injRef));
32589566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", (PetscObject)*injRef));
3259ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
32609566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3261ebf164c7SToby Isaac   }
32623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32636148253fSToby Isaac }
3264f30e825dSToby Isaac 
3265d71ae5a4SJacob Faibussowitsch 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)
3266d71ae5a4SJacob Faibussowitsch {
3267c921d74cSToby Isaac   PetscInt        pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3268ebf164c7SToby Isaac   PetscSection    globalCoarse, globalFine;
3269ebf164c7SToby Isaac   PetscSection    localCoarse, localFine, leafIndicesSec;
3270c921d74cSToby Isaac   PetscSection    multiRootSec, rootIndicesSec;
3271c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3272c921d74cSToby Isaac   const PetscInt *rootDegrees;
3273c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3274ebf164c7SToby Isaac   PetscSF         coarseToFineEmbedded;
3275ebf164c7SToby Isaac 
3276ebf164c7SToby Isaac   PetscFunctionBegin;
32779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
32789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
32799566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
32809566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
32819566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
32829566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafIndicesSec, pStartF, pEndF));
32839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
32848d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
32857e96bdafSToby Isaac     PetscInt        l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
32867e96bdafSToby Isaac     const PetscInt *leaves;
32878d2f55e7SToby Isaac 
32889566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
32897e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
32907e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
32919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
32929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
32938d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
32948d2f55e7SToby Isaac         numPointsWithDofs++;
3295f30e825dSToby Isaac 
32969566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localFine, p, &dof));
32979566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafIndicesSec, p, dof + 1));
32988d2f55e7SToby Isaac       }
32998d2f55e7SToby Isaac     }
33009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
33019566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafIndicesSec));
33029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numIndices));
33039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1), &leafInds));
33049566063dSJacob Faibussowitsch     if (gatheredValues) PetscCall(PetscMalloc1(numIndices, &leafVals));
33057e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
33067e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
33079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
33089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
33098d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3310f30e825dSToby Isaac         PetscInt     off, gOff;
3311f30e825dSToby Isaac         PetscInt    *pInd;
3312c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3313f30e825dSToby Isaac 
33147e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3315f30e825dSToby Isaac 
33169566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3317f30e825dSToby Isaac 
3318c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3319c921d74cSToby Isaac         if (gatheredValues) {
3320c921d74cSToby Isaac           PetscInt i;
3321c921d74cSToby Isaac 
3322c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3323c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3324c921d74cSToby Isaac         }
33259566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
3326f30e825dSToby Isaac 
3327f30e825dSToby Isaac         offsets[0] = 0;
3328f30e825dSToby Isaac         if (numFields) {
3329f30e825dSToby Isaac           PetscInt f;
3330f30e825dSToby Isaac 
3331f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3332f30e825dSToby Isaac             PetscInt fDof;
33339566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localFine, p, f, &fDof));
3334f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3335f30e825dSToby Isaac           }
33369566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
3337367003a6SStefano Zampini         } else {
33389566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
3339f30e825dSToby Isaac         }
33409566063dSJacob Faibussowitsch         if (gatheredValues) PetscCall(VecGetValues(fineVec, dof, pInd, pVal));
33418d2f55e7SToby Isaac       }
33428d2f55e7SToby Isaac     }
33439566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
33449566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
33458d2f55e7SToby Isaac   }
3346f30e825dSToby Isaac 
33479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
33489566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
33499566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3350f30e825dSToby Isaac 
33516148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
33526148253fSToby Isaac     MPI_Datatype threeInt;
33536148253fSToby Isaac     PetscMPIInt  rank;
33546148253fSToby Isaac     PetscInt(*parentNodeAndIdCoarse)[3];
33556148253fSToby Isaac     PetscInt(*parentNodeAndIdFine)[3];
33566148253fSToby Isaac     PetscInt           p, nleaves, nleavesToParents;
33576148253fSToby Isaac     PetscSF            pointSF, sfToParents;
33586148253fSToby Isaac     const PetscInt    *ilocal;
33596148253fSToby Isaac     const PetscSFNode *iremote;
33606148253fSToby Isaac     PetscSFNode       *iremoteToParents;
33616148253fSToby Isaac     PetscInt          *ilocalToParents;
33626148253fSToby Isaac 
33639566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse), &rank));
33649566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &threeInt));
33659566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&threeInt));
33669566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEndC - pStartC, &parentNodeAndIdCoarse, pEndF - pStartF, &parentNodeAndIdFine));
33679566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(coarse, &pointSF));
33689566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, &iremote));
33696148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
33706148253fSToby Isaac       PetscInt parent, childId;
33719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(coarse, p, &parent, &childId));
33726148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
33736148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
33746148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
33756148253fSToby Isaac       if (nleaves > 0) {
33766148253fSToby Isaac         PetscInt leaf = -1;
33776148253fSToby Isaac 
33786148253fSToby Isaac         if (ilocal) {
33799566063dSJacob Faibussowitsch           PetscCall(PetscFindInt(parent, nleaves, ilocal, &leaf));
33809371c9d4SSatish Balay         } else {
33816148253fSToby Isaac           leaf = p - pStartC;
33826148253fSToby Isaac         }
33836148253fSToby Isaac         if (leaf >= 0) {
33846148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
33856148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
33866148253fSToby Isaac         }
33876148253fSToby Isaac       }
33886148253fSToby Isaac     }
33896148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
33906148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
33916148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
33926148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
33936148253fSToby Isaac     }
33949566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
33959566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
33966148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3397f30e825dSToby Isaac       PetscInt dof;
3398f30e825dSToby Isaac 
33999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &dof));
3400f30e825dSToby Isaac       if (dof) {
3401f30e825dSToby Isaac         PetscInt off;
3402f30e825dSToby Isaac 
34039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3404c921d74cSToby Isaac         if (gatheredIndices) {
3405c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3406c921d74cSToby Isaac         } else if (gatheredValues) {
3407c921d74cSToby Isaac           leafVals[off] = (PetscScalar)PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3408c921d74cSToby Isaac         }
3409f30e825dSToby Isaac       }
3410ad540459SPierre Jolivet       if (parentNodeAndIdFine[p - pStartF][0] >= 0) nleavesToParents++;
34116148253fSToby Isaac     }
34129566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &ilocalToParents));
34139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &iremoteToParents));
34146148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
34156148253fSToby Isaac       if (parentNodeAndIdFine[p - pStartF][0] >= 0) {
34166148253fSToby Isaac         ilocalToParents[nleavesToParents]        = p - pStartF;
34176148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p - pStartF][0];
34186148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p - pStartF][1];
34196148253fSToby Isaac         nleavesToParents++;
34206148253fSToby Isaac       }
34216148253fSToby Isaac     }
34229566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse), &sfToParents));
34239566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(sfToParents, pEndC - pStartC, nleavesToParents, ilocalToParents, PETSC_OWN_POINTER, iremoteToParents, PETSC_OWN_POINTER));
34249566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34256148253fSToby Isaac 
34266148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
34276148253fSToby Isaac 
34289566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parentNodeAndIdCoarse, parentNodeAndIdFine));
34299566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&threeInt));
34306148253fSToby Isaac   }
3431f30e825dSToby Isaac 
34326148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
34336148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
34346148253fSToby Isaac     PetscSF  sfDofsOnly;
34356148253fSToby Isaac 
34366148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
34379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34389566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3439ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
34406148253fSToby Isaac     }
34419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
34426148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
34439566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3445ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = p - pStartC;
34466148253fSToby Isaac     }
34479566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
34489566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34499566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
34506148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
34516148253fSToby Isaac   }
3452f30e825dSToby Isaac 
34536148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
34549566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded, &rootDegrees));
34559566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded, &rootDegrees));
34569566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &multiRootSec));
34579566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(multiRootSec, pStartC, pEndC));
345848a46eb9SPierre Jolivet   for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionSetDof(multiRootSec, p, rootDegrees[p - pStartC]));
34599566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(multiRootSec));
34609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(multiRootSec, &numMulti));
34619566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
3462f30e825dSToby Isaac   { /* distribute the leaf section */
3463f30e825dSToby Isaac     PetscSF   multi, multiInv, indicesSF;
3464f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
34658d2f55e7SToby Isaac 
34669566063dSJacob Faibussowitsch     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded, &multi));
34679566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF(multi, &multiInv));
34689566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(multiInv, leafIndicesSec, &remoteOffsets, rootIndicesSec));
34699566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(multiInv, leafIndicesSec, remoteOffsets, rootIndicesSec, &indicesSF));
34709566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
34719566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&multiInv));
34729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
3473c921d74cSToby Isaac     if (gatheredIndices) {
34749566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootInds));
34759566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
34769566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3477c921d74cSToby Isaac     }
3478c921d74cSToby Isaac     if (gatheredValues) {
34799566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootVals));
34809566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
34819566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3482c921d74cSToby Isaac     }
34839566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
34848d2f55e7SToby Isaac   }
34859566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
34869566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafInds));
34879566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafVals));
34889566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3489c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3490c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3491c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3492c921d74cSToby Isaac   if (gatheredValues) *gatheredValues = rootVals;
34933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3494ebf164c7SToby Isaac }
3495ebf164c7SToby Isaac 
3496d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3497d71ae5a4SJacob Faibussowitsch {
3498ebf164c7SToby Isaac   DM             refTree;
3499c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3500ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3501ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3502ebf164c7SToby Isaac   PetscSection   cSecRef;
3503277f51e8SBarry Smith   PetscInt      *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3504ebf164c7SToby Isaac   Mat            injRef;
3505c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3506ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3507ebf164c7SToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
3508ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3509ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3510ebf164c7SToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3511ebf164c7SToby Isaac 
3512ebf164c7SToby Isaac   PetscFunctionBegin;
3513ebf164c7SToby Isaac 
3514ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
35159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
35169566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
35179566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
35189566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
3519ebf164c7SToby Isaac 
35209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
35219566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
35229566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
35239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
35249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
35259566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
35269566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
35279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
3528ebf164c7SToby Isaac   {
3529ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
35309566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
3531ebf164c7SToby Isaac   }
3532ebf164c7SToby Isaac 
35339566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, childIds, NULL, numFields, offsets, &multiRootSec, &rootIndicesSec, &rootIndices, NULL));
35348d2f55e7SToby Isaac 
35359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &parentIndices));
3536f30e825dSToby Isaac 
3537f30e825dSToby Isaac   /* count indices */
35389566063dSJacob Faibussowitsch   PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
35399566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
35409566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
35419566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
35429566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
35439566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(rowEnd - rowStart, &nnzD, rowEnd - rowStart, &nnzO));
3544f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3545f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
35468d2f55e7SToby Isaac 
35479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
35489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3549f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
35509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
35518d2f55e7SToby Isaac 
35528d2f55e7SToby Isaac     rowOffsets[0]  = 0;
3553f30e825dSToby Isaac     offsetsCopy[0] = 0;
35548d2f55e7SToby Isaac     if (numFields) {
35558d2f55e7SToby Isaac       PetscInt f;
35568d2f55e7SToby Isaac 
3557f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3558f30e825dSToby Isaac         PetscInt fDof;
35599566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3560f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
35618d2f55e7SToby Isaac       }
35629566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3563367003a6SStefano Zampini     } else {
35649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3565f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
35668d2f55e7SToby Isaac     }
3567f30e825dSToby Isaac 
35689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
35699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3570f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3571f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3572f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3573f30e825dSToby Isaac       const PetscInt *childIndices;
3574f30e825dSToby Isaac 
35759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
35769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3577f30e825dSToby Isaac       childId      = rootIndices[offset++];
3578f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3579f30e825dSToby Isaac       numIndices--;
3580f30e825dSToby Isaac 
3581f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3582f30e825dSToby Isaac         PetscInt i;
3583f30e825dSToby Isaac 
3584f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3585f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3586f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3587f30e825dSToby Isaac           if (rowIndex < 0) continue;
358808401ef6SPierre Jolivet           PetscCheck(colIndex >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unconstrained fine and constrained coarse");
3589a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3590f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
35919371c9d4SSatish Balay           } else {
3592f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3593f30e825dSToby Isaac           }
3594f30e825dSToby Isaac         }
35959371c9d4SSatish Balay       } else {
3596f30e825dSToby Isaac         PetscInt parentId, f, lim;
3597f30e825dSToby Isaac 
35989566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3599f30e825dSToby Isaac 
3600f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3601f30e825dSToby Isaac         offsets[0] = 0;
36028d2f55e7SToby Isaac         if (numFields) {
36038d2f55e7SToby Isaac           PetscInt f;
3604f30e825dSToby Isaac 
36058d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3606f30e825dSToby Isaac             PetscInt fDof;
36079566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3608f30e825dSToby Isaac 
3609f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
36108d2f55e7SToby Isaac           }
36119371c9d4SSatish Balay         } else {
3612f30e825dSToby Isaac           PetscInt cDof;
3613f30e825dSToby Isaac 
36149566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3615f30e825dSToby Isaac           offsets[1] = cDof;
3616f30e825dSToby Isaac         }
3617f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3618f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3619f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3620f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3621f30e825dSToby Isaac 
3622f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3623f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3624f30e825dSToby Isaac 
3625f30e825dSToby Isaac             if (colIndex < 0) continue;
3626f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3627f30e825dSToby Isaac               numD++;
36289371c9d4SSatish Balay             } else {
3629f30e825dSToby Isaac               numO++;
3630f30e825dSToby Isaac             }
3631f30e825dSToby Isaac           }
3632f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3633f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3634f30e825dSToby Isaac 
3635f30e825dSToby Isaac             if (rowIndex < 0) continue;
3636f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3637f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
36388d2f55e7SToby Isaac           }
36398d2f55e7SToby Isaac         }
36408d2f55e7SToby Isaac       }
3641f30e825dSToby Isaac     }
3642f30e825dSToby Isaac   }
3643f30e825dSToby Isaac   /* preallocate */
36449566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mat, 1, nnzD, nnzO, NULL, NULL));
36459566063dSJacob Faibussowitsch   PetscCall(PetscFree2(nnzD, nnzO));
3646f30e825dSToby Isaac   /* insert values */
36479566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3648f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3649f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3650f30e825dSToby Isaac 
36519566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
36529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3653f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
36549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
3655f30e825dSToby Isaac 
3656f30e825dSToby Isaac     rowOffsets[0]  = 0;
3657f30e825dSToby Isaac     offsetsCopy[0] = 0;
36588d2f55e7SToby Isaac     if (numFields) {
36598d2f55e7SToby Isaac       PetscInt f;
3660f30e825dSToby Isaac 
36618d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3662f30e825dSToby Isaac         PetscInt fDof;
36639566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3664f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3665f30e825dSToby Isaac       }
36669566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3667367003a6SStefano Zampini     } else {
36689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3669f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3670f30e825dSToby Isaac     }
3671f30e825dSToby Isaac 
36729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
36739566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3674f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3675f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3676f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3677f30e825dSToby Isaac       const PetscInt *childIndices;
3678f30e825dSToby Isaac 
36799566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
36809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3681f30e825dSToby Isaac       childId      = rootIndices[offset++];
3682f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3683f30e825dSToby Isaac       numIndices--;
3684f30e825dSToby Isaac 
3685f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3686f30e825dSToby Isaac         PetscInt i;
3687f30e825dSToby Isaac 
368848a46eb9SPierre Jolivet         for (i = 0; i < numIndices; i++) PetscCall(MatSetValue(mat, parentIndices[i], childIndices[i], 1., INSERT_VALUES));
36899371c9d4SSatish Balay       } else {
3690f30e825dSToby Isaac         PetscInt parentId, f, lim;
36918d2f55e7SToby Isaac 
36929566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3693f30e825dSToby Isaac 
3694f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3695f30e825dSToby Isaac         offsets[0] = 0;
36968d2f55e7SToby Isaac         if (numFields) {
3697f30e825dSToby Isaac           PetscInt f;
36988d2f55e7SToby Isaac 
3699f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3700f30e825dSToby Isaac             PetscInt fDof;
37019566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3702f30e825dSToby Isaac 
3703f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
37048d2f55e7SToby Isaac           }
37059371c9d4SSatish Balay         } else {
3706f30e825dSToby Isaac           PetscInt cDof;
3707f30e825dSToby Isaac 
37089566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3709f30e825dSToby Isaac           offsets[1] = cDof;
37108d2f55e7SToby Isaac         }
3711f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3712f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3713f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3714f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3715f30e825dSToby Isaac 
37169566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat, rowOffsets[f + 1] - rowOffsets[f], rowIndices, offsets[f + 1] - offsets[f], colIndices, childMat, INSERT_VALUES));
37178d2f55e7SToby Isaac         }
37188d2f55e7SToby Isaac       }
37198d2f55e7SToby Isaac     }
37208d2f55e7SToby Isaac   }
37219566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
37229566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
37239566063dSJacob Faibussowitsch   PetscCall(PetscFree(parentIndices));
37249566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
37259566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootIndices));
37269566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
3727f30e825dSToby Isaac 
37289566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
37299566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
37303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3731154bca37SToby Isaac }
373238fc2455SToby Isaac 
3733d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3734d71ae5a4SJacob Faibussowitsch {
373562095d54SToby Isaac   PetscSF            coarseToFineEmbedded;
373662095d54SToby Isaac   PetscSection       globalCoarse, globalFine;
373762095d54SToby Isaac   PetscSection       localCoarse, localFine;
373862095d54SToby Isaac   PetscSection       aSec, cSec;
373962095d54SToby Isaac   PetscSection       rootValuesSec;
374062095d54SToby Isaac   PetscSection       leafValuesSec;
374162095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
374262095d54SToby Isaac   IS                 aIS;
374362095d54SToby Isaac   const PetscInt    *anchors;
374462095d54SToby Isaac   Mat                cMat;
374562095d54SToby Isaac   PetscInt           numFields;
3746412e9a14SMatthew G. Knepley   PetscInt           pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
374762095d54SToby Isaac   PetscInt           aStart, aEnd, cStart, cEnd;
374862095d54SToby Isaac   PetscInt          *maxChildIds;
374962095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
37500eb7e1eaSToby Isaac   PetscFV            fv = NULL;
37510eb7e1eaSToby Isaac   PetscInt           dim, numFVcomps = -1, fvField = -1;
37520eb7e1eaSToby Isaac   DM                 cellDM = NULL, gradDM = NULL;
37530eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
37540eb7e1eaSToby Isaac   const PetscScalar *gradArray     = NULL;
375562095d54SToby Isaac 
3756ebf164c7SToby Isaac   PetscFunctionBegin;
37579566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
37589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
37599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(coarse, 0, &cellStart, &cellEnd));
37609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
37619566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
37629566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(coarse, &dim));
376362095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3764e4a60869SToby Isaac     PetscInt        nleaves, l;
3765e4a60869SToby Isaac     const PetscInt *leaves;
376662095d54SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
376762095d54SToby Isaac 
37689566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
3769e4a60869SToby Isaac 
3770e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3771e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3772e4a60869SToby Isaac 
37739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3775ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
377662095d54SToby Isaac     }
37779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
37784833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
3779e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3780e4a60869SToby Isaac 
37819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3783ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
378462095d54SToby Isaac     }
37859566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
37869566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
378762095d54SToby Isaac   }
378862095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
37899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
3790ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
37919566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
37929566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
379362095d54SToby Isaac 
37949566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
37959566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
379662095d54SToby Isaac 
37979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
37989566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
37999566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
380062095d54SToby Isaac 
38019566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
38029566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
380362095d54SToby Isaac 
380462095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
38059566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootValuesSec));
38069566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootValuesSec, pStartC, pEndC));
38079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
380862095d54SToby Isaac   {
380962095d54SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
38109566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &newOffsets, maxFields, &newOffsetsCopy, maxFields, &rowOffsets, maxFields, &numD, maxFields, &numO));
381162095d54SToby Isaac   }
38120eb7e1eaSToby Isaac   if (grad) {
38130eb7e1eaSToby Isaac     PetscInt i;
38140eb7e1eaSToby Isaac 
38159566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeom, &cellDM));
38169566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeom, &cellGeomArray));
38179566063dSJacob Faibussowitsch     PetscCall(VecGetDM(grad, &gradDM));
38189566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(grad, &gradArray));
38190eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1, numFields); i++) {
38200eb7e1eaSToby Isaac       PetscObject  obj;
38210eb7e1eaSToby Isaac       PetscClassId id;
38220eb7e1eaSToby Isaac 
38239566063dSJacob Faibussowitsch       PetscCall(DMGetField(coarse, i, NULL, &obj));
38249566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
38250eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
38260eb7e1eaSToby Isaac         fv = (PetscFV)obj;
38279566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &numFVcomps));
38280eb7e1eaSToby Isaac         fvField = i;
38290eb7e1eaSToby Isaac         break;
38300eb7e1eaSToby Isaac       }
38310eb7e1eaSToby Isaac     }
38320eb7e1eaSToby Isaac   }
383362095d54SToby Isaac 
383462095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
383562095d54SToby Isaac     PetscInt dof;
383662095d54SToby Isaac     PetscInt maxChildId = maxChildIds[p - pStartC];
383762095d54SToby Isaac     PetscInt numValues  = 0;
383862095d54SToby Isaac 
38399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3840ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
384162095d54SToby Isaac     offsets[0]    = 0;
384262095d54SToby Isaac     newOffsets[0] = 0;
384362095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
384462095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
384562095d54SToby Isaac 
38469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
384762095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
384862095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
384962095d54SToby Isaac 
38509566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
385162095d54SToby Isaac         numValues += clDof;
385262095d54SToby Isaac       }
38539566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
38549371c9d4SSatish Balay     } else if (maxChildId == -1) {
38559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localCoarse, p, &numValues));
385662095d54SToby Isaac     }
385762095d54SToby Isaac     /* we will pack the column indices with the field offsets */
385878b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
38590eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
38600eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
38610eb7e1eaSToby Isaac     }
38629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootValuesSec, p, numValues));
386362095d54SToby Isaac   }
38649566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootValuesSec));
386562095d54SToby Isaac   {
386662095d54SToby Isaac     PetscInt           numRootValues;
386762095d54SToby Isaac     const PetscScalar *coarseArray;
386862095d54SToby Isaac 
38699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootValuesSec, &numRootValues));
38709566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRootValues, &rootValues));
38719566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecCoarseLocal, &coarseArray));
387262095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
387362095d54SToby Isaac       PetscInt     numValues;
387462095d54SToby Isaac       PetscInt     pValOff;
387562095d54SToby Isaac       PetscScalar *pVal;
387662095d54SToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
387762095d54SToby Isaac 
38789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootValuesSec, p, &numValues));
3879ad540459SPierre Jolivet       if (!numValues) continue;
38809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootValuesSec, p, &pValOff));
388162095d54SToby Isaac       pVal = &(rootValues[pValOff]);
388262095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
38830eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
38849566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(coarse, NULL, vecCoarseLocal, p, &closureSize, &pVal));
38850eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
3886193eb951SToby Isaac           PetscFVCellGeom *cg;
38876dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
38880eb7e1eaSToby Isaac           PetscInt         i;
38890eb7e1eaSToby Isaac 
38900eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
38910eb7e1eaSToby Isaac 
38929566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(cellDM, p, cellGeomArray, (void *)&cg));
38930eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
38940eb7e1eaSToby Isaac           pVal += dim;
38959566063dSJacob Faibussowitsch           PetscCall(DMPlexPointGlobalRead(gradDM, p, gradArray, (void *)&gradVals));
38960eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
38970eb7e1eaSToby Isaac         }
38989371c9d4SSatish Balay       } else if (maxChildId == -1) {
389978b7adb5SToby Isaac         PetscInt lDof, lOff, i;
390078b7adb5SToby Isaac 
39019566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, p, &lDof));
39029566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(localCoarse, p, &lOff));
390378b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
390478b7adb5SToby Isaac       }
390578b7adb5SToby Isaac     }
39069566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecCoarseLocal, &coarseArray));
39079566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
390862095d54SToby Isaac   }
390962095d54SToby Isaac   {
391062095d54SToby Isaac     PetscSF   valuesSF;
391162095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
391262095d54SToby Isaac 
39139566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafValuesSec));
39149566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootValuesSec, &remoteOffsetsValues, leafValuesSec));
39159566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootValuesSec, remoteOffsetsValues, leafValuesSec, &valuesSF));
39169566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
39179566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsValues));
39189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafValuesSec, &numLeafValues));
39199566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafValues, &leafValues));
39209566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39219566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39229566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&valuesSF));
39239566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootValues));
39249566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootValuesSec));
392562095d54SToby Isaac   }
39269566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
392762095d54SToby Isaac   {
392862095d54SToby Isaac     PetscInt       maxDof;
392962095d54SToby Isaac     PetscInt      *rowIndices;
393062095d54SToby Isaac     DM             refTree;
393162095d54SToby Isaac     PetscInt     **refPointFieldN;
393262095d54SToby Isaac     PetscScalar ***refPointFieldMats;
393362095d54SToby Isaac     PetscSection   refConSec, refAnSec;
39340eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, leafStart, leafEnd;
393562095d54SToby Isaac     PetscScalar   *pointWork;
393662095d54SToby Isaac 
39379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
39389566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
39399566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
39409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
39419566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(fine, refTree));
39429566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
39439566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
39449566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
39459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
39469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafValuesSec, &leafStart, &leafEnd));
39479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSimplexOrBoxCells(fine, 0, &cellStart, &cellEnd));
39480eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
394962095d54SToby Isaac       PetscInt           gDof, gcDof, gOff, lDof;
395062095d54SToby Isaac       PetscInt           numValues, pValOff;
395162095d54SToby Isaac       PetscInt           childId;
395262095d54SToby Isaac       const PetscScalar *pVal;
39530eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
395462095d54SToby Isaac 
39559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
39569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localFine, p, &lDof));
39579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
3958ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
39599566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
39609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafValuesSec, p, &numValues));
396162095d54SToby Isaac       if (!numValues) continue;
39629566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafValuesSec, p, &pValOff));
396362095d54SToby Isaac       pVal              = &leafValues[pValOff];
396462095d54SToby Isaac       offsets[0]        = 0;
396562095d54SToby Isaac       offsetsCopy[0]    = 0;
396662095d54SToby Isaac       newOffsets[0]     = 0;
396762095d54SToby Isaac       newOffsetsCopy[0] = 0;
39684833aeb0SToby Isaac       childId           = cids[p - pStartF];
396962095d54SToby Isaac       if (numFields) {
397062095d54SToby Isaac         PetscInt f;
397162095d54SToby Isaac         for (f = 0; f < numFields; f++) {
397262095d54SToby Isaac           PetscInt rowDof;
397362095d54SToby Isaac 
39749566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
397562095d54SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
397662095d54SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
397762095d54SToby Isaac           /* TODO: closure indices */
39789f4e70e1SToby Isaac           newOffsets[f + 1] = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
397962095d54SToby Isaac         }
39809566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
39819371c9d4SSatish Balay       } else {
39824833aeb0SToby Isaac         offsets[0]    = 0;
39834833aeb0SToby Isaac         offsets[1]    = lDof;
39844833aeb0SToby Isaac         newOffsets[0] = 0;
39854833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
39869566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
398762095d54SToby Isaac       }
398862095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
39899566063dSJacob Faibussowitsch         PetscCall(VecSetValues(vecFine, numValues, rowIndices, pVal, INSERT_VALUES));
399062095d54SToby Isaac       } else {
399162095d54SToby Isaac         PetscInt f;
399262095d54SToby Isaac 
399378b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
399478b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
399578b7adb5SToby Isaac           fvGradData = &pVal[numValues];
399678b7adb5SToby Isaac         }
399762095d54SToby Isaac         for (f = 0; f < PetscMax(1, numFields); f++) {
399862095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
399962095d54SToby Isaac           PetscInt           numRows  = offsets[f + 1] - offsets[f];
400062095d54SToby Isaac           PetscInt           numCols  = newOffsets[f + 1] - newOffsets[f];
400162095d54SToby Isaac           const PetscScalar *cVal     = &pVal[newOffsets[f]];
400262095d54SToby Isaac           PetscScalar       *rVal     = &pointWork[offsets[f]];
400362095d54SToby Isaac           PetscInt           i, j;
400462095d54SToby Isaac 
4005708c7f19SToby Isaac #if 0
400663a3b9bcSJacob 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));
4007708c7f19SToby Isaac #endif
400862095d54SToby Isaac           for (i = 0; i < numRows; i++) {
400962095d54SToby Isaac             PetscScalar val = 0.;
4010ad540459SPierre Jolivet             for (j = 0; j < numCols; j++) val += childMat[i * numCols + j] * cVal[j];
401162095d54SToby Isaac             rVal[i] = val;
401262095d54SToby Isaac           }
40130eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
40140eb7e1eaSToby Isaac             PetscReal          centroid[3];
40150eb7e1eaSToby Isaac             PetscScalar        diff[3];
40160eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
40170eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
40180eb7e1eaSToby Isaac 
40199566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFVM(fine, p, NULL, centroid, NULL));
4020ad540459SPierre Jolivet             for (i = 0; i < dim; i++) diff[i] = centroid[i] - parentCentroid[i];
40210eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
40220eb7e1eaSToby Isaac               PetscScalar val = 0.;
40230eb7e1eaSToby Isaac 
4024ad540459SPierre Jolivet               for (j = 0; j < dim; j++) val += gradient[dim * i + j] * diff[j];
40250eb7e1eaSToby Isaac               rVal[i] += val;
40260eb7e1eaSToby Isaac             }
40270eb7e1eaSToby Isaac           }
40289566063dSJacob Faibussowitsch           PetscCall(VecSetValues(vecFine, numRows, &rowIndices[offsets[f]], rVal, INSERT_VALUES));
402962095d54SToby Isaac         }
403062095d54SToby Isaac       }
403162095d54SToby Isaac     }
40329566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
40339566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
40349566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
403562095d54SToby Isaac   }
40369566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafValues));
40379566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafValuesSec));
40389566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
40399566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
40403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4041ebf164c7SToby Isaac }
4042ebf164c7SToby Isaac 
4043d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4044d71ae5a4SJacob Faibussowitsch {
4045c921d74cSToby Isaac   DM             refTree;
4046c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4047c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4048c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4049c921d74cSToby Isaac   PetscSection   cSecRef;
4050c921d74cSToby Isaac   PetscInt      *parentIndices, pRefStart, pRefEnd;
4051d3bc4906SToby Isaac   PetscScalar   *rootValues, *parentValues;
4052c921d74cSToby Isaac   Mat            injRef;
4053c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4054c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4055c921d74cSToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
4056c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4057c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4058c921d74cSToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4059c921d74cSToby Isaac 
4060ebf164c7SToby Isaac   PetscFunctionBegin;
4061c921d74cSToby Isaac 
4062c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
40639566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40649566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecCoarse, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
40669566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(coarse, refTree));
40679566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
40689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
40699566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
4070c921d74cSToby Isaac 
40719566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
40729566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
40739566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
40749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
40759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
40769566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
40779566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
40789566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
4079c921d74cSToby Isaac   {
4080c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
40819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
4082c921d74cSToby Isaac   }
4083c921d74cSToby Isaac 
40849566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, cids, vecFine, numFields, offsets, &multiRootSec, &rootIndicesSec, NULL, &rootValues));
4085c921d74cSToby Isaac 
40869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxDof, &parentIndices, maxDof, &parentValues));
4087c921d74cSToby Isaac 
4088c921d74cSToby Isaac   /* count indices */
40899566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecFine, &colMap));
40909566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecCoarse, &rowMap));
40919566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
40929566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
40939566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
40949566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
4095c921d74cSToby Isaac   /* insert values */
40969566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4097c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4098c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
409978b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4100c921d74cSToby Isaac 
41019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
41029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
4103c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
41049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localCoarse, p, &dof));
41059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
4106c921d74cSToby Isaac 
4107c921d74cSToby Isaac     rowOffsets[0]  = 0;
4108c921d74cSToby Isaac     offsetsCopy[0] = 0;
4109c921d74cSToby Isaac     if (numFields) {
4110c921d74cSToby Isaac       PetscInt f;
4111c921d74cSToby Isaac 
4112c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4113c921d74cSToby Isaac         PetscInt fDof;
41149566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
4115c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4116c921d74cSToby Isaac       }
41179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
4118367003a6SStefano Zampini     } else {
41199566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
4120c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4121c921d74cSToby Isaac     }
4122c921d74cSToby Isaac 
41239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
41249566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
4125c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
41262f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4127c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4128c921d74cSToby Isaac       PetscInt           numIndices, childId, offset;
4129c921d74cSToby Isaac       const PetscScalar *childValues;
4130c921d74cSToby Isaac 
41319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
41329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
4133c921d74cSToby Isaac       childId     = (PetscInt)PetscRealPart(rootValues[offset++]);
4134c921d74cSToby Isaac       childValues = &rootValues[offset];
4135c921d74cSToby Isaac       numIndices--;
4136c921d74cSToby Isaac 
4137c921d74cSToby Isaac       if (childId == -2) { /* skip */
4138c921d74cSToby Isaac         continue;
4139c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
41402f65e181SToby Isaac         PetscInt m;
41412f65e181SToby Isaac 
414278b7adb5SToby Isaac         contribute = PETSC_TRUE;
41432f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4144beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4145d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4146d3bc4906SToby Isaac 
414778b7adb5SToby Isaac         contribute = PETSC_TRUE;
41489566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
4149d3bc4906SToby Isaac 
4150d3bc4906SToby Isaac         lim        = PetscMax(1, numFields);
4151d3bc4906SToby Isaac         offsets[0] = 0;
4152d3bc4906SToby Isaac         if (numFields) {
4153d3bc4906SToby Isaac           PetscInt f;
4154d3bc4906SToby Isaac 
4155d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4156d3bc4906SToby Isaac             PetscInt fDof;
41579566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
4158d3bc4906SToby Isaac 
4159d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4160d3bc4906SToby Isaac           }
41619371c9d4SSatish Balay         } else {
4162d3bc4906SToby Isaac           PetscInt cDof;
4163d3bc4906SToby Isaac 
41649566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
4165d3bc4906SToby Isaac           offsets[1] = cDof;
4166d3bc4906SToby Isaac         }
4167d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4168d3bc4906SToby Isaac           PetscScalar       *childMat = &childrenMats[childId - pRefStart][f][0];
4169d3bc4906SToby Isaac           PetscInt           n        = offsets[f + 1] - offsets[f];
4170e328ff09SToby Isaac           PetscInt           m        = rowOffsets[f + 1] - rowOffsets[f];
4171d3bc4906SToby Isaac           PetscInt           i, j;
4172d3bc4906SToby Isaac           const PetscScalar *colValues = &childValues[offsets[f]];
4173d3bc4906SToby Isaac 
4174e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4175d3bc4906SToby Isaac             PetscScalar val = 0.;
4176ad540459SPierre Jolivet             for (j = 0; j < n; j++) val += childMat[n * i + j] * colValues[j];
4177e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4178d3bc4906SToby Isaac           }
4179d3bc4906SToby Isaac         }
4180c921d74cSToby Isaac       }
4181c921d74cSToby Isaac     }
41829566063dSJacob Faibussowitsch     if (contribute) PetscCall(VecSetValues(vecCoarse, dof, parentIndices, parentValues, INSERT_VALUES));
4183c921d74cSToby Isaac   }
41849566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
41859566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
41869566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parentIndices, parentValues));
41879566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
41889566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootValues));
41899566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
41903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4191ebf164c7SToby Isaac }
4192ebf164c7SToby Isaac 
4193ff1f73f7SToby Isaac /*@
4194ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4195ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4196ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4197ff1f73f7SToby Isaac 
419820f4b53cSBarry Smith   Collective
4199ff1f73f7SToby Isaac 
4200ff1f73f7SToby Isaac   Input Parameters:
4201a1cb98faSBarry Smith + dmIn        - The `DMPLEX` mesh for the input vector
420220f4b53cSBarry Smith . dmOut        - The second `DMPLEX` mesh
4203ff1f73f7SToby Isaac . vecIn       - The input vector
420420f4b53cSBarry Smith . sfRefine    - A star forest indicating points in the mesh `dmIn` (roots in the star forest) that are parents to points in
420520f4b53cSBarry Smith                 the mesh `dmOut` (leaves in the star forest), i.e. where `dmOut` is more refined than `dmIn`
420620f4b53cSBarry Smith . sfCoarsen   - A star forest indicating points in the mesh `dmOut` (roots in the star forest) that are parents to points in
420720f4b53cSBarry Smith                 the mesh `dmIn` (leaves in the star forest), i.e. where `dmOut` is more coarsened than `dmIn`
420820f4b53cSBarry Smith . cidsRefine  - The childIds of the points in `dmOut`.  These childIds relate back to the reference tree: childid[j] = k implies
420920f4b53cSBarry Smith                 that mesh point j of `dmOut` was refined from a point in `dmIn` just as the mesh point k in the reference
421020f4b53cSBarry Smith                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in `dmOut` is exactly
421120f4b53cSBarry Smith                 equivalent to its root in `dmIn`, so no interpolation is necessary.  childid[j] = -2 indicates that this
421220f4b53cSBarry Smith                 point j in `dmOut` is not a leaf of `sfRefine`.
421320f4b53cSBarry Smith . cidsCoarsen - The childIds of the points in `dmIn`.  These childIds relate back to the reference tree: childid[j] = k implies
421420f4b53cSBarry Smith                 that mesh point j of dmIn coarsens to a point in `dmOut` just as the mesh point k in the reference
421520f4b53cSBarry Smith                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in `dmOut` is not a leaf in `sfCoarsen`.
421620f4b53cSBarry Smith . useBCs      - `PETSC_TRUE` indicates that boundary values should be inserted into `vecIn` before transfer.
4217ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4218ff1f73f7SToby Isaac 
42192fe279fdSBarry Smith   Output Parameter:
42208966356dSPierre Jolivet . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transferred
422120f4b53cSBarry Smith                 projection of `vecIn` from `dmIn` to `dmOut`.  Note that any field discretized with a `PetscFV` finite volume
4222ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4223ff1f73f7SToby Isaac                 coarse points to fine points.
4224ff1f73f7SToby Isaac 
4225ff1f73f7SToby Isaac   Level: developer
4226ff1f73f7SToby Isaac 
4227a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `Vec`, `PetscFV`, `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4228ff1f73f7SToby Isaac @*/
4229d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
4230d71ae5a4SJacob Faibussowitsch {
423138fc2455SToby Isaac   PetscFunctionBegin;
42329566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
4233ff1f73f7SToby Isaac   if (sfRefine) {
4234fbfa57b9SToby Isaac     Vec vecInLocal;
42350eb7e1eaSToby Isaac     DM  dmGrad   = NULL;
42360eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4237fbfa57b9SToby Isaac 
42389566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
42399566063dSJacob Faibussowitsch     PetscCall(VecSet(vecInLocal, 0.0));
42400eb7e1eaSToby Isaac     {
42410eb7e1eaSToby Isaac       PetscInt numFields, i;
42420eb7e1eaSToby Isaac 
42439566063dSJacob Faibussowitsch       PetscCall(DMGetNumFields(dmIn, &numFields));
42440eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
42450eb7e1eaSToby Isaac         PetscObject  obj;
42460eb7e1eaSToby Isaac         PetscClassId classid;
42470eb7e1eaSToby Isaac 
42489566063dSJacob Faibussowitsch         PetscCall(DMGetField(dmIn, i, NULL, &obj));
42499566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &classid));
42500eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
42519566063dSJacob Faibussowitsch           PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
42520eb7e1eaSToby Isaac           break;
42530eb7e1eaSToby Isaac         }
42540eb7e1eaSToby Isaac       }
42550eb7e1eaSToby Isaac     }
42561baa6e33SBarry Smith     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
42579566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42589566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42590eb7e1eaSToby Isaac     if (dmGrad) {
42609566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad, &grad));
42619566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
42620eb7e1eaSToby Isaac     }
42639566063dSJacob Faibussowitsch     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
42649566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
426548a46eb9SPierre Jolivet     if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
4266ebf164c7SToby Isaac   }
42671baa6e33SBarry Smith   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
42689566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(vecOut));
42699566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(vecOut));
42703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
427138fc2455SToby Isaac }
4272