xref: /petsc/src/dm/impls/plex/plextree.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2af0996ceSBarry Smith #include <petsc/private/isimpl.h>
3af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
4d6a7ad0dSToby Isaac #include <petscsf.h>
50c37af3bSToby Isaac #include <petscds.h>
6d6a7ad0dSToby Isaac 
70e3d61c9SBarry Smith /* hierarchy routines */
8d6a7ad0dSToby Isaac 
9d6a7ad0dSToby Isaac /*@
10d6a7ad0dSToby Isaac   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
11d6a7ad0dSToby Isaac 
12d6a7ad0dSToby Isaac   Not collective
13d6a7ad0dSToby Isaac 
14d6a7ad0dSToby Isaac   Input Parameters:
15d6a7ad0dSToby Isaac + dm - The DMPlex object
16d6a7ad0dSToby Isaac - ref - The reference tree DMPlex object
17d6a7ad0dSToby Isaac 
180b7167a0SToby Isaac   Level: intermediate
19d6a7ad0dSToby Isaac 
20db781477SPatrick Sanan .seealso: `DMPlexGetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
21d6a7ad0dSToby Isaac @*/
22*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
23*d71ae5a4SJacob 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;
32d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
33d6a7ad0dSToby Isaac }
34d6a7ad0dSToby Isaac 
35d6a7ad0dSToby Isaac /*@
36d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
37d6a7ad0dSToby Isaac 
38d6a7ad0dSToby Isaac   Not collective
39d6a7ad0dSToby Isaac 
40d6a7ad0dSToby Isaac   Input Parameters:
41d6a7ad0dSToby Isaac . dm - The DMPlex object
42d6a7ad0dSToby Isaac 
437a7aea1fSJed Brown   Output Parameters:
44d6a7ad0dSToby Isaac . ref - The reference tree DMPlex object
45d6a7ad0dSToby Isaac 
460b7167a0SToby Isaac   Level: intermediate
47d6a7ad0dSToby Isaac 
48db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
49d6a7ad0dSToby Isaac @*/
50*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
51*d71ae5a4SJacob 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;
58d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
59d6a7ad0dSToby Isaac }
60d6a7ad0dSToby Isaac 
61*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
62*d71ae5a4SJacob 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;
69dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
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");
128dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
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);
171dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
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:
178dcbd3bf7SToby Isaac + 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:
186dcbd3bf7SToby Isaac + childOrientB - if not NULL, set to the new oreintation for describing the child
187ff1f73f7SToby Isaac - childB - if not NULL, the new childID for describing the child
188dcbd3bf7SToby Isaac 
189dcbd3bf7SToby Isaac   Level: developer
190dcbd3bf7SToby Isaac 
191db781477SPatrick Sanan .seealso: `DMPlexGetReferenceTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetTree()`
192dcbd3bf7SToby Isaac @*/
193*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
194*d71ae5a4SJacob 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));
201dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
202dcbd3bf7SToby Isaac }
203dcbd3bf7SToby Isaac 
204776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM, PetscSection, PetscInt *, PetscInt *, PetscBool, PetscBool);
205f9f063d4SToby Isaac 
206*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
207*d71ae5a4SJacob Faibussowitsch {
208f2c1aa1dSLisandro Dalcin   PetscFunctionBegin;
2099566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_TRUE, PETSC_FALSE));
210f2c1aa1dSLisandro Dalcin   PetscFunctionReturn(0);
211f2c1aa1dSLisandro Dalcin }
212f2c1aa1dSLisandro Dalcin 
213*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
214*d71ae5a4SJacob 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));
4160e2cc29aSToby Isaac   PetscFunctionReturn(0);
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 
4290e2cc29aSToby Isaac   Output Parameters:
4300e2cc29aSToby Isaac . ref     - the reference tree DMPlex object
4310e2cc29aSToby Isaac 
4320e2cc29aSToby Isaac   Level: intermediate
4330e2cc29aSToby Isaac 
434db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`
4350e2cc29aSToby Isaac @*/
436*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
437*d71ae5a4SJacob 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));
463da43764aSToby Isaac   PetscFunctionReturn(0);
464da43764aSToby Isaac }
465da43764aSToby Isaac 
466*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
467*d71ae5a4SJacob 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;
478878b19aaSToby Isaac   if (!pSec) PetscFunctionReturn(0);
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));
517878b19aaSToby Isaac   PetscFunctionReturn(0);
518878b19aaSToby Isaac }
519878b19aaSToby Isaac 
520*d71ae5a4SJacob Faibussowitsch static PetscErrorCode AnchorsFlatten(PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
521*d71ae5a4SJacob 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   }
6476dd5a8c8SToby Isaac   PetscFunctionReturn(0);
6486dd5a8c8SToby Isaac }
6496dd5a8c8SToby Isaac 
650*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
651*d71ae5a4SJacob 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));
75266af876cSToby Isaac   PetscFunctionReturn(0);
75366af876cSToby Isaac }
75466af876cSToby Isaac 
755*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTrueSupportSize(DM dm, PetscInt p, PetscInt *dof, PetscInt *numTrueSupp)
756*d71ae5a4SJacob 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];
7796461c1adSToby Isaac   PetscFunctionReturn(0);
7806461c1adSToby Isaac }
7816461c1adSToby Isaac 
782*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
783*d71ae5a4SJacob 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 
888776742edSToby Isaac   PetscFunctionReturn(0);
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 
894*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
895*d71ae5a4SJacob 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));
972f9f063d4SToby Isaac   PetscFunctionReturn(0);
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
9770b7167a0SToby Isaac   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
9780b7167a0SToby Isaac   tree root.
9790b7167a0SToby Isaac 
9800b7167a0SToby Isaac   Collective on dm
9810b7167a0SToby Isaac 
9820b7167a0SToby Isaac   Input Parameters:
9830b7167a0SToby Isaac + 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 
992db781477SPatrick Sanan .seealso: `DMPlexGetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
9930b7167a0SToby Isaac @*/
994*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
995*d71ae5a4SJacob Faibussowitsch {
9960b7167a0SToby Isaac   PetscFunctionBegin;
9979566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_FALSE, PETSC_TRUE));
9980b7167a0SToby Isaac   PetscFunctionReturn(0);
9990b7167a0SToby Isaac }
10000b7167a0SToby Isaac 
1001b2f41788SToby Isaac /*@
1002b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1003b2f41788SToby Isaac   Collective on dm
1004b2f41788SToby Isaac 
1005f899ff85SJose E. Roman   Input Parameter:
1006b2f41788SToby Isaac . 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 
1019db781477SPatrick Sanan .seealso: `DMPlexSetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
1020b2f41788SToby Isaac @*/
1021*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1022*d71ae5a4SJacob 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;
1032b2f41788SToby Isaac   PetscFunctionReturn(0);
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:
1039d961a43aSToby Isaac + dm - the DMPlex object
1040d961a43aSToby Isaac - point - the query point
1041d961a43aSToby Isaac 
1042d961a43aSToby Isaac   Output Parameters:
1043d961a43aSToby Isaac + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1044d961a43aSToby Isaac - 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 
1049db781477SPatrick Sanan .seealso: `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeChildren()`
1050d961a43aSToby Isaac @*/
1051*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1052*d71ae5a4SJacob 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];
1069d961a43aSToby Isaac       PetscFunctionReturn(0);
1070d961a43aSToby Isaac     }
1071d961a43aSToby Isaac   }
1072ad540459SPierre Jolivet   if (parent) *parent = point;
1073ad540459SPierre Jolivet   if (childID) *childID = 0;
1074d961a43aSToby Isaac   PetscFunctionReturn(0);
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:
1081d961a43aSToby Isaac + dm - the DMPlex object
1082d961a43aSToby Isaac - point - the query point
1083d961a43aSToby Isaac 
1084d961a43aSToby Isaac   Output Parameters:
1085d961a43aSToby Isaac + numChildren - if not NULL, set to the number of children
1086d961a43aSToby Isaac - 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 
1090d961a43aSToby Isaac   Fortran Notes:
1091d961a43aSToby Isaac   Since it returns an array, this routine is only available in Fortran 90, and you must
1092d961a43aSToby Isaac   include petsc.h90 in your code.
1093d961a43aSToby Isaac 
1094db781477SPatrick Sanan .seealso: `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeParent()`
1095d961a43aSToby Isaac @*/
1096*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1097*d71ae5a4SJacob Faibussowitsch {
1098d961a43aSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
1099d961a43aSToby Isaac   PetscSection childSec;
1100d961a43aSToby Isaac   PetscInt     dof = 0;
1101d961a43aSToby Isaac 
1102d961a43aSToby Isaac   PetscFunctionBegin;
1103d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1104d961a43aSToby Isaac   childSec = mesh->childSection;
110548a46eb9SPierre Jolivet   if (childSec && point >= childSec->pStart && point < childSec->pEnd) PetscCall(PetscSectionGetDof(childSec, point, &dof));
1106d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1107d961a43aSToby Isaac   if (children) {
1108d961a43aSToby Isaac     if (dof) {
1109d961a43aSToby Isaac       PetscInt off;
1110d961a43aSToby Isaac 
11119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec, point, &off));
1112d961a43aSToby Isaac       *children = &mesh->children[off];
11139371c9d4SSatish Balay     } else {
1114d961a43aSToby Isaac       *children = NULL;
1115d961a43aSToby Isaac     }
1116d961a43aSToby Isaac   }
1117d961a43aSToby Isaac   PetscFunctionReturn(0);
1118d961a43aSToby Isaac }
11190c37af3bSToby Isaac 
1120*d71ae5a4SJacob 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)
1121*d71ae5a4SJacob Faibussowitsch {
112252a3aeb4SToby Isaac   PetscInt f, b, p, c, offset, qPoints;
1123b3a4bf2aSToby Isaac 
1124b3a4bf2aSToby Isaac   PetscFunctionBegin;
11259566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(space, nPoints, points, work, NULL, NULL));
112652a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
112752a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
112852a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1129b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1130b3a4bf2aSToby Isaac 
113152a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
1132ad540459SPierre Jolivet         for (c = 0; c < nComps; c++) val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
113352a3aeb4SToby Isaac       }
11349566063dSJacob Faibussowitsch       PetscCall(MatSetValue(basisAtPoints, b, f, val, INSERT_VALUES));
1135b3a4bf2aSToby Isaac     }
1136b3a4bf2aSToby Isaac     offset += qPoints;
1137b3a4bf2aSToby Isaac   }
11389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(basisAtPoints, MAT_FINAL_ASSEMBLY));
11399566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(basisAtPoints, MAT_FINAL_ASSEMBLY));
1140b3a4bf2aSToby Isaac   PetscFunctionReturn(0);
1141b3a4bf2aSToby Isaac }
1142b3a4bf2aSToby Isaac 
1143*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
1144*d71ae5a4SJacob Faibussowitsch {
11450c37af3bSToby Isaac   PetscDS         ds;
11460c37af3bSToby Isaac   PetscInt        spdim;
11470c37af3bSToby Isaac   PetscInt        numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
11480c37af3bSToby Isaac   const PetscInt *anchors;
1149f7c74593SToby Isaac   PetscSection    aSec;
11500c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
11510c37af3bSToby Isaac   IS              aIS;
11520c37af3bSToby Isaac 
11530c37af3bSToby Isaac   PetscFunctionBegin;
11549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
11559566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
11569566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
11579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
11589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
11599566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
11609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &conStart, &conEnd));
11619566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &spdim));
11629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(spdim, &v0, spdim, &v0parent, spdim, &vtmp, spdim * spdim, &J, spdim * spdim, &Jparent, spdim * spdim, &invJparent));
11630c37af3bSToby Isaac 
11640c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
11650dd1b1feSToby Isaac     PetscObject          disc;
11660dd1b1feSToby Isaac     PetscClassId         id;
1167b3a4bf2aSToby Isaac     PetscSpace           bspace;
1168b3a4bf2aSToby Isaac     PetscDualSpace       dspace;
11699c3cf19fSMatthew G. Knepley     PetscInt             i, j, k, nPoints, Nc, offset;
117052a3aeb4SToby Isaac     PetscInt             fSize, maxDof;
1171b3a4bf2aSToby Isaac     PetscReal           *weights, *pointsRef, *pointsReal, *work;
11721683a169SBarry Smith     PetscScalar         *scwork;
11731683a169SBarry Smith     const PetscScalar   *X;
11742c44ad04SToby Isaac     PetscInt            *sizes, *workIndRow, *workIndCol;
11750c37af3bSToby Isaac     Mat                  Amat, Bmat, Xmat;
11762c44ad04SToby Isaac     const PetscInt      *numDof = NULL;
1177085f0adfSToby Isaac     const PetscInt    ***perms  = NULL;
1178085f0adfSToby Isaac     const PetscScalar ***flips  = NULL;
11790c37af3bSToby Isaac 
11809566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(ds, f, &disc));
11819566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(disc, &id));
11820dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1183b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE)disc;
1184b3a4bf2aSToby Isaac 
11859566063dSJacob Faibussowitsch       PetscCall(PetscFEGetBasisSpace(fe, &bspace));
11869566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(fe, &dspace));
11879566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
11889566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
11899371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
1190b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV)disc;
1191b3a4bf2aSToby Isaac 
11929566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
11939566063dSJacob Faibussowitsch       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)fv), &bspace));
11949566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetType(bspace, PETSCSPACEPOLYNOMIAL));
11959566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetDegree(bspace, 0, PETSC_DETERMINE));
11969566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumComponents(bspace, Nc));
11979566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumVariables(bspace, spdim));
11989566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(bspace));
11999566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &dspace));
12009566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
12019371c9d4SSatish Balay     } else SETERRQ(PetscObjectComm(disc), PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
12029566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetNumDof(dspace, &numDof));
1203ad540459SPierre Jolivet     for (i = 0, maxDof = 0; i <= spdim; i++) maxDof = PetscMax(maxDof, numDof[i]);
12049566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSymmetries(dspace, &perms, &flips));
12050dd1b1feSToby Isaac 
12069566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &Amat));
12079566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Amat, fSize, fSize, fSize, fSize));
12089566063dSJacob Faibussowitsch     PetscCall(MatSetType(Amat, MATSEQDENSE));
12099566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Amat));
12109566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Bmat));
12119566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Xmat));
12120c37af3bSToby Isaac     nPoints = 0;
12130c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
121452a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
12150c37af3bSToby Isaac       PetscQuadrature quad;
12160c37af3bSToby Isaac 
12179566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
12189566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, &thisNc, &qPoints, NULL, NULL));
121963a3b9bcSJacob Faibussowitsch       PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
12200c37af3bSToby Isaac       nPoints += qPoints;
12210c37af3bSToby Isaac     }
12229566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(fSize, &sizes, nPoints * Nc, &weights, spdim * nPoints, &pointsRef, spdim * nPoints, &pointsReal, nPoints * fSize * Nc, &work, maxDof, &workIndRow, maxDof, &workIndCol));
12239566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof * maxDof, &scwork));
12240c37af3bSToby Isaac     offset = 0;
12250c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12260c37af3bSToby Isaac       PetscInt         qPoints;
12270c37af3bSToby Isaac       const PetscReal *p, *w;
12280c37af3bSToby Isaac       PetscQuadrature  quad;
12290c37af3bSToby Isaac 
12309566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
12319566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &qPoints, &p, &w));
12329566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(weights + Nc * offset, w, Nc * qPoints));
12339566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pointsRef + spdim * offset, p, spdim * qPoints));
1234b3a4bf2aSToby Isaac       sizes[i] = qPoints;
12350c37af3bSToby Isaac       offset += qPoints;
12360c37af3bSToby Isaac     }
12379566063dSJacob Faibussowitsch     PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsRef, weights, work, Amat));
12389566063dSJacob Faibussowitsch     PetscCall(MatLUFactor(Amat, NULL, NULL, NULL));
12390c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
12400c37af3bSToby Isaac       PetscInt  parent;
12410c37af3bSToby Isaac       PetscInt  closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
12420c37af3bSToby Isaac       PetscInt *childOffsets, *parentOffsets;
12430c37af3bSToby Isaac 
12449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, c, &parent, NULL));
12450c37af3bSToby Isaac       if (parent == c) continue;
12469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12470c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12480c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12490c37af3bSToby Isaac         PetscInt conDof;
12500c37af3bSToby Isaac 
12510c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1252085f0adfSToby Isaac         if (numFields) {
12539566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
12549371c9d4SSatish Balay         } else {
12559566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
12560c37af3bSToby Isaac         }
12570c37af3bSToby Isaac         if (conDof) break;
12580c37af3bSToby Isaac       }
12590c37af3bSToby Isaac       if (i == closureSize) {
12609566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12610c37af3bSToby Isaac         continue;
12620c37af3bSToby Isaac       }
12630c37af3bSToby Isaac 
12649566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ));
12659566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent));
12660c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1267c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
1268c330f8ffSToby Isaac 
1269c330f8ffSToby Isaac         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i * spdim], vtmp);
1270c330f8ffSToby Isaac         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i * spdim]);
12710c37af3bSToby Isaac       }
12729566063dSJacob Faibussowitsch       PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsReal, weights, work, Bmat));
12739566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(Amat, Bmat, Xmat));
12749566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Xmat, &X));
12759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
12769566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(closureSize + 1, &childOffsets, closureSizeP + 1, &parentOffsets));
12770c37af3bSToby Isaac       childOffsets[0] = 0;
12780c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12790c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12800c37af3bSToby Isaac         PetscInt dof;
12810c37af3bSToby Isaac 
1282085f0adfSToby Isaac         if (numFields) {
12839566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12849371c9d4SSatish Balay         } else {
12859566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12860c37af3bSToby Isaac         }
128752a3aeb4SToby Isaac         childOffsets[i + 1] = childOffsets[i] + dof;
12880c37af3bSToby Isaac       }
12890c37af3bSToby Isaac       parentOffsets[0] = 0;
12900c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
12910c37af3bSToby Isaac         PetscInt p = closureP[2 * i];
12920c37af3bSToby Isaac         PetscInt dof;
12930c37af3bSToby Isaac 
1294085f0adfSToby Isaac         if (numFields) {
12959566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12969371c9d4SSatish Balay         } else {
12979566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12980c37af3bSToby Isaac         }
129952a3aeb4SToby Isaac         parentOffsets[i + 1] = parentOffsets[i] + dof;
13000c37af3bSToby Isaac       }
13010c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13022c44ad04SToby Isaac         PetscInt           conDof, conOff, aDof, aOff, nWork;
13030c37af3bSToby Isaac         PetscInt           p = closure[2 * i];
13040c37af3bSToby Isaac         PetscInt           o = closure[2 * i + 1];
1305085f0adfSToby Isaac         const PetscInt    *perm;
1306085f0adfSToby Isaac         const PetscScalar *flip;
13070c37af3bSToby Isaac 
13080c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1309085f0adfSToby Isaac         if (numFields) {
13109566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
13119566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &conOff));
13129371c9d4SSatish Balay         } else {
13139566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
13149566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(cSec, p, &conOff));
13150c37af3bSToby Isaac         }
13160c37af3bSToby Isaac         if (!conDof) continue;
1317085f0adfSToby Isaac         perm = (perms && perms[i]) ? perms[i][o] : NULL;
1318085f0adfSToby Isaac         flip = (flips && flips[i]) ? flips[i][o] : NULL;
13199566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
13209566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
13212c44ad04SToby Isaac         nWork = childOffsets[i + 1] - childOffsets[i];
13220c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
13230c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
13240c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
13250c37af3bSToby Isaac 
1326085f0adfSToby Isaac           if (numFields) {
13279566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aSecDof));
13289566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aSecOff));
13299371c9d4SSatish Balay           } else {
13309566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, a, &aSecDof));
13319566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, a, &aSecOff));
13320c37af3bSToby Isaac           }
13330c37af3bSToby Isaac           if (!aSecDof) continue;
13340c37af3bSToby Isaac 
13350c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
13360c37af3bSToby Isaac             PetscInt q  = closureP[2 * j];
13370c37af3bSToby Isaac             PetscInt oq = closureP[2 * j + 1];
13382c44ad04SToby Isaac 
13392c44ad04SToby Isaac             if (q == a) {
134052a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1341085f0adfSToby Isaac               const PetscInt    *permP;
1342085f0adfSToby Isaac               const PetscScalar *flipP;
1343085f0adfSToby Isaac 
1344085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1345085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
13462c44ad04SToby Isaac               nWorkP = parentOffsets[j + 1] - parentOffsets[j];
13472c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
13481683a169SBarry Smith                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
13492c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
13502c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
1351ad540459SPierre Jolivet                 for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
13522c44ad04SToby Isaac               }
1353ad540459SPierre Jolivet               for (r = 0; r < nWork; r++) workIndRow[perm ? perm[r] : r] = conOff + r;
1354ad540459SPierre Jolivet               for (s = 0; s < nWorkP; s++) workIndCol[permP ? permP[s] : s] = aSecOff + s;
13552c44ad04SToby Isaac               if (flip) {
13562c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1357ad540459SPierre Jolivet                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flip[r];
13582c44ad04SToby Isaac                 }
13592c44ad04SToby Isaac               }
13602c44ad04SToby Isaac               if (flipP) {
13612c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1362ad540459SPierre Jolivet                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flipP[s];
13632c44ad04SToby Isaac                 }
13642c44ad04SToby Isaac               }
13659566063dSJacob Faibussowitsch               PetscCall(MatSetValues(cMat, nWork, workIndRow, nWorkP, workIndCol, scwork, INSERT_VALUES));
13662c44ad04SToby Isaac               break;
13670c37af3bSToby Isaac             }
13680c37af3bSToby Isaac           }
13690c37af3bSToby Isaac         }
13700c37af3bSToby Isaac       }
13719566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Xmat, &X));
13729566063dSJacob Faibussowitsch       PetscCall(PetscFree2(childOffsets, parentOffsets));
13739566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
13749566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
13750c37af3bSToby Isaac     }
13769566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Amat));
13779566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Bmat));
13789566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Xmat));
13799566063dSJacob Faibussowitsch     PetscCall(PetscFree(scwork));
13809566063dSJacob Faibussowitsch     PetscCall(PetscFree7(sizes, weights, pointsRef, pointsReal, work, workIndRow, workIndCol));
138148a46eb9SPierre Jolivet     if (id == PETSCFV_CLASSID) PetscCall(PetscSpaceDestroy(&bspace));
13820c37af3bSToby Isaac   }
13839566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
13849566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
13859566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJparent));
13869566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
13870c37af3bSToby Isaac 
13880c37af3bSToby Isaac   PetscFunctionReturn(0);
13890c37af3bSToby Isaac }
139095a0b26dSToby Isaac 
1391*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1392*d71ae5a4SJacob Faibussowitsch {
1393f7c74593SToby Isaac   Mat                 refCmat;
139421968bf8SToby Isaac   PetscDS             ds;
1395085f0adfSToby Isaac   PetscInt            numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
139621968bf8SToby Isaac   PetscScalar      ***refPointFieldMats;
139721968bf8SToby Isaac   PetscSection        refConSec, refAnSec, refSection;
139821968bf8SToby Isaac   IS                  refAnIS;
139921968bf8SToby Isaac   const PetscInt     *refAnchors;
1400085f0adfSToby Isaac   const PetscInt    **perms;
1401085f0adfSToby Isaac   const PetscScalar **flips;
140295a0b26dSToby Isaac 
140395a0b26dSToby Isaac   PetscFunctionBegin;
14049566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
14059566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1406085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
14079566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
14089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
14099566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(refAnIS, &refAnchors));
14109566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
14119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
14129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
14139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldN));
14149566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
14159566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
14169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
14179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxAnDof, &cols));
141895a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
141995a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
142095a0b26dSToby Isaac 
14219566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
14229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
142395a0b26dSToby Isaac     if (!pDof || parent == p) continue;
142495a0b26dSToby Isaac 
14259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxFields, &refPointFieldMats[p - pRefStart]));
14269566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(maxFields, &refPointFieldN[p - pRefStart]));
14279566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
1428085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1429085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
143095a0b26dSToby Isaac 
1431085f0adfSToby Isaac       if (f < numFields) {
14329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
14339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
14349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1435085f0adfSToby Isaac       } else {
14369566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
14379566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
14389566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetPointSyms(refSection, closureSize, closure, &perms, &flips));
143995a0b26dSToby Isaac       }
144095a0b26dSToby Isaac 
1441ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
144295a0b26dSToby Isaac       numCols = 0;
144395a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
144495a0b26dSToby Isaac         PetscInt        q = closure[2 * i];
144595a0b26dSToby Isaac         PetscInt        aDof, aOff, j;
1446085f0adfSToby Isaac         const PetscInt *perm = perms ? perms[i] : NULL;
144795a0b26dSToby Isaac 
1448085f0adfSToby Isaac         if (numFields) {
14499566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14509566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14519371c9d4SSatish Balay         } else {
14529566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14539566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
145495a0b26dSToby Isaac         }
145595a0b26dSToby Isaac 
1456ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + (perm ? perm[j] : j);
145795a0b26dSToby Isaac       }
145895a0b26dSToby Isaac       refPointFieldN[p - pRefStart][f] = numCols;
14599566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
14609566063dSJacob Faibussowitsch       PetscCall(MatGetValues(refCmat, cDof, rows, numCols, cols, refPointFieldMats[p - pRefStart][f]));
1461085f0adfSToby Isaac       if (flips) {
1462085f0adfSToby Isaac         PetscInt colOff = 0;
1463085f0adfSToby Isaac 
1464085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1465085f0adfSToby Isaac           PetscInt           q = closure[2 * i];
1466085f0adfSToby Isaac           PetscInt           aDof, aOff, j;
1467085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1468085f0adfSToby Isaac 
1469085f0adfSToby Isaac           if (numFields) {
14709566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14719566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14729371c9d4SSatish Balay           } else {
14739566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14749566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
1475085f0adfSToby Isaac           }
1476085f0adfSToby Isaac           if (flip) {
1477085f0adfSToby Isaac             PetscInt k;
1478085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1479ad540459SPierre Jolivet               for (j = 0; j < aDof; j++) refPointFieldMats[p - pRefStart][f][k * numCols + colOff + j] *= flip[j];
1480085f0adfSToby Isaac             }
1481085f0adfSToby Isaac           }
1482085f0adfSToby Isaac           colOff += aDof;
1483085f0adfSToby Isaac         }
1484085f0adfSToby Isaac       }
1485085f0adfSToby Isaac       if (numFields) {
14869566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestoreFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1487085f0adfSToby Isaac       } else {
14889566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestorePointSyms(refSection, closureSize, closure, &perms, &flips));
1489085f0adfSToby Isaac       }
149095a0b26dSToby Isaac     }
14919566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
149295a0b26dSToby Isaac   }
149321968bf8SToby Isaac   *childrenMats = refPointFieldMats;
149421968bf8SToby Isaac   *childrenN    = refPointFieldN;
14959566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(refAnIS, &refAnchors));
14969566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
14979566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
149821968bf8SToby Isaac   PetscFunctionReturn(0);
149921968bf8SToby Isaac }
150021968bf8SToby Isaac 
1501*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1502*d71ae5a4SJacob Faibussowitsch {
150321968bf8SToby Isaac   PetscDS        ds;
150421968bf8SToby Isaac   PetscInt     **refPointFieldN;
150521968bf8SToby Isaac   PetscScalar ***refPointFieldMats;
1506085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
150721968bf8SToby Isaac   PetscSection   refConSec;
150821968bf8SToby Isaac 
150921968bf8SToby Isaac   PetscFunctionBegin;
151021968bf8SToby Isaac   refPointFieldN    = *childrenN;
151121968bf8SToby Isaac   *childrenN        = NULL;
151221968bf8SToby Isaac   refPointFieldMats = *childrenMats;
151321968bf8SToby Isaac   *childrenMats     = NULL;
15149566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
15159566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1516367003a6SStefano Zampini   maxFields = PetscMax(1, numFields);
15179566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
15189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
151921968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
152021968bf8SToby Isaac     PetscInt parent, pDof;
152121968bf8SToby Isaac 
15229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
15239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
152421968bf8SToby Isaac     if (!pDof || parent == p) continue;
152521968bf8SToby Isaac 
1526085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
152721968bf8SToby Isaac       PetscInt cDof;
152821968bf8SToby Isaac 
1529085f0adfSToby Isaac       if (numFields) {
15309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
15319371c9d4SSatish Balay       } else {
15329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
153321968bf8SToby Isaac       }
153421968bf8SToby Isaac 
15359566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
153621968bf8SToby Isaac     }
15379566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
15389566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldN[p - pRefStart]));
153921968bf8SToby Isaac   }
15409566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
15419566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldN));
154221968bf8SToby Isaac   PetscFunctionReturn(0);
154321968bf8SToby Isaac }
154421968bf8SToby Isaac 
1545*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
1546*d71ae5a4SJacob Faibussowitsch {
154721968bf8SToby Isaac   DM              refTree;
154821968bf8SToby Isaac   PetscDS         ds;
154921968bf8SToby Isaac   Mat             refCmat;
1550085f0adfSToby Isaac   PetscInt        numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
155121968bf8SToby Isaac   PetscScalar  ***refPointFieldMats, *pointWork;
155221968bf8SToby Isaac   PetscSection    refConSec, refAnSec, anSec;
155321968bf8SToby Isaac   IS              refAnIS, anIS;
155421968bf8SToby Isaac   const PetscInt *anchors;
155521968bf8SToby Isaac 
155621968bf8SToby Isaac   PetscFunctionBegin;
155721968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
15589566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
15599566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1560085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
15619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
15629566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, refTree));
15639566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
15649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
15659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anSec, &anIS));
15669566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(anIS, &anchors));
15679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
15689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(conSec, &conStart, &conEnd));
15699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
15709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
15719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof * maxAnDof, &pointWork));
157221968bf8SToby Isaac 
157321968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
15749566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
157595a0b26dSToby Isaac 
157695a0b26dSToby Isaac   /* step 2: compute the preorder */
15779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
15789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(pEnd - pStart, &perm, pEnd - pStart, &iperm));
157995a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
158095a0b26dSToby Isaac     perm[p - pStart]  = p;
158195a0b26dSToby Isaac     iperm[p - pStart] = p - pStart;
158295a0b26dSToby Isaac   }
158395a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
158495a0b26dSToby Isaac     PetscInt point = perm[p];
158595a0b26dSToby Isaac     PetscInt parent;
158695a0b26dSToby Isaac 
15879566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
158895a0b26dSToby Isaac     if (parent == point) {
158995a0b26dSToby Isaac       p++;
15909371c9d4SSatish Balay     } else {
159195a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
159295a0b26dSToby Isaac 
15939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
159495a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
159595a0b26dSToby Isaac         PetscInt q = closure[2 * i];
159695a0b26dSToby Isaac         if (iperm[q - pStart] > iperm[point - pStart]) {
159795a0b26dSToby Isaac           /* swap */
159895a0b26dSToby Isaac           perm[p]                 = q;
159995a0b26dSToby Isaac           perm[iperm[q - pStart]] = point;
160095a0b26dSToby Isaac           iperm[point - pStart]   = iperm[q - pStart];
160195a0b26dSToby Isaac           iperm[q - pStart]       = p;
160295a0b26dSToby Isaac           break;
160395a0b26dSToby Isaac         }
160495a0b26dSToby Isaac       }
160595a0b26dSToby Isaac       size = closureSize;
16069566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1607ad540459SPierre Jolivet       if (i == size) p++;
160895a0b26dSToby Isaac     }
160995a0b26dSToby Isaac   }
161095a0b26dSToby Isaac 
161195a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
161295a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
161395a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
161495a0b26dSToby Isaac    * values outside of the Mat first.
161595a0b26dSToby Isaac    */
161695a0b26dSToby Isaac   {
161795a0b26dSToby Isaac     PetscInt        nRows, row, nnz;
161895a0b26dSToby Isaac     PetscBool       done;
1619cd6fc93eSToby Isaac     PetscInt        secStart, secEnd;
162095a0b26dSToby Isaac     const PetscInt *ia, *ja;
162195a0b26dSToby Isaac     PetscScalar    *vals;
162295a0b26dSToby Isaac 
1623cd6fc93eSToby Isaac     PetscCall(PetscSectionGetChart(section, &secStart, &secEnd));
16249566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
162528b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not get RowIJ of constraint matrix");
162695a0b26dSToby Isaac     nnz = ia[nRows];
162795a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
162895a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
16299566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vals));
163095a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
163195a0b26dSToby Isaac       PetscInt parent, childid, closureSize, *closure = NULL;
163295a0b26dSToby Isaac       PetscInt point = perm[p], pointDof;
163395a0b26dSToby Isaac 
16349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, point, &parent, &childid));
163595a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
16369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(conSec, point, &pointDof));
163795a0b26dSToby Isaac       if (!pointDof) continue;
16389566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1639085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1640085f0adfSToby Isaac         PetscInt            cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
164195a0b26dSToby Isaac         PetscScalar        *pointMat;
1642085f0adfSToby Isaac         const PetscInt    **perms;
1643085f0adfSToby Isaac         const PetscScalar **flips;
164495a0b26dSToby Isaac 
1645085f0adfSToby Isaac         if (numFields) {
16469566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(conSec, point, f, &cDof));
16479566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(conSec, point, f, &cOff));
16489371c9d4SSatish Balay         } else {
16499566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(conSec, point, &cDof));
16509566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(conSec, point, &cOff));
165195a0b26dSToby Isaac         }
165295a0b26dSToby Isaac         if (!cDof) continue;
16539566063dSJacob Faibussowitsch         if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
16549566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetPointSyms(section, closureSize, closure, &perms, &flips));
165595a0b26dSToby Isaac 
165695a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
165776bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
165895a0b26dSToby Isaac           for (r = 0; r < cDof; r++) {
165995a0b26dSToby Isaac             if (cDof > 1 && r) {
166063a3b9bcSJacob 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]));
166195a0b26dSToby Isaac             }
166295a0b26dSToby Isaac           }
166376bd3646SJed Brown         }
166495a0b26dSToby Isaac         /* zero rows */
1665ad540459SPierre Jolivet         for (i = ia[cOff]; i < ia[cOff + cDof]; i++) vals[i] = 0.;
166695a0b26dSToby Isaac         matOffset   = ia[cOff];
166795a0b26dSToby Isaac         numFillCols = ia[cOff + 1] - matOffset;
166895a0b26dSToby Isaac         pointMat    = refPointFieldMats[childid - pRefStart][f];
166995a0b26dSToby Isaac         numCols     = refPointFieldN[childid - pRefStart][f];
167095a0b26dSToby Isaac         offset      = 0;
167195a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
167295a0b26dSToby Isaac           PetscInt           q = closure[2 * i];
167395a0b26dSToby Isaac           PetscInt           aDof, aOff, j, k, qConDof, qConOff;
1674085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1675085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
167695a0b26dSToby Isaac 
167795a0b26dSToby Isaac           qConDof = qConOff = 0;
1678cd6fc93eSToby Isaac           if (q < secStart || q >= secEnd) continue;
1679085f0adfSToby Isaac           if (numFields) {
16809566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, q, f, &aDof));
16819566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, q, f, &aOff));
168295a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16839566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(conSec, q, f, &qConDof));
16849566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldOffset(conSec, q, f, &qConOff));
168595a0b26dSToby Isaac             }
16869371c9d4SSatish Balay           } else {
16879566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, q, &aDof));
16889566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, q, &aOff));
168995a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16909566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(conSec, q, &qConDof));
16919566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(conSec, q, &qConOff));
169295a0b26dSToby Isaac             }
169395a0b26dSToby Isaac           }
169495a0b26dSToby Isaac           if (!aDof) continue;
169595a0b26dSToby Isaac           if (qConDof) {
169695a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
169795a0b26dSToby Isaac              * be filled, thanks to preordering */
169895a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
169995a0b26dSToby Isaac             PetscInt aMatOffset   = ia[qConOff];
170095a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
170195a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
170295a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
170395a0b26dSToby Isaac                 PetscScalar inVal = 0;
170495a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1705085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
170695a0b26dSToby Isaac 
1707085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
170895a0b26dSToby Isaac                 }
170995a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
171095a0b26dSToby Isaac               }
171195a0b26dSToby Isaac             }
171295a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
171395a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
171495a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
171595a0b26dSToby Isaac               for (; k < numFillCols; k++) {
1716ad540459SPierre Jolivet                 if (ja[matOffset + k] == col) break;
171795a0b26dSToby Isaac               }
171863a3b9bcSJacob Faibussowitsch               PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, col);
1719ad540459SPierre Jolivet               for (r = 0; r < cDof; r++) vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
172095a0b26dSToby Isaac             }
17219371c9d4SSatish Balay           } else {
172295a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
172395a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
1724ad540459SPierre Jolivet               if (ja[matOffset + k] == aOff) break;
172595a0b26dSToby Isaac             }
172663a3b9bcSJacob Faibussowitsch             PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, aOff);
172795a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1728085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1729085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1730085f0adfSToby Isaac 
1731085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
173295a0b26dSToby Isaac               }
173395a0b26dSToby Isaac             }
173495a0b26dSToby Isaac           }
173595a0b26dSToby Isaac           offset += aDof;
173695a0b26dSToby Isaac         }
1737085f0adfSToby Isaac         if (numFields) {
17389566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestoreFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
1739085f0adfSToby Isaac         } else {
17409566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestorePointSyms(section, closureSize, closure, &perms, &flips));
1741085f0adfSToby Isaac         }
174295a0b26dSToby Isaac       }
17439566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
174495a0b26dSToby Isaac     }
174548a46eb9SPierre 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));
17469566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
174728b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not restore RowIJ of constraint matrix");
17489566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
17499566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
17509566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
175195a0b26dSToby Isaac   }
175295a0b26dSToby Isaac 
175395a0b26dSToby Isaac   /* clean up */
17549566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(anIS, &anchors));
17559566063dSJacob Faibussowitsch   PetscCall(PetscFree2(perm, iperm));
17569566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointWork));
17579566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
175895a0b26dSToby Isaac   PetscFunctionReturn(0);
175995a0b26dSToby Isaac }
176095a0b26dSToby Isaac 
17616f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
17626f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
1763*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTreeRefineCell(DM dm, PetscInt cell, DM *ncdm)
1764*d71ae5a4SJacob Faibussowitsch {
17656f5f1567SToby Isaac   DM           K;
1766420f55faSMatthew G. Knepley   PetscMPIInt  rank;
17676f5f1567SToby Isaac   PetscInt     dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
17686f5f1567SToby Isaac   PetscInt     numNewCones, *newConeSizes, *newCones, *newOrientations;
17696f5f1567SToby Isaac   PetscInt    *Kembedding;
17706f5f1567SToby Isaac   PetscInt    *cellClosure = NULL, nc;
17716f5f1567SToby Isaac   PetscScalar *newVertexCoords;
17726f5f1567SToby Isaac   PetscInt     numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
17736f5f1567SToby Isaac   PetscSection parentSection;
17746f5f1567SToby Isaac 
17756f5f1567SToby Isaac   PetscFunctionBegin;
17769566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
17779566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
17789566063dSJacob Faibussowitsch   PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
17799566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ncdm, dim));
17806f5f1567SToby Isaac 
17819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
17829566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &parentSection));
17839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &K));
17846858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
1785dd400576SPatrick Sanan   if (rank == 0) {
17866f5f1567SToby Isaac     /* compute the new charts */
17879566063dSJacob Faibussowitsch     PetscCall(PetscMalloc5(dim + 1, &pNewCount, dim + 1, &pNewStart, dim + 1, &pNewEnd, dim + 1, &pOldStart, dim + 1, &pOldEnd));
17886f5f1567SToby Isaac     offset = 0;
17896f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
17906f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
17916f5f1567SToby Isaac 
17926f5f1567SToby Isaac       pNewStart[d] = offset;
17939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, d, &pOldStart[d], &pOldEnd[d]));
17949566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
17956f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
17966f5f1567SToby Isaac       /* adding the new points */
17976f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
17986f5f1567SToby Isaac       if (!d) {
17996f5f1567SToby Isaac         /* removing the cell */
18006f5f1567SToby Isaac         pNewCount[d]--;
18016f5f1567SToby Isaac       }
18026f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18036f5f1567SToby Isaac         PetscInt parent;
18049566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &parent, NULL));
18056f5f1567SToby Isaac         if (parent == k) {
18066f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
18076f5f1567SToby Isaac           pNewCount[d]--;
18086f5f1567SToby Isaac         }
18096f5f1567SToby Isaac       }
18106f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
18116f5f1567SToby Isaac       offset     = pNewEnd[d];
18126f5f1567SToby Isaac     }
18131dca8a05SBarry 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]);
18146f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
18159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
18166f5f1567SToby Isaac 
18179566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pNewEnd[dim], &newConeSizes));
18186f5f1567SToby Isaac     {
1819b5a892a1SMatthew G. Knepley       DMPolytopeType pct, qct;
18206f5f1567SToby Isaac       PetscInt       kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
18216f5f1567SToby Isaac 
18229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetChart(K, &kStart, &kEnd));
18239566063dSJacob Faibussowitsch       PetscCall(PetscMalloc4(kEnd - kStart, &Kembedding, kEnd - kStart, &perm, kEnd - kStart, &iperm, kEnd - kStart, &preOrient));
18246f5f1567SToby Isaac 
18256f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18266f5f1567SToby Isaac         perm[k - kStart]      = k;
18276f5f1567SToby Isaac         iperm[k - kStart]     = k - kStart;
18286f5f1567SToby Isaac         preOrient[k - kStart] = 0;
18296f5f1567SToby Isaac       }
18306f5f1567SToby Isaac 
18319566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18326f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
18336f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2 * j + 1];
18346f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2 * j + 1];
18356f5f1567SToby Isaac         PetscInt p, q;
18366f5f1567SToby Isaac 
18376f5f1567SToby Isaac         p = closureK[2 * j];
18386f5f1567SToby Isaac         q = cellClosure[2 * j];
18399566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(K, p, &pct));
18409566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, q, &qct));
18416f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
1842ad540459SPierre Jolivet           if (q >= pOldStart[d] && q < pOldEnd[d]) Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
18436f5f1567SToby Isaac         }
1844b5a892a1SMatthew G. Knepley         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1845b5a892a1SMatthew G. Knepley         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
18466f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
18476f5f1567SToby Isaac           PetscInt        numChildren, i;
18486f5f1567SToby Isaac           const PetscInt *children;
18496f5f1567SToby Isaac 
18509566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(K, p, &numChildren, &children));
18516f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
18526f5f1567SToby Isaac             PetscInt kPerm, oPerm;
18536f5f1567SToby Isaac 
18546f5f1567SToby Isaac             k = children[i];
18559566063dSJacob Faibussowitsch             PetscCall(DMPlexReferenceTreeGetChildSymmetry(K, p, parentOrientA, 0, k, parentOrientB, &oPerm, &kPerm));
18566f5f1567SToby Isaac             /* perm = what refTree position I'm in */
18576f5f1567SToby Isaac             perm[kPerm - kStart] = k;
18586f5f1567SToby Isaac             /* iperm = who is at this position */
18596f5f1567SToby Isaac             iperm[k - kStart]         = kPerm - kStart;
18606f5f1567SToby Isaac             preOrient[kPerm - kStart] = oPerm;
18616f5f1567SToby Isaac           }
18626f5f1567SToby Isaac         }
18636f5f1567SToby Isaac       }
18649566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18656f5f1567SToby Isaac     }
18669566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, 0, pNewEnd[dim]));
18676f5f1567SToby Isaac     offset      = 0;
18686f5f1567SToby Isaac     numNewCones = 0;
18696f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18706f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
18716f5f1567SToby Isaac       PetscInt p;
18726f5f1567SToby Isaac       PetscInt size;
18736f5f1567SToby Isaac 
18746f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
18756f5f1567SToby Isaac         /* skip cell 0 */
18766f5f1567SToby Isaac         if (p == cell) continue;
18776f5f1567SToby Isaac         /* old cones to new cones */
18789566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
18796f5f1567SToby Isaac         newConeSizes[offset++] = size;
18806f5f1567SToby Isaac         numNewCones += size;
18816f5f1567SToby Isaac       }
18826f5f1567SToby Isaac 
18839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
18846f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18856f5f1567SToby Isaac         PetscInt kParent;
18866f5f1567SToby Isaac 
18879566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
18886f5f1567SToby Isaac         if (kParent != k) {
18896f5f1567SToby Isaac           Kembedding[k] = offset;
18909566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
18916f5f1567SToby Isaac           newConeSizes[offset++] = size;
18926f5f1567SToby Isaac           numNewCones += size;
189348a46eb9SPierre Jolivet           if (kParent != 0) PetscCall(PetscSectionSetDof(parentSection, Kembedding[k], 1));
18946f5f1567SToby Isaac         }
18956f5f1567SToby Isaac       }
18966f5f1567SToby Isaac     }
18976f5f1567SToby Isaac 
18989566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
18999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(parentSection, &numPointsWithParents));
19009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numNewCones, &newCones, numNewCones, &newOrientations));
19019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPointsWithParents, &parents, numPointsWithParents, &childIDs));
19026f5f1567SToby Isaac 
19036f5f1567SToby Isaac     /* fill new cones */
19046f5f1567SToby Isaac     offset = 0;
19056f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19066f5f1567SToby Isaac       PetscInt        kStart, kEnd, k, l;
19076f5f1567SToby Isaac       PetscInt        p;
19086f5f1567SToby Isaac       PetscInt        size;
19096f5f1567SToby Isaac       const PetscInt *cone, *orientation;
19106f5f1567SToby Isaac 
19116f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19126f5f1567SToby Isaac         /* skip cell 0 */
19136f5f1567SToby Isaac         if (p == cell) continue;
19146f5f1567SToby Isaac         /* old cones to new cones */
19159566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
19169566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
19179566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeOrientation(dm, p, &orientation));
19186f5f1567SToby Isaac         for (l = 0; l < size; l++) {
19196f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
19206f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
19216f5f1567SToby Isaac         }
19226f5f1567SToby Isaac       }
19236f5f1567SToby Isaac 
19249566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
19256f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19266f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
19276f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
19286f5f1567SToby Isaac 
19299566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
19306f5f1567SToby Isaac         if (kParent != k) {
19316f5f1567SToby Isaac           /* embed new cones */
19329566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
19339566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(K, kPerm, &cone));
19349566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeOrientation(K, kPerm, &orientation));
19356f5f1567SToby Isaac           for (l = 0; l < size; l++) {
19366f5f1567SToby Isaac             PetscInt       q, m = (preO >= 0) ? ((preO + l) % size) : ((size - (preO + 1) - l) % size);
19376f5f1567SToby Isaac             PetscInt       newO, lSize, oTrue;
1938b5a892a1SMatthew G. Knepley             DMPolytopeType ct = DM_NUM_POLYTOPES;
19396f5f1567SToby Isaac 
19406f5f1567SToby Isaac             q                = iperm[cone[m]];
19416f5f1567SToby Isaac             newCones[offset] = Kembedding[q];
19429566063dSJacob Faibussowitsch             PetscCall(DMPlexGetConeSize(K, q, &lSize));
1943b5a892a1SMatthew G. Knepley             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
1944b5a892a1SMatthew G. Knepley             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
1945b5a892a1SMatthew G. Knepley             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
19466f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
19476f5f1567SToby Isaac             newO                      = DihedralCompose(lSize, oTrue, preOrient[q]);
1948b5a892a1SMatthew G. Knepley             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
19496f5f1567SToby Isaac           }
19506f5f1567SToby Isaac           if (kParent != 0) {
19516f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
19529566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(parentSection, Kembedding[k], &pOffset));
19536f5f1567SToby Isaac             parents[pOffset]  = newPoint;
19546f5f1567SToby Isaac             childIDs[pOffset] = k;
19556f5f1567SToby Isaac           }
19566f5f1567SToby Isaac         }
19576f5f1567SToby Isaac       }
19586f5f1567SToby Isaac     }
19596f5f1567SToby Isaac 
19609566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(dim * (pNewEnd[dim] - pNewStart[dim]), &newVertexCoords));
19616f5f1567SToby Isaac 
19626f5f1567SToby Isaac     /* fill coordinates */
19636f5f1567SToby Isaac     offset = 0;
19646f5f1567SToby Isaac     {
1965d90620a3SMatthew G. Knepley       PetscInt     kStart, kEnd, l;
19666f5f1567SToby Isaac       PetscSection vSection;
19676f5f1567SToby Isaac       PetscInt     v;
19686f5f1567SToby Isaac       Vec          coords;
19696f5f1567SToby Isaac       PetscScalar *coordvals;
19706f5f1567SToby Isaac       PetscInt     dof, off;
1971c111c6b7SMatthew G. Knepley       PetscReal    v0[3], J[9], detJ;
19726f5f1567SToby Isaac 
197376bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
1974d90620a3SMatthew G. Knepley         PetscInt k;
19759566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(K, 0, &kStart, &kEnd));
19766f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
19779566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
197863a3b9bcSJacob Faibussowitsch           PetscCheck(detJ > 0., PETSC_COMM_SELF, PETSC_ERR_PLIB, "reference tree cell %" PetscInt_FMT " has bad determinant", k);
19796f5f1567SToby Isaac         }
1980d90620a3SMatthew G. Knepley       }
19819566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
19829566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &vSection));
19839566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coords));
19849566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19856f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
19869566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(vSection, v, &dof));
19879566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(vSection, v, &off));
1988ad540459SPierre Jolivet         for (l = 0; l < dof; l++) newVertexCoords[offset++] = coordvals[off + l];
19896f5f1567SToby Isaac       }
19909566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
19916f5f1567SToby Isaac 
19929566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(K, &vSection));
19939566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(K, &coords));
19949566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19959566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(K, 0, &kStart, &kEnd));
19966f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
19979bc368c7SMatthew G. Knepley         PetscReal       coord[3], newCoord[3];
19986f5f1567SToby Isaac         PetscInt        vPerm = perm[v];
19996f5f1567SToby Isaac         PetscInt        kParent;
2000c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
20016f5f1567SToby Isaac 
20029566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, v, &kParent, NULL));
20036f5f1567SToby Isaac         if (kParent != v) {
20046f5f1567SToby Isaac           /* this is a new vertex */
20059566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(vSection, vPerm, &off));
20069bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off + l]);
2007367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
20089bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset + l] = newCoord[l];
20096f5f1567SToby Isaac           offset += dim;
20106f5f1567SToby Isaac         }
20116f5f1567SToby Isaac       }
20129566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
20136f5f1567SToby Isaac     }
20146f5f1567SToby Isaac 
20156f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
20166f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
20176f5f1567SToby Isaac       PetscInt tmp;
20186f5f1567SToby Isaac 
20196f5f1567SToby Isaac       tmp                = pNewCount[d];
20206f5f1567SToby Isaac       pNewCount[d]       = pNewCount[dim - d];
20216f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
20226f5f1567SToby Isaac     }
20236f5f1567SToby Isaac 
20249566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, pNewCount, newConeSizes, newCones, newOrientations, newVertexCoords));
20259566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20269566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, parents, childIDs));
20276f5f1567SToby Isaac 
20286f5f1567SToby Isaac     /* clean up */
20299566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
20309566063dSJacob Faibussowitsch     PetscCall(PetscFree5(pNewCount, pNewStart, pNewEnd, pOldStart, pOldEnd));
20319566063dSJacob Faibussowitsch     PetscCall(PetscFree(newConeSizes));
20329566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCones, newOrientations));
20339566063dSJacob Faibussowitsch     PetscCall(PetscFree(newVertexCoords));
20349566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parents, childIDs));
20359566063dSJacob Faibussowitsch     PetscCall(PetscFree4(Kembedding, perm, iperm, preOrient));
20369371c9d4SSatish Balay   } else {
20376f5f1567SToby Isaac     PetscInt     p, counts[4];
20386f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
20396f5f1567SToby Isaac     Vec          coordVec;
20406f5f1567SToby Isaac     PetscScalar *coords;
20416f5f1567SToby Isaac 
20426f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20436f5f1567SToby Isaac       PetscInt dStart, dEnd;
20446f5f1567SToby Isaac 
20459566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
20466f5f1567SToby Isaac       counts[d] = dEnd - dStart;
20476f5f1567SToby Isaac     }
20489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEnd - pStart, &coneSizes));
204948a46eb9SPierre Jolivet     for (p = pStart; p < pEnd; p++) PetscCall(DMPlexGetConeSize(dm, p, &coneSizes[p - pStart]));
20509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCones(dm, &cones));
20519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientations(dm, &orientations));
20529566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordVec));
20539566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordVec, &coords));
20546f5f1567SToby Isaac 
20559566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
20569566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
20579566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, counts, coneSizes, cones, orientations, NULL));
20589566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20599566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, NULL, NULL));
20609566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordVec, &coords));
20616f5f1567SToby Isaac   }
20629566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
20636f5f1567SToby Isaac 
20646f5f1567SToby Isaac   PetscFunctionReturn(0);
20656f5f1567SToby Isaac }
20666ecaa68aSToby Isaac 
2067*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
2068*d71ae5a4SJacob Faibussowitsch {
20696ecaa68aSToby Isaac   PetscSF              coarseToFineEmbedded;
20706ecaa68aSToby Isaac   PetscSection         globalCoarse, globalFine;
20716ecaa68aSToby Isaac   PetscSection         localCoarse, localFine;
20726ecaa68aSToby Isaac   PetscSection         aSec, cSec;
20736ecaa68aSToby Isaac   PetscSection         rootIndicesSec, rootMatricesSec;
207446bdb399SToby Isaac   PetscSection         leafIndicesSec, leafMatricesSec;
207546bdb399SToby Isaac   PetscInt            *rootIndices, *leafIndices;
207646bdb399SToby Isaac   PetscScalar         *rootMatrices, *leafMatrices;
20776ecaa68aSToby Isaac   IS                   aIS;
20786ecaa68aSToby Isaac   const PetscInt      *anchors;
20796ecaa68aSToby Isaac   Mat                  cMat;
20804acb8e1eSToby Isaac   PetscInt             numFields, maxFields;
20816ecaa68aSToby Isaac   PetscInt             pStartC, pEndC, pStartF, pEndF, p;
20826ecaa68aSToby Isaac   PetscInt             aStart, aEnd, cStart, cEnd;
20831c58ffc4SToby Isaac   PetscInt            *maxChildIds;
2084e44e4e7fSToby Isaac   PetscInt            *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
20854acb8e1eSToby Isaac   const PetscInt    ***perms;
20864acb8e1eSToby Isaac   const PetscScalar ***flips;
20876ecaa68aSToby Isaac 
20886ecaa68aSToby Isaac   PetscFunctionBegin;
20899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
20909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
20919566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
20926ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
209389698031SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
209489698031SToby Isaac     const PetscInt *leaves;
20956ecaa68aSToby Isaac 
20969566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
209789698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
209889698031SToby Isaac       p = leaves ? leaves[l] : l;
20999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
21009566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2101ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
21026ecaa68aSToby Isaac     }
21039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
21047cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
210589698031SToby Isaac       p = leaves ? leaves[l] : l;
21069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
21079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2108ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
21096ecaa68aSToby Isaac     }
21109566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
21119566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
21126ecaa68aSToby Isaac   }
21136ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
21149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
2115ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
211657168dbeSPierre Jolivet   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211757168dbeSPierre Jolivet   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211846bdb399SToby Isaac 
21199566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
21209566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
212146bdb399SToby Isaac 
21229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
21239566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
21249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
212546bdb399SToby Isaac 
21269566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
21279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
212846bdb399SToby Isaac 
212946bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
21309566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
21319566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootMatricesSec));
21329566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootIndicesSec, pStartC, pEndC));
21339566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootMatricesSec, pStartC, pEndC));
21349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
2135713c1c5dSToby Isaac   maxFields = PetscMax(1, numFields);
21369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc7(maxFields + 1, &offsets, maxFields + 1, &offsetsCopy, maxFields + 1, &newOffsets, maxFields + 1, &newOffsetsCopy, maxFields + 1, &rowOffsets, maxFields + 1, &numD, maxFields + 1, &numO));
21379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxFields + 1, (PetscInt ****)&perms, maxFields + 1, (PetscScalar ****)&flips));
21389566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)perms, (maxFields + 1) * sizeof(const PetscInt **)));
21399566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)flips, (maxFields + 1) * sizeof(const PetscScalar **)));
214046bdb399SToby Isaac 
214146bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
21428d2f55e7SToby Isaac     PetscInt dof, matSize = 0;
21436ecaa68aSToby Isaac     PetscInt aDof          = 0;
21446ecaa68aSToby Isaac     PetscInt cDof          = 0;
21456ecaa68aSToby Isaac     PetscInt maxChildId    = maxChildIds[p - pStartC];
21466ecaa68aSToby Isaac     PetscInt numRowIndices = 0;
21476ecaa68aSToby Isaac     PetscInt numColIndices = 0;
2148f13f9184SToby Isaac     PetscInt f;
21496ecaa68aSToby Isaac 
21509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2151ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
215248a46eb9SPierre Jolivet     if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof));
215348a46eb9SPierre Jolivet     if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(cSec, p, &cDof));
2154f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2155f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
21566ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2157f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
21586ecaa68aSToby Isaac 
21599566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
216046bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
21616ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
21626ecaa68aSToby Isaac 
21639566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
21646ecaa68aSToby Isaac         numRowIndices += clDof;
21656ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21669566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &clDof));
21676ecaa68aSToby Isaac           offsets[f + 1] += clDof;
21686ecaa68aSToby Isaac         }
21696ecaa68aSToby Isaac       }
21706ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
21716ecaa68aSToby Isaac         offsets[f + 1] += offsets[f];
21726ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
21736ecaa68aSToby Isaac       }
217446bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
21759566063dSJacob Faibussowitsch       PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, NULL, NULL, NULL, &numColIndices, NULL, NULL, newOffsets, PETSC_FALSE));
21769566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
21776ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
21786ecaa68aSToby Isaac         numColIndices = numRowIndices;
21796ecaa68aSToby Isaac         matSize       = 0;
21809371c9d4SSatish Balay       } else if (numFields) { /* we send one submat for each field: sum their sizes */
21816ecaa68aSToby Isaac         matSize = 0;
21826ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21836ecaa68aSToby Isaac           PetscInt numRow, numCol;
21846ecaa68aSToby Isaac 
21856ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2186f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
21876ecaa68aSToby Isaac           matSize += numRow * numCol;
21886ecaa68aSToby Isaac         }
21899371c9d4SSatish Balay       } else {
21906ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
21916ecaa68aSToby Isaac       }
2192f13f9184SToby Isaac     } else if (maxChildId == -1) {
21938d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2194f13f9184SToby Isaac         PetscInt aOff, a;
21956ecaa68aSToby Isaac 
21969566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
21976ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21986ecaa68aSToby Isaac           PetscInt fDof;
21996ecaa68aSToby Isaac 
22009566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
220121968bf8SToby Isaac           offsets[f + 1] = fDof;
22026ecaa68aSToby Isaac         }
22036ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
22046ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
22056ecaa68aSToby Isaac 
22069566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(localCoarse, anchor, &aLocalDof));
22076ecaa68aSToby Isaac           numColIndices += aLocalDof;
22086ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
22096ecaa68aSToby Isaac             PetscInt fDof;
22106ecaa68aSToby Isaac 
22119566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
221221968bf8SToby Isaac             newOffsets[f + 1] += fDof;
22136ecaa68aSToby Isaac           }
22146ecaa68aSToby Isaac         }
22156ecaa68aSToby Isaac         if (numFields) {
22166ecaa68aSToby Isaac           matSize = 0;
2217ad540459SPierre Jolivet           for (f = 0; f < numFields; f++) matSize += offsets[f + 1] * newOffsets[f + 1];
22189371c9d4SSatish Balay         } else {
22196ecaa68aSToby Isaac           matSize = numColIndices * dof;
22206ecaa68aSToby Isaac         }
22219371c9d4SSatish Balay       } else { /* no children, and no constraints on dofs: just get the global indices */
22226ecaa68aSToby Isaac         numColIndices = dof;
22236ecaa68aSToby Isaac         matSize       = 0;
22246ecaa68aSToby Isaac       }
22258d2f55e7SToby Isaac     }
222646bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
22279566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootIndicesSec, p, numColIndices ? numColIndices + 2 * numFields : 0));
22289566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootMatricesSec, p, matSize));
22296ecaa68aSToby Isaac   }
22309566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootIndicesSec));
22319566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootMatricesSec));
22326ecaa68aSToby Isaac   {
22336ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
22346ecaa68aSToby Isaac 
22359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
22369566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootMatricesSec, &numRootMatrices));
22379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numRootIndices, &rootIndices, numRootMatrices, &rootMatrices));
22386ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
22396ecaa68aSToby Isaac       PetscInt     numRowIndices, numColIndices, matSize, dof;
2240f13f9184SToby Isaac       PetscInt     pIndOff, pMatOff, f;
22416ecaa68aSToby Isaac       PetscInt    *pInd;
22426ecaa68aSToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
22436ecaa68aSToby Isaac       PetscScalar *pMat       = NULL;
22446ecaa68aSToby Isaac 
22459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, p, &numColIndices));
2246ad540459SPierre Jolivet       if (!numColIndices) continue;
2247f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2248f13f9184SToby Isaac         offsets[f]        = 0;
2249f13f9184SToby Isaac         newOffsets[f]     = 0;
2250f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2251f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2252f13f9184SToby Isaac       }
22536ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
22549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, p, &pIndOff));
22556ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
22569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootMatricesSec, p, &matSize));
22576ecaa68aSToby Isaac       if (matSize) {
22589566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootMatricesSec, p, &pMatOff));
22596ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
22606ecaa68aSToby Isaac       }
22619566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2262ad540459SPierre Jolivet       if (dof < 0) dof = -(dof + 1);
22636ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
22646ecaa68aSToby Isaac         PetscInt i, j;
22656ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
22666ecaa68aSToby Isaac 
22676ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
22686ecaa68aSToby Isaac           PetscInt numIndices, *indices;
22699566063dSJacob Faibussowitsch           PetscCall(DMPlexGetClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
227008401ef6SPierre Jolivet           PetscCheck(numIndices == numColIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "mismatching constraint indices calculations");
2271ad540459SPierre Jolivet           for (i = 0; i < numColIndices; i++) pInd[i] = indices[i];
22726ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
227346bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i + 1];
227446bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i + 1];
22756ecaa68aSToby Isaac           }
22769566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
22779371c9d4SSatish Balay         } else {
22786ecaa68aSToby Isaac           PetscInt     closureSize, *closure = NULL, cl;
22796ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
22806ecaa68aSToby Isaac           PetscInt     numPoints, *points;
22816ecaa68aSToby Isaac 
22829566063dSJacob Faibussowitsch           PetscCall(DMGetWorkArray(coarse, numRowIndices * numRowIndices, MPIU_SCALAR, &pMatIn));
22836ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
2284ad540459SPierre Jolivet             for (j = 0; j < numRowIndices; j++) pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
22856ecaa68aSToby Isaac           }
22869566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22874acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
22889566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
22899566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
22904acb8e1eSToby Isaac           }
22916ecaa68aSToby Isaac           if (numFields) {
22926ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
22936ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
22946ecaa68aSToby Isaac 
22956ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
22966ecaa68aSToby Isaac                 PetscInt fDof;
22976ecaa68aSToby Isaac 
22989566063dSJacob Faibussowitsch                 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &fDof));
22996ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
23006ecaa68aSToby Isaac               }
23016ecaa68aSToby Isaac             }
23026ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
23036ecaa68aSToby Isaac               offsets[f + 1] += offsets[f];
23046ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
23056ecaa68aSToby Isaac             }
23066ecaa68aSToby Isaac           }
23074acb8e1eSToby Isaac           /* TODO : flips here ? */
23086ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
23099566063dSJacob Faibussowitsch           PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, perms, pMatIn, &numPoints, NULL, &points, &pMatModified, newOffsets, PETSC_FALSE));
23104acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23119566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
23129566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
23134acb8e1eSToby Isaac           }
23144acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23159566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23169566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23174acb8e1eSToby Isaac           }
23186ecaa68aSToby Isaac           if (!numFields) {
2319ad540459SPierre Jolivet             for (i = 0; i < numRowIndices * numColIndices; i++) pMat[i] = pMatModified[i];
23209371c9d4SSatish Balay           } else {
2321f13f9184SToby Isaac             PetscInt i, j, count;
23226ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
23236ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f + 1]; i++) {
2324ad540459SPierre Jolivet                 for (j = newOffsets[f]; j < newOffsets[f + 1]; j++, count++) pMat[count] = pMatModified[i * numColIndices + j];
23256ecaa68aSToby Isaac               }
23266ecaa68aSToby Isaac             }
23276ecaa68aSToby Isaac           }
23289566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatModified));
23299566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
23309566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatIn));
23316ecaa68aSToby Isaac           if (numFields) {
233246bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
233346bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f + 1];
233446bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f + 1];
23356ecaa68aSToby Isaac             }
23364acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23374acb8e1eSToby Isaac               PetscInt globalOff, c = points[2 * cl];
23389566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23399566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
23406ecaa68aSToby Isaac             }
23416ecaa68aSToby Isaac           } else {
23424acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23434acb8e1eSToby Isaac               PetscInt        c    = points[2 * cl], globalOff;
23444acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
23454acb8e1eSToby Isaac 
23469566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23479566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
23486ecaa68aSToby Isaac             }
23496ecaa68aSToby Isaac           }
23504acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23519566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23529566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23534acb8e1eSToby Isaac           }
23549566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numPoints, MPIU_SCALAR, &points));
23556ecaa68aSToby Isaac         }
23569371c9d4SSatish Balay       } else if (matSize) {
23576ecaa68aSToby Isaac         PetscInt  cOff;
23586ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
23596ecaa68aSToby Isaac 
23606ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
236108401ef6SPierre Jolivet         PetscCheck(numRowIndices == dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Miscounted dofs");
23629566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
23639566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
23649566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, p, &cOff));
23659566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
23669566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
23676ecaa68aSToby Isaac         if (numFields) {
23686ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23696ecaa68aSToby Isaac             PetscInt fDof;
2370f13f9184SToby Isaac 
23719566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSec, p, f, &fDof));
23726ecaa68aSToby Isaac             offsets[f + 1] = fDof;
23736ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
23746ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
23759566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
23766ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
23776ecaa68aSToby Isaac             }
23786ecaa68aSToby Isaac           }
23796ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23806ecaa68aSToby Isaac             offsets[f + 1] += offsets[f];
23816ecaa68aSToby Isaac             offsetsCopy[f + 1] = offsets[f + 1];
23826ecaa68aSToby Isaac             newOffsets[f + 1] += newOffsets[f];
23836ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
23846ecaa68aSToby Isaac           }
23859566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, -1, NULL, rowIndices));
23866ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23876ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23889566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23899566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, -1, NULL, colIndices));
23906ecaa68aSToby Isaac           }
23919371c9d4SSatish Balay         } else {
23929566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, NULL, rowIndices));
23936ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23946ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23959566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23969566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, NULL, colIndices));
23976ecaa68aSToby Isaac           }
23986ecaa68aSToby Isaac         }
23996ecaa68aSToby Isaac         if (numFields) {
2400f13f9184SToby Isaac           PetscInt count, a;
2401f13f9184SToby Isaac 
24026ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
24036ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
24046ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
24059566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat, iSize, &rowIndices[offsets[f]], jSize, &colIndices[newOffsets[f]], &pMat[count]));
24066ecaa68aSToby Isaac             count += iSize * jSize;
240746bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
240846bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f + 1];
24096ecaa68aSToby Isaac           }
24106ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24116ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24126ecaa68aSToby Isaac             PetscInt gOff;
24139566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24149566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, -1, NULL, pInd));
24156ecaa68aSToby Isaac           }
24169371c9d4SSatish Balay         } else {
24176ecaa68aSToby Isaac           PetscInt a;
24189566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat, numRowIndices, rowIndices, numColIndices, colIndices, pMat));
24196ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24206ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24216ecaa68aSToby Isaac             PetscInt gOff;
24229566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24239566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, NULL, pInd));
24246ecaa68aSToby Isaac           }
24256ecaa68aSToby Isaac         }
24269566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
24279566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
24289371c9d4SSatish Balay       } else {
24296ecaa68aSToby Isaac         PetscInt gOff;
24306ecaa68aSToby Isaac 
24319566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
24326ecaa68aSToby Isaac         if (numFields) {
24336ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
24346ecaa68aSToby Isaac             PetscInt fDof;
24359566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
24366ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
24376ecaa68aSToby Isaac           }
24386ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
243946bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
244046bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f + 1];
24416ecaa68aSToby Isaac           }
24429566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2443367003a6SStefano Zampini         } else {
24449566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
24456ecaa68aSToby Isaac         }
24466ecaa68aSToby Isaac       }
24476ecaa68aSToby Isaac     }
24489566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
24496ecaa68aSToby Isaac   }
245046bdb399SToby Isaac   {
245146bdb399SToby Isaac     PetscSF   indicesSF, matricesSF;
245246bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
245346bdb399SToby Isaac 
24549566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
24559566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafMatricesSec));
24569566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootIndicesSec, &remoteOffsetsIndices, leafIndicesSec));
24579566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootMatricesSec, &remoteOffsetsMatrices, leafMatricesSec));
24589566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootIndicesSec, remoteOffsetsIndices, leafIndicesSec, &indicesSF));
24599566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootMatricesSec, remoteOffsetsMatrices, leafMatricesSec, &matricesSF));
24609566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
24619566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsIndices));
24629566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsMatrices));
24639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numLeafIndices));
24649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafMatricesSec, &numLeafMatrices));
24659566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numLeafIndices, &leafIndices, numLeafMatrices, &leafMatrices));
24669566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24679566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24689566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24699566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24709566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&matricesSF));
24719566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
24729566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rootIndices, rootMatrices));
24739566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootIndicesSec));
24749566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootMatricesSec));
247546bdb399SToby Isaac   }
247646bdb399SToby Isaac   /* count to preallocate */
24779566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
247846bdb399SToby Isaac   {
247946bdb399SToby Isaac     PetscInt       nGlobal;
248046bdb399SToby Isaac     PetscInt      *dnnz, *onnz;
2481b9a5774bSToby Isaac     PetscLayout    rowMap, colMap;
2482b9a5774bSToby Isaac     PetscInt       rowStart, rowEnd, colStart, colEnd;
24831c58ffc4SToby Isaac     PetscInt       maxDof;
24841c58ffc4SToby Isaac     PetscInt      *rowIndices;
24851c58ffc4SToby Isaac     DM             refTree;
24861c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
24871c58ffc4SToby Isaac     PetscScalar ***refPointFieldMats;
24881c58ffc4SToby Isaac     PetscSection   refConSec, refAnSec;
24890eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, maxConDof, maxColumns, leafStart, leafEnd;
24901c58ffc4SToby Isaac     PetscScalar   *pointWork;
249146bdb399SToby Isaac 
24929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine, &nGlobal));
24939566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nGlobal, &dnnz, nGlobal, &onnz));
24949566063dSJacob Faibussowitsch     PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
24959566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rowMap));
24969566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(colMap));
24979566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
24989566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
24999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
25009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafIndicesSec, &leafStart, &leafEnd));
25019566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
25020eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
250346bdb399SToby Isaac       PetscInt gDof, gcDof, gOff;
250446bdb399SToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
250546bdb399SToby Isaac       PetscInt matSize;
250621968bf8SToby Isaac       PetscInt i;
250746bdb399SToby Isaac 
25089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
25099566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2510ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
25119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
251208401ef6SPierre Jolivet       PetscCheck(gOff >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I though having global dofs meant a non-negative offset");
25131dca8a05SBarry Smith       PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I thought the row map would constrain the global dofs");
25149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
25159566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
251646bdb399SToby Isaac       numColIndices -= 2 * numFields;
251708401ef6SPierre Jolivet       PetscCheck(numColIndices > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "global fine dof with no dofs to interpolate from");
251846bdb399SToby Isaac       pInd              = &leafIndices[pIndOff];
251921968bf8SToby Isaac       offsets[0]        = 0;
252021968bf8SToby Isaac       offsetsCopy[0]    = 0;
252121968bf8SToby Isaac       newOffsets[0]     = 0;
252221968bf8SToby Isaac       newOffsetsCopy[0] = 0;
252346bdb399SToby Isaac       if (numFields) {
252421968bf8SToby Isaac         PetscInt f;
252546bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
252646bdb399SToby Isaac           PetscInt rowDof;
252746bdb399SToby Isaac 
25289566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
252921968bf8SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
253021968bf8SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
253121968bf8SToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
253221968bf8SToby Isaac           numD[f]            = 0;
253321968bf8SToby Isaac           numO[f]            = 0;
253446bdb399SToby Isaac         }
25359566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
253646bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
253721968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
253821968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
253946bdb399SToby Isaac 
254046bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
254146bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
254246bdb399SToby Isaac 
254346bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
254421968bf8SToby Isaac               numD[f]++;
25459371c9d4SSatish Balay             } else if (gInd >= 0) { /* negative means non-entry */
254621968bf8SToby Isaac               numO[f]++;
254746bdb399SToby Isaac             }
254846bdb399SToby Isaac           }
254946bdb399SToby Isaac         }
25509371c9d4SSatish Balay       } else {
25519566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
255221968bf8SToby Isaac         numD[0] = 0;
255321968bf8SToby Isaac         numO[0] = 0;
255446bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
255546bdb399SToby Isaac           PetscInt gInd = pInd[i];
255646bdb399SToby Isaac 
255746bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
255821968bf8SToby Isaac             numD[0]++;
25599371c9d4SSatish Balay           } else if (gInd >= 0) { /* negative means non-entry */
256021968bf8SToby Isaac             numO[0]++;
256146bdb399SToby Isaac           }
256246bdb399SToby Isaac         }
256346bdb399SToby Isaac       }
25649566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
256546bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
256646bdb399SToby Isaac         PetscInt childId;
256746bdb399SToby Isaac 
256846bdb399SToby Isaac         childId = childIds[p - pStartF];
256921968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
257046bdb399SToby Isaac           if (numFields) {
2571b9a5774bSToby Isaac             PetscInt f;
2572b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
257321968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
257446bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
257521968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
257621968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
257746bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25781dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2579b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
25809371c9d4SSatish Balay                 } else if (gIndCoarse >= 0) { /* remote */
25811dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2582b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
25839371c9d4SSatish Balay                 } else { /* constrained */
258408401ef6SPierre Jolivet                   PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
258546bdb399SToby Isaac                 }
258646bdb399SToby Isaac               }
258746bdb399SToby Isaac             }
25889371c9d4SSatish Balay           } else {
2589b9a5774bSToby Isaac             PetscInt i;
2590b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
259146bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
259246bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
259346bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25941dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2595b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
25969371c9d4SSatish Balay               } else if (gIndCoarse >= 0) { /* remote */
25971dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2598b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
25999371c9d4SSatish Balay               } else { /* constrained */
260008401ef6SPierre Jolivet                 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
260146bdb399SToby Isaac               }
260246bdb399SToby Isaac             }
260346bdb399SToby Isaac           }
26049371c9d4SSatish Balay         } else { /* interpolate from all */
260546bdb399SToby Isaac           if (numFields) {
2606b9a5774bSToby Isaac             PetscInt f;
2607b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
260821968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
260946bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
261021968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
261146bdb399SToby Isaac                 if (gIndFine >= 0) {
26121dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2613b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2614b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
261546bdb399SToby Isaac                 }
261646bdb399SToby Isaac               }
261746bdb399SToby Isaac             }
26189371c9d4SSatish Balay           } else {
2619b9a5774bSToby Isaac             PetscInt i;
2620b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
262146bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
262246bdb399SToby Isaac               if (gIndFine >= 0) {
26231dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2624b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2625b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
262646bdb399SToby Isaac               }
262746bdb399SToby Isaac             }
262846bdb399SToby Isaac           }
262946bdb399SToby Isaac         }
26309371c9d4SSatish Balay       } else { /* interpolate from all */
263146bdb399SToby Isaac         if (numFields) {
2632b9a5774bSToby Isaac           PetscInt f;
2633b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
263421968bf8SToby Isaac             PetscInt numRows = offsets[f + 1] - offsets[f], row;
263546bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
263621968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
263746bdb399SToby Isaac               if (gIndFine >= 0) {
26381dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2639b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2640b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
264146bdb399SToby Isaac               }
264246bdb399SToby Isaac             }
264346bdb399SToby Isaac           }
26449371c9d4SSatish Balay         } else { /* every dof get a full row */
2645b9a5774bSToby Isaac           PetscInt i;
2646b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
264746bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
264846bdb399SToby Isaac             if (gIndFine >= 0) {
26491dca8a05SBarry Smith               PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2650b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2651b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
265246bdb399SToby Isaac             }
265346bdb399SToby Isaac           }
265446bdb399SToby Isaac         }
265546bdb399SToby Isaac       }
265646bdb399SToby Isaac     }
26579566063dSJacob Faibussowitsch     PetscCall(MatXAIJSetPreallocation(mat, 1, dnnz, onnz, NULL, NULL));
26589566063dSJacob Faibussowitsch     PetscCall(PetscFree2(dnnz, onnz));
265921968bf8SToby Isaac 
26609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
26619566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
26629566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
26639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
26649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
26659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(refConSec, &maxConDof));
26669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(leafIndicesSec, &maxColumns));
26679566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxConDof * maxColumns, &pointWork));
26680eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2669e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2670e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2671e44e4e7fSToby Isaac       PetscInt matSize;
2672e44e4e7fSToby Isaac       PetscInt childId;
2673e44e4e7fSToby Isaac 
26749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
26759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2676ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
2677e44e4e7fSToby Isaac       childId = childIds[p - pStartF];
26789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
26799566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
26809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2681e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2682e44e4e7fSToby Isaac       pInd              = &leafIndices[pIndOff];
2683e44e4e7fSToby Isaac       offsets[0]        = 0;
2684e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2685e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2686e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2687e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2688e44e4e7fSToby Isaac       if (numFields) {
2689e44e4e7fSToby Isaac         PetscInt f;
2690e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2691e44e4e7fSToby Isaac           PetscInt rowDof;
2692e44e4e7fSToby Isaac 
26939566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2694e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2695e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2696e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2697e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2698e44e4e7fSToby Isaac         }
26999566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
27009371c9d4SSatish Balay       } else {
27019566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
27021c58ffc4SToby Isaac       }
27039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2704e44e4e7fSToby Isaac       if (!matSize) {      /* incoming matrix is identity */
2705e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2706e44e4e7fSToby Isaac           if (numFields) {
2707e44e4e7fSToby Isaac             PetscInt f;
2708e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2709e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
271048a46eb9SPierre Jolivet               for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[offsets[f] + row], pInd[newOffsets[f] + row], 1., INSERT_VALUES));
271121968bf8SToby Isaac             }
27129371c9d4SSatish Balay           } else {
2713e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
271448a46eb9SPierre Jolivet             for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[row], pInd[row], 1., INSERT_VALUES));
2715e44e4e7fSToby Isaac           }
27169371c9d4SSatish Balay         } else { /* interpolate from all */
2717e44e4e7fSToby Isaac           if (numFields) {
2718e44e4e7fSToby Isaac             PetscInt f;
2719e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2720e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f];
2721e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
27229566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], refPointFieldMats[childId - pRefStart][f], INSERT_VALUES));
2723e44e4e7fSToby Isaac             }
27249371c9d4SSatish Balay           } else {
27259566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, refPointFieldMats[childId - pRefStart][0], INSERT_VALUES));
2726e44e4e7fSToby Isaac           }
2727e44e4e7fSToby Isaac         }
27289371c9d4SSatish Balay       } else { /* interpolate from all */
2729e44e4e7fSToby Isaac         PetscInt     pMatOff;
2730e44e4e7fSToby Isaac         PetscScalar *pMat;
2731e44e4e7fSToby Isaac 
27329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafMatricesSec, p, &pMatOff));
2733e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2734e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2735e44e4e7fSToby Isaac           if (numFields) {
2736e44e4e7fSToby Isaac             PetscInt f, count;
2737e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2738e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2739e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2740e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2741e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2742e44e4e7fSToby Isaac 
27439566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], inMat, INSERT_VALUES));
2744e44e4e7fSToby Isaac               count += numCols * numInRows;
2745e44e4e7fSToby Isaac             }
27469371c9d4SSatish Balay           } else {
27479566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, pMat, INSERT_VALUES));
2748e44e4e7fSToby Isaac           }
27499371c9d4SSatish Balay         } else { /* multiply the incoming matrix by the child interpolation */
2750e44e4e7fSToby Isaac           if (numFields) {
2751e44e4e7fSToby Isaac             PetscInt f, count;
2752e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2753e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2754e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2755e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2756e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2757e44e4e7fSToby Isaac               PetscInt     i, j, k;
275808401ef6SPierre Jolivet               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2759e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2760e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2761e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2762ad540459SPierre Jolivet                   for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2763e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2764e44e4e7fSToby Isaac                 }
2765e44e4e7fSToby Isaac               }
27669566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], pointWork, INSERT_VALUES));
2767e44e4e7fSToby Isaac               count += numCols * numInRows;
2768e44e4e7fSToby Isaac             }
27699371c9d4SSatish Balay           } else { /* every dof gets a full row */
2770e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2771e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2772e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2773e44e4e7fSToby Isaac             PetscInt i, j, k;
277408401ef6SPierre Jolivet             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2775e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2776e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2777e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2778ad540459SPierre Jolivet                 for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2779e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2780e44e4e7fSToby Isaac               }
2781e44e4e7fSToby Isaac             }
27829566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, numRows, rowIndices, numCols, pInd, pointWork, INSERT_VALUES));
2783e44e4e7fSToby Isaac           }
2784e44e4e7fSToby Isaac         }
2785e44e4e7fSToby Isaac       }
2786e44e4e7fSToby Isaac     }
27879566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
27889566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
27899566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointWork));
2790e44e4e7fSToby Isaac   }
27919566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
27929566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
27939566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
27949566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafMatricesSec));
27959566063dSJacob Faibussowitsch   PetscCall(PetscFree2(leafIndices, leafMatrices));
27969566063dSJacob Faibussowitsch   PetscCall(PetscFree2(*(PetscInt ****)&perms, *(PetscScalar ****)&flips));
27979566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
27989566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
27996ecaa68aSToby Isaac   PetscFunctionReturn(0);
28006ecaa68aSToby Isaac }
2801154bca37SToby Isaac 
28028d2f55e7SToby Isaac /*
28038d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
28048d2f55e7SToby Isaac  *
28058d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
28068d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
28078d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
28088d2f55e7SToby Isaac  *       a_{i,j} = 0;
28098d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
28108d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
28118d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
28128d2f55e7SToby Isaac  */
2813*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
2814*d71ae5a4SJacob Faibussowitsch {
28158d2f55e7SToby Isaac   PetscDS      ds;
28168d2f55e7SToby Isaac   PetscSection section, cSection;
28178d2f55e7SToby Isaac   DMLabel      canonical, depth;
28188d2f55e7SToby Isaac   Mat          cMat, mat;
28198d2f55e7SToby Isaac   PetscInt    *nnz;
28208d2f55e7SToby Isaac   PetscInt     f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
28218d2f55e7SToby Isaac   PetscInt     m, n;
28228d2f55e7SToby Isaac   PetscScalar *pointScalar;
28238d2f55e7SToby Isaac   PetscReal   *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
28248d2f55e7SToby Isaac 
28258d2f55e7SToby Isaac   PetscFunctionBegin;
28269566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &section));
28279566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(refTree, &dim));
28289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(dim, &v0, dim, &v0parent, dim, &vtmp, dim * dim, &J, dim * dim, &Jparent, dim * dim, &invJ));
28299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(dim, &pointScalar, dim, &pointRef));
28309566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
28319566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
28329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numSecFields));
28339566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "canonical", &canonical));
28349566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "depth", &depth));
28359566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSection, &cMat, NULL));
28369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
28379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
28389566063dSJacob Faibussowitsch   PetscCall(MatGetSize(cMat, &n, &m)); /* the injector has transpose sizes from the constraint matrix */
28398d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
28409566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(m, &nnz));
28418d2f55e7SToby 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 */
28428d2f55e7SToby Isaac     const PetscInt *children;
28438d2f55e7SToby Isaac     PetscInt        numChildren;
28448d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28458d2f55e7SToby Isaac 
28468d2f55e7SToby Isaac     if (canonical) {
28478d2f55e7SToby Isaac       PetscInt pCanonical;
28489566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28498d2f55e7SToby Isaac       if (p != pCanonical) continue;
28508d2f55e7SToby Isaac     }
28519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28528d2f55e7SToby Isaac     if (!numChildren) continue;
28538d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28548d2f55e7SToby Isaac       PetscInt child = children[i];
28558d2f55e7SToby Isaac       PetscInt dof;
28568d2f55e7SToby Isaac 
28579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
28588d2f55e7SToby Isaac       numChildDof += dof;
28598d2f55e7SToby Isaac     }
28609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
28618d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
28628d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
28638d2f55e7SToby Isaac       PetscInt selfOff;
28648d2f55e7SToby Isaac 
28658d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
28668d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
28678d2f55e7SToby Isaac           PetscInt child = children[i];
28688d2f55e7SToby Isaac           PetscInt dof;
28698d2f55e7SToby Isaac 
28709566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
28718d2f55e7SToby Isaac           numChildDof += dof;
28728d2f55e7SToby Isaac         }
28739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
28749566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
28759371c9d4SSatish Balay       } else {
28769566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
28778d2f55e7SToby Isaac       }
2878ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) nnz[selfOff + i] = numChildDof;
28798d2f55e7SToby Isaac     }
28808d2f55e7SToby Isaac   }
28819566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(PETSC_COMM_SELF, m, n, m, n, -1, nnz, -1, NULL, &mat));
28829566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
28838d2f55e7SToby Isaac   /* Setp 2: compute entries */
28848d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
28858d2f55e7SToby Isaac     const PetscInt *children;
28868d2f55e7SToby Isaac     PetscInt        numChildren;
28878d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28888d2f55e7SToby Isaac 
28898d2f55e7SToby Isaac     /* same conditions about when entries occur */
28908d2f55e7SToby Isaac     if (canonical) {
28918d2f55e7SToby Isaac       PetscInt pCanonical;
28929566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28938d2f55e7SToby Isaac       if (p != pCanonical) continue;
28948d2f55e7SToby Isaac     }
28959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28968d2f55e7SToby Isaac     if (!numChildren) continue;
28978d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28988d2f55e7SToby Isaac       PetscInt child = children[i];
28998d2f55e7SToby Isaac       PetscInt dof;
29008d2f55e7SToby Isaac 
29019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
29028d2f55e7SToby Isaac       numChildDof += dof;
29038d2f55e7SToby Isaac     }
29049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
29058d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
29068d2f55e7SToby Isaac 
29078d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
290859fc6756SToby Isaac       PetscInt        pI = -1, cI = -1;
290952a3aeb4SToby Isaac       PetscInt        selfOff, Nc, parentCell;
29108d2f55e7SToby Isaac       PetscInt        cellShapeOff;
29118d2f55e7SToby Isaac       PetscObject     disc;
29128d2f55e7SToby Isaac       PetscDualSpace  dsp;
29138d2f55e7SToby Isaac       PetscClassId    classId;
29148d2f55e7SToby Isaac       PetscScalar    *pointMat;
29153b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
29168d2f55e7SToby Isaac       PetscInt        pO = PETSC_MIN_INT;
29178d2f55e7SToby Isaac       const PetscInt *depthNumDof;
29188d2f55e7SToby Isaac 
29198d2f55e7SToby Isaac       if (numSecFields) {
29208d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
29218d2f55e7SToby Isaac           PetscInt child = children[i];
29228d2f55e7SToby Isaac           PetscInt dof;
29238d2f55e7SToby Isaac 
29249566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
29258d2f55e7SToby Isaac           numChildDof += dof;
29268d2f55e7SToby Isaac         }
29279566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
29289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
29299371c9d4SSatish Balay       } else {
29309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
29318d2f55e7SToby Isaac       }
29328d2f55e7SToby Isaac 
29333b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
29348d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
29358d2f55e7SToby Isaac         parentCell = p;
29369371c9d4SSatish Balay       } else {
29378d2f55e7SToby Isaac         PetscInt *star = NULL;
29388d2f55e7SToby Isaac         PetscInt  numStar;
29398d2f55e7SToby Isaac 
29408d2f55e7SToby Isaac         parentCell = -1;
29419566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29428d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
29438d2f55e7SToby Isaac           PetscInt c = star[2 * i];
29448d2f55e7SToby Isaac 
29458d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
29468d2f55e7SToby Isaac             parentCell = c;
29478d2f55e7SToby Isaac             break;
29488d2f55e7SToby Isaac           }
29498d2f55e7SToby Isaac         }
29509566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29518d2f55e7SToby Isaac       }
2952a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
29539566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
29549566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc, &classId));
2955c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
29569566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
29579371c9d4SSatish Balay       } else if (classId == PETSCFV_CLASSID) {
29589566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace((PetscFV)disc, &dsp));
29599371c9d4SSatish Balay       } else {
29609b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported discretization object");
2961c5356c36SToby Isaac       }
29629566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumDof(dsp, &depthNumDof));
29639566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumComponents(dsp, &Nc));
29648d2f55e7SToby Isaac       {
29658d2f55e7SToby Isaac         PetscInt *closure = NULL;
29668d2f55e7SToby Isaac         PetscInt  numClosure;
29678d2f55e7SToby Isaac 
29689566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
296959fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
29708d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
29718d2f55e7SToby Isaac 
29728d2f55e7SToby Isaac           pO = closure[2 * i + 1];
297359fc6756SToby Isaac           if (point == p) {
297459fc6756SToby Isaac             pI = i;
297559fc6756SToby Isaac             break;
297659fc6756SToby Isaac           }
29779566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(depth, point, &pointDepth));
29788d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
29798d2f55e7SToby Isaac         }
29809566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
29818d2f55e7SToby Isaac       }
29828d2f55e7SToby Isaac 
29839566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
29849566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
298552a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
2986ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) matRows[i] = selfOff + i;
298752a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
29883b1c2a6aSToby Isaac       {
29893b1c2a6aSToby Isaac         PetscInt colOff = 0;
29903b1c2a6aSToby Isaac 
29913b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
29923b1c2a6aSToby Isaac           PetscInt child = children[i];
29933b1c2a6aSToby Isaac           PetscInt dof, off, j;
29943b1c2a6aSToby Isaac 
29953b1c2a6aSToby Isaac           if (numSecFields) {
29969566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSection, child, f, &dof));
29979566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(cSection, child, f, &off));
29989371c9d4SSatish Balay           } else {
29999566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(cSection, child, &dof));
30009566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(cSection, child, &off));
30013b1c2a6aSToby Isaac           }
30023b1c2a6aSToby Isaac 
3003ad540459SPierre Jolivet           for (j = 0; j < dof; j++) matCols[colOff++] = off + j;
30043b1c2a6aSToby Isaac         }
30053b1c2a6aSToby Isaac       }
30068d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
30078d2f55e7SToby Isaac         PetscFE              fe = (PetscFE)disc;
30088d2f55e7SToby Isaac         PetscInt             fSize;
300959fc6756SToby Isaac         const PetscInt    ***perms;
301059fc6756SToby Isaac         const PetscScalar ***flips;
301159fc6756SToby Isaac         const PetscInt      *pperms;
301259fc6756SToby Isaac 
30139566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &dsp));
30149566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetDimension(dsp, &fSize));
30159566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
301659fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
301752a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
30188d2f55e7SToby Isaac           PetscQuadrature  q;
301952a3aeb4SToby Isaac           PetscInt         dim, thisNc, numPoints, j, k;
30208d2f55e7SToby Isaac           const PetscReal *points;
30218d2f55e7SToby Isaac           const PetscReal *weights;
30228d2f55e7SToby Isaac           PetscInt        *closure = NULL;
30238d2f55e7SToby Isaac           PetscInt         numClosure;
302459fc6756SToby Isaac           PetscInt         iCell              = pperms ? pperms[i] : i;
302559fc6756SToby Isaac           PetscInt         parentCellShapeDof = cellShapeOff + iCell;
3026ef0bb6c7SMatthew G. Knepley           PetscTabulation  Tparent;
30278d2f55e7SToby Isaac 
30289566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(dsp, parentCellShapeDof, &q));
30299566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(q, &dim, &thisNc, &numPoints, &points, &weights));
303063a3b9bcSJacob Faibussowitsch           PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
30319566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe, 1, numPoints, points, 0, &Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
30323b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
30338d2f55e7SToby Isaac             PetscInt           childCell = -1;
303452a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3035c330f8ffSToby Isaac             const PetscReal    xi0[3]    = {-1., -1., -1.};
30368d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
30378d2f55e7SToby Isaac             const PetscScalar *point;
3038ef0bb6c7SMatthew G. Knepley             PetscTabulation    Tchild;
30398d2f55e7SToby Isaac             PetscInt           childCellShapeOff, pointMatOff;
30408d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
30418d2f55e7SToby Isaac             PetscInt d;
30428d2f55e7SToby Isaac 
3043ad540459SPierre Jolivet             for (d = 0; d < dim; d++) pointScalar[d] = points[dim * j + d];
30448d2f55e7SToby Isaac             point = pointScalar;
30458d2f55e7SToby Isaac #else
30468d2f55e7SToby Isaac             point = pointReal;
30478d2f55e7SToby Isaac #endif
30488d2f55e7SToby Isaac 
3049ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
30503b1c2a6aSToby Isaac 
30513b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
30528d2f55e7SToby Isaac               PetscInt  child = children[k];
30538d2f55e7SToby Isaac               PetscInt *star  = NULL;
30548d2f55e7SToby Isaac               PetscInt  numStar, s;
30558d2f55e7SToby Isaac 
30569566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30578d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
30588d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
30598d2f55e7SToby Isaac 
30608d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
30619566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(refTree, dim, point, c, &childCell));
30628d2f55e7SToby Isaac                 if (childCell >= 0) break;
30638d2f55e7SToby Isaac               }
30649566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30658d2f55e7SToby Isaac               if (childCell >= 0) break;
30668d2f55e7SToby Isaac             }
306708401ef6SPierre Jolivet             PetscCheck(childCell >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not locate quadrature point");
30689566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
30699566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3070c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3071c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
30728d2f55e7SToby Isaac 
30739566063dSJacob Faibussowitsch             PetscCall(PetscFECreateTabulation(fe, 1, 1, pointRef, 0, &Tchild));
30749566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
30753b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3076c5356c36SToby Isaac               PetscInt        child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
30778d2f55e7SToby Isaac               PetscInt        l;
307859fc6756SToby Isaac               const PetscInt *cperms;
30798d2f55e7SToby Isaac 
30809566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(depth, child, &childDepth));
30818d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
308259fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
30838d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
30848d2f55e7SToby Isaac                 PetscInt pointDepth;
30858d2f55e7SToby Isaac 
30868d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
308759fc6756SToby Isaac                 if (point == child) {
308859fc6756SToby Isaac                   cI = l;
308959fc6756SToby Isaac                   break;
309059fc6756SToby Isaac                 }
30919566063dSJacob Faibussowitsch                 PetscCall(DMLabelGetValue(depth, point, &pointDepth));
30928d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
30938d2f55e7SToby Isaac               }
30948d2f55e7SToby Isaac               if (l == numClosure) {
30958d2f55e7SToby Isaac                 pointMatOff += childDof;
30968d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
30978d2f55e7SToby Isaac               }
309859fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
30998d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
310059fc6756SToby Isaac                 PetscInt   lCell        = cperms ? cperms[l] : l;
310159fc6756SToby Isaac                 PetscInt   childCellDof = childCellShapeOff + lCell;
310252a3aeb4SToby Isaac                 PetscReal *childValAtPoint;
310352a3aeb4SToby Isaac                 PetscReal  val = 0.;
31048d2f55e7SToby Isaac 
3105ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
3106ad540459SPierre Jolivet                 for (m = 0; m < Nc; m++) val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
310752a3aeb4SToby Isaac 
310852a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
31098d2f55e7SToby Isaac               }
31108d2f55e7SToby Isaac               pointMatOff += childDof;
31118d2f55e7SToby Isaac             }
31129566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
31139566063dSJacob Faibussowitsch             PetscCall(PetscTabulationDestroy(&Tchild));
31148d2f55e7SToby Isaac           }
31159566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&Tparent));
31168d2f55e7SToby Isaac         }
31179371c9d4SSatish Balay       } else { /* just the volume-weighted averages of the children */
31183b1c2a6aSToby Isaac         PetscReal parentVol;
3119bfaa5bdcSToby Isaac         PetscInt  childCell;
31203b1c2a6aSToby Isaac 
31219566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3122bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
312352a3aeb4SToby Isaac           PetscInt  child = children[i], j;
31243b1c2a6aSToby Isaac           PetscReal childVol;
31253b1c2a6aSToby Isaac 
31263b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
31279566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
3128ad540459SPierre Jolivet           for (j = 0; j < Nc; j++) pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
3129bfaa5bdcSToby Isaac           childCell++;
31303b1c2a6aSToby Isaac         }
31318d2f55e7SToby Isaac       }
31323b1c2a6aSToby Isaac       /* Insert pointMat into mat */
31339566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, numSelfDof, matRows, numChildDof, matCols, pointMat, INSERT_VALUES));
31349566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
31359566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
31368d2f55e7SToby Isaac     }
31378d2f55e7SToby Isaac   }
31389566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJ));
31399566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointScalar, pointRef));
31409566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
31419566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
31428d2f55e7SToby Isaac   *inj = mat;
31438d2f55e7SToby Isaac   PetscFunctionReturn(0);
31448d2f55e7SToby Isaac }
31458d2f55e7SToby Isaac 
3146*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3147*d71ae5a4SJacob Faibussowitsch {
3148f30e825dSToby Isaac   PetscDS        ds;
3149f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3150f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3151f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3152f30e825dSToby Isaac 
3153f30e825dSToby Isaac   PetscFunctionBegin;
31549566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
31559566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
31569566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
31579566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
31589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
31599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
31609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
31619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
31629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof, &cols));
3163f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3164f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3165f30e825dSToby Isaac 
31669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
31679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
31689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3169f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3170f30e825dSToby Isaac 
31719566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFields, &refPointFieldMats[p - pRefStart]));
3172f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
317352a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3174f30e825dSToby Isaac 
3175f30e825dSToby Isaac       if (numFields > 1) {
31769566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
31779566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
31789371c9d4SSatish Balay       } else {
31799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
31809566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
3181f30e825dSToby Isaac       }
3182f30e825dSToby Isaac 
3183ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
3184f30e825dSToby Isaac       numCols = 0;
3185f30e825dSToby Isaac       {
3186f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3187f30e825dSToby Isaac 
3188f30e825dSToby Isaac         if (numFields > 1) {
31899566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, parent, f, &aDof));
31909566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, parent, f, &aOff));
31919371c9d4SSatish Balay         } else {
31929566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, parent, &aDof));
31939566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, parent, &aOff));
3194f30e825dSToby Isaac         }
3195f30e825dSToby Isaac 
3196ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + j;
3197f30e825dSToby Isaac       }
31989566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
3199f30e825dSToby Isaac       /* transpose of constraint matrix */
32009566063dSJacob Faibussowitsch       PetscCall(MatGetValues(inj, numCols, cols, cDof, rows, refPointFieldMats[p - pRefStart][f]));
3201f30e825dSToby Isaac     }
3202f30e825dSToby Isaac   }
3203f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
32049566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
32059566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
3206f30e825dSToby Isaac   PetscFunctionReturn(0);
3207f30e825dSToby Isaac }
3208f30e825dSToby Isaac 
3209*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3210*d71ae5a4SJacob Faibussowitsch {
3211f30e825dSToby Isaac   PetscDS        ds;
3212f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3213f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3214c6154584SToby Isaac   PetscSection   refConSec, refSection;
3215f30e825dSToby Isaac 
3216f30e825dSToby Isaac   PetscFunctionBegin;
3217f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3218f30e825dSToby Isaac   *childrenMats     = NULL;
32199566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
32209566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
32219566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
32229566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
32239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3224f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3225f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3226f30e825dSToby Isaac 
32279566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
32289566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
32299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3230f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3231f30e825dSToby Isaac 
3232f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3233f30e825dSToby Isaac       PetscInt cDof;
3234f30e825dSToby Isaac 
3235f30e825dSToby Isaac       if (numFields > 1) {
32369566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
32379371c9d4SSatish Balay       } else {
32389566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3239f30e825dSToby Isaac       }
3240f30e825dSToby Isaac 
32419566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3242f30e825dSToby Isaac     }
32439566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3244f30e825dSToby Isaac   }
32459566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
3246f30e825dSToby Isaac   PetscFunctionReturn(0);
3247f30e825dSToby Isaac }
3248f30e825dSToby Isaac 
3249*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree, Mat *injRef)
3250*d71ae5a4SJacob Faibussowitsch {
3251ebf164c7SToby Isaac   Mat         cMatRef;
32526148253fSToby Isaac   PetscObject injRefObj;
32538d2f55e7SToby Isaac 
3254154bca37SToby Isaac   PetscFunctionBegin;
32559566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, NULL, &cMatRef, NULL));
32569566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", &injRefObj));
3257ebf164c7SToby Isaac   *injRef = (Mat)injRefObj;
3258ebf164c7SToby Isaac   if (!*injRef) {
32599566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorReferenceTree(refTree, injRef));
32609566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", (PetscObject)*injRef));
3261ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
32629566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3263ebf164c7SToby Isaac   }
3264ebf164c7SToby Isaac   PetscFunctionReturn(0);
32656148253fSToby Isaac }
3266f30e825dSToby Isaac 
3267*d71ae5a4SJacob 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)
3268*d71ae5a4SJacob Faibussowitsch {
3269c921d74cSToby Isaac   PetscInt        pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3270ebf164c7SToby Isaac   PetscSection    globalCoarse, globalFine;
3271ebf164c7SToby Isaac   PetscSection    localCoarse, localFine, leafIndicesSec;
3272c921d74cSToby Isaac   PetscSection    multiRootSec, rootIndicesSec;
3273c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3274c921d74cSToby Isaac   const PetscInt *rootDegrees;
3275c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3276ebf164c7SToby Isaac   PetscSF         coarseToFineEmbedded;
3277ebf164c7SToby Isaac 
3278ebf164c7SToby Isaac   PetscFunctionBegin;
32799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
32809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
32819566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
32829566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
32839566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
32849566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafIndicesSec, pStartF, pEndF));
32859566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
32868d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
32877e96bdafSToby Isaac     PetscInt        l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
32887e96bdafSToby Isaac     const PetscInt *leaves;
32898d2f55e7SToby Isaac 
32909566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
32917e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
32927e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
32939566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
32949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
32958d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
32968d2f55e7SToby Isaac         numPointsWithDofs++;
3297f30e825dSToby Isaac 
32989566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localFine, p, &dof));
32999566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafIndicesSec, p, dof + 1));
33008d2f55e7SToby Isaac       }
33018d2f55e7SToby Isaac     }
33029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
33039566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafIndicesSec));
33049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numIndices));
33059566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1), &leafInds));
33069566063dSJacob Faibussowitsch     if (gatheredValues) PetscCall(PetscMalloc1(numIndices, &leafVals));
33077e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
33087e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
33099566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
33109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
33118d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3312f30e825dSToby Isaac         PetscInt     off, gOff;
3313f30e825dSToby Isaac         PetscInt    *pInd;
3314c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3315f30e825dSToby Isaac 
33167e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3317f30e825dSToby Isaac 
33189566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3319f30e825dSToby Isaac 
3320c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3321c921d74cSToby Isaac         if (gatheredValues) {
3322c921d74cSToby Isaac           PetscInt i;
3323c921d74cSToby Isaac 
3324c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3325c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3326c921d74cSToby Isaac         }
33279566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
3328f30e825dSToby Isaac 
3329f30e825dSToby Isaac         offsets[0] = 0;
3330f30e825dSToby Isaac         if (numFields) {
3331f30e825dSToby Isaac           PetscInt f;
3332f30e825dSToby Isaac 
3333f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3334f30e825dSToby Isaac             PetscInt fDof;
33359566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localFine, p, f, &fDof));
3336f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3337f30e825dSToby Isaac           }
33389566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
3339367003a6SStefano Zampini         } else {
33409566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
3341f30e825dSToby Isaac         }
33429566063dSJacob Faibussowitsch         if (gatheredValues) PetscCall(VecGetValues(fineVec, dof, pInd, pVal));
33438d2f55e7SToby Isaac       }
33448d2f55e7SToby Isaac     }
33459566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
33469566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
33478d2f55e7SToby Isaac   }
3348f30e825dSToby Isaac 
33499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
33509566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
33519566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3352f30e825dSToby Isaac 
33536148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
33546148253fSToby Isaac     MPI_Datatype threeInt;
33556148253fSToby Isaac     PetscMPIInt  rank;
33566148253fSToby Isaac     PetscInt(*parentNodeAndIdCoarse)[3];
33576148253fSToby Isaac     PetscInt(*parentNodeAndIdFine)[3];
33586148253fSToby Isaac     PetscInt           p, nleaves, nleavesToParents;
33596148253fSToby Isaac     PetscSF            pointSF, sfToParents;
33606148253fSToby Isaac     const PetscInt    *ilocal;
33616148253fSToby Isaac     const PetscSFNode *iremote;
33626148253fSToby Isaac     PetscSFNode       *iremoteToParents;
33636148253fSToby Isaac     PetscInt          *ilocalToParents;
33646148253fSToby Isaac 
33659566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse), &rank));
33669566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &threeInt));
33679566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&threeInt));
33689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEndC - pStartC, &parentNodeAndIdCoarse, pEndF - pStartF, &parentNodeAndIdFine));
33699566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(coarse, &pointSF));
33709566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, &iremote));
33716148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
33726148253fSToby Isaac       PetscInt parent, childId;
33739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(coarse, p, &parent, &childId));
33746148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
33756148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
33766148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
33776148253fSToby Isaac       if (nleaves > 0) {
33786148253fSToby Isaac         PetscInt leaf = -1;
33796148253fSToby Isaac 
33806148253fSToby Isaac         if (ilocal) {
33819566063dSJacob Faibussowitsch           PetscCall(PetscFindInt(parent, nleaves, ilocal, &leaf));
33829371c9d4SSatish Balay         } else {
33836148253fSToby Isaac           leaf = p - pStartC;
33846148253fSToby Isaac         }
33856148253fSToby Isaac         if (leaf >= 0) {
33866148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
33876148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
33886148253fSToby Isaac         }
33896148253fSToby Isaac       }
33906148253fSToby Isaac     }
33916148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
33926148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
33936148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
33946148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
33956148253fSToby Isaac     }
33969566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
33979566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
33986148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3399f30e825dSToby Isaac       PetscInt dof;
3400f30e825dSToby Isaac 
34019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &dof));
3402f30e825dSToby Isaac       if (dof) {
3403f30e825dSToby Isaac         PetscInt off;
3404f30e825dSToby Isaac 
34059566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3406c921d74cSToby Isaac         if (gatheredIndices) {
3407c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3408c921d74cSToby Isaac         } else if (gatheredValues) {
3409c921d74cSToby Isaac           leafVals[off] = (PetscScalar)PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3410c921d74cSToby Isaac         }
3411f30e825dSToby Isaac       }
3412ad540459SPierre Jolivet       if (parentNodeAndIdFine[p - pStartF][0] >= 0) nleavesToParents++;
34136148253fSToby Isaac     }
34149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &ilocalToParents));
34159566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &iremoteToParents));
34166148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
34176148253fSToby Isaac       if (parentNodeAndIdFine[p - pStartF][0] >= 0) {
34186148253fSToby Isaac         ilocalToParents[nleavesToParents]        = p - pStartF;
34196148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p - pStartF][0];
34206148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p - pStartF][1];
34216148253fSToby Isaac         nleavesToParents++;
34226148253fSToby Isaac       }
34236148253fSToby Isaac     }
34249566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse), &sfToParents));
34259566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(sfToParents, pEndC - pStartC, nleavesToParents, ilocalToParents, PETSC_OWN_POINTER, iremoteToParents, PETSC_OWN_POINTER));
34269566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34276148253fSToby Isaac 
34286148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
34296148253fSToby Isaac 
34309566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parentNodeAndIdCoarse, parentNodeAndIdFine));
34319566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&threeInt));
34326148253fSToby Isaac   }
3433f30e825dSToby Isaac 
34346148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
34356148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
34366148253fSToby Isaac     PetscSF  sfDofsOnly;
34376148253fSToby Isaac 
34386148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
34399566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34409566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3441ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
34426148253fSToby Isaac     }
34439566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
34446148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
34459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34469566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3447ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = p - pStartC;
34486148253fSToby Isaac     }
34499566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
34509566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34519566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
34526148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
34536148253fSToby Isaac   }
3454f30e825dSToby Isaac 
34556148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
34569566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded, &rootDegrees));
34579566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded, &rootDegrees));
34589566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &multiRootSec));
34599566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(multiRootSec, pStartC, pEndC));
346048a46eb9SPierre Jolivet   for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionSetDof(multiRootSec, p, rootDegrees[p - pStartC]));
34619566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(multiRootSec));
34629566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(multiRootSec, &numMulti));
34639566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
3464f30e825dSToby Isaac   { /* distribute the leaf section */
3465f30e825dSToby Isaac     PetscSF   multi, multiInv, indicesSF;
3466f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
34678d2f55e7SToby Isaac 
34689566063dSJacob Faibussowitsch     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded, &multi));
34699566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF(multi, &multiInv));
34709566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(multiInv, leafIndicesSec, &remoteOffsets, rootIndicesSec));
34719566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(multiInv, leafIndicesSec, remoteOffsets, rootIndicesSec, &indicesSF));
34729566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
34739566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&multiInv));
34749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
3475c921d74cSToby Isaac     if (gatheredIndices) {
34769566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootInds));
34779566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
34789566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3479c921d74cSToby Isaac     }
3480c921d74cSToby Isaac     if (gatheredValues) {
34819566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootVals));
34829566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
34839566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3484c921d74cSToby Isaac     }
34859566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
34868d2f55e7SToby Isaac   }
34879566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
34889566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafInds));
34899566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafVals));
34909566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3491c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3492c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3493c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3494c921d74cSToby Isaac   if (gatheredValues) *gatheredValues = rootVals;
3495ebf164c7SToby Isaac   PetscFunctionReturn(0);
3496ebf164c7SToby Isaac }
3497ebf164c7SToby Isaac 
3498*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3499*d71ae5a4SJacob Faibussowitsch {
3500ebf164c7SToby Isaac   DM             refTree;
3501c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3502ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3503ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3504ebf164c7SToby Isaac   PetscSection   cSecRef;
3505277f51e8SBarry Smith   PetscInt      *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3506ebf164c7SToby Isaac   Mat            injRef;
3507c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3508ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3509ebf164c7SToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
3510ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3511ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3512ebf164c7SToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3513ebf164c7SToby Isaac 
3514ebf164c7SToby Isaac   PetscFunctionBegin;
3515ebf164c7SToby Isaac 
3516ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
35179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
35189566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
35199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
35209566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
3521ebf164c7SToby Isaac 
35229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
35239566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
35249566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
35259566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
35269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
35279566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
35289566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
35299566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
3530ebf164c7SToby Isaac   {
3531ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
35329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
3533ebf164c7SToby Isaac   }
3534ebf164c7SToby Isaac 
35359566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, childIds, NULL, numFields, offsets, &multiRootSec, &rootIndicesSec, &rootIndices, NULL));
35368d2f55e7SToby Isaac 
35379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &parentIndices));
3538f30e825dSToby Isaac 
3539f30e825dSToby Isaac   /* count indices */
35409566063dSJacob Faibussowitsch   PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
35419566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
35429566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
35439566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
35449566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
35459566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(rowEnd - rowStart, &nnzD, rowEnd - rowStart, &nnzO));
3546f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3547f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
35488d2f55e7SToby Isaac 
35499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
35509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3551f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
35529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
35538d2f55e7SToby Isaac 
35548d2f55e7SToby Isaac     rowOffsets[0]  = 0;
3555f30e825dSToby Isaac     offsetsCopy[0] = 0;
35568d2f55e7SToby Isaac     if (numFields) {
35578d2f55e7SToby Isaac       PetscInt f;
35588d2f55e7SToby Isaac 
3559f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3560f30e825dSToby Isaac         PetscInt fDof;
35619566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3562f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
35638d2f55e7SToby Isaac       }
35649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3565367003a6SStefano Zampini     } else {
35669566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3567f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
35688d2f55e7SToby Isaac     }
3569f30e825dSToby Isaac 
35709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
35719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3572f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3573f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3574f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3575f30e825dSToby Isaac       const PetscInt *childIndices;
3576f30e825dSToby Isaac 
35779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
35789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3579f30e825dSToby Isaac       childId      = rootIndices[offset++];
3580f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3581f30e825dSToby Isaac       numIndices--;
3582f30e825dSToby Isaac 
3583f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3584f30e825dSToby Isaac         PetscInt i;
3585f30e825dSToby Isaac 
3586f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3587f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3588f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3589f30e825dSToby Isaac           if (rowIndex < 0) continue;
359008401ef6SPierre Jolivet           PetscCheck(colIndex >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unconstrained fine and constrained coarse");
3591a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3592f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
35939371c9d4SSatish Balay           } else {
3594f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3595f30e825dSToby Isaac           }
3596f30e825dSToby Isaac         }
35979371c9d4SSatish Balay       } else {
3598f30e825dSToby Isaac         PetscInt parentId, f, lim;
3599f30e825dSToby Isaac 
36009566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3601f30e825dSToby Isaac 
3602f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3603f30e825dSToby Isaac         offsets[0] = 0;
36048d2f55e7SToby Isaac         if (numFields) {
36058d2f55e7SToby Isaac           PetscInt f;
3606f30e825dSToby Isaac 
36078d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3608f30e825dSToby Isaac             PetscInt fDof;
36099566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3610f30e825dSToby Isaac 
3611f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
36128d2f55e7SToby Isaac           }
36139371c9d4SSatish Balay         } else {
3614f30e825dSToby Isaac           PetscInt cDof;
3615f30e825dSToby Isaac 
36169566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3617f30e825dSToby Isaac           offsets[1] = cDof;
3618f30e825dSToby Isaac         }
3619f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3620f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3621f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3622f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3623f30e825dSToby Isaac 
3624f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3625f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3626f30e825dSToby Isaac 
3627f30e825dSToby Isaac             if (colIndex < 0) continue;
3628f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3629f30e825dSToby Isaac               numD++;
36309371c9d4SSatish Balay             } else {
3631f30e825dSToby Isaac               numO++;
3632f30e825dSToby Isaac             }
3633f30e825dSToby Isaac           }
3634f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3635f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3636f30e825dSToby Isaac 
3637f30e825dSToby Isaac             if (rowIndex < 0) continue;
3638f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3639f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
36408d2f55e7SToby Isaac           }
36418d2f55e7SToby Isaac         }
36428d2f55e7SToby Isaac       }
3643f30e825dSToby Isaac     }
3644f30e825dSToby Isaac   }
3645f30e825dSToby Isaac   /* preallocate */
36469566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mat, 1, nnzD, nnzO, NULL, NULL));
36479566063dSJacob Faibussowitsch   PetscCall(PetscFree2(nnzD, nnzO));
3648f30e825dSToby Isaac   /* insert values */
36499566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3650f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3651f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3652f30e825dSToby Isaac 
36539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
36549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3655f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
36569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
3657f30e825dSToby Isaac 
3658f30e825dSToby Isaac     rowOffsets[0]  = 0;
3659f30e825dSToby Isaac     offsetsCopy[0] = 0;
36608d2f55e7SToby Isaac     if (numFields) {
36618d2f55e7SToby Isaac       PetscInt f;
3662f30e825dSToby Isaac 
36638d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3664f30e825dSToby Isaac         PetscInt fDof;
36659566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3666f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3667f30e825dSToby Isaac       }
36689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3669367003a6SStefano Zampini     } else {
36709566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3671f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3672f30e825dSToby Isaac     }
3673f30e825dSToby Isaac 
36749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
36759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3676f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3677f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3678f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3679f30e825dSToby Isaac       const PetscInt *childIndices;
3680f30e825dSToby Isaac 
36819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
36829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3683f30e825dSToby Isaac       childId      = rootIndices[offset++];
3684f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3685f30e825dSToby Isaac       numIndices--;
3686f30e825dSToby Isaac 
3687f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3688f30e825dSToby Isaac         PetscInt i;
3689f30e825dSToby Isaac 
369048a46eb9SPierre Jolivet         for (i = 0; i < numIndices; i++) PetscCall(MatSetValue(mat, parentIndices[i], childIndices[i], 1., INSERT_VALUES));
36919371c9d4SSatish Balay       } else {
3692f30e825dSToby Isaac         PetscInt parentId, f, lim;
36938d2f55e7SToby Isaac 
36949566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3695f30e825dSToby Isaac 
3696f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3697f30e825dSToby Isaac         offsets[0] = 0;
36988d2f55e7SToby Isaac         if (numFields) {
3699f30e825dSToby Isaac           PetscInt f;
37008d2f55e7SToby Isaac 
3701f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3702f30e825dSToby Isaac             PetscInt fDof;
37039566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3704f30e825dSToby Isaac 
3705f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
37068d2f55e7SToby Isaac           }
37079371c9d4SSatish Balay         } else {
3708f30e825dSToby Isaac           PetscInt cDof;
3709f30e825dSToby Isaac 
37109566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3711f30e825dSToby Isaac           offsets[1] = cDof;
37128d2f55e7SToby Isaac         }
3713f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3714f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3715f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3716f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3717f30e825dSToby Isaac 
37189566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat, rowOffsets[f + 1] - rowOffsets[f], rowIndices, offsets[f + 1] - offsets[f], colIndices, childMat, INSERT_VALUES));
37198d2f55e7SToby Isaac         }
37208d2f55e7SToby Isaac       }
37218d2f55e7SToby Isaac     }
37228d2f55e7SToby Isaac   }
37239566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
37249566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
37259566063dSJacob Faibussowitsch   PetscCall(PetscFree(parentIndices));
37269566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
37279566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootIndices));
37289566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
3729f30e825dSToby Isaac 
37309566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
37319566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
3732154bca37SToby Isaac   PetscFunctionReturn(0);
3733154bca37SToby Isaac }
373438fc2455SToby Isaac 
3735*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3736*d71ae5a4SJacob Faibussowitsch {
373762095d54SToby Isaac   PetscSF            coarseToFineEmbedded;
373862095d54SToby Isaac   PetscSection       globalCoarse, globalFine;
373962095d54SToby Isaac   PetscSection       localCoarse, localFine;
374062095d54SToby Isaac   PetscSection       aSec, cSec;
374162095d54SToby Isaac   PetscSection       rootValuesSec;
374262095d54SToby Isaac   PetscSection       leafValuesSec;
374362095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
374462095d54SToby Isaac   IS                 aIS;
374562095d54SToby Isaac   const PetscInt    *anchors;
374662095d54SToby Isaac   Mat                cMat;
374762095d54SToby Isaac   PetscInt           numFields;
3748412e9a14SMatthew G. Knepley   PetscInt           pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
374962095d54SToby Isaac   PetscInt           aStart, aEnd, cStart, cEnd;
375062095d54SToby Isaac   PetscInt          *maxChildIds;
375162095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
37520eb7e1eaSToby Isaac   PetscFV            fv = NULL;
37530eb7e1eaSToby Isaac   PetscInt           dim, numFVcomps = -1, fvField = -1;
37540eb7e1eaSToby Isaac   DM                 cellDM = NULL, gradDM = NULL;
37550eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
37560eb7e1eaSToby Isaac   const PetscScalar *gradArray     = NULL;
375762095d54SToby Isaac 
3758ebf164c7SToby Isaac   PetscFunctionBegin;
37599566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
37609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
37619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(coarse, 0, &cellStart, &cellEnd));
37629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
37639566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
37649566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(coarse, &dim));
376562095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3766e4a60869SToby Isaac     PetscInt        nleaves, l;
3767e4a60869SToby Isaac     const PetscInt *leaves;
376862095d54SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
376962095d54SToby Isaac 
37709566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
3771e4a60869SToby Isaac 
3772e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3773e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3774e4a60869SToby Isaac 
37759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3777ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
377862095d54SToby Isaac     }
37799566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
37804833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
3781e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3782e4a60869SToby Isaac 
37839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37849566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3785ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
378662095d54SToby Isaac     }
37879566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
37889566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
378962095d54SToby Isaac   }
379062095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
37919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
3792ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
37939566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
37949566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
379562095d54SToby Isaac 
37969566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
37979566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
379862095d54SToby Isaac 
37999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
38009566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
38019566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
380262095d54SToby Isaac 
38039566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
38049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
380562095d54SToby Isaac 
380662095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
38079566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootValuesSec));
38089566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootValuesSec, pStartC, pEndC));
38099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
381062095d54SToby Isaac   {
381162095d54SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
38129566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &newOffsets, maxFields, &newOffsetsCopy, maxFields, &rowOffsets, maxFields, &numD, maxFields, &numO));
381362095d54SToby Isaac   }
38140eb7e1eaSToby Isaac   if (grad) {
38150eb7e1eaSToby Isaac     PetscInt i;
38160eb7e1eaSToby Isaac 
38179566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeom, &cellDM));
38189566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeom, &cellGeomArray));
38199566063dSJacob Faibussowitsch     PetscCall(VecGetDM(grad, &gradDM));
38209566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(grad, &gradArray));
38210eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1, numFields); i++) {
38220eb7e1eaSToby Isaac       PetscObject  obj;
38230eb7e1eaSToby Isaac       PetscClassId id;
38240eb7e1eaSToby Isaac 
38259566063dSJacob Faibussowitsch       PetscCall(DMGetField(coarse, i, NULL, &obj));
38269566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
38270eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
38280eb7e1eaSToby Isaac         fv = (PetscFV)obj;
38299566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &numFVcomps));
38300eb7e1eaSToby Isaac         fvField = i;
38310eb7e1eaSToby Isaac         break;
38320eb7e1eaSToby Isaac       }
38330eb7e1eaSToby Isaac     }
38340eb7e1eaSToby Isaac   }
383562095d54SToby Isaac 
383662095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
383762095d54SToby Isaac     PetscInt dof;
383862095d54SToby Isaac     PetscInt maxChildId = maxChildIds[p - pStartC];
383962095d54SToby Isaac     PetscInt numValues  = 0;
384062095d54SToby Isaac 
38419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3842ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
384362095d54SToby Isaac     offsets[0]    = 0;
384462095d54SToby Isaac     newOffsets[0] = 0;
384562095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
384662095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
384762095d54SToby Isaac 
38489566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
384962095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
385062095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
385162095d54SToby Isaac 
38529566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
385362095d54SToby Isaac         numValues += clDof;
385462095d54SToby Isaac       }
38559566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
38569371c9d4SSatish Balay     } else if (maxChildId == -1) {
38579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localCoarse, p, &numValues));
385862095d54SToby Isaac     }
385962095d54SToby Isaac     /* we will pack the column indices with the field offsets */
386078b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
38610eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
38620eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
38630eb7e1eaSToby Isaac     }
38649566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootValuesSec, p, numValues));
386562095d54SToby Isaac   }
38669566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootValuesSec));
386762095d54SToby Isaac   {
386862095d54SToby Isaac     PetscInt           numRootValues;
386962095d54SToby Isaac     const PetscScalar *coarseArray;
387062095d54SToby Isaac 
38719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootValuesSec, &numRootValues));
38729566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRootValues, &rootValues));
38739566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecCoarseLocal, &coarseArray));
387462095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
387562095d54SToby Isaac       PetscInt     numValues;
387662095d54SToby Isaac       PetscInt     pValOff;
387762095d54SToby Isaac       PetscScalar *pVal;
387862095d54SToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
387962095d54SToby Isaac 
38809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootValuesSec, p, &numValues));
3881ad540459SPierre Jolivet       if (!numValues) continue;
38829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootValuesSec, p, &pValOff));
388362095d54SToby Isaac       pVal = &(rootValues[pValOff]);
388462095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
38850eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
38869566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(coarse, NULL, vecCoarseLocal, p, &closureSize, &pVal));
38870eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
3888193eb951SToby Isaac           PetscFVCellGeom *cg;
38896dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
38900eb7e1eaSToby Isaac           PetscInt         i;
38910eb7e1eaSToby Isaac 
38920eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
38930eb7e1eaSToby Isaac 
38949566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(cellDM, p, cellGeomArray, (void *)&cg));
38950eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
38960eb7e1eaSToby Isaac           pVal += dim;
38979566063dSJacob Faibussowitsch           PetscCall(DMPlexPointGlobalRead(gradDM, p, gradArray, (void *)&gradVals));
38980eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
38990eb7e1eaSToby Isaac         }
39009371c9d4SSatish Balay       } else if (maxChildId == -1) {
390178b7adb5SToby Isaac         PetscInt lDof, lOff, i;
390278b7adb5SToby Isaac 
39039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, p, &lDof));
39049566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(localCoarse, p, &lOff));
390578b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
390678b7adb5SToby Isaac       }
390778b7adb5SToby Isaac     }
39089566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecCoarseLocal, &coarseArray));
39099566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
391062095d54SToby Isaac   }
391162095d54SToby Isaac   {
391262095d54SToby Isaac     PetscSF   valuesSF;
391362095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
391462095d54SToby Isaac 
39159566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafValuesSec));
39169566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootValuesSec, &remoteOffsetsValues, leafValuesSec));
39179566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootValuesSec, remoteOffsetsValues, leafValuesSec, &valuesSF));
39189566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
39199566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsValues));
39209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafValuesSec, &numLeafValues));
39219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafValues, &leafValues));
39229566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39239566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39249566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&valuesSF));
39259566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootValues));
39269566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootValuesSec));
392762095d54SToby Isaac   }
39289566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
392962095d54SToby Isaac   {
393062095d54SToby Isaac     PetscInt       maxDof;
393162095d54SToby Isaac     PetscInt      *rowIndices;
393262095d54SToby Isaac     DM             refTree;
393362095d54SToby Isaac     PetscInt     **refPointFieldN;
393462095d54SToby Isaac     PetscScalar ***refPointFieldMats;
393562095d54SToby Isaac     PetscSection   refConSec, refAnSec;
39360eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, leafStart, leafEnd;
393762095d54SToby Isaac     PetscScalar   *pointWork;
393862095d54SToby Isaac 
39399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
39409566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
39419566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
39429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
39439566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(fine, refTree));
39449566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
39459566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
39469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
39479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
39489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafValuesSec, &leafStart, &leafEnd));
39499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSimplexOrBoxCells(fine, 0, &cellStart, &cellEnd));
39500eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
395162095d54SToby Isaac       PetscInt           gDof, gcDof, gOff, lDof;
395262095d54SToby Isaac       PetscInt           numValues, pValOff;
395362095d54SToby Isaac       PetscInt           childId;
395462095d54SToby Isaac       const PetscScalar *pVal;
39550eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
395662095d54SToby Isaac 
39579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
39589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localFine, p, &lDof));
39599566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
3960ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
39619566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
39629566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafValuesSec, p, &numValues));
396362095d54SToby Isaac       if (!numValues) continue;
39649566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafValuesSec, p, &pValOff));
396562095d54SToby Isaac       pVal              = &leafValues[pValOff];
396662095d54SToby Isaac       offsets[0]        = 0;
396762095d54SToby Isaac       offsetsCopy[0]    = 0;
396862095d54SToby Isaac       newOffsets[0]     = 0;
396962095d54SToby Isaac       newOffsetsCopy[0] = 0;
39704833aeb0SToby Isaac       childId           = cids[p - pStartF];
397162095d54SToby Isaac       if (numFields) {
397262095d54SToby Isaac         PetscInt f;
397362095d54SToby Isaac         for (f = 0; f < numFields; f++) {
397462095d54SToby Isaac           PetscInt rowDof;
397562095d54SToby Isaac 
39769566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
397762095d54SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
397862095d54SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
397962095d54SToby Isaac           /* TODO: closure indices */
39809f4e70e1SToby Isaac           newOffsets[f + 1] = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
398162095d54SToby Isaac         }
39829566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
39839371c9d4SSatish Balay       } else {
39844833aeb0SToby Isaac         offsets[0]    = 0;
39854833aeb0SToby Isaac         offsets[1]    = lDof;
39864833aeb0SToby Isaac         newOffsets[0] = 0;
39874833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
39889566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
398962095d54SToby Isaac       }
399062095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
39919566063dSJacob Faibussowitsch         PetscCall(VecSetValues(vecFine, numValues, rowIndices, pVal, INSERT_VALUES));
399262095d54SToby Isaac       } else {
399362095d54SToby Isaac         PetscInt f;
399462095d54SToby Isaac 
399578b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
399678b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
399778b7adb5SToby Isaac           fvGradData = &pVal[numValues];
399878b7adb5SToby Isaac         }
399962095d54SToby Isaac         for (f = 0; f < PetscMax(1, numFields); f++) {
400062095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
400162095d54SToby Isaac           PetscInt           numRows  = offsets[f + 1] - offsets[f];
400262095d54SToby Isaac           PetscInt           numCols  = newOffsets[f + 1] - newOffsets[f];
400362095d54SToby Isaac           const PetscScalar *cVal     = &pVal[newOffsets[f]];
400462095d54SToby Isaac           PetscScalar       *rVal     = &pointWork[offsets[f]];
400562095d54SToby Isaac           PetscInt           i, j;
400662095d54SToby Isaac 
4007708c7f19SToby Isaac #if 0
400863a3b9bcSJacob 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));
4009708c7f19SToby Isaac #endif
401062095d54SToby Isaac           for (i = 0; i < numRows; i++) {
401162095d54SToby Isaac             PetscScalar val = 0.;
4012ad540459SPierre Jolivet             for (j = 0; j < numCols; j++) val += childMat[i * numCols + j] * cVal[j];
401362095d54SToby Isaac             rVal[i] = val;
401462095d54SToby Isaac           }
40150eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
40160eb7e1eaSToby Isaac             PetscReal          centroid[3];
40170eb7e1eaSToby Isaac             PetscScalar        diff[3];
40180eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
40190eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
40200eb7e1eaSToby Isaac 
40219566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFVM(fine, p, NULL, centroid, NULL));
4022ad540459SPierre Jolivet             for (i = 0; i < dim; i++) diff[i] = centroid[i] - parentCentroid[i];
40230eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
40240eb7e1eaSToby Isaac               PetscScalar val = 0.;
40250eb7e1eaSToby Isaac 
4026ad540459SPierre Jolivet               for (j = 0; j < dim; j++) val += gradient[dim * i + j] * diff[j];
40270eb7e1eaSToby Isaac               rVal[i] += val;
40280eb7e1eaSToby Isaac             }
40290eb7e1eaSToby Isaac           }
40309566063dSJacob Faibussowitsch           PetscCall(VecSetValues(vecFine, numRows, &rowIndices[offsets[f]], rVal, INSERT_VALUES));
403162095d54SToby Isaac         }
403262095d54SToby Isaac       }
403362095d54SToby Isaac     }
40349566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
40359566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
40369566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
403762095d54SToby Isaac   }
40389566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafValues));
40399566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafValuesSec));
40409566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
40419566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
4042ebf164c7SToby Isaac   PetscFunctionReturn(0);
4043ebf164c7SToby Isaac }
4044ebf164c7SToby Isaac 
4045*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4046*d71ae5a4SJacob Faibussowitsch {
4047c921d74cSToby Isaac   DM             refTree;
4048c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4049c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4050c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4051c921d74cSToby Isaac   PetscSection   cSecRef;
4052c921d74cSToby Isaac   PetscInt      *parentIndices, pRefStart, pRefEnd;
4053d3bc4906SToby Isaac   PetscScalar   *rootValues, *parentValues;
4054c921d74cSToby Isaac   Mat            injRef;
4055c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4056c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4057c921d74cSToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
4058c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4059c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4060c921d74cSToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4061c921d74cSToby Isaac 
4062ebf164c7SToby Isaac   PetscFunctionBegin;
4063c921d74cSToby Isaac 
4064c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
40659566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40669566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecCoarse, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
40689566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(coarse, refTree));
40699566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
40709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
40719566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
4072c921d74cSToby Isaac 
40739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
40749566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
40759566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
40769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
40779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
40789566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
40799566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
40809566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
4081c921d74cSToby Isaac   {
4082c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
40839566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
4084c921d74cSToby Isaac   }
4085c921d74cSToby Isaac 
40869566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, cids, vecFine, numFields, offsets, &multiRootSec, &rootIndicesSec, NULL, &rootValues));
4087c921d74cSToby Isaac 
40889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxDof, &parentIndices, maxDof, &parentValues));
4089c921d74cSToby Isaac 
4090c921d74cSToby Isaac   /* count indices */
40919566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecFine, &colMap));
40929566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecCoarse, &rowMap));
40939566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
40949566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
40959566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
40969566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
4097c921d74cSToby Isaac   /* insert values */
40989566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4099c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4100c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
410178b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4102c921d74cSToby Isaac 
41039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
41049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
4105c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
41069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localCoarse, p, &dof));
41079566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
4108c921d74cSToby Isaac 
4109c921d74cSToby Isaac     rowOffsets[0]  = 0;
4110c921d74cSToby Isaac     offsetsCopy[0] = 0;
4111c921d74cSToby Isaac     if (numFields) {
4112c921d74cSToby Isaac       PetscInt f;
4113c921d74cSToby Isaac 
4114c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4115c921d74cSToby Isaac         PetscInt fDof;
41169566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
4117c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4118c921d74cSToby Isaac       }
41199566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
4120367003a6SStefano Zampini     } else {
41219566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
4122c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4123c921d74cSToby Isaac     }
4124c921d74cSToby Isaac 
41259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
41269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
4127c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
41282f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4129c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4130c921d74cSToby Isaac       PetscInt           numIndices, childId, offset;
4131c921d74cSToby Isaac       const PetscScalar *childValues;
4132c921d74cSToby Isaac 
41339566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
41349566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
4135c921d74cSToby Isaac       childId     = (PetscInt)PetscRealPart(rootValues[offset++]);
4136c921d74cSToby Isaac       childValues = &rootValues[offset];
4137c921d74cSToby Isaac       numIndices--;
4138c921d74cSToby Isaac 
4139c921d74cSToby Isaac       if (childId == -2) { /* skip */
4140c921d74cSToby Isaac         continue;
4141c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
41422f65e181SToby Isaac         PetscInt m;
41432f65e181SToby Isaac 
414478b7adb5SToby Isaac         contribute = PETSC_TRUE;
41452f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4146beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4147d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4148d3bc4906SToby Isaac 
414978b7adb5SToby Isaac         contribute = PETSC_TRUE;
41509566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
4151d3bc4906SToby Isaac 
4152d3bc4906SToby Isaac         lim        = PetscMax(1, numFields);
4153d3bc4906SToby Isaac         offsets[0] = 0;
4154d3bc4906SToby Isaac         if (numFields) {
4155d3bc4906SToby Isaac           PetscInt f;
4156d3bc4906SToby Isaac 
4157d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4158d3bc4906SToby Isaac             PetscInt fDof;
41599566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
4160d3bc4906SToby Isaac 
4161d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4162d3bc4906SToby Isaac           }
41639371c9d4SSatish Balay         } else {
4164d3bc4906SToby Isaac           PetscInt cDof;
4165d3bc4906SToby Isaac 
41669566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
4167d3bc4906SToby Isaac           offsets[1] = cDof;
4168d3bc4906SToby Isaac         }
4169d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4170d3bc4906SToby Isaac           PetscScalar       *childMat = &childrenMats[childId - pRefStart][f][0];
4171d3bc4906SToby Isaac           PetscInt           n        = offsets[f + 1] - offsets[f];
4172e328ff09SToby Isaac           PetscInt           m        = rowOffsets[f + 1] - rowOffsets[f];
4173d3bc4906SToby Isaac           PetscInt           i, j;
4174d3bc4906SToby Isaac           const PetscScalar *colValues = &childValues[offsets[f]];
4175d3bc4906SToby Isaac 
4176e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4177d3bc4906SToby Isaac             PetscScalar val = 0.;
4178ad540459SPierre Jolivet             for (j = 0; j < n; j++) val += childMat[n * i + j] * colValues[j];
4179e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4180d3bc4906SToby Isaac           }
4181d3bc4906SToby Isaac         }
4182c921d74cSToby Isaac       }
4183c921d74cSToby Isaac     }
41849566063dSJacob Faibussowitsch     if (contribute) PetscCall(VecSetValues(vecCoarse, dof, parentIndices, parentValues, INSERT_VALUES));
4185c921d74cSToby Isaac   }
41869566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
41879566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
41889566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parentIndices, parentValues));
41899566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
41909566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootValues));
41919566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
4192ebf164c7SToby Isaac   PetscFunctionReturn(0);
4193ebf164c7SToby Isaac }
4194ebf164c7SToby Isaac 
4195ff1f73f7SToby Isaac /*@
4196ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4197ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4198ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4199ff1f73f7SToby Isaac 
4200ff1f73f7SToby Isaac   collective
4201ff1f73f7SToby Isaac 
4202ff1f73f7SToby Isaac   Input Parameters:
4203ff1f73f7SToby Isaac + dmIn        - The DMPlex mesh for the input vector
4204ff1f73f7SToby Isaac . vecIn       - The input vector
4205ff1f73f7SToby Isaac . sfRefine    - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4206ff1f73f7SToby Isaac                 the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4207ff1f73f7SToby Isaac . sfCoarsen   - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4208ff1f73f7SToby Isaac                 the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4209ff1f73f7SToby Isaac . cidsRefine  - The childIds of the points in dmOut.  These childIds relate back to the reference tree: childid[j] = k implies
4210ff1f73f7SToby Isaac                 that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4211ff1f73f7SToby Isaac                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in dmOut is exactly
4212ff1f73f7SToby Isaac                 equivalent to its root in dmIn, so no interpolation is necessary.  childid[j] = -2 indicates that this
4213ff1f73f7SToby Isaac                 point j in dmOut is not a leaf of sfRefine.
4214ff1f73f7SToby Isaac . cidsCoarsen - The childIds of the points in dmIn.  These childIds relate back to the reference tree: childid[j] = k implies
4215ff1f73f7SToby Isaac                 that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4216ff1f73f7SToby Isaac                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4217ff1f73f7SToby Isaac . useBCs      - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4218ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4219ff1f73f7SToby Isaac 
4220ff1f73f7SToby Isaac   Output Parameters:
42218966356dSPierre Jolivet . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transferred
4222ff1f73f7SToby Isaac                 projection of vecIn from dmIn to dmOut.  Note that any field discretized with a PetscFV finite volume
4223ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4224ff1f73f7SToby Isaac                 coarse points to fine points.
4225ff1f73f7SToby Isaac 
4226ff1f73f7SToby Isaac   Level: developer
4227ff1f73f7SToby Isaac 
4228db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4229ff1f73f7SToby Isaac @*/
4230*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
4231*d71ae5a4SJacob Faibussowitsch {
423238fc2455SToby Isaac   PetscFunctionBegin;
42339566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
4234ff1f73f7SToby Isaac   if (sfRefine) {
4235fbfa57b9SToby Isaac     Vec vecInLocal;
42360eb7e1eaSToby Isaac     DM  dmGrad   = NULL;
42370eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4238fbfa57b9SToby Isaac 
42399566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
42409566063dSJacob Faibussowitsch     PetscCall(VecSet(vecInLocal, 0.0));
42410eb7e1eaSToby Isaac     {
42420eb7e1eaSToby Isaac       PetscInt numFields, i;
42430eb7e1eaSToby Isaac 
42449566063dSJacob Faibussowitsch       PetscCall(DMGetNumFields(dmIn, &numFields));
42450eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
42460eb7e1eaSToby Isaac         PetscObject  obj;
42470eb7e1eaSToby Isaac         PetscClassId classid;
42480eb7e1eaSToby Isaac 
42499566063dSJacob Faibussowitsch         PetscCall(DMGetField(dmIn, i, NULL, &obj));
42509566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &classid));
42510eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
42529566063dSJacob Faibussowitsch           PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
42530eb7e1eaSToby Isaac           break;
42540eb7e1eaSToby Isaac         }
42550eb7e1eaSToby Isaac       }
42560eb7e1eaSToby Isaac     }
42571baa6e33SBarry Smith     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
42589566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42599566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42600eb7e1eaSToby Isaac     if (dmGrad) {
42619566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad, &grad));
42629566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
42630eb7e1eaSToby Isaac     }
42649566063dSJacob Faibussowitsch     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
42659566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
426648a46eb9SPierre Jolivet     if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
4267ebf164c7SToby Isaac   }
42681baa6e33SBarry Smith   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
42699566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(vecOut));
42709566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(vecOut));
427138fc2455SToby Isaac   PetscFunctionReturn(0);
427238fc2455SToby Isaac }
4273