xref: /petsc/src/dm/impls/plex/plextree.c (revision aaa8cc7d2a5c3913edcbb923e20f154fe9c4aa65)
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
977*aaa8cc7dSPierre 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));
15599566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
15609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
15619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anSec, &anIS));
15629566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(anIS, &anchors));
15639566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
15649566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(conSec, &conStart, &conEnd));
15659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
15669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
15679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof * maxAnDof, &pointWork));
156821968bf8SToby Isaac 
156921968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
15709566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
157195a0b26dSToby Isaac 
157295a0b26dSToby Isaac   /* step 2: compute the preorder */
15739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
15749566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(pEnd - pStart, &perm, pEnd - pStart, &iperm));
157595a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
157695a0b26dSToby Isaac     perm[p - pStart]  = p;
157795a0b26dSToby Isaac     iperm[p - pStart] = p - pStart;
157895a0b26dSToby Isaac   }
157995a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
158095a0b26dSToby Isaac     PetscInt point = perm[p];
158195a0b26dSToby Isaac     PetscInt parent;
158295a0b26dSToby Isaac 
15839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
158495a0b26dSToby Isaac     if (parent == point) {
158595a0b26dSToby Isaac       p++;
15869371c9d4SSatish Balay     } else {
158795a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
158895a0b26dSToby Isaac 
15899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
159095a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
159195a0b26dSToby Isaac         PetscInt q = closure[2 * i];
159295a0b26dSToby Isaac         if (iperm[q - pStart] > iperm[point - pStart]) {
159395a0b26dSToby Isaac           /* swap */
159495a0b26dSToby Isaac           perm[p]                 = q;
159595a0b26dSToby Isaac           perm[iperm[q - pStart]] = point;
159695a0b26dSToby Isaac           iperm[point - pStart]   = iperm[q - pStart];
159795a0b26dSToby Isaac           iperm[q - pStart]       = p;
159895a0b26dSToby Isaac           break;
159995a0b26dSToby Isaac         }
160095a0b26dSToby Isaac       }
160195a0b26dSToby Isaac       size = closureSize;
16029566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1603ad540459SPierre Jolivet       if (i == size) p++;
160495a0b26dSToby Isaac     }
160595a0b26dSToby Isaac   }
160695a0b26dSToby Isaac 
160795a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
160895a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
160995a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
161095a0b26dSToby Isaac    * values outside of the Mat first.
161195a0b26dSToby Isaac    */
161295a0b26dSToby Isaac   {
161395a0b26dSToby Isaac     PetscInt        nRows, row, nnz;
161495a0b26dSToby Isaac     PetscBool       done;
1615cd6fc93eSToby Isaac     PetscInt        secStart, secEnd;
161695a0b26dSToby Isaac     const PetscInt *ia, *ja;
161795a0b26dSToby Isaac     PetscScalar    *vals;
161895a0b26dSToby Isaac 
1619cd6fc93eSToby Isaac     PetscCall(PetscSectionGetChart(section, &secStart, &secEnd));
16209566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
162128b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not get RowIJ of constraint matrix");
162295a0b26dSToby Isaac     nnz = ia[nRows];
162395a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
162495a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
16259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vals));
162695a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
162795a0b26dSToby Isaac       PetscInt parent, childid, closureSize, *closure = NULL;
162895a0b26dSToby Isaac       PetscInt point = perm[p], pointDof;
162995a0b26dSToby Isaac 
16309566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, point, &parent, &childid));
163195a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
16329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(conSec, point, &pointDof));
163395a0b26dSToby Isaac       if (!pointDof) continue;
16349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1635085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1636085f0adfSToby Isaac         PetscInt            cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
163795a0b26dSToby Isaac         PetscScalar        *pointMat;
1638085f0adfSToby Isaac         const PetscInt    **perms;
1639085f0adfSToby Isaac         const PetscScalar **flips;
164095a0b26dSToby Isaac 
1641085f0adfSToby Isaac         if (numFields) {
16429566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(conSec, point, f, &cDof));
16439566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(conSec, point, f, &cOff));
16449371c9d4SSatish Balay         } else {
16459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(conSec, point, &cDof));
16469566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(conSec, point, &cOff));
164795a0b26dSToby Isaac         }
164895a0b26dSToby Isaac         if (!cDof) continue;
16499566063dSJacob Faibussowitsch         if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
16509566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetPointSyms(section, closureSize, closure, &perms, &flips));
165195a0b26dSToby Isaac 
165295a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
165376bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
165495a0b26dSToby Isaac           for (r = 0; r < cDof; r++) {
165595a0b26dSToby Isaac             if (cDof > 1 && r) {
165663a3b9bcSJacob 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]));
165795a0b26dSToby Isaac             }
165895a0b26dSToby Isaac           }
165976bd3646SJed Brown         }
166095a0b26dSToby Isaac         /* zero rows */
1661ad540459SPierre Jolivet         for (i = ia[cOff]; i < ia[cOff + cDof]; i++) vals[i] = 0.;
166295a0b26dSToby Isaac         matOffset   = ia[cOff];
166395a0b26dSToby Isaac         numFillCols = ia[cOff + 1] - matOffset;
166495a0b26dSToby Isaac         pointMat    = refPointFieldMats[childid - pRefStart][f];
166595a0b26dSToby Isaac         numCols     = refPointFieldN[childid - pRefStart][f];
166695a0b26dSToby Isaac         offset      = 0;
166795a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
166895a0b26dSToby Isaac           PetscInt           q = closure[2 * i];
166995a0b26dSToby Isaac           PetscInt           aDof, aOff, j, k, qConDof, qConOff;
1670085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1671085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
167295a0b26dSToby Isaac 
167395a0b26dSToby Isaac           qConDof = qConOff = 0;
1674cd6fc93eSToby Isaac           if (q < secStart || q >= secEnd) continue;
1675085f0adfSToby Isaac           if (numFields) {
16769566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, q, f, &aDof));
16779566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, q, f, &aOff));
167895a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16799566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(conSec, q, f, &qConDof));
16809566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldOffset(conSec, q, f, &qConOff));
168195a0b26dSToby Isaac             }
16829371c9d4SSatish Balay           } else {
16839566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, q, &aDof));
16849566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, q, &aOff));
168595a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16869566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(conSec, q, &qConDof));
16879566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(conSec, q, &qConOff));
168895a0b26dSToby Isaac             }
168995a0b26dSToby Isaac           }
169095a0b26dSToby Isaac           if (!aDof) continue;
169195a0b26dSToby Isaac           if (qConDof) {
169295a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
169395a0b26dSToby Isaac              * be filled, thanks to preordering */
169495a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
169595a0b26dSToby Isaac             PetscInt aMatOffset   = ia[qConOff];
169695a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
169795a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
169895a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
169995a0b26dSToby Isaac                 PetscScalar inVal = 0;
170095a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1701085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
170295a0b26dSToby Isaac 
1703085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
170495a0b26dSToby Isaac                 }
170595a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
170695a0b26dSToby Isaac               }
170795a0b26dSToby Isaac             }
170895a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
170995a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
171095a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
171195a0b26dSToby Isaac               for (; k < numFillCols; k++) {
1712ad540459SPierre Jolivet                 if (ja[matOffset + k] == col) break;
171395a0b26dSToby Isaac               }
171463a3b9bcSJacob Faibussowitsch               PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, col);
1715ad540459SPierre Jolivet               for (r = 0; r < cDof; r++) vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
171695a0b26dSToby Isaac             }
17179371c9d4SSatish Balay           } else {
171895a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
171995a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
1720ad540459SPierre Jolivet               if (ja[matOffset + k] == aOff) break;
172195a0b26dSToby Isaac             }
172263a3b9bcSJacob Faibussowitsch             PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, aOff);
172395a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1724085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1725085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1726085f0adfSToby Isaac 
1727085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
172895a0b26dSToby Isaac               }
172995a0b26dSToby Isaac             }
173095a0b26dSToby Isaac           }
173195a0b26dSToby Isaac           offset += aDof;
173295a0b26dSToby Isaac         }
1733085f0adfSToby Isaac         if (numFields) {
17349566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestoreFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
1735085f0adfSToby Isaac         } else {
17369566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestorePointSyms(section, closureSize, closure, &perms, &flips));
1737085f0adfSToby Isaac         }
173895a0b26dSToby Isaac       }
17399566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
174095a0b26dSToby Isaac     }
174148a46eb9SPierre 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));
17429566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
174328b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not restore RowIJ of constraint matrix");
17449566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
17459566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
17469566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
174795a0b26dSToby Isaac   }
174895a0b26dSToby Isaac 
174995a0b26dSToby Isaac   /* clean up */
17509566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(anIS, &anchors));
17519566063dSJacob Faibussowitsch   PetscCall(PetscFree2(perm, iperm));
17529566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointWork));
17539566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
17543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
175595a0b26dSToby Isaac }
175695a0b26dSToby Isaac 
17576f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
17586f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
1759d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTreeRefineCell(DM dm, PetscInt cell, DM *ncdm)
1760d71ae5a4SJacob Faibussowitsch {
17616f5f1567SToby Isaac   DM           K;
1762420f55faSMatthew G. Knepley   PetscMPIInt  rank;
17636f5f1567SToby Isaac   PetscInt     dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
17646f5f1567SToby Isaac   PetscInt     numNewCones, *newConeSizes, *newCones, *newOrientations;
17656f5f1567SToby Isaac   PetscInt    *Kembedding;
17666f5f1567SToby Isaac   PetscInt    *cellClosure = NULL, nc;
17676f5f1567SToby Isaac   PetscScalar *newVertexCoords;
17686f5f1567SToby Isaac   PetscInt     numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
17696f5f1567SToby Isaac   PetscSection parentSection;
17706f5f1567SToby Isaac 
17716f5f1567SToby Isaac   PetscFunctionBegin;
17729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
17739566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
17749566063dSJacob Faibussowitsch   PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
17759566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ncdm, dim));
17766f5f1567SToby Isaac 
17779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
17789566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &parentSection));
17799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &K));
17806858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
1781dd400576SPatrick Sanan   if (rank == 0) {
17826f5f1567SToby Isaac     /* compute the new charts */
17839566063dSJacob Faibussowitsch     PetscCall(PetscMalloc5(dim + 1, &pNewCount, dim + 1, &pNewStart, dim + 1, &pNewEnd, dim + 1, &pOldStart, dim + 1, &pOldEnd));
17846f5f1567SToby Isaac     offset = 0;
17856f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
17866f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
17876f5f1567SToby Isaac 
17886f5f1567SToby Isaac       pNewStart[d] = offset;
17899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, d, &pOldStart[d], &pOldEnd[d]));
17909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
17916f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
17926f5f1567SToby Isaac       /* adding the new points */
17936f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
17946f5f1567SToby Isaac       if (!d) {
17956f5f1567SToby Isaac         /* removing the cell */
17966f5f1567SToby Isaac         pNewCount[d]--;
17976f5f1567SToby Isaac       }
17986f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
17996f5f1567SToby Isaac         PetscInt parent;
18009566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &parent, NULL));
18016f5f1567SToby Isaac         if (parent == k) {
18026f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
18036f5f1567SToby Isaac           pNewCount[d]--;
18046f5f1567SToby Isaac         }
18056f5f1567SToby Isaac       }
18066f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
18076f5f1567SToby Isaac       offset     = pNewEnd[d];
18086f5f1567SToby Isaac     }
18091dca8a05SBarry 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]);
18106f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
18119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
18126f5f1567SToby Isaac 
18139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pNewEnd[dim], &newConeSizes));
18146f5f1567SToby Isaac     {
1815b5a892a1SMatthew G. Knepley       DMPolytopeType pct, qct;
18166f5f1567SToby Isaac       PetscInt       kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
18176f5f1567SToby Isaac 
18189566063dSJacob Faibussowitsch       PetscCall(DMPlexGetChart(K, &kStart, &kEnd));
18199566063dSJacob Faibussowitsch       PetscCall(PetscMalloc4(kEnd - kStart, &Kembedding, kEnd - kStart, &perm, kEnd - kStart, &iperm, kEnd - kStart, &preOrient));
18206f5f1567SToby Isaac 
18216f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18226f5f1567SToby Isaac         perm[k - kStart]      = k;
18236f5f1567SToby Isaac         iperm[k - kStart]     = k - kStart;
18246f5f1567SToby Isaac         preOrient[k - kStart] = 0;
18256f5f1567SToby Isaac       }
18266f5f1567SToby Isaac 
18279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18286f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
18296f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2 * j + 1];
18306f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2 * j + 1];
18316f5f1567SToby Isaac         PetscInt p, q;
18326f5f1567SToby Isaac 
18336f5f1567SToby Isaac         p = closureK[2 * j];
18346f5f1567SToby Isaac         q = cellClosure[2 * j];
18359566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(K, p, &pct));
18369566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, q, &qct));
18376f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
1838ad540459SPierre Jolivet           if (q >= pOldStart[d] && q < pOldEnd[d]) Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
18396f5f1567SToby Isaac         }
1840b5a892a1SMatthew G. Knepley         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1841b5a892a1SMatthew G. Knepley         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
18426f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
18436f5f1567SToby Isaac           PetscInt        numChildren, i;
18446f5f1567SToby Isaac           const PetscInt *children;
18456f5f1567SToby Isaac 
18469566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(K, p, &numChildren, &children));
18476f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
18486f5f1567SToby Isaac             PetscInt kPerm, oPerm;
18496f5f1567SToby Isaac 
18506f5f1567SToby Isaac             k = children[i];
18519566063dSJacob Faibussowitsch             PetscCall(DMPlexReferenceTreeGetChildSymmetry(K, p, parentOrientA, 0, k, parentOrientB, &oPerm, &kPerm));
18526f5f1567SToby Isaac             /* perm = what refTree position I'm in */
18536f5f1567SToby Isaac             perm[kPerm - kStart] = k;
18546f5f1567SToby Isaac             /* iperm = who is at this position */
18556f5f1567SToby Isaac             iperm[k - kStart]         = kPerm - kStart;
18566f5f1567SToby Isaac             preOrient[kPerm - kStart] = oPerm;
18576f5f1567SToby Isaac           }
18586f5f1567SToby Isaac         }
18596f5f1567SToby Isaac       }
18609566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18616f5f1567SToby Isaac     }
18629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, 0, pNewEnd[dim]));
18636f5f1567SToby Isaac     offset      = 0;
18646f5f1567SToby Isaac     numNewCones = 0;
18656f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18666f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
18676f5f1567SToby Isaac       PetscInt p;
18686f5f1567SToby Isaac       PetscInt size;
18696f5f1567SToby Isaac 
18706f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
18716f5f1567SToby Isaac         /* skip cell 0 */
18726f5f1567SToby Isaac         if (p == cell) continue;
18736f5f1567SToby Isaac         /* old cones to new cones */
18749566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
18756f5f1567SToby Isaac         newConeSizes[offset++] = size;
18766f5f1567SToby Isaac         numNewCones += size;
18776f5f1567SToby Isaac       }
18786f5f1567SToby Isaac 
18799566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
18806f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18816f5f1567SToby Isaac         PetscInt kParent;
18826f5f1567SToby Isaac 
18839566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
18846f5f1567SToby Isaac         if (kParent != k) {
18856f5f1567SToby Isaac           Kembedding[k] = offset;
18869566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
18876f5f1567SToby Isaac           newConeSizes[offset++] = size;
18886f5f1567SToby Isaac           numNewCones += size;
188948a46eb9SPierre Jolivet           if (kParent != 0) PetscCall(PetscSectionSetDof(parentSection, Kembedding[k], 1));
18906f5f1567SToby Isaac         }
18916f5f1567SToby Isaac       }
18926f5f1567SToby Isaac     }
18936f5f1567SToby Isaac 
18949566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
18959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(parentSection, &numPointsWithParents));
18969566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numNewCones, &newCones, numNewCones, &newOrientations));
18979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPointsWithParents, &parents, numPointsWithParents, &childIDs));
18986f5f1567SToby Isaac 
18996f5f1567SToby Isaac     /* fill new cones */
19006f5f1567SToby Isaac     offset = 0;
19016f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19026f5f1567SToby Isaac       PetscInt        kStart, kEnd, k, l;
19036f5f1567SToby Isaac       PetscInt        p;
19046f5f1567SToby Isaac       PetscInt        size;
19056f5f1567SToby Isaac       const PetscInt *cone, *orientation;
19066f5f1567SToby Isaac 
19076f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19086f5f1567SToby Isaac         /* skip cell 0 */
19096f5f1567SToby Isaac         if (p == cell) continue;
19106f5f1567SToby Isaac         /* old cones to new cones */
19119566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
19129566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
19139566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeOrientation(dm, p, &orientation));
19146f5f1567SToby Isaac         for (l = 0; l < size; l++) {
19156f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
19166f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
19176f5f1567SToby Isaac         }
19186f5f1567SToby Isaac       }
19196f5f1567SToby Isaac 
19209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
19216f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19226f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
19236f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
19246f5f1567SToby Isaac 
19259566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
19266f5f1567SToby Isaac         if (kParent != k) {
19276f5f1567SToby Isaac           /* embed new cones */
19289566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
19299566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(K, kPerm, &cone));
19309566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeOrientation(K, kPerm, &orientation));
19316f5f1567SToby Isaac           for (l = 0; l < size; l++) {
19326f5f1567SToby Isaac             PetscInt       q, m = (preO >= 0) ? ((preO + l) % size) : ((size - (preO + 1) - l) % size);
19336f5f1567SToby Isaac             PetscInt       newO, lSize, oTrue;
1934b5a892a1SMatthew G. Knepley             DMPolytopeType ct = DM_NUM_POLYTOPES;
19356f5f1567SToby Isaac 
19366f5f1567SToby Isaac             q                = iperm[cone[m]];
19376f5f1567SToby Isaac             newCones[offset] = Kembedding[q];
19389566063dSJacob Faibussowitsch             PetscCall(DMPlexGetConeSize(K, q, &lSize));
1939b5a892a1SMatthew G. Knepley             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
1940b5a892a1SMatthew G. Knepley             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
1941b5a892a1SMatthew G. Knepley             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
19426f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
19436f5f1567SToby Isaac             newO                      = DihedralCompose(lSize, oTrue, preOrient[q]);
1944b5a892a1SMatthew G. Knepley             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
19456f5f1567SToby Isaac           }
19466f5f1567SToby Isaac           if (kParent != 0) {
19476f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
19489566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(parentSection, Kembedding[k], &pOffset));
19496f5f1567SToby Isaac             parents[pOffset]  = newPoint;
19506f5f1567SToby Isaac             childIDs[pOffset] = k;
19516f5f1567SToby Isaac           }
19526f5f1567SToby Isaac         }
19536f5f1567SToby Isaac       }
19546f5f1567SToby Isaac     }
19556f5f1567SToby Isaac 
19569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(dim * (pNewEnd[dim] - pNewStart[dim]), &newVertexCoords));
19576f5f1567SToby Isaac 
19586f5f1567SToby Isaac     /* fill coordinates */
19596f5f1567SToby Isaac     offset = 0;
19606f5f1567SToby Isaac     {
1961d90620a3SMatthew G. Knepley       PetscInt     kStart, kEnd, l;
19626f5f1567SToby Isaac       PetscSection vSection;
19636f5f1567SToby Isaac       PetscInt     v;
19646f5f1567SToby Isaac       Vec          coords;
19656f5f1567SToby Isaac       PetscScalar *coordvals;
19666f5f1567SToby Isaac       PetscInt     dof, off;
1967c111c6b7SMatthew G. Knepley       PetscReal    v0[3], J[9], detJ;
19686f5f1567SToby Isaac 
196976bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
1970d90620a3SMatthew G. Knepley         PetscInt k;
19719566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(K, 0, &kStart, &kEnd));
19726f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
19739566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
197463a3b9bcSJacob Faibussowitsch           PetscCheck(detJ > 0., PETSC_COMM_SELF, PETSC_ERR_PLIB, "reference tree cell %" PetscInt_FMT " has bad determinant", k);
19756f5f1567SToby Isaac         }
1976d90620a3SMatthew G. Knepley       }
19779566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
19789566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &vSection));
19799566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coords));
19809566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19816f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
19829566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(vSection, v, &dof));
19839566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(vSection, v, &off));
1984ad540459SPierre Jolivet         for (l = 0; l < dof; l++) newVertexCoords[offset++] = coordvals[off + l];
19856f5f1567SToby Isaac       }
19869566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
19876f5f1567SToby Isaac 
19889566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(K, &vSection));
19899566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(K, &coords));
19909566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(K, 0, &kStart, &kEnd));
19926f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
19939bc368c7SMatthew G. Knepley         PetscReal       coord[3], newCoord[3];
19946f5f1567SToby Isaac         PetscInt        vPerm = perm[v];
19956f5f1567SToby Isaac         PetscInt        kParent;
1996c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
19976f5f1567SToby Isaac 
19989566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, v, &kParent, NULL));
19996f5f1567SToby Isaac         if (kParent != v) {
20006f5f1567SToby Isaac           /* this is a new vertex */
20019566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(vSection, vPerm, &off));
20029bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off + l]);
2003367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
20049bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset + l] = newCoord[l];
20056f5f1567SToby Isaac           offset += dim;
20066f5f1567SToby Isaac         }
20076f5f1567SToby Isaac       }
20089566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
20096f5f1567SToby Isaac     }
20106f5f1567SToby Isaac 
20116f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
20126f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
20136f5f1567SToby Isaac       PetscInt tmp;
20146f5f1567SToby Isaac 
20156f5f1567SToby Isaac       tmp                = pNewCount[d];
20166f5f1567SToby Isaac       pNewCount[d]       = pNewCount[dim - d];
20176f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
20186f5f1567SToby Isaac     }
20196f5f1567SToby Isaac 
20209566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, pNewCount, newConeSizes, newCones, newOrientations, newVertexCoords));
20219566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20229566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, parents, childIDs));
20236f5f1567SToby Isaac 
20246f5f1567SToby Isaac     /* clean up */
20259566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
20269566063dSJacob Faibussowitsch     PetscCall(PetscFree5(pNewCount, pNewStart, pNewEnd, pOldStart, pOldEnd));
20279566063dSJacob Faibussowitsch     PetscCall(PetscFree(newConeSizes));
20289566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCones, newOrientations));
20299566063dSJacob Faibussowitsch     PetscCall(PetscFree(newVertexCoords));
20309566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parents, childIDs));
20319566063dSJacob Faibussowitsch     PetscCall(PetscFree4(Kembedding, perm, iperm, preOrient));
20329371c9d4SSatish Balay   } else {
20336f5f1567SToby Isaac     PetscInt     p, counts[4];
20346f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
20356f5f1567SToby Isaac     Vec          coordVec;
20366f5f1567SToby Isaac     PetscScalar *coords;
20376f5f1567SToby Isaac 
20386f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20396f5f1567SToby Isaac       PetscInt dStart, dEnd;
20406f5f1567SToby Isaac 
20419566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
20426f5f1567SToby Isaac       counts[d] = dEnd - dStart;
20436f5f1567SToby Isaac     }
20449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEnd - pStart, &coneSizes));
204548a46eb9SPierre Jolivet     for (p = pStart; p < pEnd; p++) PetscCall(DMPlexGetConeSize(dm, p, &coneSizes[p - pStart]));
20469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCones(dm, &cones));
20479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientations(dm, &orientations));
20489566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordVec));
20499566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordVec, &coords));
20506f5f1567SToby Isaac 
20519566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
20529566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
20539566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, counts, coneSizes, cones, orientations, NULL));
20549566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20559566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, NULL, NULL));
20569566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordVec, &coords));
20576f5f1567SToby Isaac   }
20589566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
20596f5f1567SToby Isaac 
20603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20616f5f1567SToby Isaac }
20626ecaa68aSToby Isaac 
2063d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
2064d71ae5a4SJacob Faibussowitsch {
20656ecaa68aSToby Isaac   PetscSF              coarseToFineEmbedded;
20666ecaa68aSToby Isaac   PetscSection         globalCoarse, globalFine;
20676ecaa68aSToby Isaac   PetscSection         localCoarse, localFine;
20686ecaa68aSToby Isaac   PetscSection         aSec, cSec;
20696ecaa68aSToby Isaac   PetscSection         rootIndicesSec, rootMatricesSec;
207046bdb399SToby Isaac   PetscSection         leafIndicesSec, leafMatricesSec;
207146bdb399SToby Isaac   PetscInt            *rootIndices, *leafIndices;
207246bdb399SToby Isaac   PetscScalar         *rootMatrices, *leafMatrices;
20736ecaa68aSToby Isaac   IS                   aIS;
20746ecaa68aSToby Isaac   const PetscInt      *anchors;
20756ecaa68aSToby Isaac   Mat                  cMat;
20764acb8e1eSToby Isaac   PetscInt             numFields, maxFields;
20776ecaa68aSToby Isaac   PetscInt             pStartC, pEndC, pStartF, pEndF, p;
20786ecaa68aSToby Isaac   PetscInt             aStart, aEnd, cStart, cEnd;
20791c58ffc4SToby Isaac   PetscInt            *maxChildIds;
2080e44e4e7fSToby Isaac   PetscInt            *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
20814acb8e1eSToby Isaac   const PetscInt    ***perms;
20824acb8e1eSToby Isaac   const PetscScalar ***flips;
20836ecaa68aSToby Isaac 
20846ecaa68aSToby Isaac   PetscFunctionBegin;
20859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
20869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
20879566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
20886ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
208989698031SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
209089698031SToby Isaac     const PetscInt *leaves;
20916ecaa68aSToby Isaac 
20929566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
209389698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
209489698031SToby Isaac       p = leaves ? leaves[l] : l;
20959566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
20969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2097ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
20986ecaa68aSToby Isaac     }
20999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
21007cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
210189698031SToby Isaac       p = leaves ? leaves[l] : l;
21029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
21039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2104ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
21056ecaa68aSToby Isaac     }
21069566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
21079566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
21086ecaa68aSToby Isaac   }
21096ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
21109566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
2111ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
211257168dbeSPierre Jolivet   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211357168dbeSPierre Jolivet   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211446bdb399SToby Isaac 
21159566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
21169566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
211746bdb399SToby Isaac 
21189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
21199566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
21209566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
212146bdb399SToby Isaac 
21229566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
21239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
212446bdb399SToby Isaac 
212546bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
21269566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
21279566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootMatricesSec));
21289566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootIndicesSec, pStartC, pEndC));
21299566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootMatricesSec, pStartC, pEndC));
21309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
2131713c1c5dSToby Isaac   maxFields = PetscMax(1, numFields);
21329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc7(maxFields + 1, &offsets, maxFields + 1, &offsetsCopy, maxFields + 1, &newOffsets, maxFields + 1, &newOffsetsCopy, maxFields + 1, &rowOffsets, maxFields + 1, &numD, maxFields + 1, &numO));
21339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxFields + 1, (PetscInt ****)&perms, maxFields + 1, (PetscScalar ****)&flips));
21349566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)perms, (maxFields + 1) * sizeof(const PetscInt **)));
21359566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)flips, (maxFields + 1) * sizeof(const PetscScalar **)));
213646bdb399SToby Isaac 
213746bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
21388d2f55e7SToby Isaac     PetscInt dof, matSize = 0;
21396ecaa68aSToby Isaac     PetscInt aDof          = 0;
21406ecaa68aSToby Isaac     PetscInt cDof          = 0;
21416ecaa68aSToby Isaac     PetscInt maxChildId    = maxChildIds[p - pStartC];
21426ecaa68aSToby Isaac     PetscInt numRowIndices = 0;
21436ecaa68aSToby Isaac     PetscInt numColIndices = 0;
2144f13f9184SToby Isaac     PetscInt f;
21456ecaa68aSToby Isaac 
21469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2147ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
214848a46eb9SPierre Jolivet     if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof));
214948a46eb9SPierre Jolivet     if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(cSec, p, &cDof));
2150f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2151f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
21526ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2153f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
21546ecaa68aSToby Isaac 
21559566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
215646bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
21576ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
21586ecaa68aSToby Isaac 
21599566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
21606ecaa68aSToby Isaac         numRowIndices += clDof;
21616ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21629566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &clDof));
21636ecaa68aSToby Isaac           offsets[f + 1] += clDof;
21646ecaa68aSToby Isaac         }
21656ecaa68aSToby Isaac       }
21666ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
21676ecaa68aSToby Isaac         offsets[f + 1] += offsets[f];
21686ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
21696ecaa68aSToby Isaac       }
217046bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
21719566063dSJacob Faibussowitsch       PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, NULL, NULL, NULL, &numColIndices, NULL, NULL, newOffsets, PETSC_FALSE));
21729566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
21736ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
21746ecaa68aSToby Isaac         numColIndices = numRowIndices;
21756ecaa68aSToby Isaac         matSize       = 0;
21769371c9d4SSatish Balay       } else if (numFields) { /* we send one submat for each field: sum their sizes */
21776ecaa68aSToby Isaac         matSize = 0;
21786ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21796ecaa68aSToby Isaac           PetscInt numRow, numCol;
21806ecaa68aSToby Isaac 
21816ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2182f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
21836ecaa68aSToby Isaac           matSize += numRow * numCol;
21846ecaa68aSToby Isaac         }
21859371c9d4SSatish Balay       } else {
21866ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
21876ecaa68aSToby Isaac       }
2188f13f9184SToby Isaac     } else if (maxChildId == -1) {
21898d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2190f13f9184SToby Isaac         PetscInt aOff, a;
21916ecaa68aSToby Isaac 
21929566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
21936ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21946ecaa68aSToby Isaac           PetscInt fDof;
21956ecaa68aSToby Isaac 
21969566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
219721968bf8SToby Isaac           offsets[f + 1] = fDof;
21986ecaa68aSToby Isaac         }
21996ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
22006ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
22016ecaa68aSToby Isaac 
22029566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(localCoarse, anchor, &aLocalDof));
22036ecaa68aSToby Isaac           numColIndices += aLocalDof;
22046ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
22056ecaa68aSToby Isaac             PetscInt fDof;
22066ecaa68aSToby Isaac 
22079566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
220821968bf8SToby Isaac             newOffsets[f + 1] += fDof;
22096ecaa68aSToby Isaac           }
22106ecaa68aSToby Isaac         }
22116ecaa68aSToby Isaac         if (numFields) {
22126ecaa68aSToby Isaac           matSize = 0;
2213ad540459SPierre Jolivet           for (f = 0; f < numFields; f++) matSize += offsets[f + 1] * newOffsets[f + 1];
22149371c9d4SSatish Balay         } else {
22156ecaa68aSToby Isaac           matSize = numColIndices * dof;
22166ecaa68aSToby Isaac         }
22179371c9d4SSatish Balay       } else { /* no children, and no constraints on dofs: just get the global indices */
22186ecaa68aSToby Isaac         numColIndices = dof;
22196ecaa68aSToby Isaac         matSize       = 0;
22206ecaa68aSToby Isaac       }
22218d2f55e7SToby Isaac     }
222246bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
22239566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootIndicesSec, p, numColIndices ? numColIndices + 2 * numFields : 0));
22249566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootMatricesSec, p, matSize));
22256ecaa68aSToby Isaac   }
22269566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootIndicesSec));
22279566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootMatricesSec));
22286ecaa68aSToby Isaac   {
22296ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
22306ecaa68aSToby Isaac 
22319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
22329566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootMatricesSec, &numRootMatrices));
22339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numRootIndices, &rootIndices, numRootMatrices, &rootMatrices));
22346ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
22356ecaa68aSToby Isaac       PetscInt     numRowIndices, numColIndices, matSize, dof;
2236f13f9184SToby Isaac       PetscInt     pIndOff, pMatOff, f;
22376ecaa68aSToby Isaac       PetscInt    *pInd;
22386ecaa68aSToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
22396ecaa68aSToby Isaac       PetscScalar *pMat       = NULL;
22406ecaa68aSToby Isaac 
22419566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, p, &numColIndices));
2242ad540459SPierre Jolivet       if (!numColIndices) continue;
2243f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2244f13f9184SToby Isaac         offsets[f]        = 0;
2245f13f9184SToby Isaac         newOffsets[f]     = 0;
2246f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2247f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2248f13f9184SToby Isaac       }
22496ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
22509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, p, &pIndOff));
22516ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
22529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootMatricesSec, p, &matSize));
22536ecaa68aSToby Isaac       if (matSize) {
22549566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootMatricesSec, p, &pMatOff));
22556ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
22566ecaa68aSToby Isaac       }
22579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2258ad540459SPierre Jolivet       if (dof < 0) dof = -(dof + 1);
22596ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
22606ecaa68aSToby Isaac         PetscInt i, j;
22616ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
22626ecaa68aSToby Isaac 
22636ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
22646ecaa68aSToby Isaac           PetscInt numIndices, *indices;
22659566063dSJacob Faibussowitsch           PetscCall(DMPlexGetClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
226608401ef6SPierre Jolivet           PetscCheck(numIndices == numColIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "mismatching constraint indices calculations");
2267ad540459SPierre Jolivet           for (i = 0; i < numColIndices; i++) pInd[i] = indices[i];
22686ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
226946bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i + 1];
227046bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i + 1];
22716ecaa68aSToby Isaac           }
22729566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
22739371c9d4SSatish Balay         } else {
22746ecaa68aSToby Isaac           PetscInt     closureSize, *closure = NULL, cl;
22756ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
22766ecaa68aSToby Isaac           PetscInt     numPoints, *points;
22776ecaa68aSToby Isaac 
22789566063dSJacob Faibussowitsch           PetscCall(DMGetWorkArray(coarse, numRowIndices * numRowIndices, MPIU_SCALAR, &pMatIn));
22796ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
2280ad540459SPierre Jolivet             for (j = 0; j < numRowIndices; j++) pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
22816ecaa68aSToby Isaac           }
22829566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22834acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
22849566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
22859566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
22864acb8e1eSToby Isaac           }
22876ecaa68aSToby Isaac           if (numFields) {
22886ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
22896ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
22906ecaa68aSToby Isaac 
22916ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
22926ecaa68aSToby Isaac                 PetscInt fDof;
22936ecaa68aSToby Isaac 
22949566063dSJacob Faibussowitsch                 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &fDof));
22956ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
22966ecaa68aSToby Isaac               }
22976ecaa68aSToby Isaac             }
22986ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
22996ecaa68aSToby Isaac               offsets[f + 1] += offsets[f];
23006ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
23016ecaa68aSToby Isaac             }
23026ecaa68aSToby Isaac           }
23034acb8e1eSToby Isaac           /* TODO : flips here ? */
23046ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
23059566063dSJacob Faibussowitsch           PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, perms, pMatIn, &numPoints, NULL, &points, &pMatModified, newOffsets, PETSC_FALSE));
23064acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23079566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
23089566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
23094acb8e1eSToby Isaac           }
23104acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23119566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23129566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23134acb8e1eSToby Isaac           }
23146ecaa68aSToby Isaac           if (!numFields) {
2315ad540459SPierre Jolivet             for (i = 0; i < numRowIndices * numColIndices; i++) pMat[i] = pMatModified[i];
23169371c9d4SSatish Balay           } else {
2317f13f9184SToby Isaac             PetscInt i, j, count;
23186ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
23196ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f + 1]; i++) {
2320ad540459SPierre Jolivet                 for (j = newOffsets[f]; j < newOffsets[f + 1]; j++, count++) pMat[count] = pMatModified[i * numColIndices + j];
23216ecaa68aSToby Isaac               }
23226ecaa68aSToby Isaac             }
23236ecaa68aSToby Isaac           }
23249566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatModified));
23259566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
23269566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatIn));
23276ecaa68aSToby Isaac           if (numFields) {
232846bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
232946bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f + 1];
233046bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f + 1];
23316ecaa68aSToby Isaac             }
23324acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23334acb8e1eSToby Isaac               PetscInt globalOff, c = points[2 * cl];
23349566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23359566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
23366ecaa68aSToby Isaac             }
23376ecaa68aSToby Isaac           } else {
23384acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23394acb8e1eSToby Isaac               PetscInt        c    = points[2 * cl], globalOff;
23404acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
23414acb8e1eSToby Isaac 
23429566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23439566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
23446ecaa68aSToby Isaac             }
23456ecaa68aSToby Isaac           }
23464acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23479566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23489566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23494acb8e1eSToby Isaac           }
23509566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numPoints, MPIU_SCALAR, &points));
23516ecaa68aSToby Isaac         }
23529371c9d4SSatish Balay       } else if (matSize) {
23536ecaa68aSToby Isaac         PetscInt  cOff;
23546ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
23556ecaa68aSToby Isaac 
23566ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
235708401ef6SPierre Jolivet         PetscCheck(numRowIndices == dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Miscounted dofs");
23589566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
23599566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
23609566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, p, &cOff));
23619566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
23629566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
23636ecaa68aSToby Isaac         if (numFields) {
23646ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23656ecaa68aSToby Isaac             PetscInt fDof;
2366f13f9184SToby Isaac 
23679566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSec, p, f, &fDof));
23686ecaa68aSToby Isaac             offsets[f + 1] = fDof;
23696ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
23706ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
23719566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
23726ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
23736ecaa68aSToby Isaac             }
23746ecaa68aSToby Isaac           }
23756ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23766ecaa68aSToby Isaac             offsets[f + 1] += offsets[f];
23776ecaa68aSToby Isaac             offsetsCopy[f + 1] = offsets[f + 1];
23786ecaa68aSToby Isaac             newOffsets[f + 1] += newOffsets[f];
23796ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
23806ecaa68aSToby Isaac           }
23819566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, -1, NULL, rowIndices));
23826ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23836ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23849566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23859566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, -1, NULL, colIndices));
23866ecaa68aSToby Isaac           }
23879371c9d4SSatish Balay         } else {
23889566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, NULL, rowIndices));
23896ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23906ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23919566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23929566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, NULL, colIndices));
23936ecaa68aSToby Isaac           }
23946ecaa68aSToby Isaac         }
23956ecaa68aSToby Isaac         if (numFields) {
2396f13f9184SToby Isaac           PetscInt count, a;
2397f13f9184SToby Isaac 
23986ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
23996ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
24006ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
24019566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat, iSize, &rowIndices[offsets[f]], jSize, &colIndices[newOffsets[f]], &pMat[count]));
24026ecaa68aSToby Isaac             count += iSize * jSize;
240346bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
240446bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f + 1];
24056ecaa68aSToby Isaac           }
24066ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24076ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24086ecaa68aSToby Isaac             PetscInt gOff;
24099566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24109566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, -1, NULL, pInd));
24116ecaa68aSToby Isaac           }
24129371c9d4SSatish Balay         } else {
24136ecaa68aSToby Isaac           PetscInt a;
24149566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat, numRowIndices, rowIndices, numColIndices, colIndices, pMat));
24156ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24166ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24176ecaa68aSToby Isaac             PetscInt gOff;
24189566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24199566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, NULL, pInd));
24206ecaa68aSToby Isaac           }
24216ecaa68aSToby Isaac         }
24229566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
24239566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
24249371c9d4SSatish Balay       } else {
24256ecaa68aSToby Isaac         PetscInt gOff;
24266ecaa68aSToby Isaac 
24279566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
24286ecaa68aSToby Isaac         if (numFields) {
24296ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
24306ecaa68aSToby Isaac             PetscInt fDof;
24319566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
24326ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
24336ecaa68aSToby Isaac           }
24346ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
243546bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
243646bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f + 1];
24376ecaa68aSToby Isaac           }
24389566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2439367003a6SStefano Zampini         } else {
24409566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
24416ecaa68aSToby Isaac         }
24426ecaa68aSToby Isaac       }
24436ecaa68aSToby Isaac     }
24449566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
24456ecaa68aSToby Isaac   }
244646bdb399SToby Isaac   {
244746bdb399SToby Isaac     PetscSF   indicesSF, matricesSF;
244846bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
244946bdb399SToby Isaac 
24509566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
24519566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafMatricesSec));
24529566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootIndicesSec, &remoteOffsetsIndices, leafIndicesSec));
24539566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootMatricesSec, &remoteOffsetsMatrices, leafMatricesSec));
24549566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootIndicesSec, remoteOffsetsIndices, leafIndicesSec, &indicesSF));
24559566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootMatricesSec, remoteOffsetsMatrices, leafMatricesSec, &matricesSF));
24569566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
24579566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsIndices));
24589566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsMatrices));
24599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numLeafIndices));
24609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafMatricesSec, &numLeafMatrices));
24619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numLeafIndices, &leafIndices, numLeafMatrices, &leafMatrices));
24629566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24639566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24649566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24659566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24669566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&matricesSF));
24679566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
24689566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rootIndices, rootMatrices));
24699566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootIndicesSec));
24709566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootMatricesSec));
247146bdb399SToby Isaac   }
247246bdb399SToby Isaac   /* count to preallocate */
24739566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
247446bdb399SToby Isaac   {
247546bdb399SToby Isaac     PetscInt       nGlobal;
247646bdb399SToby Isaac     PetscInt      *dnnz, *onnz;
2477b9a5774bSToby Isaac     PetscLayout    rowMap, colMap;
2478b9a5774bSToby Isaac     PetscInt       rowStart, rowEnd, colStart, colEnd;
24791c58ffc4SToby Isaac     PetscInt       maxDof;
24801c58ffc4SToby Isaac     PetscInt      *rowIndices;
24811c58ffc4SToby Isaac     DM             refTree;
24821c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
24831c58ffc4SToby Isaac     PetscScalar ***refPointFieldMats;
24841c58ffc4SToby Isaac     PetscSection   refConSec, refAnSec;
24850eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, maxConDof, maxColumns, leafStart, leafEnd;
24861c58ffc4SToby Isaac     PetscScalar   *pointWork;
248746bdb399SToby Isaac 
24889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine, &nGlobal));
24899566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nGlobal, &dnnz, nGlobal, &onnz));
24909566063dSJacob Faibussowitsch     PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
24919566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rowMap));
24929566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(colMap));
24939566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
24949566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
24959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
24969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafIndicesSec, &leafStart, &leafEnd));
24979566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
24980eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
249946bdb399SToby Isaac       PetscInt gDof, gcDof, gOff;
250046bdb399SToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
250146bdb399SToby Isaac       PetscInt matSize;
250221968bf8SToby Isaac       PetscInt i;
250346bdb399SToby Isaac 
25049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
25059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2506ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
25079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
250808401ef6SPierre Jolivet       PetscCheck(gOff >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I though having global dofs meant a non-negative offset");
25091dca8a05SBarry Smith       PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I thought the row map would constrain the global dofs");
25109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
25119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
251246bdb399SToby Isaac       numColIndices -= 2 * numFields;
251308401ef6SPierre Jolivet       PetscCheck(numColIndices > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "global fine dof with no dofs to interpolate from");
251446bdb399SToby Isaac       pInd              = &leafIndices[pIndOff];
251521968bf8SToby Isaac       offsets[0]        = 0;
251621968bf8SToby Isaac       offsetsCopy[0]    = 0;
251721968bf8SToby Isaac       newOffsets[0]     = 0;
251821968bf8SToby Isaac       newOffsetsCopy[0] = 0;
251946bdb399SToby Isaac       if (numFields) {
252021968bf8SToby Isaac         PetscInt f;
252146bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
252246bdb399SToby Isaac           PetscInt rowDof;
252346bdb399SToby Isaac 
25249566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
252521968bf8SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
252621968bf8SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
252721968bf8SToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
252821968bf8SToby Isaac           numD[f]            = 0;
252921968bf8SToby Isaac           numO[f]            = 0;
253046bdb399SToby Isaac         }
25319566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
253246bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
253321968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
253421968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
253546bdb399SToby Isaac 
253646bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
253746bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
253846bdb399SToby Isaac 
253946bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
254021968bf8SToby Isaac               numD[f]++;
25419371c9d4SSatish Balay             } else if (gInd >= 0) { /* negative means non-entry */
254221968bf8SToby Isaac               numO[f]++;
254346bdb399SToby Isaac             }
254446bdb399SToby Isaac           }
254546bdb399SToby Isaac         }
25469371c9d4SSatish Balay       } else {
25479566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
254821968bf8SToby Isaac         numD[0] = 0;
254921968bf8SToby Isaac         numO[0] = 0;
255046bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
255146bdb399SToby Isaac           PetscInt gInd = pInd[i];
255246bdb399SToby Isaac 
255346bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
255421968bf8SToby Isaac             numD[0]++;
25559371c9d4SSatish Balay           } else if (gInd >= 0) { /* negative means non-entry */
255621968bf8SToby Isaac             numO[0]++;
255746bdb399SToby Isaac           }
255846bdb399SToby Isaac         }
255946bdb399SToby Isaac       }
25609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
256146bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
256246bdb399SToby Isaac         PetscInt childId;
256346bdb399SToby Isaac 
256446bdb399SToby Isaac         childId = childIds[p - pStartF];
256521968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
256646bdb399SToby Isaac           if (numFields) {
2567b9a5774bSToby Isaac             PetscInt f;
2568b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
256921968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
257046bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
257121968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
257221968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
257346bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25741dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2575b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
25769371c9d4SSatish Balay                 } else if (gIndCoarse >= 0) { /* remote */
25771dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2578b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
25799371c9d4SSatish Balay                 } else { /* constrained */
258008401ef6SPierre Jolivet                   PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
258146bdb399SToby Isaac                 }
258246bdb399SToby Isaac               }
258346bdb399SToby Isaac             }
25849371c9d4SSatish Balay           } else {
2585b9a5774bSToby Isaac             PetscInt i;
2586b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
258746bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
258846bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
258946bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25901dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2591b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
25929371c9d4SSatish Balay               } else if (gIndCoarse >= 0) { /* remote */
25931dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2594b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
25959371c9d4SSatish Balay               } else { /* constrained */
259608401ef6SPierre Jolivet                 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
259746bdb399SToby Isaac               }
259846bdb399SToby Isaac             }
259946bdb399SToby Isaac           }
26009371c9d4SSatish Balay         } else { /* interpolate from all */
260146bdb399SToby Isaac           if (numFields) {
2602b9a5774bSToby Isaac             PetscInt f;
2603b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
260421968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
260546bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
260621968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
260746bdb399SToby Isaac                 if (gIndFine >= 0) {
26081dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2609b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2610b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
261146bdb399SToby Isaac                 }
261246bdb399SToby Isaac               }
261346bdb399SToby Isaac             }
26149371c9d4SSatish Balay           } else {
2615b9a5774bSToby Isaac             PetscInt i;
2616b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
261746bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
261846bdb399SToby Isaac               if (gIndFine >= 0) {
26191dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2620b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2621b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
262246bdb399SToby Isaac               }
262346bdb399SToby Isaac             }
262446bdb399SToby Isaac           }
262546bdb399SToby Isaac         }
26269371c9d4SSatish Balay       } else { /* interpolate from all */
262746bdb399SToby Isaac         if (numFields) {
2628b9a5774bSToby Isaac           PetscInt f;
2629b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
263021968bf8SToby Isaac             PetscInt numRows = offsets[f + 1] - offsets[f], row;
263146bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
263221968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
263346bdb399SToby Isaac               if (gIndFine >= 0) {
26341dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2635b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2636b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
263746bdb399SToby Isaac               }
263846bdb399SToby Isaac             }
263946bdb399SToby Isaac           }
26409371c9d4SSatish Balay         } else { /* every dof get a full row */
2641b9a5774bSToby Isaac           PetscInt i;
2642b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
264346bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
264446bdb399SToby Isaac             if (gIndFine >= 0) {
26451dca8a05SBarry Smith               PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2646b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2647b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
264846bdb399SToby Isaac             }
264946bdb399SToby Isaac           }
265046bdb399SToby Isaac         }
265146bdb399SToby Isaac       }
265246bdb399SToby Isaac     }
26539566063dSJacob Faibussowitsch     PetscCall(MatXAIJSetPreallocation(mat, 1, dnnz, onnz, NULL, NULL));
26549566063dSJacob Faibussowitsch     PetscCall(PetscFree2(dnnz, onnz));
265521968bf8SToby Isaac 
26569566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
26579566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
26589566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
26599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
26609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
26619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(refConSec, &maxConDof));
26629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(leafIndicesSec, &maxColumns));
26639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxConDof * maxColumns, &pointWork));
26640eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2665e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2666e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2667e44e4e7fSToby Isaac       PetscInt matSize;
2668e44e4e7fSToby Isaac       PetscInt childId;
2669e44e4e7fSToby Isaac 
26709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
26719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2672ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
2673e44e4e7fSToby Isaac       childId = childIds[p - pStartF];
26749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
26759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
26769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2677e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2678e44e4e7fSToby Isaac       pInd              = &leafIndices[pIndOff];
2679e44e4e7fSToby Isaac       offsets[0]        = 0;
2680e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2681e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2682e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2683e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2684e44e4e7fSToby Isaac       if (numFields) {
2685e44e4e7fSToby Isaac         PetscInt f;
2686e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2687e44e4e7fSToby Isaac           PetscInt rowDof;
2688e44e4e7fSToby Isaac 
26899566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2690e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2691e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2692e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2693e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2694e44e4e7fSToby Isaac         }
26959566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
26969371c9d4SSatish Balay       } else {
26979566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
26981c58ffc4SToby Isaac       }
26999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2700e44e4e7fSToby Isaac       if (!matSize) {      /* incoming matrix is identity */
2701e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2702e44e4e7fSToby Isaac           if (numFields) {
2703e44e4e7fSToby Isaac             PetscInt f;
2704e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2705e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
270648a46eb9SPierre Jolivet               for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[offsets[f] + row], pInd[newOffsets[f] + row], 1., INSERT_VALUES));
270721968bf8SToby Isaac             }
27089371c9d4SSatish Balay           } else {
2709e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
271048a46eb9SPierre Jolivet             for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[row], pInd[row], 1., INSERT_VALUES));
2711e44e4e7fSToby Isaac           }
27129371c9d4SSatish Balay         } else { /* interpolate from all */
2713e44e4e7fSToby Isaac           if (numFields) {
2714e44e4e7fSToby Isaac             PetscInt f;
2715e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2716e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f];
2717e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
27189566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], refPointFieldMats[childId - pRefStart][f], INSERT_VALUES));
2719e44e4e7fSToby Isaac             }
27209371c9d4SSatish Balay           } else {
27219566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, refPointFieldMats[childId - pRefStart][0], INSERT_VALUES));
2722e44e4e7fSToby Isaac           }
2723e44e4e7fSToby Isaac         }
27249371c9d4SSatish Balay       } else { /* interpolate from all */
2725e44e4e7fSToby Isaac         PetscInt     pMatOff;
2726e44e4e7fSToby Isaac         PetscScalar *pMat;
2727e44e4e7fSToby Isaac 
27289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafMatricesSec, p, &pMatOff));
2729e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2730e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2731e44e4e7fSToby Isaac           if (numFields) {
2732e44e4e7fSToby Isaac             PetscInt f, count;
2733e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2734e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2735e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2736e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2737e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2738e44e4e7fSToby Isaac 
27399566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], inMat, INSERT_VALUES));
2740e44e4e7fSToby Isaac               count += numCols * numInRows;
2741e44e4e7fSToby Isaac             }
27429371c9d4SSatish Balay           } else {
27439566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, pMat, INSERT_VALUES));
2744e44e4e7fSToby Isaac           }
27459371c9d4SSatish Balay         } else { /* multiply the incoming matrix by the child interpolation */
2746e44e4e7fSToby Isaac           if (numFields) {
2747e44e4e7fSToby Isaac             PetscInt f, count;
2748e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2749e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2750e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2751e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2752e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2753e44e4e7fSToby Isaac               PetscInt     i, j, k;
275408401ef6SPierre Jolivet               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2755e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2756e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2757e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2758ad540459SPierre Jolivet                   for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2759e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2760e44e4e7fSToby Isaac                 }
2761e44e4e7fSToby Isaac               }
27629566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], pointWork, INSERT_VALUES));
2763e44e4e7fSToby Isaac               count += numCols * numInRows;
2764e44e4e7fSToby Isaac             }
27659371c9d4SSatish Balay           } else { /* every dof gets a full row */
2766e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2767e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2768e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2769e44e4e7fSToby Isaac             PetscInt i, j, k;
277008401ef6SPierre Jolivet             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2771e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2772e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2773e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2774ad540459SPierre Jolivet                 for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2775e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2776e44e4e7fSToby Isaac               }
2777e44e4e7fSToby Isaac             }
27789566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, numRows, rowIndices, numCols, pInd, pointWork, INSERT_VALUES));
2779e44e4e7fSToby Isaac           }
2780e44e4e7fSToby Isaac         }
2781e44e4e7fSToby Isaac       }
2782e44e4e7fSToby Isaac     }
27839566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
27849566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
27859566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointWork));
2786e44e4e7fSToby Isaac   }
27879566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
27889566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
27899566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
27909566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafMatricesSec));
27919566063dSJacob Faibussowitsch   PetscCall(PetscFree2(leafIndices, leafMatrices));
27929566063dSJacob Faibussowitsch   PetscCall(PetscFree2(*(PetscInt ****)&perms, *(PetscScalar ****)&flips));
27939566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
27949566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
27953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27966ecaa68aSToby Isaac }
2797154bca37SToby Isaac 
27988d2f55e7SToby Isaac /*
27998d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
28008d2f55e7SToby Isaac  *
28018d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
28028d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
28038d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
28048d2f55e7SToby Isaac  *       a_{i,j} = 0;
28058d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
28068d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
28078d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
28088d2f55e7SToby Isaac  */
2809d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
2810d71ae5a4SJacob Faibussowitsch {
28118d2f55e7SToby Isaac   PetscDS      ds;
28128d2f55e7SToby Isaac   PetscSection section, cSection;
28138d2f55e7SToby Isaac   DMLabel      canonical, depth;
28148d2f55e7SToby Isaac   Mat          cMat, mat;
28158d2f55e7SToby Isaac   PetscInt    *nnz;
28168d2f55e7SToby Isaac   PetscInt     f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
28178d2f55e7SToby Isaac   PetscInt     m, n;
28188d2f55e7SToby Isaac   PetscScalar *pointScalar;
28198d2f55e7SToby Isaac   PetscReal   *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
28208d2f55e7SToby Isaac 
28218d2f55e7SToby Isaac   PetscFunctionBegin;
28229566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &section));
28239566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(refTree, &dim));
28249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(dim, &v0, dim, &v0parent, dim, &vtmp, dim * dim, &J, dim * dim, &Jparent, dim * dim, &invJ));
28259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(dim, &pointScalar, dim, &pointRef));
28269566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
28279566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
28289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numSecFields));
28299566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "canonical", &canonical));
28309566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "depth", &depth));
28319566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSection, &cMat, NULL));
28329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
28339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
28349566063dSJacob Faibussowitsch   PetscCall(MatGetSize(cMat, &n, &m)); /* the injector has transpose sizes from the constraint matrix */
28358d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
28369566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(m, &nnz));
28378d2f55e7SToby 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 */
28388d2f55e7SToby Isaac     const PetscInt *children;
28398d2f55e7SToby Isaac     PetscInt        numChildren;
28408d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28418d2f55e7SToby Isaac 
28428d2f55e7SToby Isaac     if (canonical) {
28438d2f55e7SToby Isaac       PetscInt pCanonical;
28449566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28458d2f55e7SToby Isaac       if (p != pCanonical) continue;
28468d2f55e7SToby Isaac     }
28479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28488d2f55e7SToby Isaac     if (!numChildren) continue;
28498d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28508d2f55e7SToby Isaac       PetscInt child = children[i];
28518d2f55e7SToby Isaac       PetscInt dof;
28528d2f55e7SToby Isaac 
28539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
28548d2f55e7SToby Isaac       numChildDof += dof;
28558d2f55e7SToby Isaac     }
28569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
28578d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
28588d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
28598d2f55e7SToby Isaac       PetscInt selfOff;
28608d2f55e7SToby Isaac 
28618d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
28628d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
28638d2f55e7SToby Isaac           PetscInt child = children[i];
28648d2f55e7SToby Isaac           PetscInt dof;
28658d2f55e7SToby Isaac 
28669566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
28678d2f55e7SToby Isaac           numChildDof += dof;
28688d2f55e7SToby Isaac         }
28699566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
28709566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
28719371c9d4SSatish Balay       } else {
28729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
28738d2f55e7SToby Isaac       }
2874ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) nnz[selfOff + i] = numChildDof;
28758d2f55e7SToby Isaac     }
28768d2f55e7SToby Isaac   }
28779566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(PETSC_COMM_SELF, m, n, m, n, -1, nnz, -1, NULL, &mat));
28789566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
28798d2f55e7SToby Isaac   /* Setp 2: compute entries */
28808d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
28818d2f55e7SToby Isaac     const PetscInt *children;
28828d2f55e7SToby Isaac     PetscInt        numChildren;
28838d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28848d2f55e7SToby Isaac 
28858d2f55e7SToby Isaac     /* same conditions about when entries occur */
28868d2f55e7SToby Isaac     if (canonical) {
28878d2f55e7SToby Isaac       PetscInt pCanonical;
28889566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28898d2f55e7SToby Isaac       if (p != pCanonical) continue;
28908d2f55e7SToby Isaac     }
28919566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28928d2f55e7SToby Isaac     if (!numChildren) continue;
28938d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28948d2f55e7SToby Isaac       PetscInt child = children[i];
28958d2f55e7SToby Isaac       PetscInt dof;
28968d2f55e7SToby Isaac 
28979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
28988d2f55e7SToby Isaac       numChildDof += dof;
28998d2f55e7SToby Isaac     }
29009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
29018d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
29028d2f55e7SToby Isaac 
29038d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
290459fc6756SToby Isaac       PetscInt        pI = -1, cI = -1;
290552a3aeb4SToby Isaac       PetscInt        selfOff, Nc, parentCell;
29068d2f55e7SToby Isaac       PetscInt        cellShapeOff;
29078d2f55e7SToby Isaac       PetscObject     disc;
29088d2f55e7SToby Isaac       PetscDualSpace  dsp;
29098d2f55e7SToby Isaac       PetscClassId    classId;
29108d2f55e7SToby Isaac       PetscScalar    *pointMat;
29113b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
29128d2f55e7SToby Isaac       PetscInt        pO = PETSC_MIN_INT;
29138d2f55e7SToby Isaac       const PetscInt *depthNumDof;
29148d2f55e7SToby Isaac 
29158d2f55e7SToby Isaac       if (numSecFields) {
29168d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
29178d2f55e7SToby Isaac           PetscInt child = children[i];
29188d2f55e7SToby Isaac           PetscInt dof;
29198d2f55e7SToby Isaac 
29209566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
29218d2f55e7SToby Isaac           numChildDof += dof;
29228d2f55e7SToby Isaac         }
29239566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
29249566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
29259371c9d4SSatish Balay       } else {
29269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
29278d2f55e7SToby Isaac       }
29288d2f55e7SToby Isaac 
29293b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
29308d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
29318d2f55e7SToby Isaac         parentCell = p;
29329371c9d4SSatish Balay       } else {
29338d2f55e7SToby Isaac         PetscInt *star = NULL;
29348d2f55e7SToby Isaac         PetscInt  numStar;
29358d2f55e7SToby Isaac 
29368d2f55e7SToby Isaac         parentCell = -1;
29379566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29388d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
29398d2f55e7SToby Isaac           PetscInt c = star[2 * i];
29408d2f55e7SToby Isaac 
29418d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
29428d2f55e7SToby Isaac             parentCell = c;
29438d2f55e7SToby Isaac             break;
29448d2f55e7SToby Isaac           }
29458d2f55e7SToby Isaac         }
29469566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29478d2f55e7SToby Isaac       }
2948a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
29499566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
29509566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc, &classId));
2951c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
29529566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
29539371c9d4SSatish Balay       } else if (classId == PETSCFV_CLASSID) {
29549566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace((PetscFV)disc, &dsp));
29559371c9d4SSatish Balay       } else {
29569b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported discretization object");
2957c5356c36SToby Isaac       }
29589566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumDof(dsp, &depthNumDof));
29599566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumComponents(dsp, &Nc));
29608d2f55e7SToby Isaac       {
29618d2f55e7SToby Isaac         PetscInt *closure = NULL;
29628d2f55e7SToby Isaac         PetscInt  numClosure;
29638d2f55e7SToby Isaac 
29649566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
296559fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
29668d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
29678d2f55e7SToby Isaac 
29688d2f55e7SToby Isaac           pO = closure[2 * i + 1];
296959fc6756SToby Isaac           if (point == p) {
297059fc6756SToby Isaac             pI = i;
297159fc6756SToby Isaac             break;
297259fc6756SToby Isaac           }
29739566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(depth, point, &pointDepth));
29748d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
29758d2f55e7SToby Isaac         }
29769566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
29778d2f55e7SToby Isaac       }
29788d2f55e7SToby Isaac 
29799566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
29809566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
298152a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
2982ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) matRows[i] = selfOff + i;
298352a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
29843b1c2a6aSToby Isaac       {
29853b1c2a6aSToby Isaac         PetscInt colOff = 0;
29863b1c2a6aSToby Isaac 
29873b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
29883b1c2a6aSToby Isaac           PetscInt child = children[i];
29893b1c2a6aSToby Isaac           PetscInt dof, off, j;
29903b1c2a6aSToby Isaac 
29913b1c2a6aSToby Isaac           if (numSecFields) {
29929566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSection, child, f, &dof));
29939566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(cSection, child, f, &off));
29949371c9d4SSatish Balay           } else {
29959566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(cSection, child, &dof));
29969566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(cSection, child, &off));
29973b1c2a6aSToby Isaac           }
29983b1c2a6aSToby Isaac 
2999ad540459SPierre Jolivet           for (j = 0; j < dof; j++) matCols[colOff++] = off + j;
30003b1c2a6aSToby Isaac         }
30013b1c2a6aSToby Isaac       }
30028d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
30038d2f55e7SToby Isaac         PetscFE              fe = (PetscFE)disc;
30048d2f55e7SToby Isaac         PetscInt             fSize;
300559fc6756SToby Isaac         const PetscInt    ***perms;
300659fc6756SToby Isaac         const PetscScalar ***flips;
300759fc6756SToby Isaac         const PetscInt      *pperms;
300859fc6756SToby Isaac 
30099566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &dsp));
30109566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetDimension(dsp, &fSize));
30119566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
301259fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
301352a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
30148d2f55e7SToby Isaac           PetscQuadrature  q;
301552a3aeb4SToby Isaac           PetscInt         dim, thisNc, numPoints, j, k;
30168d2f55e7SToby Isaac           const PetscReal *points;
30178d2f55e7SToby Isaac           const PetscReal *weights;
30188d2f55e7SToby Isaac           PetscInt        *closure = NULL;
30198d2f55e7SToby Isaac           PetscInt         numClosure;
302059fc6756SToby Isaac           PetscInt         iCell              = pperms ? pperms[i] : i;
302159fc6756SToby Isaac           PetscInt         parentCellShapeDof = cellShapeOff + iCell;
3022ef0bb6c7SMatthew G. Knepley           PetscTabulation  Tparent;
30238d2f55e7SToby Isaac 
30249566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(dsp, parentCellShapeDof, &q));
30259566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(q, &dim, &thisNc, &numPoints, &points, &weights));
302663a3b9bcSJacob Faibussowitsch           PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
30279566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe, 1, numPoints, points, 0, &Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
30283b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
30298d2f55e7SToby Isaac             PetscInt           childCell = -1;
303052a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3031c330f8ffSToby Isaac             const PetscReal    xi0[3]    = {-1., -1., -1.};
30328d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
30338d2f55e7SToby Isaac             const PetscScalar *point;
3034ef0bb6c7SMatthew G. Knepley             PetscTabulation    Tchild;
30358d2f55e7SToby Isaac             PetscInt           childCellShapeOff, pointMatOff;
30368d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
30378d2f55e7SToby Isaac             PetscInt d;
30388d2f55e7SToby Isaac 
3039ad540459SPierre Jolivet             for (d = 0; d < dim; d++) pointScalar[d] = points[dim * j + d];
30408d2f55e7SToby Isaac             point = pointScalar;
30418d2f55e7SToby Isaac #else
30428d2f55e7SToby Isaac             point = pointReal;
30438d2f55e7SToby Isaac #endif
30448d2f55e7SToby Isaac 
3045ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
30463b1c2a6aSToby Isaac 
30473b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
30488d2f55e7SToby Isaac               PetscInt  child = children[k];
30498d2f55e7SToby Isaac               PetscInt *star  = NULL;
30508d2f55e7SToby Isaac               PetscInt  numStar, s;
30518d2f55e7SToby Isaac 
30529566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30538d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
30548d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
30558d2f55e7SToby Isaac 
30568d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
30579566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(refTree, dim, point, c, &childCell));
30588d2f55e7SToby Isaac                 if (childCell >= 0) break;
30598d2f55e7SToby Isaac               }
30609566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30618d2f55e7SToby Isaac               if (childCell >= 0) break;
30628d2f55e7SToby Isaac             }
306308401ef6SPierre Jolivet             PetscCheck(childCell >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not locate quadrature point");
30649566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
30659566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3066c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3067c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
30688d2f55e7SToby Isaac 
30699566063dSJacob Faibussowitsch             PetscCall(PetscFECreateTabulation(fe, 1, 1, pointRef, 0, &Tchild));
30709566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
30713b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3072c5356c36SToby Isaac               PetscInt        child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
30738d2f55e7SToby Isaac               PetscInt        l;
307459fc6756SToby Isaac               const PetscInt *cperms;
30758d2f55e7SToby Isaac 
30769566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(depth, child, &childDepth));
30778d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
307859fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
30798d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
30808d2f55e7SToby Isaac                 PetscInt pointDepth;
30818d2f55e7SToby Isaac 
30828d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
308359fc6756SToby Isaac                 if (point == child) {
308459fc6756SToby Isaac                   cI = l;
308559fc6756SToby Isaac                   break;
308659fc6756SToby Isaac                 }
30879566063dSJacob Faibussowitsch                 PetscCall(DMLabelGetValue(depth, point, &pointDepth));
30888d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
30898d2f55e7SToby Isaac               }
30908d2f55e7SToby Isaac               if (l == numClosure) {
30918d2f55e7SToby Isaac                 pointMatOff += childDof;
30928d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
30938d2f55e7SToby Isaac               }
309459fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
30958d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
309659fc6756SToby Isaac                 PetscInt   lCell        = cperms ? cperms[l] : l;
309759fc6756SToby Isaac                 PetscInt   childCellDof = childCellShapeOff + lCell;
309852a3aeb4SToby Isaac                 PetscReal *childValAtPoint;
309952a3aeb4SToby Isaac                 PetscReal  val = 0.;
31008d2f55e7SToby Isaac 
3101ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
3102ad540459SPierre Jolivet                 for (m = 0; m < Nc; m++) val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
310352a3aeb4SToby Isaac 
310452a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
31058d2f55e7SToby Isaac               }
31068d2f55e7SToby Isaac               pointMatOff += childDof;
31078d2f55e7SToby Isaac             }
31089566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
31099566063dSJacob Faibussowitsch             PetscCall(PetscTabulationDestroy(&Tchild));
31108d2f55e7SToby Isaac           }
31119566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&Tparent));
31128d2f55e7SToby Isaac         }
31139371c9d4SSatish Balay       } else { /* just the volume-weighted averages of the children */
31143b1c2a6aSToby Isaac         PetscReal parentVol;
3115bfaa5bdcSToby Isaac         PetscInt  childCell;
31163b1c2a6aSToby Isaac 
31179566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3118bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
311952a3aeb4SToby Isaac           PetscInt  child = children[i], j;
31203b1c2a6aSToby Isaac           PetscReal childVol;
31213b1c2a6aSToby Isaac 
31223b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
31239566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
3124ad540459SPierre Jolivet           for (j = 0; j < Nc; j++) pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
3125bfaa5bdcSToby Isaac           childCell++;
31263b1c2a6aSToby Isaac         }
31278d2f55e7SToby Isaac       }
31283b1c2a6aSToby Isaac       /* Insert pointMat into mat */
31299566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, numSelfDof, matRows, numChildDof, matCols, pointMat, INSERT_VALUES));
31309566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
31319566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
31328d2f55e7SToby Isaac     }
31338d2f55e7SToby Isaac   }
31349566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJ));
31359566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointScalar, pointRef));
31369566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
31379566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
31388d2f55e7SToby Isaac   *inj = mat;
31393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31408d2f55e7SToby Isaac }
31418d2f55e7SToby Isaac 
3142d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3143d71ae5a4SJacob Faibussowitsch {
3144f30e825dSToby Isaac   PetscDS        ds;
3145f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3146f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3147f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3148f30e825dSToby Isaac 
3149f30e825dSToby Isaac   PetscFunctionBegin;
31509566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
31519566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
31529566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
31539566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
31549566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
31559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
31569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
31579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
31589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof, &cols));
3159f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3160f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3161f30e825dSToby Isaac 
31629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
31639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
31649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3165f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3166f30e825dSToby Isaac 
31679566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFields, &refPointFieldMats[p - pRefStart]));
3168f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
316952a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3170f30e825dSToby Isaac 
3171f30e825dSToby Isaac       if (numFields > 1) {
31729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
31739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
31749371c9d4SSatish Balay       } else {
31759566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
31769566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
3177f30e825dSToby Isaac       }
3178f30e825dSToby Isaac 
3179ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
3180f30e825dSToby Isaac       numCols = 0;
3181f30e825dSToby Isaac       {
3182f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3183f30e825dSToby Isaac 
3184f30e825dSToby Isaac         if (numFields > 1) {
31859566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, parent, f, &aDof));
31869566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, parent, f, &aOff));
31879371c9d4SSatish Balay         } else {
31889566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, parent, &aDof));
31899566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, parent, &aOff));
3190f30e825dSToby Isaac         }
3191f30e825dSToby Isaac 
3192ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + j;
3193f30e825dSToby Isaac       }
31949566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
3195f30e825dSToby Isaac       /* transpose of constraint matrix */
31969566063dSJacob Faibussowitsch       PetscCall(MatGetValues(inj, numCols, cols, cDof, rows, refPointFieldMats[p - pRefStart][f]));
3197f30e825dSToby Isaac     }
3198f30e825dSToby Isaac   }
3199f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
32009566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
32019566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
32023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3203f30e825dSToby Isaac }
3204f30e825dSToby Isaac 
3205d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3206d71ae5a4SJacob Faibussowitsch {
3207f30e825dSToby Isaac   PetscDS        ds;
3208f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3209f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3210c6154584SToby Isaac   PetscSection   refConSec, refSection;
3211f30e825dSToby Isaac 
3212f30e825dSToby Isaac   PetscFunctionBegin;
3213f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3214f30e825dSToby Isaac   *childrenMats     = NULL;
32159566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
32169566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
32179566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
32189566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
32199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3220f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3221f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3222f30e825dSToby Isaac 
32239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
32249566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
32259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3226f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3227f30e825dSToby Isaac 
3228f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3229f30e825dSToby Isaac       PetscInt cDof;
3230f30e825dSToby Isaac 
3231f30e825dSToby Isaac       if (numFields > 1) {
32329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
32339371c9d4SSatish Balay       } else {
32349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3235f30e825dSToby Isaac       }
3236f30e825dSToby Isaac 
32379566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3238f30e825dSToby Isaac     }
32399566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3240f30e825dSToby Isaac   }
32419566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
32423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3243f30e825dSToby Isaac }
3244f30e825dSToby Isaac 
3245d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree, Mat *injRef)
3246d71ae5a4SJacob Faibussowitsch {
3247ebf164c7SToby Isaac   Mat         cMatRef;
32486148253fSToby Isaac   PetscObject injRefObj;
32498d2f55e7SToby Isaac 
3250154bca37SToby Isaac   PetscFunctionBegin;
32519566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, NULL, &cMatRef, NULL));
32529566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", &injRefObj));
3253ebf164c7SToby Isaac   *injRef = (Mat)injRefObj;
3254ebf164c7SToby Isaac   if (!*injRef) {
32559566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorReferenceTree(refTree, injRef));
32569566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", (PetscObject)*injRef));
3257ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
32589566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3259ebf164c7SToby Isaac   }
32603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32616148253fSToby Isaac }
3262f30e825dSToby Isaac 
3263d71ae5a4SJacob 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)
3264d71ae5a4SJacob Faibussowitsch {
3265c921d74cSToby Isaac   PetscInt        pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3266ebf164c7SToby Isaac   PetscSection    globalCoarse, globalFine;
3267ebf164c7SToby Isaac   PetscSection    localCoarse, localFine, leafIndicesSec;
3268c921d74cSToby Isaac   PetscSection    multiRootSec, rootIndicesSec;
3269c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3270c921d74cSToby Isaac   const PetscInt *rootDegrees;
3271c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3272ebf164c7SToby Isaac   PetscSF         coarseToFineEmbedded;
3273ebf164c7SToby Isaac 
3274ebf164c7SToby Isaac   PetscFunctionBegin;
32759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
32769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
32779566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
32789566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
32799566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
32809566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafIndicesSec, pStartF, pEndF));
32819566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
32828d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
32837e96bdafSToby Isaac     PetscInt        l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
32847e96bdafSToby Isaac     const PetscInt *leaves;
32858d2f55e7SToby Isaac 
32869566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
32877e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
32887e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
32899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
32909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
32918d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
32928d2f55e7SToby Isaac         numPointsWithDofs++;
3293f30e825dSToby Isaac 
32949566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localFine, p, &dof));
32959566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafIndicesSec, p, dof + 1));
32968d2f55e7SToby Isaac       }
32978d2f55e7SToby Isaac     }
32989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
32999566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafIndicesSec));
33009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numIndices));
33019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1), &leafInds));
33029566063dSJacob Faibussowitsch     if (gatheredValues) PetscCall(PetscMalloc1(numIndices, &leafVals));
33037e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
33047e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
33059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
33069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
33078d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3308f30e825dSToby Isaac         PetscInt     off, gOff;
3309f30e825dSToby Isaac         PetscInt    *pInd;
3310c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3311f30e825dSToby Isaac 
33127e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3313f30e825dSToby Isaac 
33149566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3315f30e825dSToby Isaac 
3316c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3317c921d74cSToby Isaac         if (gatheredValues) {
3318c921d74cSToby Isaac           PetscInt i;
3319c921d74cSToby Isaac 
3320c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3321c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3322c921d74cSToby Isaac         }
33239566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
3324f30e825dSToby Isaac 
3325f30e825dSToby Isaac         offsets[0] = 0;
3326f30e825dSToby Isaac         if (numFields) {
3327f30e825dSToby Isaac           PetscInt f;
3328f30e825dSToby Isaac 
3329f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3330f30e825dSToby Isaac             PetscInt fDof;
33319566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localFine, p, f, &fDof));
3332f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3333f30e825dSToby Isaac           }
33349566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
3335367003a6SStefano Zampini         } else {
33369566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
3337f30e825dSToby Isaac         }
33389566063dSJacob Faibussowitsch         if (gatheredValues) PetscCall(VecGetValues(fineVec, dof, pInd, pVal));
33398d2f55e7SToby Isaac       }
33408d2f55e7SToby Isaac     }
33419566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
33429566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
33438d2f55e7SToby Isaac   }
3344f30e825dSToby Isaac 
33459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
33469566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
33479566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3348f30e825dSToby Isaac 
33496148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
33506148253fSToby Isaac     MPI_Datatype threeInt;
33516148253fSToby Isaac     PetscMPIInt  rank;
33526148253fSToby Isaac     PetscInt(*parentNodeAndIdCoarse)[3];
33536148253fSToby Isaac     PetscInt(*parentNodeAndIdFine)[3];
33546148253fSToby Isaac     PetscInt           p, nleaves, nleavesToParents;
33556148253fSToby Isaac     PetscSF            pointSF, sfToParents;
33566148253fSToby Isaac     const PetscInt    *ilocal;
33576148253fSToby Isaac     const PetscSFNode *iremote;
33586148253fSToby Isaac     PetscSFNode       *iremoteToParents;
33596148253fSToby Isaac     PetscInt          *ilocalToParents;
33606148253fSToby Isaac 
33619566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse), &rank));
33629566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &threeInt));
33639566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&threeInt));
33649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEndC - pStartC, &parentNodeAndIdCoarse, pEndF - pStartF, &parentNodeAndIdFine));
33659566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(coarse, &pointSF));
33669566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, &iremote));
33676148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
33686148253fSToby Isaac       PetscInt parent, childId;
33699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(coarse, p, &parent, &childId));
33706148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
33716148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
33726148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
33736148253fSToby Isaac       if (nleaves > 0) {
33746148253fSToby Isaac         PetscInt leaf = -1;
33756148253fSToby Isaac 
33766148253fSToby Isaac         if (ilocal) {
33779566063dSJacob Faibussowitsch           PetscCall(PetscFindInt(parent, nleaves, ilocal, &leaf));
33789371c9d4SSatish Balay         } else {
33796148253fSToby Isaac           leaf = p - pStartC;
33806148253fSToby Isaac         }
33816148253fSToby Isaac         if (leaf >= 0) {
33826148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
33836148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
33846148253fSToby Isaac         }
33856148253fSToby Isaac       }
33866148253fSToby Isaac     }
33876148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
33886148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
33896148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
33906148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
33916148253fSToby Isaac     }
33929566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
33939566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
33946148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3395f30e825dSToby Isaac       PetscInt dof;
3396f30e825dSToby Isaac 
33979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &dof));
3398f30e825dSToby Isaac       if (dof) {
3399f30e825dSToby Isaac         PetscInt off;
3400f30e825dSToby Isaac 
34019566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3402c921d74cSToby Isaac         if (gatheredIndices) {
3403c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3404c921d74cSToby Isaac         } else if (gatheredValues) {
3405c921d74cSToby Isaac           leafVals[off] = (PetscScalar)PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3406c921d74cSToby Isaac         }
3407f30e825dSToby Isaac       }
3408ad540459SPierre Jolivet       if (parentNodeAndIdFine[p - pStartF][0] >= 0) nleavesToParents++;
34096148253fSToby Isaac     }
34109566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &ilocalToParents));
34119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &iremoteToParents));
34126148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
34136148253fSToby Isaac       if (parentNodeAndIdFine[p - pStartF][0] >= 0) {
34146148253fSToby Isaac         ilocalToParents[nleavesToParents]        = p - pStartF;
34156148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p - pStartF][0];
34166148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p - pStartF][1];
34176148253fSToby Isaac         nleavesToParents++;
34186148253fSToby Isaac       }
34196148253fSToby Isaac     }
34209566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse), &sfToParents));
34219566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(sfToParents, pEndC - pStartC, nleavesToParents, ilocalToParents, PETSC_OWN_POINTER, iremoteToParents, PETSC_OWN_POINTER));
34229566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34236148253fSToby Isaac 
34246148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
34256148253fSToby Isaac 
34269566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parentNodeAndIdCoarse, parentNodeAndIdFine));
34279566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&threeInt));
34286148253fSToby Isaac   }
3429f30e825dSToby Isaac 
34306148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
34316148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
34326148253fSToby Isaac     PetscSF  sfDofsOnly;
34336148253fSToby Isaac 
34346148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
34359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3437ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
34386148253fSToby Isaac     }
34399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
34406148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
34419566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34429566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3443ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = p - pStartC;
34446148253fSToby Isaac     }
34459566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
34469566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34479566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
34486148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
34496148253fSToby Isaac   }
3450f30e825dSToby Isaac 
34516148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
34529566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded, &rootDegrees));
34539566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded, &rootDegrees));
34549566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &multiRootSec));
34559566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(multiRootSec, pStartC, pEndC));
345648a46eb9SPierre Jolivet   for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionSetDof(multiRootSec, p, rootDegrees[p - pStartC]));
34579566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(multiRootSec));
34589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(multiRootSec, &numMulti));
34599566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
3460f30e825dSToby Isaac   { /* distribute the leaf section */
3461f30e825dSToby Isaac     PetscSF   multi, multiInv, indicesSF;
3462f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
34638d2f55e7SToby Isaac 
34649566063dSJacob Faibussowitsch     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded, &multi));
34659566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF(multi, &multiInv));
34669566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(multiInv, leafIndicesSec, &remoteOffsets, rootIndicesSec));
34679566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(multiInv, leafIndicesSec, remoteOffsets, rootIndicesSec, &indicesSF));
34689566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
34699566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&multiInv));
34709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
3471c921d74cSToby Isaac     if (gatheredIndices) {
34729566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootInds));
34739566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
34749566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3475c921d74cSToby Isaac     }
3476c921d74cSToby Isaac     if (gatheredValues) {
34779566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootVals));
34789566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
34799566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3480c921d74cSToby Isaac     }
34819566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
34828d2f55e7SToby Isaac   }
34839566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
34849566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafInds));
34859566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafVals));
34869566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3487c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3488c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3489c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3490c921d74cSToby Isaac   if (gatheredValues) *gatheredValues = rootVals;
34913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3492ebf164c7SToby Isaac }
3493ebf164c7SToby Isaac 
3494d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3495d71ae5a4SJacob Faibussowitsch {
3496ebf164c7SToby Isaac   DM             refTree;
3497c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3498ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3499ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3500ebf164c7SToby Isaac   PetscSection   cSecRef;
3501277f51e8SBarry Smith   PetscInt      *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3502ebf164c7SToby Isaac   Mat            injRef;
3503c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3504ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3505ebf164c7SToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
3506ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3507ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3508ebf164c7SToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3509ebf164c7SToby Isaac 
3510ebf164c7SToby Isaac   PetscFunctionBegin;
3511ebf164c7SToby Isaac 
3512ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
35139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
35149566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
35159566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
35169566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
3517ebf164c7SToby Isaac 
35189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
35199566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
35209566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
35219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
35229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
35239566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
35249566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
35259566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
3526ebf164c7SToby Isaac   {
3527ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
35289566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
3529ebf164c7SToby Isaac   }
3530ebf164c7SToby Isaac 
35319566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, childIds, NULL, numFields, offsets, &multiRootSec, &rootIndicesSec, &rootIndices, NULL));
35328d2f55e7SToby Isaac 
35339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &parentIndices));
3534f30e825dSToby Isaac 
3535f30e825dSToby Isaac   /* count indices */
35369566063dSJacob Faibussowitsch   PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
35379566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
35389566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
35399566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
35409566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
35419566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(rowEnd - rowStart, &nnzD, rowEnd - rowStart, &nnzO));
3542f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3543f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
35448d2f55e7SToby Isaac 
35459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
35469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3547f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
35489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
35498d2f55e7SToby Isaac 
35508d2f55e7SToby Isaac     rowOffsets[0]  = 0;
3551f30e825dSToby Isaac     offsetsCopy[0] = 0;
35528d2f55e7SToby Isaac     if (numFields) {
35538d2f55e7SToby Isaac       PetscInt f;
35548d2f55e7SToby Isaac 
3555f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3556f30e825dSToby Isaac         PetscInt fDof;
35579566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3558f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
35598d2f55e7SToby Isaac       }
35609566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3561367003a6SStefano Zampini     } else {
35629566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3563f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
35648d2f55e7SToby Isaac     }
3565f30e825dSToby Isaac 
35669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
35679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3568f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3569f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3570f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3571f30e825dSToby Isaac       const PetscInt *childIndices;
3572f30e825dSToby Isaac 
35739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
35749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3575f30e825dSToby Isaac       childId      = rootIndices[offset++];
3576f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3577f30e825dSToby Isaac       numIndices--;
3578f30e825dSToby Isaac 
3579f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3580f30e825dSToby Isaac         PetscInt i;
3581f30e825dSToby Isaac 
3582f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3583f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3584f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3585f30e825dSToby Isaac           if (rowIndex < 0) continue;
358608401ef6SPierre Jolivet           PetscCheck(colIndex >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unconstrained fine and constrained coarse");
3587a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3588f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
35899371c9d4SSatish Balay           } else {
3590f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3591f30e825dSToby Isaac           }
3592f30e825dSToby Isaac         }
35939371c9d4SSatish Balay       } else {
3594f30e825dSToby Isaac         PetscInt parentId, f, lim;
3595f30e825dSToby Isaac 
35969566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3597f30e825dSToby Isaac 
3598f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3599f30e825dSToby Isaac         offsets[0] = 0;
36008d2f55e7SToby Isaac         if (numFields) {
36018d2f55e7SToby Isaac           PetscInt f;
3602f30e825dSToby Isaac 
36038d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3604f30e825dSToby Isaac             PetscInt fDof;
36059566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3606f30e825dSToby Isaac 
3607f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
36088d2f55e7SToby Isaac           }
36099371c9d4SSatish Balay         } else {
3610f30e825dSToby Isaac           PetscInt cDof;
3611f30e825dSToby Isaac 
36129566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3613f30e825dSToby Isaac           offsets[1] = cDof;
3614f30e825dSToby Isaac         }
3615f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3616f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3617f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3618f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3619f30e825dSToby Isaac 
3620f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3621f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3622f30e825dSToby Isaac 
3623f30e825dSToby Isaac             if (colIndex < 0) continue;
3624f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3625f30e825dSToby Isaac               numD++;
36269371c9d4SSatish Balay             } else {
3627f30e825dSToby Isaac               numO++;
3628f30e825dSToby Isaac             }
3629f30e825dSToby Isaac           }
3630f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3631f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3632f30e825dSToby Isaac 
3633f30e825dSToby Isaac             if (rowIndex < 0) continue;
3634f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3635f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
36368d2f55e7SToby Isaac           }
36378d2f55e7SToby Isaac         }
36388d2f55e7SToby Isaac       }
3639f30e825dSToby Isaac     }
3640f30e825dSToby Isaac   }
3641f30e825dSToby Isaac   /* preallocate */
36429566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mat, 1, nnzD, nnzO, NULL, NULL));
36439566063dSJacob Faibussowitsch   PetscCall(PetscFree2(nnzD, nnzO));
3644f30e825dSToby Isaac   /* insert values */
36459566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3646f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3647f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3648f30e825dSToby Isaac 
36499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
36509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3651f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
36529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
3653f30e825dSToby Isaac 
3654f30e825dSToby Isaac     rowOffsets[0]  = 0;
3655f30e825dSToby Isaac     offsetsCopy[0] = 0;
36568d2f55e7SToby Isaac     if (numFields) {
36578d2f55e7SToby Isaac       PetscInt f;
3658f30e825dSToby Isaac 
36598d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3660f30e825dSToby Isaac         PetscInt fDof;
36619566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3662f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3663f30e825dSToby Isaac       }
36649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3665367003a6SStefano Zampini     } else {
36669566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3667f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3668f30e825dSToby Isaac     }
3669f30e825dSToby Isaac 
36709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
36719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3672f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3673f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3674f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3675f30e825dSToby Isaac       const PetscInt *childIndices;
3676f30e825dSToby Isaac 
36779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
36789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3679f30e825dSToby Isaac       childId      = rootIndices[offset++];
3680f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3681f30e825dSToby Isaac       numIndices--;
3682f30e825dSToby Isaac 
3683f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3684f30e825dSToby Isaac         PetscInt i;
3685f30e825dSToby Isaac 
368648a46eb9SPierre Jolivet         for (i = 0; i < numIndices; i++) PetscCall(MatSetValue(mat, parentIndices[i], childIndices[i], 1., INSERT_VALUES));
36879371c9d4SSatish Balay       } else {
3688f30e825dSToby Isaac         PetscInt parentId, f, lim;
36898d2f55e7SToby Isaac 
36909566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3691f30e825dSToby Isaac 
3692f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3693f30e825dSToby Isaac         offsets[0] = 0;
36948d2f55e7SToby Isaac         if (numFields) {
3695f30e825dSToby Isaac           PetscInt f;
36968d2f55e7SToby Isaac 
3697f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3698f30e825dSToby Isaac             PetscInt fDof;
36999566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3700f30e825dSToby Isaac 
3701f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
37028d2f55e7SToby Isaac           }
37039371c9d4SSatish Balay         } else {
3704f30e825dSToby Isaac           PetscInt cDof;
3705f30e825dSToby Isaac 
37069566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3707f30e825dSToby Isaac           offsets[1] = cDof;
37088d2f55e7SToby Isaac         }
3709f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3710f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3711f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3712f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3713f30e825dSToby Isaac 
37149566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat, rowOffsets[f + 1] - rowOffsets[f], rowIndices, offsets[f + 1] - offsets[f], colIndices, childMat, INSERT_VALUES));
37158d2f55e7SToby Isaac         }
37168d2f55e7SToby Isaac       }
37178d2f55e7SToby Isaac     }
37188d2f55e7SToby Isaac   }
37199566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
37209566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
37219566063dSJacob Faibussowitsch   PetscCall(PetscFree(parentIndices));
37229566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
37239566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootIndices));
37249566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
3725f30e825dSToby Isaac 
37269566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
37279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
37283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3729154bca37SToby Isaac }
373038fc2455SToby Isaac 
3731d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3732d71ae5a4SJacob Faibussowitsch {
373362095d54SToby Isaac   PetscSF            coarseToFineEmbedded;
373462095d54SToby Isaac   PetscSection       globalCoarse, globalFine;
373562095d54SToby Isaac   PetscSection       localCoarse, localFine;
373662095d54SToby Isaac   PetscSection       aSec, cSec;
373762095d54SToby Isaac   PetscSection       rootValuesSec;
373862095d54SToby Isaac   PetscSection       leafValuesSec;
373962095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
374062095d54SToby Isaac   IS                 aIS;
374162095d54SToby Isaac   const PetscInt    *anchors;
374262095d54SToby Isaac   Mat                cMat;
374362095d54SToby Isaac   PetscInt           numFields;
3744412e9a14SMatthew G. Knepley   PetscInt           pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
374562095d54SToby Isaac   PetscInt           aStart, aEnd, cStart, cEnd;
374662095d54SToby Isaac   PetscInt          *maxChildIds;
374762095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
37480eb7e1eaSToby Isaac   PetscFV            fv = NULL;
37490eb7e1eaSToby Isaac   PetscInt           dim, numFVcomps = -1, fvField = -1;
37500eb7e1eaSToby Isaac   DM                 cellDM = NULL, gradDM = NULL;
37510eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
37520eb7e1eaSToby Isaac   const PetscScalar *gradArray     = NULL;
375362095d54SToby Isaac 
3754ebf164c7SToby Isaac   PetscFunctionBegin;
37559566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
37569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
37579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(coarse, 0, &cellStart, &cellEnd));
37589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
37599566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
37609566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(coarse, &dim));
376162095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3762e4a60869SToby Isaac     PetscInt        nleaves, l;
3763e4a60869SToby Isaac     const PetscInt *leaves;
376462095d54SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
376562095d54SToby Isaac 
37669566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
3767e4a60869SToby Isaac 
3768e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3769e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3770e4a60869SToby Isaac 
37719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3773ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
377462095d54SToby Isaac     }
37759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
37764833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
3777e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3778e4a60869SToby Isaac 
37799566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3781ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
378262095d54SToby Isaac     }
37839566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
37849566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
378562095d54SToby Isaac   }
378662095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
37879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
3788ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
37899566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
37909566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
379162095d54SToby Isaac 
37929566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
37939566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
379462095d54SToby Isaac 
37959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
37969566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
37979566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
379862095d54SToby Isaac 
37999566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
38009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
380162095d54SToby Isaac 
380262095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
38039566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootValuesSec));
38049566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootValuesSec, pStartC, pEndC));
38059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
380662095d54SToby Isaac   {
380762095d54SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
38089566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &newOffsets, maxFields, &newOffsetsCopy, maxFields, &rowOffsets, maxFields, &numD, maxFields, &numO));
380962095d54SToby Isaac   }
38100eb7e1eaSToby Isaac   if (grad) {
38110eb7e1eaSToby Isaac     PetscInt i;
38120eb7e1eaSToby Isaac 
38139566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeom, &cellDM));
38149566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeom, &cellGeomArray));
38159566063dSJacob Faibussowitsch     PetscCall(VecGetDM(grad, &gradDM));
38169566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(grad, &gradArray));
38170eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1, numFields); i++) {
38180eb7e1eaSToby Isaac       PetscObject  obj;
38190eb7e1eaSToby Isaac       PetscClassId id;
38200eb7e1eaSToby Isaac 
38219566063dSJacob Faibussowitsch       PetscCall(DMGetField(coarse, i, NULL, &obj));
38229566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
38230eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
38240eb7e1eaSToby Isaac         fv = (PetscFV)obj;
38259566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &numFVcomps));
38260eb7e1eaSToby Isaac         fvField = i;
38270eb7e1eaSToby Isaac         break;
38280eb7e1eaSToby Isaac       }
38290eb7e1eaSToby Isaac     }
38300eb7e1eaSToby Isaac   }
383162095d54SToby Isaac 
383262095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
383362095d54SToby Isaac     PetscInt dof;
383462095d54SToby Isaac     PetscInt maxChildId = maxChildIds[p - pStartC];
383562095d54SToby Isaac     PetscInt numValues  = 0;
383662095d54SToby Isaac 
38379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3838ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
383962095d54SToby Isaac     offsets[0]    = 0;
384062095d54SToby Isaac     newOffsets[0] = 0;
384162095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
384262095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
384362095d54SToby Isaac 
38449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
384562095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
384662095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
384762095d54SToby Isaac 
38489566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
384962095d54SToby Isaac         numValues += clDof;
385062095d54SToby Isaac       }
38519566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
38529371c9d4SSatish Balay     } else if (maxChildId == -1) {
38539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localCoarse, p, &numValues));
385462095d54SToby Isaac     }
385562095d54SToby Isaac     /* we will pack the column indices with the field offsets */
385678b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
38570eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
38580eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
38590eb7e1eaSToby Isaac     }
38609566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootValuesSec, p, numValues));
386162095d54SToby Isaac   }
38629566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootValuesSec));
386362095d54SToby Isaac   {
386462095d54SToby Isaac     PetscInt           numRootValues;
386562095d54SToby Isaac     const PetscScalar *coarseArray;
386662095d54SToby Isaac 
38679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootValuesSec, &numRootValues));
38689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRootValues, &rootValues));
38699566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecCoarseLocal, &coarseArray));
387062095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
387162095d54SToby Isaac       PetscInt     numValues;
387262095d54SToby Isaac       PetscInt     pValOff;
387362095d54SToby Isaac       PetscScalar *pVal;
387462095d54SToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
387562095d54SToby Isaac 
38769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootValuesSec, p, &numValues));
3877ad540459SPierre Jolivet       if (!numValues) continue;
38789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootValuesSec, p, &pValOff));
387962095d54SToby Isaac       pVal = &(rootValues[pValOff]);
388062095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
38810eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
38829566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(coarse, NULL, vecCoarseLocal, p, &closureSize, &pVal));
38830eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
3884193eb951SToby Isaac           PetscFVCellGeom *cg;
38856dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
38860eb7e1eaSToby Isaac           PetscInt         i;
38870eb7e1eaSToby Isaac 
38880eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
38890eb7e1eaSToby Isaac 
38909566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(cellDM, p, cellGeomArray, (void *)&cg));
38910eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
38920eb7e1eaSToby Isaac           pVal += dim;
38939566063dSJacob Faibussowitsch           PetscCall(DMPlexPointGlobalRead(gradDM, p, gradArray, (void *)&gradVals));
38940eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
38950eb7e1eaSToby Isaac         }
38969371c9d4SSatish Balay       } else if (maxChildId == -1) {
389778b7adb5SToby Isaac         PetscInt lDof, lOff, i;
389878b7adb5SToby Isaac 
38999566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, p, &lDof));
39009566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(localCoarse, p, &lOff));
390178b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
390278b7adb5SToby Isaac       }
390378b7adb5SToby Isaac     }
39049566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecCoarseLocal, &coarseArray));
39059566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
390662095d54SToby Isaac   }
390762095d54SToby Isaac   {
390862095d54SToby Isaac     PetscSF   valuesSF;
390962095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
391062095d54SToby Isaac 
39119566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafValuesSec));
39129566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootValuesSec, &remoteOffsetsValues, leafValuesSec));
39139566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootValuesSec, remoteOffsetsValues, leafValuesSec, &valuesSF));
39149566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
39159566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsValues));
39169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafValuesSec, &numLeafValues));
39179566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafValues, &leafValues));
39189566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39199566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39209566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&valuesSF));
39219566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootValues));
39229566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootValuesSec));
392362095d54SToby Isaac   }
39249566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
392562095d54SToby Isaac   {
392662095d54SToby Isaac     PetscInt       maxDof;
392762095d54SToby Isaac     PetscInt      *rowIndices;
392862095d54SToby Isaac     DM             refTree;
392962095d54SToby Isaac     PetscInt     **refPointFieldN;
393062095d54SToby Isaac     PetscScalar ***refPointFieldMats;
393162095d54SToby Isaac     PetscSection   refConSec, refAnSec;
39320eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, leafStart, leafEnd;
393362095d54SToby Isaac     PetscScalar   *pointWork;
393462095d54SToby Isaac 
39359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
39369566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
39379566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
39389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
39399566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(fine, refTree));
39409566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
39419566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
39429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
39439566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
39449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafValuesSec, &leafStart, &leafEnd));
39459566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSimplexOrBoxCells(fine, 0, &cellStart, &cellEnd));
39460eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
394762095d54SToby Isaac       PetscInt           gDof, gcDof, gOff, lDof;
394862095d54SToby Isaac       PetscInt           numValues, pValOff;
394962095d54SToby Isaac       PetscInt           childId;
395062095d54SToby Isaac       const PetscScalar *pVal;
39510eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
395262095d54SToby Isaac 
39539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
39549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localFine, p, &lDof));
39559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
3956ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
39579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
39589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafValuesSec, p, &numValues));
395962095d54SToby Isaac       if (!numValues) continue;
39609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafValuesSec, p, &pValOff));
396162095d54SToby Isaac       pVal              = &leafValues[pValOff];
396262095d54SToby Isaac       offsets[0]        = 0;
396362095d54SToby Isaac       offsetsCopy[0]    = 0;
396462095d54SToby Isaac       newOffsets[0]     = 0;
396562095d54SToby Isaac       newOffsetsCopy[0] = 0;
39664833aeb0SToby Isaac       childId           = cids[p - pStartF];
396762095d54SToby Isaac       if (numFields) {
396862095d54SToby Isaac         PetscInt f;
396962095d54SToby Isaac         for (f = 0; f < numFields; f++) {
397062095d54SToby Isaac           PetscInt rowDof;
397162095d54SToby Isaac 
39729566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
397362095d54SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
397462095d54SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
397562095d54SToby Isaac           /* TODO: closure indices */
39769f4e70e1SToby Isaac           newOffsets[f + 1] = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
397762095d54SToby Isaac         }
39789566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
39799371c9d4SSatish Balay       } else {
39804833aeb0SToby Isaac         offsets[0]    = 0;
39814833aeb0SToby Isaac         offsets[1]    = lDof;
39824833aeb0SToby Isaac         newOffsets[0] = 0;
39834833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
39849566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
398562095d54SToby Isaac       }
398662095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
39879566063dSJacob Faibussowitsch         PetscCall(VecSetValues(vecFine, numValues, rowIndices, pVal, INSERT_VALUES));
398862095d54SToby Isaac       } else {
398962095d54SToby Isaac         PetscInt f;
399062095d54SToby Isaac 
399178b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
399278b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
399378b7adb5SToby Isaac           fvGradData = &pVal[numValues];
399478b7adb5SToby Isaac         }
399562095d54SToby Isaac         for (f = 0; f < PetscMax(1, numFields); f++) {
399662095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
399762095d54SToby Isaac           PetscInt           numRows  = offsets[f + 1] - offsets[f];
399862095d54SToby Isaac           PetscInt           numCols  = newOffsets[f + 1] - newOffsets[f];
399962095d54SToby Isaac           const PetscScalar *cVal     = &pVal[newOffsets[f]];
400062095d54SToby Isaac           PetscScalar       *rVal     = &pointWork[offsets[f]];
400162095d54SToby Isaac           PetscInt           i, j;
400262095d54SToby Isaac 
4003708c7f19SToby Isaac #if 0
400463a3b9bcSJacob 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));
4005708c7f19SToby Isaac #endif
400662095d54SToby Isaac           for (i = 0; i < numRows; i++) {
400762095d54SToby Isaac             PetscScalar val = 0.;
4008ad540459SPierre Jolivet             for (j = 0; j < numCols; j++) val += childMat[i * numCols + j] * cVal[j];
400962095d54SToby Isaac             rVal[i] = val;
401062095d54SToby Isaac           }
40110eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
40120eb7e1eaSToby Isaac             PetscReal          centroid[3];
40130eb7e1eaSToby Isaac             PetscScalar        diff[3];
40140eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
40150eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
40160eb7e1eaSToby Isaac 
40179566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFVM(fine, p, NULL, centroid, NULL));
4018ad540459SPierre Jolivet             for (i = 0; i < dim; i++) diff[i] = centroid[i] - parentCentroid[i];
40190eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
40200eb7e1eaSToby Isaac               PetscScalar val = 0.;
40210eb7e1eaSToby Isaac 
4022ad540459SPierre Jolivet               for (j = 0; j < dim; j++) val += gradient[dim * i + j] * diff[j];
40230eb7e1eaSToby Isaac               rVal[i] += val;
40240eb7e1eaSToby Isaac             }
40250eb7e1eaSToby Isaac           }
40269566063dSJacob Faibussowitsch           PetscCall(VecSetValues(vecFine, numRows, &rowIndices[offsets[f]], rVal, INSERT_VALUES));
402762095d54SToby Isaac         }
402862095d54SToby Isaac       }
402962095d54SToby Isaac     }
40309566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
40319566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
40329566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
403362095d54SToby Isaac   }
40349566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafValues));
40359566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafValuesSec));
40369566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
40379566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
40383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4039ebf164c7SToby Isaac }
4040ebf164c7SToby Isaac 
4041d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4042d71ae5a4SJacob Faibussowitsch {
4043c921d74cSToby Isaac   DM             refTree;
4044c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4045c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4046c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4047c921d74cSToby Isaac   PetscSection   cSecRef;
4048c921d74cSToby Isaac   PetscInt      *parentIndices, pRefStart, pRefEnd;
4049d3bc4906SToby Isaac   PetscScalar   *rootValues, *parentValues;
4050c921d74cSToby Isaac   Mat            injRef;
4051c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4052c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4053c921d74cSToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
4054c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4055c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4056c921d74cSToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4057c921d74cSToby Isaac 
4058ebf164c7SToby Isaac   PetscFunctionBegin;
4059c921d74cSToby Isaac 
4060c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
40619566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40629566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecCoarse, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
40649566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(coarse, refTree));
40659566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
40669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
40679566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
4068c921d74cSToby Isaac 
40699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
40709566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
40719566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
40729566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
40739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
40749566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
40759566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
40769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
4077c921d74cSToby Isaac   {
4078c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
40799566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
4080c921d74cSToby Isaac   }
4081c921d74cSToby Isaac 
40829566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, cids, vecFine, numFields, offsets, &multiRootSec, &rootIndicesSec, NULL, &rootValues));
4083c921d74cSToby Isaac 
40849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxDof, &parentIndices, maxDof, &parentValues));
4085c921d74cSToby Isaac 
4086c921d74cSToby Isaac   /* count indices */
40879566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecFine, &colMap));
40889566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecCoarse, &rowMap));
40899566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
40909566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
40919566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
40929566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
4093c921d74cSToby Isaac   /* insert values */
40949566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4095c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4096c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
409778b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4098c921d74cSToby Isaac 
40999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
41009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
4101c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
41029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localCoarse, p, &dof));
41039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
4104c921d74cSToby Isaac 
4105c921d74cSToby Isaac     rowOffsets[0]  = 0;
4106c921d74cSToby Isaac     offsetsCopy[0] = 0;
4107c921d74cSToby Isaac     if (numFields) {
4108c921d74cSToby Isaac       PetscInt f;
4109c921d74cSToby Isaac 
4110c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4111c921d74cSToby Isaac         PetscInt fDof;
41129566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
4113c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4114c921d74cSToby Isaac       }
41159566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
4116367003a6SStefano Zampini     } else {
41179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
4118c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4119c921d74cSToby Isaac     }
4120c921d74cSToby Isaac 
41219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
41229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
4123c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
41242f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4125c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4126c921d74cSToby Isaac       PetscInt           numIndices, childId, offset;
4127c921d74cSToby Isaac       const PetscScalar *childValues;
4128c921d74cSToby Isaac 
41299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
41309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
4131c921d74cSToby Isaac       childId     = (PetscInt)PetscRealPart(rootValues[offset++]);
4132c921d74cSToby Isaac       childValues = &rootValues[offset];
4133c921d74cSToby Isaac       numIndices--;
4134c921d74cSToby Isaac 
4135c921d74cSToby Isaac       if (childId == -2) { /* skip */
4136c921d74cSToby Isaac         continue;
4137c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
41382f65e181SToby Isaac         PetscInt m;
41392f65e181SToby Isaac 
414078b7adb5SToby Isaac         contribute = PETSC_TRUE;
41412f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4142beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4143d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4144d3bc4906SToby Isaac 
414578b7adb5SToby Isaac         contribute = PETSC_TRUE;
41469566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
4147d3bc4906SToby Isaac 
4148d3bc4906SToby Isaac         lim        = PetscMax(1, numFields);
4149d3bc4906SToby Isaac         offsets[0] = 0;
4150d3bc4906SToby Isaac         if (numFields) {
4151d3bc4906SToby Isaac           PetscInt f;
4152d3bc4906SToby Isaac 
4153d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4154d3bc4906SToby Isaac             PetscInt fDof;
41559566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
4156d3bc4906SToby Isaac 
4157d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4158d3bc4906SToby Isaac           }
41599371c9d4SSatish Balay         } else {
4160d3bc4906SToby Isaac           PetscInt cDof;
4161d3bc4906SToby Isaac 
41629566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
4163d3bc4906SToby Isaac           offsets[1] = cDof;
4164d3bc4906SToby Isaac         }
4165d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4166d3bc4906SToby Isaac           PetscScalar       *childMat = &childrenMats[childId - pRefStart][f][0];
4167d3bc4906SToby Isaac           PetscInt           n        = offsets[f + 1] - offsets[f];
4168e328ff09SToby Isaac           PetscInt           m        = rowOffsets[f + 1] - rowOffsets[f];
4169d3bc4906SToby Isaac           PetscInt           i, j;
4170d3bc4906SToby Isaac           const PetscScalar *colValues = &childValues[offsets[f]];
4171d3bc4906SToby Isaac 
4172e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4173d3bc4906SToby Isaac             PetscScalar val = 0.;
4174ad540459SPierre Jolivet             for (j = 0; j < n; j++) val += childMat[n * i + j] * colValues[j];
4175e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4176d3bc4906SToby Isaac           }
4177d3bc4906SToby Isaac         }
4178c921d74cSToby Isaac       }
4179c921d74cSToby Isaac     }
41809566063dSJacob Faibussowitsch     if (contribute) PetscCall(VecSetValues(vecCoarse, dof, parentIndices, parentValues, INSERT_VALUES));
4181c921d74cSToby Isaac   }
41829566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
41839566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
41849566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parentIndices, parentValues));
41859566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
41869566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootValues));
41879566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
41883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4189ebf164c7SToby Isaac }
4190ebf164c7SToby Isaac 
4191ff1f73f7SToby Isaac /*@
4192ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4193ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4194ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4195ff1f73f7SToby Isaac 
419620f4b53cSBarry Smith   Collective
4197ff1f73f7SToby Isaac 
4198ff1f73f7SToby Isaac   Input Parameters:
4199a1cb98faSBarry Smith + dmIn        - The `DMPLEX` mesh for the input vector
420020f4b53cSBarry Smith . dmOut        - The second `DMPLEX` mesh
4201ff1f73f7SToby Isaac . vecIn       - The input vector
420220f4b53cSBarry Smith . sfRefine    - A star forest indicating points in the mesh `dmIn` (roots in the star forest) that are parents to points in
420320f4b53cSBarry Smith                 the mesh `dmOut` (leaves in the star forest), i.e. where `dmOut` is more refined than `dmIn`
420420f4b53cSBarry Smith . sfCoarsen   - A star forest indicating points in the mesh `dmOut` (roots in the star forest) that are parents to points in
420520f4b53cSBarry Smith                 the mesh `dmIn` (leaves in the star forest), i.e. where `dmOut` is more coarsened than `dmIn`
420620f4b53cSBarry Smith . cidsRefine  - The childIds of the points in `dmOut`.  These childIds relate back to the reference tree: childid[j] = k implies
420720f4b53cSBarry Smith                 that mesh point j of `dmOut` was refined from a point in `dmIn` just as the mesh point k in the reference
420820f4b53cSBarry Smith                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in `dmOut` is exactly
420920f4b53cSBarry Smith                 equivalent to its root in `dmIn`, so no interpolation is necessary.  childid[j] = -2 indicates that this
421020f4b53cSBarry Smith                 point j in `dmOut` is not a leaf of `sfRefine`.
421120f4b53cSBarry Smith . cidsCoarsen - The childIds of the points in `dmIn`.  These childIds relate back to the reference tree: childid[j] = k implies
421220f4b53cSBarry Smith                 that mesh point j of dmIn coarsens to a point in `dmOut` just as the mesh point k in the reference
421320f4b53cSBarry Smith                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in `dmOut` is not a leaf in `sfCoarsen`.
421420f4b53cSBarry Smith . useBCs      - `PETSC_TRUE` indicates that boundary values should be inserted into `vecIn` before transfer.
4215ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4216ff1f73f7SToby Isaac 
42172fe279fdSBarry Smith   Output Parameter:
42188966356dSPierre Jolivet . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transferred
421920f4b53cSBarry Smith                 projection of `vecIn` from `dmIn` to `dmOut`.  Note that any field discretized with a `PetscFV` finite volume
4220ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4221ff1f73f7SToby Isaac                 coarse points to fine points.
4222ff1f73f7SToby Isaac 
4223ff1f73f7SToby Isaac   Level: developer
4224ff1f73f7SToby Isaac 
4225a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `Vec`, `PetscFV`, `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4226ff1f73f7SToby Isaac @*/
4227d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
4228d71ae5a4SJacob Faibussowitsch {
422938fc2455SToby Isaac   PetscFunctionBegin;
42309566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
4231ff1f73f7SToby Isaac   if (sfRefine) {
4232fbfa57b9SToby Isaac     Vec vecInLocal;
42330eb7e1eaSToby Isaac     DM  dmGrad   = NULL;
42340eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4235fbfa57b9SToby Isaac 
42369566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
42379566063dSJacob Faibussowitsch     PetscCall(VecSet(vecInLocal, 0.0));
42380eb7e1eaSToby Isaac     {
42390eb7e1eaSToby Isaac       PetscInt numFields, i;
42400eb7e1eaSToby Isaac 
42419566063dSJacob Faibussowitsch       PetscCall(DMGetNumFields(dmIn, &numFields));
42420eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
42430eb7e1eaSToby Isaac         PetscObject  obj;
42440eb7e1eaSToby Isaac         PetscClassId classid;
42450eb7e1eaSToby Isaac 
42469566063dSJacob Faibussowitsch         PetscCall(DMGetField(dmIn, i, NULL, &obj));
42479566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &classid));
42480eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
42499566063dSJacob Faibussowitsch           PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
42500eb7e1eaSToby Isaac           break;
42510eb7e1eaSToby Isaac         }
42520eb7e1eaSToby Isaac       }
42530eb7e1eaSToby Isaac     }
42541baa6e33SBarry Smith     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
42559566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42569566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42570eb7e1eaSToby Isaac     if (dmGrad) {
42589566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad, &grad));
42599566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
42600eb7e1eaSToby Isaac     }
42619566063dSJacob Faibussowitsch     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
42629566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
426348a46eb9SPierre Jolivet     if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
4264ebf164c7SToby Isaac   }
42651baa6e33SBarry Smith   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
42669566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(vecOut));
42679566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(vecOut));
42683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
426938fc2455SToby Isaac }
4270