xref: /petsc/src/dm/impls/plex/plextree.c (revision a1cb98fac0cdf0eb4d3e8a0c8b58f3fe8f800bc6)
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:
15*a1cb98faSBarry Smith + dm - The `DMPLEX` object
16*a1cb98faSBarry Smith - ref - The reference tree `DMPLEX` object
17d6a7ad0dSToby Isaac 
180b7167a0SToby Isaac   Level: intermediate
19d6a7ad0dSToby Isaac 
20*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`,`DMPlexGetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
21d6a7ad0dSToby Isaac @*/
22d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
23d71ae5a4SJacob Faibussowitsch {
24d6a7ad0dSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
25d6a7ad0dSToby Isaac 
26d6a7ad0dSToby Isaac   PetscFunctionBegin;
27d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28ad540459SPierre Jolivet   if (ref) PetscValidHeaderSpecific(ref, DM_CLASSID, 2);
299566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)ref));
309566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
31d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
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:
41*a1cb98faSBarry Smith . dm - The `DMPLEX` object
42d6a7ad0dSToby Isaac 
437a7aea1fSJed Brown   Output Parameters:
44*a1cb98faSBarry Smith . ref - The reference tree `DMPLEX` object
45d6a7ad0dSToby Isaac 
460b7167a0SToby Isaac   Level: intermediate
47d6a7ad0dSToby Isaac 
48*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
49d6a7ad0dSToby Isaac @*/
50d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
51d71ae5a4SJacob Faibussowitsch {
52d6a7ad0dSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
53d6a7ad0dSToby Isaac 
54d6a7ad0dSToby Isaac   PetscFunctionBegin;
55d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
56d6a7ad0dSToby Isaac   PetscValidPointer(ref, 2);
57d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
58d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
59d6a7ad0dSToby Isaac }
60d6a7ad0dSToby Isaac 
61d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
62d71ae5a4SJacob Faibussowitsch {
63dcbd3bf7SToby Isaac   PetscInt coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
64dcbd3bf7SToby Isaac 
65dcbd3bf7SToby Isaac   PetscFunctionBegin;
66dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
67dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
68dcbd3bf7SToby Isaac     if (childB) *childB = childA;
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:
178*a1cb98faSBarry Smith + dm - the reference tree `DMPLEX` object
179dcbd3bf7SToby Isaac . parent - the parent point
180dcbd3bf7SToby Isaac . parentOrientA - the reference orientation for describing the parent
181dcbd3bf7SToby Isaac . childOrientA - the reference orientation for describing the child
182dcbd3bf7SToby Isaac . childA - the reference childID for describing the child
183dcbd3bf7SToby Isaac - parentOrientB - the new orientation for describing the parent
184dcbd3bf7SToby Isaac 
185dcbd3bf7SToby Isaac   Output Parameters:
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 
191*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetReferenceTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetTree()`
192dcbd3bf7SToby Isaac @*/
193d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
194d71ae5a4SJacob Faibussowitsch {
195dcbd3bf7SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
196dcbd3bf7SToby Isaac 
197dcbd3bf7SToby Isaac   PetscFunctionBegin;
198dcbd3bf7SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
19928b400f6SJacob Faibussowitsch   PetscCheck(mesh->getchildsymmetry, PETSC_COMM_SELF, PETSC_ERR_SUP, "DMPlexReferenceTreeGetChildSymmetry not implemented");
2009566063dSJacob Faibussowitsch   PetscCall(mesh->getchildsymmetry(dm, parent, parentOrientA, childOrientA, childA, parentOrientB, childOrientB, childB));
201dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
202dcbd3bf7SToby Isaac }
203dcbd3bf7SToby Isaac 
204776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM, PetscSection, PetscInt *, PetscInt *, PetscBool, PetscBool);
205f9f063d4SToby Isaac 
206d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
207d71ae5a4SJacob Faibussowitsch {
208f2c1aa1dSLisandro Dalcin   PetscFunctionBegin;
2099566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_TRUE, PETSC_FALSE));
210f2c1aa1dSLisandro Dalcin   PetscFunctionReturn(0);
211f2c1aa1dSLisandro Dalcin }
212f2c1aa1dSLisandro Dalcin 
213d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
214d71ae5a4SJacob Faibussowitsch {
2150e2cc29aSToby Isaac   MPI_Comm     comm;
2160e2cc29aSToby Isaac   PetscInt     dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
217da43764aSToby Isaac   PetscInt    *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
218da43764aSToby Isaac   DMLabel      identity, identityRef;
21910f7e118SToby Isaac   PetscSection unionSection, unionConeSection, parentSection;
220da43764aSToby Isaac   PetscScalar *unionCoords;
221da43764aSToby Isaac   IS           perm;
222da43764aSToby Isaac 
223da43764aSToby Isaac   PetscFunctionBegin;
2240e2cc29aSToby Isaac   comm = PetscObjectComm((PetscObject)K);
2259566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(K, &dim));
2269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
2279566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, labelName, &identity));
2289566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(Kref, labelName, &identityRef));
2299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(Kref, &pRefStart, &pRefEnd));
2309566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionSection));
2319566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart)));
232da43764aSToby Isaac   /* count points that will go in the union */
23348a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; p++) PetscCall(PetscSectionSetDof(unionSection, p - pStart, 1));
234da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
235da43764aSToby Isaac     PetscInt q, qSize;
2369566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(identityRef, p, &q));
2379566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(identityRef, q, &qSize));
23848a46eb9SPierre Jolivet     if (qSize > 1) PetscCall(PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1));
239da43764aSToby Isaac   }
2409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart, &permvals));
241da43764aSToby Isaac   offset = 0;
242da43764aSToby Isaac   /* stratify points in the union by topological dimension */
243da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
244da43764aSToby Isaac     PetscInt cStart, cEnd, c;
245da43764aSToby Isaac 
2469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, &cEnd));
247ad540459SPierre Jolivet     for (c = cStart; c < cEnd; c++) permvals[offset++] = c;
248da43764aSToby Isaac 
2499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd));
250ad540459SPierre Jolivet     for (c = cStart; c < cEnd; c++) permvals[offset++] = c + (pEnd - pStart);
251da43764aSToby Isaac   }
2529566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm));
2539566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetPermutation(unionSection, perm));
2549566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionSection));
2559566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionSection, &numUnionPoints));
2569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numUnionPoints, &coneSizes, dim + 1, &numDimPoints));
257da43764aSToby Isaac   /* count dimension points */
258da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
259da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
2609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, NULL));
2619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff));
262da43764aSToby Isaac     if (d < dim) {
2639566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d + 1, &cStart, NULL));
2649566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff2));
2659371c9d4SSatish Balay     } else {
266da43764aSToby Isaac       cOff2 = numUnionPoints;
267da43764aSToby Isaac     }
268da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
269da43764aSToby Isaac   }
2709566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionConeSection));
2719566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(unionConeSection, 0, numUnionPoints));
272da43764aSToby Isaac   /* count the cones in the union */
273da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
274da43764aSToby Isaac     PetscInt dof, uOff;
275da43764aSToby Isaac 
2769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
2779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
2789566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
279da43764aSToby Isaac     coneSizes[uOff] = dof;
280da43764aSToby Isaac   }
281da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
282da43764aSToby Isaac     PetscInt dof, uDof, uOff;
283da43764aSToby Isaac 
2849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
2859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
2869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
287da43764aSToby Isaac     if (uDof) {
2889566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
289da43764aSToby Isaac       coneSizes[uOff] = dof;
290da43764aSToby Isaac     }
291da43764aSToby Isaac   }
2929566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionConeSection));
2939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionConeSection, &numCones));
2949566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numCones, &unionCones, numCones, &unionOrientations));
295da43764aSToby Isaac   /* write the cones in the union */
296da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
297da43764aSToby Isaac     PetscInt        dof, uOff, c, cOff;
298da43764aSToby Isaac     const PetscInt *cone, *orientation;
299da43764aSToby Isaac 
3009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
3019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(K, p, &cone));
3029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(K, p, &orientation));
3039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
3049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
305da43764aSToby Isaac     for (c = 0; c < dof; c++) {
306da43764aSToby Isaac       PetscInt e, eOff;
307da43764aSToby Isaac       e = cone[c];
3089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
309da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
310da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
311da43764aSToby Isaac     }
312da43764aSToby Isaac   }
313da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
314da43764aSToby Isaac     PetscInt        dof, uDof, uOff, c, cOff;
315da43764aSToby Isaac     const PetscInt *cone, *orientation;
316da43764aSToby Isaac 
3179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
3189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(Kref, p, &cone));
3199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(Kref, p, &orientation));
3209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
322da43764aSToby Isaac     if (uDof) {
3239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
324da43764aSToby Isaac       for (c = 0; c < dof; c++) {
325da43764aSToby Isaac         PetscInt e, eOff, eDof;
326da43764aSToby Isaac 
327da43764aSToby Isaac         e = cone[c];
3289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart), &eDof));
329da43764aSToby Isaac         if (eDof) {
3309566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff));
3319371c9d4SSatish Balay         } else {
3329566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(identityRef, e, &e));
3339566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
334da43764aSToby Isaac         }
335da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
336da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
337da43764aSToby Isaac       }
338da43764aSToby Isaac     }
339da43764aSToby Isaac   }
340da43764aSToby Isaac   /* get the coordinates */
341da43764aSToby Isaac   {
342da43764aSToby Isaac     PetscInt     vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
343da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
344da43764aSToby Isaac     Vec          KcoordsVec, KrefCoordsVec;
345da43764aSToby Isaac     PetscScalar *Kcoords;
346da43764aSToby Isaac 
3479566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(K, &KcoordsSec));
3489566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(K, &KcoordsVec));
3499566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(Kref, &KrefCoordsSec));
3509566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(Kref, &KrefCoordsVec));
351da43764aSToby Isaac 
352da43764aSToby Isaac     numVerts = numDimPoints[0];
3539566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numVerts * dim, &unionCoords));
3549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(K, 0, &vStart, &vEnd));
355da43764aSToby Isaac 
356da43764aSToby Isaac     offset = 0;
357da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
3589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, v - pStart, &vOff));
3599566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords));
360ad540459SPierre Jolivet       for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
361da43764aSToby Isaac       offset++;
362da43764aSToby Isaac     }
3639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(Kref, 0, &vRefStart, &vRefEnd));
364da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
3659566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(unionSection, v - pRefStart + (pEnd - pStart), &vDof));
3669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, v - pRefStart + (pEnd - pStart), &vOff));
3679566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords));
368da43764aSToby Isaac       if (vDof) {
369ad540459SPierre Jolivet         for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
370da43764aSToby Isaac         offset++;
371da43764aSToby Isaac       }
372da43764aSToby Isaac     }
373da43764aSToby Isaac   }
3749566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, ref));
3759566063dSJacob Faibussowitsch   PetscCall(DMSetType(*ref, DMPLEX));
3769566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ref, dim));
3779566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromDAG(*ref, dim, numDimPoints, coneSizes, unionCones, unionOrientations, unionCoords));
37810f7e118SToby Isaac   /* set the tree */
3799566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &parentSection));
3809566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(parentSection, 0, numUnionPoints));
38110f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
38210f7e118SToby Isaac     PetscInt uDof, uOff;
38310f7e118SToby Isaac 
3849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
3861baa6e33SBarry Smith     if (uDof) PetscCall(PetscSectionSetDof(parentSection, uOff, 1));
38710f7e118SToby Isaac   }
3889566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(parentSection));
3899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection, &parentSize));
3909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(parentSize, &parents, parentSize, &childIDs));
39110f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
39210f7e118SToby Isaac     PetscInt uDof, uOff;
39310f7e118SToby Isaac 
3949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
39610f7e118SToby Isaac     if (uDof) {
39710f7e118SToby Isaac       PetscInt pOff, parent, parentU;
3989566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(parentSection, uOff, &pOff));
3999566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(identityRef, p, &parent));
4009566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, parent - pStart, &parentU));
40110f7e118SToby Isaac       parents[pOff]  = parentU;
40210f7e118SToby Isaac       childIDs[pOff] = uOff;
40310f7e118SToby Isaac     }
40410f7e118SToby Isaac   }
4059566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_SetTree(*ref, parentSection, parents, childIDs));
4069566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
4079566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parents, childIDs));
40810f7e118SToby Isaac 
409da43764aSToby Isaac   /* clean up */
4109566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionSection));
4119566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionConeSection));
4129566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&perm));
4139566063dSJacob Faibussowitsch   PetscCall(PetscFree(unionCoords));
4149566063dSJacob Faibussowitsch   PetscCall(PetscFree2(unionCones, unionOrientations));
4159566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coneSizes, numDimPoints));
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:
430*a1cb98faSBarry Smith . ref     - the reference tree `DMPLEX` object
4310e2cc29aSToby Isaac 
4320e2cc29aSToby Isaac   Level: intermediate
4330e2cc29aSToby Isaac 
434db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`
4350e2cc29aSToby Isaac @*/
436d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
437d71ae5a4SJacob Faibussowitsch {
4380e2cc29aSToby Isaac   DM_Plex *mesh;
4390e2cc29aSToby Isaac   DM       K, Kref;
4400e2cc29aSToby Isaac   PetscInt p, pStart, pEnd;
4410e2cc29aSToby Isaac   DMLabel  identity;
4420e2cc29aSToby Isaac 
4430e2cc29aSToby Isaac   PetscFunctionBegin;
4440e2cc29aSToby Isaac #if 1
4450e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4460e2cc29aSToby Isaac #endif
4470e2cc29aSToby Isaac   /* create a reference element */
4489566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K));
4499566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(K, "identity"));
4509566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, "identity", &identity));
4519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
45248a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; p++) PetscCall(DMLabelSetValue(identity, p, p));
4530e2cc29aSToby Isaac   /* refine it */
4549566063dSJacob Faibussowitsch   PetscCall(DMRefine(K, comm, &Kref));
4550e2cc29aSToby Isaac 
4560e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4570e2cc29aSToby Isaac    * points that appear in both */
4589566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref));
4590e2cc29aSToby Isaac   mesh                   = (DM_Plex *)(*ref)->data;
4600e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
4619566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&K));
4629566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&Kref));
463da43764aSToby Isaac   PetscFunctionReturn(0);
464da43764aSToby Isaac }
465da43764aSToby Isaac 
466d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
467d71ae5a4SJacob Faibussowitsch {
468878b19aaSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
469878b19aaSToby Isaac   PetscSection childSec, pSec;
470878b19aaSToby Isaac   PetscInt     p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
471878b19aaSToby Isaac   PetscInt    *offsets, *children, pStart, pEnd;
472878b19aaSToby Isaac 
473878b19aaSToby Isaac   PetscFunctionBegin;
474878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4759566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
4769566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
477878b19aaSToby Isaac   pSec = mesh->parentSection;
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 
520d71ae5a4SJacob Faibussowitsch static PetscErrorCode AnchorsFlatten(PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
521d71ae5a4SJacob Faibussowitsch {
5226dd5a8c8SToby Isaac   PetscInt        pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5236dd5a8c8SToby Isaac   const PetscInt *vals;
5246dd5a8c8SToby Isaac   PetscSection    secNew;
5256dd5a8c8SToby Isaac   PetscBool       anyNew, globalAnyNew;
5266dd5a8c8SToby Isaac   PetscBool       compress;
5276dd5a8c8SToby Isaac 
5286dd5a8c8SToby Isaac   PetscFunctionBegin;
5299566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
5309566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is, &size));
5319566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is, &vals));
5329566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secNew));
5339566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(secNew, pStart, pEnd));
5346dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5356dd5a8c8SToby Isaac     PetscInt dof;
5366dd5a8c8SToby Isaac 
5376dd5a8c8SToby Isaac     p = vals[i];
5386dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
5406dd5a8c8SToby Isaac     if (dof) break;
5416dd5a8c8SToby Isaac   }
5426dd5a8c8SToby Isaac   if (i == size) {
5439566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5446dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5456dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5466dd5a8c8SToby Isaac     sizeNew  = 0;
5479371c9d4SSatish Balay   } else {
5486dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5496dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5506dd5a8c8SToby Isaac       PetscInt dof, off;
5516dd5a8c8SToby Isaac 
5529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5546dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5556dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5566dd5a8c8SToby Isaac 
55748a46eb9SPierre Jolivet         if (q >= pStart && q < pEnd) PetscCall(PetscSectionGetDof(section, q, &qDof));
5581baa6e33SBarry Smith         if (qDof) PetscCall(PetscSectionAddDof(secNew, p, qDof));
55948a46eb9SPierre Jolivet         else PetscCall(PetscSectionAddDof(secNew, p, 1));
5606dd5a8c8SToby Isaac       }
5616dd5a8c8SToby Isaac     }
5629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(secNew, &sizeNew));
5649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sizeNew, &valsNew));
5656dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5666dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5676dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
5686dd5a8c8SToby Isaac 
5699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(secNew, p, &dofNew));
5729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(secNew, p, &offNew));
5736dd5a8c8SToby Isaac       count = 0;
5746dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5756dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
5766dd5a8c8SToby Isaac 
5776dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5789566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, q, &qDof));
5799566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, q, &qOff));
5806dd5a8c8SToby Isaac         }
5816dd5a8c8SToby Isaac         if (qDof) {
5826dd5a8c8SToby Isaac           PetscInt oldCount = count;
5836dd5a8c8SToby Isaac 
5846dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
5856dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
5866dd5a8c8SToby Isaac 
5876dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
588ad540459SPierre Jolivet               if (valsNew[offNew + k] == r) break;
5896dd5a8c8SToby Isaac             }
590ad540459SPierre Jolivet             if (k == oldCount) valsNew[offNew + count++] = r;
5916dd5a8c8SToby Isaac           }
5929371c9d4SSatish Balay         } else {
5936dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
5946dd5a8c8SToby Isaac 
5956dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
596ad540459SPierre Jolivet             if (valsNew[offNew + k] == q) break;
5976dd5a8c8SToby Isaac           }
598ad540459SPierre Jolivet           if (k == oldCount) valsNew[offNew + count++] = q;
5996dd5a8c8SToby Isaac         }
6006dd5a8c8SToby Isaac       }
6016dd5a8c8SToby Isaac       if (count < dofNew) {
6029566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secNew, p, count));
6036dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6046dd5a8c8SToby Isaac       }
6056dd5a8c8SToby Isaac     }
6066dd5a8c8SToby Isaac   }
6079566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is, &vals));
6081c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&anyNew, &globalAnyNew, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
6096dd5a8c8SToby Isaac   if (!globalAnyNew) {
6109566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secNew));
6116dd5a8c8SToby Isaac     *sectionNew = NULL;
6126dd5a8c8SToby Isaac     *isNew      = NULL;
6139371c9d4SSatish Balay   } else {
6146dd5a8c8SToby Isaac     PetscBool globalCompress;
6156dd5a8c8SToby Isaac 
6161c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&compress, &globalCompress, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
6176dd5a8c8SToby Isaac     if (compress) {
6186dd5a8c8SToby Isaac       PetscSection secComp;
6196dd5a8c8SToby Isaac       PetscInt    *valsComp = NULL;
6206dd5a8c8SToby Isaac 
6219566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secComp));
6229566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetChart(secComp, pStart, pEnd));
6236dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6246dd5a8c8SToby Isaac         PetscInt dof;
6256dd5a8c8SToby Isaac 
6269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6279566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secComp, p, dof));
6286dd5a8c8SToby Isaac       }
6299566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetUp(secComp));
6309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(secComp, &sizeNew));
6319566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(sizeNew, &valsComp));
6326dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6336dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6346dd5a8c8SToby Isaac 
6359566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6369566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secNew, p, &off));
6379566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secComp, p, &offNew));
638ad540459SPierre Jolivet         for (j = 0; j < dof; j++) valsComp[offNew + j] = valsNew[off + j];
6396dd5a8c8SToby Isaac       }
6409566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&secNew));
6416dd5a8c8SToby Isaac       secNew = secComp;
6429566063dSJacob Faibussowitsch       PetscCall(PetscFree(valsNew));
6436dd5a8c8SToby Isaac       valsNew = valsComp;
6446dd5a8c8SToby Isaac     }
6459566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), sizeNew, valsNew, PETSC_OWN_POINTER, isNew));
6466dd5a8c8SToby Isaac   }
6476dd5a8c8SToby Isaac   PetscFunctionReturn(0);
6486dd5a8c8SToby Isaac }
6496dd5a8c8SToby Isaac 
650d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
651d71ae5a4SJacob Faibussowitsch {
65266af876cSToby Isaac   PetscInt     p, pStart, pEnd, *anchors, size;
65366af876cSToby Isaac   PetscInt     aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
65466af876cSToby Isaac   PetscSection aSec;
655f9f063d4SToby Isaac   DMLabel      canonLabel;
65666af876cSToby Isaac   IS           aIS;
65766af876cSToby Isaac 
65866af876cSToby Isaac   PetscFunctionBegin;
65966af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
6619566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "canonical", &canonLabel));
66266af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
66366af876cSToby Isaac     PetscInt parent;
66466af876cSToby Isaac 
665f9f063d4SToby Isaac     if (canonLabel) {
666f9f063d4SToby Isaac       PetscInt canon;
667f9f063d4SToby Isaac 
6689566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
669f9f063d4SToby Isaac       if (p != canon) continue;
670f9f063d4SToby Isaac     }
6719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
67266af876cSToby Isaac     if (parent != p) {
67366af876cSToby Isaac       aMin = PetscMin(aMin, p);
67466af876cSToby Isaac       aMax = PetscMax(aMax, p + 1);
67566af876cSToby Isaac     }
67666af876cSToby Isaac   }
67766af876cSToby Isaac   if (aMin > aMax) {
67866af876cSToby Isaac     aMin = -1;
67966af876cSToby Isaac     aMax = -1;
68066af876cSToby Isaac   }
6819566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &aSec));
6829566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(aSec, aMin, aMax));
68366af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
68466af876cSToby Isaac     PetscInt parent, ancestor = p;
68566af876cSToby Isaac 
686f9f063d4SToby Isaac     if (canonLabel) {
687f9f063d4SToby Isaac       PetscInt canon;
688f9f063d4SToby Isaac 
6899566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
690f9f063d4SToby Isaac       if (p != canon) continue;
691f9f063d4SToby Isaac     }
6929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
69366af876cSToby Isaac     while (parent != ancestor) {
69466af876cSToby Isaac       ancestor = parent;
6959566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
69666af876cSToby Isaac     }
69766af876cSToby Isaac     if (ancestor != p) {
69866af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
69966af876cSToby Isaac 
7009566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
7019566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(aSec, p, closureSize));
7029566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
70366af876cSToby Isaac     }
70466af876cSToby Isaac   }
7059566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(aSec));
7069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(aSec, &size));
7079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &anchors));
70866af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
70966af876cSToby Isaac     PetscInt parent, ancestor = p;
71066af876cSToby Isaac 
711f9f063d4SToby Isaac     if (canonLabel) {
712f9f063d4SToby Isaac       PetscInt canon;
713f9f063d4SToby Isaac 
7149566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
715f9f063d4SToby Isaac       if (p != canon) continue;
716f9f063d4SToby Isaac     }
7179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
71866af876cSToby Isaac     while (parent != ancestor) {
71966af876cSToby Isaac       ancestor = parent;
7209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
72166af876cSToby Isaac     }
72266af876cSToby Isaac     if (ancestor != p) {
72366af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
72466af876cSToby Isaac 
7259566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
72666af876cSToby Isaac 
7279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
728ad540459SPierre Jolivet       for (j = 0; j < closureSize; j++) anchors[aOff + j] = closure[2 * j];
7299566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
73066af876cSToby Isaac     }
73166af876cSToby Isaac   }
7329566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, anchors, PETSC_OWN_POINTER, &aIS));
7336dd5a8c8SToby Isaac   {
7346dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7356dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7366dd5a8c8SToby Isaac 
7379566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aSec));
7389566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aIS));
7396dd5a8c8SToby Isaac     while (aSecNew) {
7409566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&aSec));
7419566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&aIS));
7426dd5a8c8SToby Isaac       aSec    = aSecNew;
7436dd5a8c8SToby Isaac       aIS     = aISNew;
7446dd5a8c8SToby Isaac       aSecNew = NULL;
7456dd5a8c8SToby Isaac       aISNew  = NULL;
7469566063dSJacob Faibussowitsch       PetscCall(AnchorsFlatten(aSec, aIS, &aSecNew, &aISNew));
7476dd5a8c8SToby Isaac     }
7486dd5a8c8SToby Isaac   }
7499566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm, aSec, aIS));
7509566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&aSec));
7519566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&aIS));
75266af876cSToby Isaac   PetscFunctionReturn(0);
75366af876cSToby Isaac }
75466af876cSToby Isaac 
755d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTrueSupportSize(DM dm, PetscInt p, PetscInt *dof, PetscInt *numTrueSupp)
756d71ae5a4SJacob Faibussowitsch {
7576461c1adSToby Isaac   PetscFunctionBegin;
7586461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
7596461c1adSToby Isaac     PetscInt        i, alldof;
7606461c1adSToby Isaac     const PetscInt *supp;
7616461c1adSToby Isaac     PetscInt        count = 0;
7626461c1adSToby Isaac 
7639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &alldof));
7649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &supp));
7656461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
7666461c1adSToby Isaac       PetscInt        q = supp[i], numCones, j;
7676461c1adSToby Isaac       const PetscInt *cone;
7686461c1adSToby Isaac 
7699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, q, &numCones));
7709566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, q, &cone));
7716461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
7726461c1adSToby Isaac         if (cone[j] == p) break;
7736461c1adSToby Isaac       }
7746461c1adSToby Isaac       if (j < numCones) count++;
7756461c1adSToby Isaac     }
7766461c1adSToby Isaac     numTrueSupp[p] = count;
7776461c1adSToby Isaac   }
7786461c1adSToby Isaac   *dof = numTrueSupp[p];
7796461c1adSToby Isaac   PetscFunctionReturn(0);
7806461c1adSToby Isaac }
7816461c1adSToby Isaac 
782d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
783d71ae5a4SJacob Faibussowitsch {
784776742edSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
785776742edSToby Isaac   PetscSection newSupportSection;
786776742edSToby Isaac   PetscInt     newSize, *newSupports, pStart, pEnd, p, d, depth;
7876461c1adSToby Isaac   PetscInt    *numTrueSupp;
788776742edSToby Isaac   PetscInt    *offsets;
789776742edSToby Isaac 
790776742edSToby Isaac   PetscFunctionBegin;
791776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
792776742edSToby Isaac   /* symmetrize the hierarchy */
7939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
7949566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)), &newSupportSection));
7959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7969566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSupportSection, pStart, pEnd));
7979566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd, &offsets));
7989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd, &numTrueSupp));
7996461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8006461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
801776742edSToby Isaac    * parent(q) */
802776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
804776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
805776742edSToby Isaac       PetscInt dof, q, qdof, parent;
806776742edSToby Isaac 
8079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTrueSupportSize(dm, p, &dof, numTrueSupp));
8089566063dSJacob Faibussowitsch       PetscCall(PetscSectionAddDof(newSupportSection, p, dof));
809776742edSToby Isaac       q = p;
8109566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
811776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
812776742edSToby Isaac         q = parent;
813776742edSToby Isaac 
8149566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTrueSupportSize(dm, q, &qdof, numTrueSupp));
8159566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection, p, qdof));
8169566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection, q, dof));
8179566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
818776742edSToby Isaac       }
819776742edSToby Isaac     }
820776742edSToby Isaac   }
8219566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSupportSection));
8229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSupportSection, &newSize));
8239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(newSize, &newSupports));
824776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
826776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
827776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
828776742edSToby Isaac 
8299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
8309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
8319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(newSupportSection, p, &newDof));
8329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(newSupportSection, p, &newOff));
833776742edSToby Isaac       for (i = 0; i < dof; i++) {
8346461c1adSToby Isaac         PetscInt        numCones, j;
8356461c1adSToby Isaac         const PetscInt *cone;
8366461c1adSToby Isaac         PetscInt        q = mesh->supports[off + i];
8376461c1adSToby Isaac 
8389566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, q, &numCones));
8399566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, q, &cone));
8406461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8416461c1adSToby Isaac           if (cone[j] == p) break;
8426461c1adSToby Isaac         }
8436461c1adSToby Isaac         if (j < numCones) newSupports[newOff + offsets[p]++] = q;
844776742edSToby Isaac       }
845776742edSToby Isaac 
846776742edSToby Isaac       q = p;
8479566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
848776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
849776742edSToby Isaac         q = parent;
8509566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->supportSection, q, &qdof));
8519566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &qoff));
8529566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(newSupportSection, q, &newqOff));
853776742edSToby Isaac         for (i = 0; i < qdof; i++) {
8546461c1adSToby Isaac           PetscInt        numCones, j;
8556461c1adSToby Isaac           const PetscInt *cone;
8566461c1adSToby Isaac           PetscInt        r = mesh->supports[qoff + i];
8576461c1adSToby Isaac 
8589566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
8599566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, r, &cone));
8606461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
8616461c1adSToby Isaac             if (cone[j] == q) break;
8626461c1adSToby Isaac           }
8636461c1adSToby Isaac           if (j < numCones) newSupports[newOff + offsets[p]++] = r;
864776742edSToby Isaac         }
865776742edSToby Isaac         for (i = 0; i < dof; i++) {
8666461c1adSToby Isaac           PetscInt        numCones, j;
8676461c1adSToby Isaac           const PetscInt *cone;
8686461c1adSToby Isaac           PetscInt        r = mesh->supports[off + i];
8696461c1adSToby Isaac 
8709566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
8719566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, r, &cone));
8726461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
8736461c1adSToby Isaac             if (cone[j] == p) break;
8746461c1adSToby Isaac           }
8756461c1adSToby Isaac           if (j < numCones) newSupports[newqOff + offsets[q]++] = r;
876776742edSToby Isaac         }
8779566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
878776742edSToby Isaac       }
879776742edSToby Isaac     }
880776742edSToby Isaac   }
8819566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
882776742edSToby Isaac   mesh->supportSection = newSupportSection;
8839566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
884776742edSToby Isaac   mesh->supports = newSupports;
8859566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
8869566063dSJacob Faibussowitsch   PetscCall(PetscFree(numTrueSupp));
887776742edSToby Isaac 
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 
894d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
895d71ae5a4SJacob Faibussowitsch {
896f9f063d4SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
897f9f063d4SToby Isaac   DM       refTree;
898f9f063d4SToby Isaac   PetscInt size;
899f9f063d4SToby Isaac 
900f9f063d4SToby Isaac   PetscFunctionBegin;
901f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
902f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
9039566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)parentSection));
9049566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
905f9f063d4SToby Isaac   mesh->parentSection = parentSection;
9069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection, &size));
907f9f063d4SToby Isaac   if (parents != mesh->parents) {
9089566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->parents));
9099566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->parents));
9109566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->parents, parents, size));
911f9f063d4SToby Isaac   }
912f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
9139566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->childIDs));
9149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->childIDs));
9159566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->childIDs, childIDs, size));
916f9f063d4SToby Isaac   }
9179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
918f9f063d4SToby Isaac   if (refTree) {
919f9f063d4SToby Isaac     DMLabel canonLabel;
920f9f063d4SToby Isaac 
9219566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(refTree, "canonical", &canonLabel));
922f9f063d4SToby Isaac     if (canonLabel) {
923f9f063d4SToby Isaac       PetscInt i;
924f9f063d4SToby Isaac 
925f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
926f9f063d4SToby Isaac         PetscInt canon;
9279566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon));
928ad540459SPierre Jolivet         if (canon >= 0) mesh->childIDs[i] = canon;
929f9f063d4SToby Isaac       }
930f9f063d4SToby Isaac     }
931f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
9326e0288c8SStefano Zampini   } else {
933f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
934f9f063d4SToby Isaac   }
9359566063dSJacob Faibussowitsch   PetscCall(DMPlexTreeSymmetrize(dm));
936f9f063d4SToby Isaac   if (computeCanonical) {
937f9f063d4SToby Isaac     PetscInt d, dim;
938f9f063d4SToby Isaac 
939f9f063d4SToby Isaac     /* add the canonical label */
9409566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
9419566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "canonical"));
942f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
943f9f063d4SToby Isaac       PetscInt        p, dStart, dEnd, canon = -1, cNumChildren;
944f9f063d4SToby Isaac       const PetscInt *cChildren;
945f9f063d4SToby Isaac 
9469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
947f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
9489566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, p, &cNumChildren, &cChildren));
949f9f063d4SToby Isaac         if (cNumChildren) {
950f9f063d4SToby Isaac           canon = p;
951f9f063d4SToby Isaac           break;
952f9f063d4SToby Isaac         }
953f9f063d4SToby Isaac       }
954f9f063d4SToby Isaac       if (canon == -1) continue;
955f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
956f9f063d4SToby Isaac         PetscInt        numChildren, i;
957f9f063d4SToby Isaac         const PetscInt *children;
958f9f063d4SToby Isaac 
9599566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, p, &numChildren, &children));
960f9f063d4SToby Isaac         if (numChildren) {
96163a3b9bcSJacob Faibussowitsch           PetscCheck(numChildren == cNumChildren, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "All parent points in a stratum should have the same number of children: %" PetscInt_FMT " != %" PetscInt_FMT, numChildren, cNumChildren);
9629566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "canonical", p, canon));
96348a46eb9SPierre Jolivet           for (i = 0; i < numChildren; i++) PetscCall(DMSetLabelValue(dm, "canonical", children[i], cChildren[i]));
964f9f063d4SToby Isaac         }
965f9f063d4SToby Isaac       }
966f9f063d4SToby Isaac     }
967f9f063d4SToby Isaac   }
9681baa6e33SBarry Smith   if (exchangeSupports) PetscCall(DMPlexTreeExchangeSupports(dm));
969f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
970f7c74593SToby Isaac   /* reset anchors */
9719566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm, NULL, NULL));
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:
983*a1cb98faSBarry Smith + dm - the `DMPLEX` object
9840b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
9850b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
9860b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
9870b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
9880b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
9890b7167a0SToby Isaac 
9900b7167a0SToby Isaac   Level: intermediate
9910b7167a0SToby Isaac 
992*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
9930b7167a0SToby Isaac @*/
994d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
995d71ae5a4SJacob Faibussowitsch {
9960b7167a0SToby Isaac   PetscFunctionBegin;
9979566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_FALSE, PETSC_TRUE));
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:
1006*a1cb98faSBarry Smith . dm - the `DMPLEX` object
1007b2f41788SToby Isaac 
1008b2f41788SToby Isaac   Output Parameters:
1009b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1010b2f41788SToby Isaac                   offset indexes the parent and childID list
1011b2f41788SToby Isaac . parents - a list of the point parents
1012b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1013b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1014b2f41788SToby Isaac . childSection - the inverse of the parent section
1015b2f41788SToby Isaac - children - a list of the point children
1016b2f41788SToby Isaac 
1017b2f41788SToby Isaac   Level: intermediate
1018b2f41788SToby Isaac 
1019*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`,`DMPlexSetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
1020b2f41788SToby Isaac @*/
1021d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1022d71ae5a4SJacob Faibussowitsch {
1023b2f41788SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
1024b2f41788SToby Isaac 
1025b2f41788SToby Isaac   PetscFunctionBegin;
1026b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1027b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1028b2f41788SToby Isaac   if (parents) *parents = mesh->parents;
1029b2f41788SToby Isaac   if (childIDs) *childIDs = mesh->childIDs;
1030b2f41788SToby Isaac   if (childSection) *childSection = mesh->childSection;
1031b2f41788SToby Isaac   if (children) *children = mesh->children;
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:
1039*a1cb98faSBarry Smith + 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 
1049*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeChildren()`
1050d961a43aSToby Isaac @*/
1051d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1052d71ae5a4SJacob Faibussowitsch {
1053d961a43aSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
1054d961a43aSToby Isaac   PetscSection pSec;
1055d961a43aSToby Isaac 
1056d961a43aSToby Isaac   PetscFunctionBegin;
1057d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1058d961a43aSToby Isaac   pSec = mesh->parentSection;
1059d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1060d961a43aSToby Isaac     PetscInt dof;
1061d961a43aSToby Isaac 
10629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pSec, point, &dof));
1063d961a43aSToby Isaac     if (dof) {
1064d961a43aSToby Isaac       PetscInt off;
1065d961a43aSToby Isaac 
10669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(pSec, point, &off));
1067d961a43aSToby Isaac       if (parent) *parent = mesh->parents[off];
1068d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
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:
1081*a1cb98faSBarry Smith + 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 
1090*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeParent()`
1091d961a43aSToby Isaac @*/
1092d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1093d71ae5a4SJacob Faibussowitsch {
1094d961a43aSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
1095d961a43aSToby Isaac   PetscSection childSec;
1096d961a43aSToby Isaac   PetscInt     dof = 0;
1097d961a43aSToby Isaac 
1098d961a43aSToby Isaac   PetscFunctionBegin;
1099d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1100d961a43aSToby Isaac   childSec = mesh->childSection;
110148a46eb9SPierre Jolivet   if (childSec && point >= childSec->pStart && point < childSec->pEnd) PetscCall(PetscSectionGetDof(childSec, point, &dof));
1102d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1103d961a43aSToby Isaac   if (children) {
1104d961a43aSToby Isaac     if (dof) {
1105d961a43aSToby Isaac       PetscInt off;
1106d961a43aSToby Isaac 
11079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec, point, &off));
1108d961a43aSToby Isaac       *children = &mesh->children[off];
11099371c9d4SSatish Balay     } else {
1110d961a43aSToby Isaac       *children = NULL;
1111d961a43aSToby Isaac     }
1112d961a43aSToby Isaac   }
1113d961a43aSToby Isaac   PetscFunctionReturn(0);
1114d961a43aSToby Isaac }
11150c37af3bSToby Isaac 
1116d71ae5a4SJacob Faibussowitsch static PetscErrorCode EvaluateBasis(PetscSpace space, PetscInt nBasis, PetscInt nFunctionals, PetscInt nComps, PetscInt nPoints, const PetscInt *pointsPerFn, const PetscReal *points, const PetscReal *weights, PetscReal *work, Mat basisAtPoints)
1117d71ae5a4SJacob Faibussowitsch {
111852a3aeb4SToby Isaac   PetscInt f, b, p, c, offset, qPoints;
1119b3a4bf2aSToby Isaac 
1120b3a4bf2aSToby Isaac   PetscFunctionBegin;
11219566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(space, nPoints, points, work, NULL, NULL));
112252a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
112352a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
112452a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1125b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1126b3a4bf2aSToby Isaac 
112752a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
1128ad540459SPierre Jolivet         for (c = 0; c < nComps; c++) val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
112952a3aeb4SToby Isaac       }
11309566063dSJacob Faibussowitsch       PetscCall(MatSetValue(basisAtPoints, b, f, val, INSERT_VALUES));
1131b3a4bf2aSToby Isaac     }
1132b3a4bf2aSToby Isaac     offset += qPoints;
1133b3a4bf2aSToby Isaac   }
11349566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(basisAtPoints, MAT_FINAL_ASSEMBLY));
11359566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(basisAtPoints, MAT_FINAL_ASSEMBLY));
1136b3a4bf2aSToby Isaac   PetscFunctionReturn(0);
1137b3a4bf2aSToby Isaac }
1138b3a4bf2aSToby Isaac 
1139d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
1140d71ae5a4SJacob Faibussowitsch {
11410c37af3bSToby Isaac   PetscDS         ds;
11420c37af3bSToby Isaac   PetscInt        spdim;
11430c37af3bSToby Isaac   PetscInt        numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
11440c37af3bSToby Isaac   const PetscInt *anchors;
1145f7c74593SToby Isaac   PetscSection    aSec;
11460c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
11470c37af3bSToby Isaac   IS              aIS;
11480c37af3bSToby Isaac 
11490c37af3bSToby Isaac   PetscFunctionBegin;
11509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
11519566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
11529566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
11539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
11549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
11559566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
11569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &conStart, &conEnd));
11579566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &spdim));
11589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(spdim, &v0, spdim, &v0parent, spdim, &vtmp, spdim * spdim, &J, spdim * spdim, &Jparent, spdim * spdim, &invJparent));
11590c37af3bSToby Isaac 
11600c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
11610dd1b1feSToby Isaac     PetscObject          disc;
11620dd1b1feSToby Isaac     PetscClassId         id;
1163b3a4bf2aSToby Isaac     PetscSpace           bspace;
1164b3a4bf2aSToby Isaac     PetscDualSpace       dspace;
11659c3cf19fSMatthew G. Knepley     PetscInt             i, j, k, nPoints, Nc, offset;
116652a3aeb4SToby Isaac     PetscInt             fSize, maxDof;
1167b3a4bf2aSToby Isaac     PetscReal           *weights, *pointsRef, *pointsReal, *work;
11681683a169SBarry Smith     PetscScalar         *scwork;
11691683a169SBarry Smith     const PetscScalar   *X;
11702c44ad04SToby Isaac     PetscInt            *sizes, *workIndRow, *workIndCol;
11710c37af3bSToby Isaac     Mat                  Amat, Bmat, Xmat;
11722c44ad04SToby Isaac     const PetscInt      *numDof = NULL;
1173085f0adfSToby Isaac     const PetscInt    ***perms  = NULL;
1174085f0adfSToby Isaac     const PetscScalar ***flips  = NULL;
11750c37af3bSToby Isaac 
11769566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(ds, f, &disc));
11779566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(disc, &id));
11780dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1179b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE)disc;
1180b3a4bf2aSToby Isaac 
11819566063dSJacob Faibussowitsch       PetscCall(PetscFEGetBasisSpace(fe, &bspace));
11829566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(fe, &dspace));
11839566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
11849566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
11859371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
1186b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV)disc;
1187b3a4bf2aSToby Isaac 
11889566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
11899566063dSJacob Faibussowitsch       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)fv), &bspace));
11909566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetType(bspace, PETSCSPACEPOLYNOMIAL));
11919566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetDegree(bspace, 0, PETSC_DETERMINE));
11929566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumComponents(bspace, Nc));
11939566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumVariables(bspace, spdim));
11949566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(bspace));
11959566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &dspace));
11969566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
11979371c9d4SSatish Balay     } else SETERRQ(PetscObjectComm(disc), PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
11989566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetNumDof(dspace, &numDof));
1199ad540459SPierre Jolivet     for (i = 0, maxDof = 0; i <= spdim; i++) maxDof = PetscMax(maxDof, numDof[i]);
12009566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSymmetries(dspace, &perms, &flips));
12010dd1b1feSToby Isaac 
12029566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &Amat));
12039566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Amat, fSize, fSize, fSize, fSize));
12049566063dSJacob Faibussowitsch     PetscCall(MatSetType(Amat, MATSEQDENSE));
12059566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Amat));
12069566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Bmat));
12079566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Xmat));
12080c37af3bSToby Isaac     nPoints = 0;
12090c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
121052a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
12110c37af3bSToby Isaac       PetscQuadrature quad;
12120c37af3bSToby Isaac 
12139566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
12149566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, &thisNc, &qPoints, NULL, NULL));
121563a3b9bcSJacob Faibussowitsch       PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
12160c37af3bSToby Isaac       nPoints += qPoints;
12170c37af3bSToby Isaac     }
12189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(fSize, &sizes, nPoints * Nc, &weights, spdim * nPoints, &pointsRef, spdim * nPoints, &pointsReal, nPoints * fSize * Nc, &work, maxDof, &workIndRow, maxDof, &workIndCol));
12199566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof * maxDof, &scwork));
12200c37af3bSToby Isaac     offset = 0;
12210c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12220c37af3bSToby Isaac       PetscInt         qPoints;
12230c37af3bSToby Isaac       const PetscReal *p, *w;
12240c37af3bSToby Isaac       PetscQuadrature  quad;
12250c37af3bSToby Isaac 
12269566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
12279566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &qPoints, &p, &w));
12289566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(weights + Nc * offset, w, Nc * qPoints));
12299566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pointsRef + spdim * offset, p, spdim * qPoints));
1230b3a4bf2aSToby Isaac       sizes[i] = qPoints;
12310c37af3bSToby Isaac       offset += qPoints;
12320c37af3bSToby Isaac     }
12339566063dSJacob Faibussowitsch     PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsRef, weights, work, Amat));
12349566063dSJacob Faibussowitsch     PetscCall(MatLUFactor(Amat, NULL, NULL, NULL));
12350c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
12360c37af3bSToby Isaac       PetscInt  parent;
12370c37af3bSToby Isaac       PetscInt  closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
12380c37af3bSToby Isaac       PetscInt *childOffsets, *parentOffsets;
12390c37af3bSToby Isaac 
12409566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, c, &parent, NULL));
12410c37af3bSToby Isaac       if (parent == c) continue;
12429566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12430c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12440c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12450c37af3bSToby Isaac         PetscInt conDof;
12460c37af3bSToby Isaac 
12470c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1248085f0adfSToby Isaac         if (numFields) {
12499566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
12509371c9d4SSatish Balay         } else {
12519566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
12520c37af3bSToby Isaac         }
12530c37af3bSToby Isaac         if (conDof) break;
12540c37af3bSToby Isaac       }
12550c37af3bSToby Isaac       if (i == closureSize) {
12569566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12570c37af3bSToby Isaac         continue;
12580c37af3bSToby Isaac       }
12590c37af3bSToby Isaac 
12609566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ));
12619566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent));
12620c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1263c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
1264c330f8ffSToby Isaac 
1265c330f8ffSToby Isaac         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i * spdim], vtmp);
1266c330f8ffSToby Isaac         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i * spdim]);
12670c37af3bSToby Isaac       }
12689566063dSJacob Faibussowitsch       PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsReal, weights, work, Bmat));
12699566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(Amat, Bmat, Xmat));
12709566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Xmat, &X));
12719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
12729566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(closureSize + 1, &childOffsets, closureSizeP + 1, &parentOffsets));
12730c37af3bSToby Isaac       childOffsets[0] = 0;
12740c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12750c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12760c37af3bSToby Isaac         PetscInt dof;
12770c37af3bSToby Isaac 
1278085f0adfSToby Isaac         if (numFields) {
12799566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12809371c9d4SSatish Balay         } else {
12819566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12820c37af3bSToby Isaac         }
128352a3aeb4SToby Isaac         childOffsets[i + 1] = childOffsets[i] + dof;
12840c37af3bSToby Isaac       }
12850c37af3bSToby Isaac       parentOffsets[0] = 0;
12860c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
12870c37af3bSToby Isaac         PetscInt p = closureP[2 * i];
12880c37af3bSToby Isaac         PetscInt dof;
12890c37af3bSToby Isaac 
1290085f0adfSToby Isaac         if (numFields) {
12919566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12929371c9d4SSatish Balay         } else {
12939566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12940c37af3bSToby Isaac         }
129552a3aeb4SToby Isaac         parentOffsets[i + 1] = parentOffsets[i] + dof;
12960c37af3bSToby Isaac       }
12970c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12982c44ad04SToby Isaac         PetscInt           conDof, conOff, aDof, aOff, nWork;
12990c37af3bSToby Isaac         PetscInt           p = closure[2 * i];
13000c37af3bSToby Isaac         PetscInt           o = closure[2 * i + 1];
1301085f0adfSToby Isaac         const PetscInt    *perm;
1302085f0adfSToby Isaac         const PetscScalar *flip;
13030c37af3bSToby Isaac 
13040c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1305085f0adfSToby Isaac         if (numFields) {
13069566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
13079566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &conOff));
13089371c9d4SSatish Balay         } else {
13099566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
13109566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(cSec, p, &conOff));
13110c37af3bSToby Isaac         }
13120c37af3bSToby Isaac         if (!conDof) continue;
1313085f0adfSToby Isaac         perm = (perms && perms[i]) ? perms[i][o] : NULL;
1314085f0adfSToby Isaac         flip = (flips && flips[i]) ? flips[i][o] : NULL;
13159566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
13169566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
13172c44ad04SToby Isaac         nWork = childOffsets[i + 1] - childOffsets[i];
13180c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
13190c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
13200c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
13210c37af3bSToby Isaac 
1322085f0adfSToby Isaac           if (numFields) {
13239566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aSecDof));
13249566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aSecOff));
13259371c9d4SSatish Balay           } else {
13269566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, a, &aSecDof));
13279566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, a, &aSecOff));
13280c37af3bSToby Isaac           }
13290c37af3bSToby Isaac           if (!aSecDof) continue;
13300c37af3bSToby Isaac 
13310c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
13320c37af3bSToby Isaac             PetscInt q  = closureP[2 * j];
13330c37af3bSToby Isaac             PetscInt oq = closureP[2 * j + 1];
13342c44ad04SToby Isaac 
13352c44ad04SToby Isaac             if (q == a) {
133652a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1337085f0adfSToby Isaac               const PetscInt    *permP;
1338085f0adfSToby Isaac               const PetscScalar *flipP;
1339085f0adfSToby Isaac 
1340085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1341085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
13422c44ad04SToby Isaac               nWorkP = parentOffsets[j + 1] - parentOffsets[j];
13432c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
13441683a169SBarry Smith                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
13452c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
13462c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
1347ad540459SPierre Jolivet                 for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
13482c44ad04SToby Isaac               }
1349ad540459SPierre Jolivet               for (r = 0; r < nWork; r++) workIndRow[perm ? perm[r] : r] = conOff + r;
1350ad540459SPierre Jolivet               for (s = 0; s < nWorkP; s++) workIndCol[permP ? permP[s] : s] = aSecOff + s;
13512c44ad04SToby Isaac               if (flip) {
13522c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1353ad540459SPierre Jolivet                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flip[r];
13542c44ad04SToby Isaac                 }
13552c44ad04SToby Isaac               }
13562c44ad04SToby Isaac               if (flipP) {
13572c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1358ad540459SPierre Jolivet                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flipP[s];
13592c44ad04SToby Isaac                 }
13602c44ad04SToby Isaac               }
13619566063dSJacob Faibussowitsch               PetscCall(MatSetValues(cMat, nWork, workIndRow, nWorkP, workIndCol, scwork, INSERT_VALUES));
13622c44ad04SToby Isaac               break;
13630c37af3bSToby Isaac             }
13640c37af3bSToby Isaac           }
13650c37af3bSToby Isaac         }
13660c37af3bSToby Isaac       }
13679566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Xmat, &X));
13689566063dSJacob Faibussowitsch       PetscCall(PetscFree2(childOffsets, parentOffsets));
13699566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
13709566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
13710c37af3bSToby Isaac     }
13729566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Amat));
13739566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Bmat));
13749566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Xmat));
13759566063dSJacob Faibussowitsch     PetscCall(PetscFree(scwork));
13769566063dSJacob Faibussowitsch     PetscCall(PetscFree7(sizes, weights, pointsRef, pointsReal, work, workIndRow, workIndCol));
137748a46eb9SPierre Jolivet     if (id == PETSCFV_CLASSID) PetscCall(PetscSpaceDestroy(&bspace));
13780c37af3bSToby Isaac   }
13799566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
13809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
13819566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJparent));
13829566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
13830c37af3bSToby Isaac 
13840c37af3bSToby Isaac   PetscFunctionReturn(0);
13850c37af3bSToby Isaac }
138695a0b26dSToby Isaac 
1387d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1388d71ae5a4SJacob Faibussowitsch {
1389f7c74593SToby Isaac   Mat                 refCmat;
139021968bf8SToby Isaac   PetscDS             ds;
1391085f0adfSToby Isaac   PetscInt            numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
139221968bf8SToby Isaac   PetscScalar      ***refPointFieldMats;
139321968bf8SToby Isaac   PetscSection        refConSec, refAnSec, refSection;
139421968bf8SToby Isaac   IS                  refAnIS;
139521968bf8SToby Isaac   const PetscInt     *refAnchors;
1396085f0adfSToby Isaac   const PetscInt    **perms;
1397085f0adfSToby Isaac   const PetscScalar **flips;
139895a0b26dSToby Isaac 
139995a0b26dSToby Isaac   PetscFunctionBegin;
14009566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
14019566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1402085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
14039566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
14049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
14059566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(refAnIS, &refAnchors));
14069566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
14079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
14089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
14099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldN));
14109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
14119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
14129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
14139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxAnDof, &cols));
141495a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
141595a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
141695a0b26dSToby Isaac 
14179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
14189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
141995a0b26dSToby Isaac     if (!pDof || parent == p) continue;
142095a0b26dSToby Isaac 
14219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxFields, &refPointFieldMats[p - pRefStart]));
14229566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(maxFields, &refPointFieldN[p - pRefStart]));
14239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
1424085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1425085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
142695a0b26dSToby Isaac 
1427085f0adfSToby Isaac       if (f < numFields) {
14289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
14299566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
14309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1431085f0adfSToby Isaac       } else {
14329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
14339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
14349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetPointSyms(refSection, closureSize, closure, &perms, &flips));
143595a0b26dSToby Isaac       }
143695a0b26dSToby Isaac 
1437ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
143895a0b26dSToby Isaac       numCols = 0;
143995a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
144095a0b26dSToby Isaac         PetscInt        q = closure[2 * i];
144195a0b26dSToby Isaac         PetscInt        aDof, aOff, j;
1442085f0adfSToby Isaac         const PetscInt *perm = perms ? perms[i] : NULL;
144395a0b26dSToby Isaac 
1444085f0adfSToby Isaac         if (numFields) {
14459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14469566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14479371c9d4SSatish Balay         } else {
14489566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14499566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
145095a0b26dSToby Isaac         }
145195a0b26dSToby Isaac 
1452ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + (perm ? perm[j] : j);
145395a0b26dSToby Isaac       }
145495a0b26dSToby Isaac       refPointFieldN[p - pRefStart][f] = numCols;
14559566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
14569566063dSJacob Faibussowitsch       PetscCall(MatGetValues(refCmat, cDof, rows, numCols, cols, refPointFieldMats[p - pRefStart][f]));
1457085f0adfSToby Isaac       if (flips) {
1458085f0adfSToby Isaac         PetscInt colOff = 0;
1459085f0adfSToby Isaac 
1460085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1461085f0adfSToby Isaac           PetscInt           q = closure[2 * i];
1462085f0adfSToby Isaac           PetscInt           aDof, aOff, j;
1463085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1464085f0adfSToby Isaac 
1465085f0adfSToby Isaac           if (numFields) {
14669566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14679566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14689371c9d4SSatish Balay           } else {
14699566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14709566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
1471085f0adfSToby Isaac           }
1472085f0adfSToby Isaac           if (flip) {
1473085f0adfSToby Isaac             PetscInt k;
1474085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1475ad540459SPierre Jolivet               for (j = 0; j < aDof; j++) refPointFieldMats[p - pRefStart][f][k * numCols + colOff + j] *= flip[j];
1476085f0adfSToby Isaac             }
1477085f0adfSToby Isaac           }
1478085f0adfSToby Isaac           colOff += aDof;
1479085f0adfSToby Isaac         }
1480085f0adfSToby Isaac       }
1481085f0adfSToby Isaac       if (numFields) {
14829566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestoreFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1483085f0adfSToby Isaac       } else {
14849566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestorePointSyms(refSection, closureSize, closure, &perms, &flips));
1485085f0adfSToby Isaac       }
148695a0b26dSToby Isaac     }
14879566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
148895a0b26dSToby Isaac   }
148921968bf8SToby Isaac   *childrenMats = refPointFieldMats;
149021968bf8SToby Isaac   *childrenN    = refPointFieldN;
14919566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(refAnIS, &refAnchors));
14929566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
14939566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
149421968bf8SToby Isaac   PetscFunctionReturn(0);
149521968bf8SToby Isaac }
149621968bf8SToby Isaac 
1497d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1498d71ae5a4SJacob Faibussowitsch {
149921968bf8SToby Isaac   PetscDS        ds;
150021968bf8SToby Isaac   PetscInt     **refPointFieldN;
150121968bf8SToby Isaac   PetscScalar ***refPointFieldMats;
1502085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
150321968bf8SToby Isaac   PetscSection   refConSec;
150421968bf8SToby Isaac 
150521968bf8SToby Isaac   PetscFunctionBegin;
150621968bf8SToby Isaac   refPointFieldN    = *childrenN;
150721968bf8SToby Isaac   *childrenN        = NULL;
150821968bf8SToby Isaac   refPointFieldMats = *childrenMats;
150921968bf8SToby Isaac   *childrenMats     = NULL;
15109566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
15119566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1512367003a6SStefano Zampini   maxFields = PetscMax(1, numFields);
15139566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
15149566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
151521968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
151621968bf8SToby Isaac     PetscInt parent, pDof;
151721968bf8SToby Isaac 
15189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
15199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
152021968bf8SToby Isaac     if (!pDof || parent == p) continue;
152121968bf8SToby Isaac 
1522085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
152321968bf8SToby Isaac       PetscInt cDof;
152421968bf8SToby Isaac 
1525085f0adfSToby Isaac       if (numFields) {
15269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
15279371c9d4SSatish Balay       } else {
15289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
152921968bf8SToby Isaac       }
153021968bf8SToby Isaac 
15319566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
153221968bf8SToby Isaac     }
15339566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
15349566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldN[p - pRefStart]));
153521968bf8SToby Isaac   }
15369566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
15379566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldN));
153821968bf8SToby Isaac   PetscFunctionReturn(0);
153921968bf8SToby Isaac }
154021968bf8SToby Isaac 
1541d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
1542d71ae5a4SJacob Faibussowitsch {
154321968bf8SToby Isaac   DM              refTree;
154421968bf8SToby Isaac   PetscDS         ds;
154521968bf8SToby Isaac   Mat             refCmat;
1546085f0adfSToby Isaac   PetscInt        numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
154721968bf8SToby Isaac   PetscScalar  ***refPointFieldMats, *pointWork;
154821968bf8SToby Isaac   PetscSection    refConSec, refAnSec, anSec;
154921968bf8SToby Isaac   IS              refAnIS, anIS;
155021968bf8SToby Isaac   const PetscInt *anchors;
155121968bf8SToby Isaac 
155221968bf8SToby Isaac   PetscFunctionBegin;
155321968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
15549566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
15559566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1556085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
15579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
15589566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, refTree));
15599566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
15609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
15619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anSec, &anIS));
15629566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(anIS, &anchors));
15639566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
15649566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(conSec, &conStart, &conEnd));
15659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
15669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
15679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof * maxAnDof, &pointWork));
156821968bf8SToby Isaac 
156921968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
15709566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
157195a0b26dSToby Isaac 
157295a0b26dSToby Isaac   /* step 2: compute the preorder */
15739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
15749566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(pEnd - pStart, &perm, pEnd - pStart, &iperm));
157595a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
157695a0b26dSToby Isaac     perm[p - pStart]  = p;
157795a0b26dSToby Isaac     iperm[p - pStart] = p - pStart;
157895a0b26dSToby Isaac   }
157995a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
158095a0b26dSToby Isaac     PetscInt point = perm[p];
158195a0b26dSToby Isaac     PetscInt parent;
158295a0b26dSToby Isaac 
15839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
158495a0b26dSToby Isaac     if (parent == point) {
158595a0b26dSToby Isaac       p++;
15869371c9d4SSatish Balay     } else {
158795a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
158895a0b26dSToby Isaac 
15899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
159095a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
159195a0b26dSToby Isaac         PetscInt q = closure[2 * i];
159295a0b26dSToby Isaac         if (iperm[q - pStart] > iperm[point - pStart]) {
159395a0b26dSToby Isaac           /* swap */
159495a0b26dSToby Isaac           perm[p]                 = q;
159595a0b26dSToby Isaac           perm[iperm[q - pStart]] = point;
159695a0b26dSToby Isaac           iperm[point - pStart]   = iperm[q - pStart];
159795a0b26dSToby Isaac           iperm[q - pStart]       = p;
159895a0b26dSToby Isaac           break;
159995a0b26dSToby Isaac         }
160095a0b26dSToby Isaac       }
160195a0b26dSToby Isaac       size = closureSize;
16029566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1603ad540459SPierre Jolivet       if (i == size) p++;
160495a0b26dSToby Isaac     }
160595a0b26dSToby Isaac   }
160695a0b26dSToby Isaac 
160795a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
160895a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
160995a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
161095a0b26dSToby Isaac    * values outside of the Mat first.
161195a0b26dSToby Isaac    */
161295a0b26dSToby Isaac   {
161395a0b26dSToby Isaac     PetscInt        nRows, row, nnz;
161495a0b26dSToby Isaac     PetscBool       done;
1615cd6fc93eSToby Isaac     PetscInt        secStart, secEnd;
161695a0b26dSToby Isaac     const PetscInt *ia, *ja;
161795a0b26dSToby Isaac     PetscScalar    *vals;
161895a0b26dSToby Isaac 
1619cd6fc93eSToby Isaac     PetscCall(PetscSectionGetChart(section, &secStart, &secEnd));
16209566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
162128b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not get RowIJ of constraint matrix");
162295a0b26dSToby Isaac     nnz = ia[nRows];
162395a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
162495a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
16259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vals));
162695a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
162795a0b26dSToby Isaac       PetscInt parent, childid, closureSize, *closure = NULL;
162895a0b26dSToby Isaac       PetscInt point = perm[p], pointDof;
162995a0b26dSToby Isaac 
16309566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, point, &parent, &childid));
163195a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
16329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(conSec, point, &pointDof));
163395a0b26dSToby Isaac       if (!pointDof) continue;
16349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1635085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1636085f0adfSToby Isaac         PetscInt            cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
163795a0b26dSToby Isaac         PetscScalar        *pointMat;
1638085f0adfSToby Isaac         const PetscInt    **perms;
1639085f0adfSToby Isaac         const PetscScalar **flips;
164095a0b26dSToby Isaac 
1641085f0adfSToby Isaac         if (numFields) {
16429566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(conSec, point, f, &cDof));
16439566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(conSec, point, f, &cOff));
16449371c9d4SSatish Balay         } else {
16459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(conSec, point, &cDof));
16469566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(conSec, point, &cOff));
164795a0b26dSToby Isaac         }
164895a0b26dSToby Isaac         if (!cDof) continue;
16499566063dSJacob Faibussowitsch         if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
16509566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetPointSyms(section, closureSize, closure, &perms, &flips));
165195a0b26dSToby Isaac 
165295a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
165376bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
165495a0b26dSToby Isaac           for (r = 0; r < cDof; r++) {
165595a0b26dSToby Isaac             if (cDof > 1 && r) {
165663a3b9bcSJacob Faibussowitsch               PetscCheck((ia[cOff + r + 1] - ia[cOff + r]) == (ia[cOff + r] - ia[cOff + r - 1]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two point rows have different nnz: %" PetscInt_FMT " vs. %" PetscInt_FMT, (ia[cOff + r + 1] - ia[cOff + r]), (ia[cOff + r] - ia[cOff + r - 1]));
165795a0b26dSToby Isaac             }
165895a0b26dSToby Isaac           }
165976bd3646SJed Brown         }
166095a0b26dSToby Isaac         /* zero rows */
1661ad540459SPierre Jolivet         for (i = ia[cOff]; i < ia[cOff + cDof]; i++) vals[i] = 0.;
166295a0b26dSToby Isaac         matOffset   = ia[cOff];
166395a0b26dSToby Isaac         numFillCols = ia[cOff + 1] - matOffset;
166495a0b26dSToby Isaac         pointMat    = refPointFieldMats[childid - pRefStart][f];
166595a0b26dSToby Isaac         numCols     = refPointFieldN[childid - pRefStart][f];
166695a0b26dSToby Isaac         offset      = 0;
166795a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
166895a0b26dSToby Isaac           PetscInt           q = closure[2 * i];
166995a0b26dSToby Isaac           PetscInt           aDof, aOff, j, k, qConDof, qConOff;
1670085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1671085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
167295a0b26dSToby Isaac 
167395a0b26dSToby Isaac           qConDof = qConOff = 0;
1674cd6fc93eSToby Isaac           if (q < secStart || q >= secEnd) continue;
1675085f0adfSToby Isaac           if (numFields) {
16769566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, q, f, &aDof));
16779566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, q, f, &aOff));
167895a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16799566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(conSec, q, f, &qConDof));
16809566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldOffset(conSec, q, f, &qConOff));
168195a0b26dSToby Isaac             }
16829371c9d4SSatish Balay           } else {
16839566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, q, &aDof));
16849566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, q, &aOff));
168595a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16869566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(conSec, q, &qConDof));
16879566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(conSec, q, &qConOff));
168895a0b26dSToby Isaac             }
168995a0b26dSToby Isaac           }
169095a0b26dSToby Isaac           if (!aDof) continue;
169195a0b26dSToby Isaac           if (qConDof) {
169295a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
169395a0b26dSToby Isaac              * be filled, thanks to preordering */
169495a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
169595a0b26dSToby Isaac             PetscInt aMatOffset   = ia[qConOff];
169695a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
169795a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
169895a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
169995a0b26dSToby Isaac                 PetscScalar inVal = 0;
170095a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1701085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
170295a0b26dSToby Isaac 
1703085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
170495a0b26dSToby Isaac                 }
170595a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
170695a0b26dSToby Isaac               }
170795a0b26dSToby Isaac             }
170895a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
170995a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
171095a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
171195a0b26dSToby Isaac               for (; k < numFillCols; k++) {
1712ad540459SPierre Jolivet                 if (ja[matOffset + k] == col) break;
171395a0b26dSToby Isaac               }
171463a3b9bcSJacob Faibussowitsch               PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, col);
1715ad540459SPierre Jolivet               for (r = 0; r < cDof; r++) vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
171695a0b26dSToby Isaac             }
17179371c9d4SSatish Balay           } else {
171895a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
171995a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
1720ad540459SPierre Jolivet               if (ja[matOffset + k] == aOff) break;
172195a0b26dSToby Isaac             }
172263a3b9bcSJacob Faibussowitsch             PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, aOff);
172395a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1724085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1725085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1726085f0adfSToby Isaac 
1727085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
172895a0b26dSToby Isaac               }
172995a0b26dSToby Isaac             }
173095a0b26dSToby Isaac           }
173195a0b26dSToby Isaac           offset += aDof;
173295a0b26dSToby Isaac         }
1733085f0adfSToby Isaac         if (numFields) {
17349566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestoreFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
1735085f0adfSToby Isaac         } else {
17369566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestorePointSyms(section, closureSize, closure, &perms, &flips));
1737085f0adfSToby Isaac         }
173895a0b26dSToby Isaac       }
17399566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
174095a0b26dSToby Isaac     }
174148a46eb9SPierre Jolivet     for (row = 0; row < nRows; row++) PetscCall(MatSetValues(cMat, 1, &row, ia[row + 1] - ia[row], &ja[ia[row]], &vals[ia[row]], INSERT_VALUES));
17429566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
174328b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not restore RowIJ of constraint matrix");
17449566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
17459566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
17469566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
174795a0b26dSToby Isaac   }
174895a0b26dSToby Isaac 
174995a0b26dSToby Isaac   /* clean up */
17509566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(anIS, &anchors));
17519566063dSJacob Faibussowitsch   PetscCall(PetscFree2(perm, iperm));
17529566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointWork));
17539566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
175495a0b26dSToby Isaac   PetscFunctionReturn(0);
175595a0b26dSToby Isaac }
175695a0b26dSToby Isaac 
17576f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
17586f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
1759d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTreeRefineCell(DM dm, PetscInt cell, DM *ncdm)
1760d71ae5a4SJacob Faibussowitsch {
17616f5f1567SToby Isaac   DM           K;
1762420f55faSMatthew G. Knepley   PetscMPIInt  rank;
17636f5f1567SToby Isaac   PetscInt     dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
17646f5f1567SToby Isaac   PetscInt     numNewCones, *newConeSizes, *newCones, *newOrientations;
17656f5f1567SToby Isaac   PetscInt    *Kembedding;
17666f5f1567SToby Isaac   PetscInt    *cellClosure = NULL, nc;
17676f5f1567SToby Isaac   PetscScalar *newVertexCoords;
17686f5f1567SToby Isaac   PetscInt     numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
17696f5f1567SToby Isaac   PetscSection parentSection;
17706f5f1567SToby Isaac 
17716f5f1567SToby Isaac   PetscFunctionBegin;
17729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
17739566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
17749566063dSJacob Faibussowitsch   PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
17759566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ncdm, dim));
17766f5f1567SToby Isaac 
17779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
17789566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &parentSection));
17799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &K));
17806858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
1781dd400576SPatrick Sanan   if (rank == 0) {
17826f5f1567SToby Isaac     /* compute the new charts */
17839566063dSJacob Faibussowitsch     PetscCall(PetscMalloc5(dim + 1, &pNewCount, dim + 1, &pNewStart, dim + 1, &pNewEnd, dim + 1, &pOldStart, dim + 1, &pOldEnd));
17846f5f1567SToby Isaac     offset = 0;
17856f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
17866f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
17876f5f1567SToby Isaac 
17886f5f1567SToby Isaac       pNewStart[d] = offset;
17899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, d, &pOldStart[d], &pOldEnd[d]));
17909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
17916f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
17926f5f1567SToby Isaac       /* adding the new points */
17936f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
17946f5f1567SToby Isaac       if (!d) {
17956f5f1567SToby Isaac         /* removing the cell */
17966f5f1567SToby Isaac         pNewCount[d]--;
17976f5f1567SToby Isaac       }
17986f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
17996f5f1567SToby Isaac         PetscInt parent;
18009566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &parent, NULL));
18016f5f1567SToby Isaac         if (parent == k) {
18026f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
18036f5f1567SToby Isaac           pNewCount[d]--;
18046f5f1567SToby Isaac         }
18056f5f1567SToby Isaac       }
18066f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
18076f5f1567SToby Isaac       offset     = pNewEnd[d];
18086f5f1567SToby Isaac     }
18091dca8a05SBarry Smith     PetscCheck(cell >= pOldStart[0] && cell < pOldEnd[0], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "%" PetscInt_FMT " not in cell range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cell, pOldStart[0], pOldEnd[0]);
18106f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
18119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
18126f5f1567SToby Isaac 
18139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pNewEnd[dim], &newConeSizes));
18146f5f1567SToby Isaac     {
1815b5a892a1SMatthew G. Knepley       DMPolytopeType pct, qct;
18166f5f1567SToby Isaac       PetscInt       kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
18176f5f1567SToby Isaac 
18189566063dSJacob Faibussowitsch       PetscCall(DMPlexGetChart(K, &kStart, &kEnd));
18199566063dSJacob Faibussowitsch       PetscCall(PetscMalloc4(kEnd - kStart, &Kembedding, kEnd - kStart, &perm, kEnd - kStart, &iperm, kEnd - kStart, &preOrient));
18206f5f1567SToby Isaac 
18216f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18226f5f1567SToby Isaac         perm[k - kStart]      = k;
18236f5f1567SToby Isaac         iperm[k - kStart]     = k - kStart;
18246f5f1567SToby Isaac         preOrient[k - kStart] = 0;
18256f5f1567SToby Isaac       }
18266f5f1567SToby Isaac 
18279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18286f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
18296f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2 * j + 1];
18306f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2 * j + 1];
18316f5f1567SToby Isaac         PetscInt p, q;
18326f5f1567SToby Isaac 
18336f5f1567SToby Isaac         p = closureK[2 * j];
18346f5f1567SToby Isaac         q = cellClosure[2 * j];
18359566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(K, p, &pct));
18369566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, q, &qct));
18376f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
1838ad540459SPierre Jolivet           if (q >= pOldStart[d] && q < pOldEnd[d]) Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
18396f5f1567SToby Isaac         }
1840b5a892a1SMatthew G. Knepley         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1841b5a892a1SMatthew G. Knepley         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
18426f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
18436f5f1567SToby Isaac           PetscInt        numChildren, i;
18446f5f1567SToby Isaac           const PetscInt *children;
18456f5f1567SToby Isaac 
18469566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(K, p, &numChildren, &children));
18476f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
18486f5f1567SToby Isaac             PetscInt kPerm, oPerm;
18496f5f1567SToby Isaac 
18506f5f1567SToby Isaac             k = children[i];
18519566063dSJacob Faibussowitsch             PetscCall(DMPlexReferenceTreeGetChildSymmetry(K, p, parentOrientA, 0, k, parentOrientB, &oPerm, &kPerm));
18526f5f1567SToby Isaac             /* perm = what refTree position I'm in */
18536f5f1567SToby Isaac             perm[kPerm - kStart] = k;
18546f5f1567SToby Isaac             /* iperm = who is at this position */
18556f5f1567SToby Isaac             iperm[k - kStart]         = kPerm - kStart;
18566f5f1567SToby Isaac             preOrient[kPerm - kStart] = oPerm;
18576f5f1567SToby Isaac           }
18586f5f1567SToby Isaac         }
18596f5f1567SToby Isaac       }
18609566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18616f5f1567SToby Isaac     }
18629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, 0, pNewEnd[dim]));
18636f5f1567SToby Isaac     offset      = 0;
18646f5f1567SToby Isaac     numNewCones = 0;
18656f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18666f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
18676f5f1567SToby Isaac       PetscInt p;
18686f5f1567SToby Isaac       PetscInt size;
18696f5f1567SToby Isaac 
18706f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
18716f5f1567SToby Isaac         /* skip cell 0 */
18726f5f1567SToby Isaac         if (p == cell) continue;
18736f5f1567SToby Isaac         /* old cones to new cones */
18749566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
18756f5f1567SToby Isaac         newConeSizes[offset++] = size;
18766f5f1567SToby Isaac         numNewCones += size;
18776f5f1567SToby Isaac       }
18786f5f1567SToby Isaac 
18799566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
18806f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18816f5f1567SToby Isaac         PetscInt kParent;
18826f5f1567SToby Isaac 
18839566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
18846f5f1567SToby Isaac         if (kParent != k) {
18856f5f1567SToby Isaac           Kembedding[k] = offset;
18869566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
18876f5f1567SToby Isaac           newConeSizes[offset++] = size;
18886f5f1567SToby Isaac           numNewCones += size;
188948a46eb9SPierre Jolivet           if (kParent != 0) PetscCall(PetscSectionSetDof(parentSection, Kembedding[k], 1));
18906f5f1567SToby Isaac         }
18916f5f1567SToby Isaac       }
18926f5f1567SToby Isaac     }
18936f5f1567SToby Isaac 
18949566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
18959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(parentSection, &numPointsWithParents));
18969566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numNewCones, &newCones, numNewCones, &newOrientations));
18979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPointsWithParents, &parents, numPointsWithParents, &childIDs));
18986f5f1567SToby Isaac 
18996f5f1567SToby Isaac     /* fill new cones */
19006f5f1567SToby Isaac     offset = 0;
19016f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19026f5f1567SToby Isaac       PetscInt        kStart, kEnd, k, l;
19036f5f1567SToby Isaac       PetscInt        p;
19046f5f1567SToby Isaac       PetscInt        size;
19056f5f1567SToby Isaac       const PetscInt *cone, *orientation;
19066f5f1567SToby Isaac 
19076f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19086f5f1567SToby Isaac         /* skip cell 0 */
19096f5f1567SToby Isaac         if (p == cell) continue;
19106f5f1567SToby Isaac         /* old cones to new cones */
19119566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
19129566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
19139566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeOrientation(dm, p, &orientation));
19146f5f1567SToby Isaac         for (l = 0; l < size; l++) {
19156f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
19166f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
19176f5f1567SToby Isaac         }
19186f5f1567SToby Isaac       }
19196f5f1567SToby Isaac 
19209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
19216f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19226f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
19236f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
19246f5f1567SToby Isaac 
19259566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
19266f5f1567SToby Isaac         if (kParent != k) {
19276f5f1567SToby Isaac           /* embed new cones */
19289566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
19299566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(K, kPerm, &cone));
19309566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeOrientation(K, kPerm, &orientation));
19316f5f1567SToby Isaac           for (l = 0; l < size; l++) {
19326f5f1567SToby Isaac             PetscInt       q, m = (preO >= 0) ? ((preO + l) % size) : ((size - (preO + 1) - l) % size);
19336f5f1567SToby Isaac             PetscInt       newO, lSize, oTrue;
1934b5a892a1SMatthew G. Knepley             DMPolytopeType ct = DM_NUM_POLYTOPES;
19356f5f1567SToby Isaac 
19366f5f1567SToby Isaac             q                = iperm[cone[m]];
19376f5f1567SToby Isaac             newCones[offset] = Kembedding[q];
19389566063dSJacob Faibussowitsch             PetscCall(DMPlexGetConeSize(K, q, &lSize));
1939b5a892a1SMatthew G. Knepley             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
1940b5a892a1SMatthew G. Knepley             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
1941b5a892a1SMatthew G. Knepley             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
19426f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
19436f5f1567SToby Isaac             newO                      = DihedralCompose(lSize, oTrue, preOrient[q]);
1944b5a892a1SMatthew G. Knepley             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
19456f5f1567SToby Isaac           }
19466f5f1567SToby Isaac           if (kParent != 0) {
19476f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
19489566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(parentSection, Kembedding[k], &pOffset));
19496f5f1567SToby Isaac             parents[pOffset]  = newPoint;
19506f5f1567SToby Isaac             childIDs[pOffset] = k;
19516f5f1567SToby Isaac           }
19526f5f1567SToby Isaac         }
19536f5f1567SToby Isaac       }
19546f5f1567SToby Isaac     }
19556f5f1567SToby Isaac 
19569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(dim * (pNewEnd[dim] - pNewStart[dim]), &newVertexCoords));
19576f5f1567SToby Isaac 
19586f5f1567SToby Isaac     /* fill coordinates */
19596f5f1567SToby Isaac     offset = 0;
19606f5f1567SToby Isaac     {
1961d90620a3SMatthew G. Knepley       PetscInt     kStart, kEnd, l;
19626f5f1567SToby Isaac       PetscSection vSection;
19636f5f1567SToby Isaac       PetscInt     v;
19646f5f1567SToby Isaac       Vec          coords;
19656f5f1567SToby Isaac       PetscScalar *coordvals;
19666f5f1567SToby Isaac       PetscInt     dof, off;
1967c111c6b7SMatthew G. Knepley       PetscReal    v0[3], J[9], detJ;
19686f5f1567SToby Isaac 
196976bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
1970d90620a3SMatthew G. Knepley         PetscInt k;
19719566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(K, 0, &kStart, &kEnd));
19726f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
19739566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
197463a3b9bcSJacob Faibussowitsch           PetscCheck(detJ > 0., PETSC_COMM_SELF, PETSC_ERR_PLIB, "reference tree cell %" PetscInt_FMT " has bad determinant", k);
19756f5f1567SToby Isaac         }
1976d90620a3SMatthew G. Knepley       }
19779566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
19789566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &vSection));
19799566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coords));
19809566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19816f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
19829566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(vSection, v, &dof));
19839566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(vSection, v, &off));
1984ad540459SPierre Jolivet         for (l = 0; l < dof; l++) newVertexCoords[offset++] = coordvals[off + l];
19856f5f1567SToby Isaac       }
19869566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
19876f5f1567SToby Isaac 
19889566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(K, &vSection));
19899566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(K, &coords));
19909566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(K, 0, &kStart, &kEnd));
19926f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
19939bc368c7SMatthew G. Knepley         PetscReal       coord[3], newCoord[3];
19946f5f1567SToby Isaac         PetscInt        vPerm = perm[v];
19956f5f1567SToby Isaac         PetscInt        kParent;
1996c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
19976f5f1567SToby Isaac 
19989566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, v, &kParent, NULL));
19996f5f1567SToby Isaac         if (kParent != v) {
20006f5f1567SToby Isaac           /* this is a new vertex */
20019566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(vSection, vPerm, &off));
20029bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off + l]);
2003367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
20049bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset + l] = newCoord[l];
20056f5f1567SToby Isaac           offset += dim;
20066f5f1567SToby Isaac         }
20076f5f1567SToby Isaac       }
20089566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
20096f5f1567SToby Isaac     }
20106f5f1567SToby Isaac 
20116f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
20126f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
20136f5f1567SToby Isaac       PetscInt tmp;
20146f5f1567SToby Isaac 
20156f5f1567SToby Isaac       tmp                = pNewCount[d];
20166f5f1567SToby Isaac       pNewCount[d]       = pNewCount[dim - d];
20176f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
20186f5f1567SToby Isaac     }
20196f5f1567SToby Isaac 
20209566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, pNewCount, newConeSizes, newCones, newOrientations, newVertexCoords));
20219566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20229566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, parents, childIDs));
20236f5f1567SToby Isaac 
20246f5f1567SToby Isaac     /* clean up */
20259566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
20269566063dSJacob Faibussowitsch     PetscCall(PetscFree5(pNewCount, pNewStart, pNewEnd, pOldStart, pOldEnd));
20279566063dSJacob Faibussowitsch     PetscCall(PetscFree(newConeSizes));
20289566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCones, newOrientations));
20299566063dSJacob Faibussowitsch     PetscCall(PetscFree(newVertexCoords));
20309566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parents, childIDs));
20319566063dSJacob Faibussowitsch     PetscCall(PetscFree4(Kembedding, perm, iperm, preOrient));
20329371c9d4SSatish Balay   } else {
20336f5f1567SToby Isaac     PetscInt     p, counts[4];
20346f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
20356f5f1567SToby Isaac     Vec          coordVec;
20366f5f1567SToby Isaac     PetscScalar *coords;
20376f5f1567SToby Isaac 
20386f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20396f5f1567SToby Isaac       PetscInt dStart, dEnd;
20406f5f1567SToby Isaac 
20419566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
20426f5f1567SToby Isaac       counts[d] = dEnd - dStart;
20436f5f1567SToby Isaac     }
20449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEnd - pStart, &coneSizes));
204548a46eb9SPierre Jolivet     for (p = pStart; p < pEnd; p++) PetscCall(DMPlexGetConeSize(dm, p, &coneSizes[p - pStart]));
20469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCones(dm, &cones));
20479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientations(dm, &orientations));
20489566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordVec));
20499566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordVec, &coords));
20506f5f1567SToby Isaac 
20519566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
20529566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
20539566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, counts, coneSizes, cones, orientations, NULL));
20549566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20559566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, NULL, NULL));
20569566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordVec, &coords));
20576f5f1567SToby Isaac   }
20589566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
20596f5f1567SToby Isaac 
20606f5f1567SToby Isaac   PetscFunctionReturn(0);
20616f5f1567SToby Isaac }
20626ecaa68aSToby Isaac 
2063d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
2064d71ae5a4SJacob Faibussowitsch {
20656ecaa68aSToby Isaac   PetscSF              coarseToFineEmbedded;
20666ecaa68aSToby Isaac   PetscSection         globalCoarse, globalFine;
20676ecaa68aSToby Isaac   PetscSection         localCoarse, localFine;
20686ecaa68aSToby Isaac   PetscSection         aSec, cSec;
20696ecaa68aSToby Isaac   PetscSection         rootIndicesSec, rootMatricesSec;
207046bdb399SToby Isaac   PetscSection         leafIndicesSec, leafMatricesSec;
207146bdb399SToby Isaac   PetscInt            *rootIndices, *leafIndices;
207246bdb399SToby Isaac   PetscScalar         *rootMatrices, *leafMatrices;
20736ecaa68aSToby Isaac   IS                   aIS;
20746ecaa68aSToby Isaac   const PetscInt      *anchors;
20756ecaa68aSToby Isaac   Mat                  cMat;
20764acb8e1eSToby Isaac   PetscInt             numFields, maxFields;
20776ecaa68aSToby Isaac   PetscInt             pStartC, pEndC, pStartF, pEndF, p;
20786ecaa68aSToby Isaac   PetscInt             aStart, aEnd, cStart, cEnd;
20791c58ffc4SToby Isaac   PetscInt            *maxChildIds;
2080e44e4e7fSToby Isaac   PetscInt            *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
20814acb8e1eSToby Isaac   const PetscInt    ***perms;
20824acb8e1eSToby Isaac   const PetscScalar ***flips;
20836ecaa68aSToby Isaac 
20846ecaa68aSToby Isaac   PetscFunctionBegin;
20859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
20869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
20879566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
20886ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
208989698031SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
209089698031SToby Isaac     const PetscInt *leaves;
20916ecaa68aSToby Isaac 
20929566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
209389698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
209489698031SToby Isaac       p = leaves ? leaves[l] : l;
20959566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
20969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2097ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
20986ecaa68aSToby Isaac     }
20999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
21007cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
210189698031SToby Isaac       p = leaves ? leaves[l] : l;
21029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
21039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2104ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
21056ecaa68aSToby Isaac     }
21069566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
21079566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
21086ecaa68aSToby Isaac   }
21096ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
21109566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
2111ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
211257168dbeSPierre Jolivet   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211357168dbeSPierre Jolivet   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211446bdb399SToby Isaac 
21159566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
21169566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
211746bdb399SToby Isaac 
21189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
21199566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
21209566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
212146bdb399SToby Isaac 
21229566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
21239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
212446bdb399SToby Isaac 
212546bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
21269566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
21279566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootMatricesSec));
21289566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootIndicesSec, pStartC, pEndC));
21299566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootMatricesSec, pStartC, pEndC));
21309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
2131713c1c5dSToby Isaac   maxFields = PetscMax(1, numFields);
21329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc7(maxFields + 1, &offsets, maxFields + 1, &offsetsCopy, maxFields + 1, &newOffsets, maxFields + 1, &newOffsetsCopy, maxFields + 1, &rowOffsets, maxFields + 1, &numD, maxFields + 1, &numO));
21339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxFields + 1, (PetscInt ****)&perms, maxFields + 1, (PetscScalar ****)&flips));
21349566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)perms, (maxFields + 1) * sizeof(const PetscInt **)));
21359566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)flips, (maxFields + 1) * sizeof(const PetscScalar **)));
213646bdb399SToby Isaac 
213746bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
21388d2f55e7SToby Isaac     PetscInt dof, matSize = 0;
21396ecaa68aSToby Isaac     PetscInt aDof          = 0;
21406ecaa68aSToby Isaac     PetscInt cDof          = 0;
21416ecaa68aSToby Isaac     PetscInt maxChildId    = maxChildIds[p - pStartC];
21426ecaa68aSToby Isaac     PetscInt numRowIndices = 0;
21436ecaa68aSToby Isaac     PetscInt numColIndices = 0;
2144f13f9184SToby Isaac     PetscInt f;
21456ecaa68aSToby Isaac 
21469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2147ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
214848a46eb9SPierre Jolivet     if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof));
214948a46eb9SPierre Jolivet     if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(cSec, p, &cDof));
2150f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2151f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
21526ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2153f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
21546ecaa68aSToby Isaac 
21559566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
215646bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
21576ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
21586ecaa68aSToby Isaac 
21599566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
21606ecaa68aSToby Isaac         numRowIndices += clDof;
21616ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21629566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &clDof));
21636ecaa68aSToby Isaac           offsets[f + 1] += clDof;
21646ecaa68aSToby Isaac         }
21656ecaa68aSToby Isaac       }
21666ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
21676ecaa68aSToby Isaac         offsets[f + 1] += offsets[f];
21686ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
21696ecaa68aSToby Isaac       }
217046bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
21719566063dSJacob Faibussowitsch       PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, NULL, NULL, NULL, &numColIndices, NULL, NULL, newOffsets, PETSC_FALSE));
21729566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
21736ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
21746ecaa68aSToby Isaac         numColIndices = numRowIndices;
21756ecaa68aSToby Isaac         matSize       = 0;
21769371c9d4SSatish Balay       } else if (numFields) { /* we send one submat for each field: sum their sizes */
21776ecaa68aSToby Isaac         matSize = 0;
21786ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21796ecaa68aSToby Isaac           PetscInt numRow, numCol;
21806ecaa68aSToby Isaac 
21816ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2182f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
21836ecaa68aSToby Isaac           matSize += numRow * numCol;
21846ecaa68aSToby Isaac         }
21859371c9d4SSatish Balay       } else {
21866ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
21876ecaa68aSToby Isaac       }
2188f13f9184SToby Isaac     } else if (maxChildId == -1) {
21898d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2190f13f9184SToby Isaac         PetscInt aOff, a;
21916ecaa68aSToby Isaac 
21929566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
21936ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21946ecaa68aSToby Isaac           PetscInt fDof;
21956ecaa68aSToby Isaac 
21969566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
219721968bf8SToby Isaac           offsets[f + 1] = fDof;
21986ecaa68aSToby Isaac         }
21996ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
22006ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
22016ecaa68aSToby Isaac 
22029566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(localCoarse, anchor, &aLocalDof));
22036ecaa68aSToby Isaac           numColIndices += aLocalDof;
22046ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
22056ecaa68aSToby Isaac             PetscInt fDof;
22066ecaa68aSToby Isaac 
22079566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
220821968bf8SToby Isaac             newOffsets[f + 1] += fDof;
22096ecaa68aSToby Isaac           }
22106ecaa68aSToby Isaac         }
22116ecaa68aSToby Isaac         if (numFields) {
22126ecaa68aSToby Isaac           matSize = 0;
2213ad540459SPierre Jolivet           for (f = 0; f < numFields; f++) matSize += offsets[f + 1] * newOffsets[f + 1];
22149371c9d4SSatish Balay         } else {
22156ecaa68aSToby Isaac           matSize = numColIndices * dof;
22166ecaa68aSToby Isaac         }
22179371c9d4SSatish Balay       } else { /* no children, and no constraints on dofs: just get the global indices */
22186ecaa68aSToby Isaac         numColIndices = dof;
22196ecaa68aSToby Isaac         matSize       = 0;
22206ecaa68aSToby Isaac       }
22218d2f55e7SToby Isaac     }
222246bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
22239566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootIndicesSec, p, numColIndices ? numColIndices + 2 * numFields : 0));
22249566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootMatricesSec, p, matSize));
22256ecaa68aSToby Isaac   }
22269566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootIndicesSec));
22279566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootMatricesSec));
22286ecaa68aSToby Isaac   {
22296ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
22306ecaa68aSToby Isaac 
22319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
22329566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootMatricesSec, &numRootMatrices));
22339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numRootIndices, &rootIndices, numRootMatrices, &rootMatrices));
22346ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
22356ecaa68aSToby Isaac       PetscInt     numRowIndices, numColIndices, matSize, dof;
2236f13f9184SToby Isaac       PetscInt     pIndOff, pMatOff, f;
22376ecaa68aSToby Isaac       PetscInt    *pInd;
22386ecaa68aSToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
22396ecaa68aSToby Isaac       PetscScalar *pMat       = NULL;
22406ecaa68aSToby Isaac 
22419566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, p, &numColIndices));
2242ad540459SPierre Jolivet       if (!numColIndices) continue;
2243f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2244f13f9184SToby Isaac         offsets[f]        = 0;
2245f13f9184SToby Isaac         newOffsets[f]     = 0;
2246f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2247f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2248f13f9184SToby Isaac       }
22496ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
22509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, p, &pIndOff));
22516ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
22529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootMatricesSec, p, &matSize));
22536ecaa68aSToby Isaac       if (matSize) {
22549566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootMatricesSec, p, &pMatOff));
22556ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
22566ecaa68aSToby Isaac       }
22579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2258ad540459SPierre Jolivet       if (dof < 0) dof = -(dof + 1);
22596ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
22606ecaa68aSToby Isaac         PetscInt i, j;
22616ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
22626ecaa68aSToby Isaac 
22636ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
22646ecaa68aSToby Isaac           PetscInt numIndices, *indices;
22659566063dSJacob Faibussowitsch           PetscCall(DMPlexGetClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
226608401ef6SPierre Jolivet           PetscCheck(numIndices == numColIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "mismatching constraint indices calculations");
2267ad540459SPierre Jolivet           for (i = 0; i < numColIndices; i++) pInd[i] = indices[i];
22686ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
226946bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i + 1];
227046bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i + 1];
22716ecaa68aSToby Isaac           }
22729566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
22739371c9d4SSatish Balay         } else {
22746ecaa68aSToby Isaac           PetscInt     closureSize, *closure = NULL, cl;
22756ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
22766ecaa68aSToby Isaac           PetscInt     numPoints, *points;
22776ecaa68aSToby Isaac 
22789566063dSJacob Faibussowitsch           PetscCall(DMGetWorkArray(coarse, numRowIndices * numRowIndices, MPIU_SCALAR, &pMatIn));
22796ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
2280ad540459SPierre Jolivet             for (j = 0; j < numRowIndices; j++) pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
22816ecaa68aSToby Isaac           }
22829566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22834acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
22849566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
22859566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
22864acb8e1eSToby Isaac           }
22876ecaa68aSToby Isaac           if (numFields) {
22886ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
22896ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
22906ecaa68aSToby Isaac 
22916ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
22926ecaa68aSToby Isaac                 PetscInt fDof;
22936ecaa68aSToby Isaac 
22949566063dSJacob Faibussowitsch                 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &fDof));
22956ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
22966ecaa68aSToby Isaac               }
22976ecaa68aSToby Isaac             }
22986ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
22996ecaa68aSToby Isaac               offsets[f + 1] += offsets[f];
23006ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
23016ecaa68aSToby Isaac             }
23026ecaa68aSToby Isaac           }
23034acb8e1eSToby Isaac           /* TODO : flips here ? */
23046ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
23059566063dSJacob Faibussowitsch           PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, perms, pMatIn, &numPoints, NULL, &points, &pMatModified, newOffsets, PETSC_FALSE));
23064acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23079566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
23089566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
23094acb8e1eSToby Isaac           }
23104acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23119566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23129566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23134acb8e1eSToby Isaac           }
23146ecaa68aSToby Isaac           if (!numFields) {
2315ad540459SPierre Jolivet             for (i = 0; i < numRowIndices * numColIndices; i++) pMat[i] = pMatModified[i];
23169371c9d4SSatish Balay           } else {
2317f13f9184SToby Isaac             PetscInt i, j, count;
23186ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
23196ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f + 1]; i++) {
2320ad540459SPierre Jolivet                 for (j = newOffsets[f]; j < newOffsets[f + 1]; j++, count++) pMat[count] = pMatModified[i * numColIndices + j];
23216ecaa68aSToby Isaac               }
23226ecaa68aSToby Isaac             }
23236ecaa68aSToby Isaac           }
23249566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatModified));
23259566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
23269566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatIn));
23276ecaa68aSToby Isaac           if (numFields) {
232846bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
232946bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f + 1];
233046bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f + 1];
23316ecaa68aSToby Isaac             }
23324acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23334acb8e1eSToby Isaac               PetscInt globalOff, c = points[2 * cl];
23349566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23359566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
23366ecaa68aSToby Isaac             }
23376ecaa68aSToby Isaac           } else {
23384acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23394acb8e1eSToby Isaac               PetscInt        c    = points[2 * cl], globalOff;
23404acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
23414acb8e1eSToby Isaac 
23429566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23439566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
23446ecaa68aSToby Isaac             }
23456ecaa68aSToby Isaac           }
23464acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23479566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23489566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23494acb8e1eSToby Isaac           }
23509566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numPoints, MPIU_SCALAR, &points));
23516ecaa68aSToby Isaac         }
23529371c9d4SSatish Balay       } else if (matSize) {
23536ecaa68aSToby Isaac         PetscInt  cOff;
23546ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
23556ecaa68aSToby Isaac 
23566ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
235708401ef6SPierre Jolivet         PetscCheck(numRowIndices == dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Miscounted dofs");
23589566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
23599566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
23609566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, p, &cOff));
23619566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
23629566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
23636ecaa68aSToby Isaac         if (numFields) {
23646ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23656ecaa68aSToby Isaac             PetscInt fDof;
2366f13f9184SToby Isaac 
23679566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSec, p, f, &fDof));
23686ecaa68aSToby Isaac             offsets[f + 1] = fDof;
23696ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
23706ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
23719566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
23726ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
23736ecaa68aSToby Isaac             }
23746ecaa68aSToby Isaac           }
23756ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23766ecaa68aSToby Isaac             offsets[f + 1] += offsets[f];
23776ecaa68aSToby Isaac             offsetsCopy[f + 1] = offsets[f + 1];
23786ecaa68aSToby Isaac             newOffsets[f + 1] += newOffsets[f];
23796ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
23806ecaa68aSToby Isaac           }
23819566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, -1, NULL, rowIndices));
23826ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23836ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23849566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23859566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, -1, NULL, colIndices));
23866ecaa68aSToby Isaac           }
23879371c9d4SSatish Balay         } else {
23889566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, NULL, rowIndices));
23896ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23906ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23919566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23929566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, NULL, colIndices));
23936ecaa68aSToby Isaac           }
23946ecaa68aSToby Isaac         }
23956ecaa68aSToby Isaac         if (numFields) {
2396f13f9184SToby Isaac           PetscInt count, a;
2397f13f9184SToby Isaac 
23986ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
23996ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
24006ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
24019566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat, iSize, &rowIndices[offsets[f]], jSize, &colIndices[newOffsets[f]], &pMat[count]));
24026ecaa68aSToby Isaac             count += iSize * jSize;
240346bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
240446bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f + 1];
24056ecaa68aSToby Isaac           }
24066ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24076ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24086ecaa68aSToby Isaac             PetscInt gOff;
24099566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24109566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, -1, NULL, pInd));
24116ecaa68aSToby Isaac           }
24129371c9d4SSatish Balay         } else {
24136ecaa68aSToby Isaac           PetscInt a;
24149566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat, numRowIndices, rowIndices, numColIndices, colIndices, pMat));
24156ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24166ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24176ecaa68aSToby Isaac             PetscInt gOff;
24189566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24199566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, NULL, pInd));
24206ecaa68aSToby Isaac           }
24216ecaa68aSToby Isaac         }
24229566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
24239566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
24249371c9d4SSatish Balay       } else {
24256ecaa68aSToby Isaac         PetscInt gOff;
24266ecaa68aSToby Isaac 
24279566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
24286ecaa68aSToby Isaac         if (numFields) {
24296ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
24306ecaa68aSToby Isaac             PetscInt fDof;
24319566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
24326ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
24336ecaa68aSToby Isaac           }
24346ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
243546bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
243646bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f + 1];
24376ecaa68aSToby Isaac           }
24389566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2439367003a6SStefano Zampini         } else {
24409566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
24416ecaa68aSToby Isaac         }
24426ecaa68aSToby Isaac       }
24436ecaa68aSToby Isaac     }
24449566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
24456ecaa68aSToby Isaac   }
244646bdb399SToby Isaac   {
244746bdb399SToby Isaac     PetscSF   indicesSF, matricesSF;
244846bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
244946bdb399SToby Isaac 
24509566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
24519566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafMatricesSec));
24529566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootIndicesSec, &remoteOffsetsIndices, leafIndicesSec));
24539566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootMatricesSec, &remoteOffsetsMatrices, leafMatricesSec));
24549566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootIndicesSec, remoteOffsetsIndices, leafIndicesSec, &indicesSF));
24559566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootMatricesSec, remoteOffsetsMatrices, leafMatricesSec, &matricesSF));
24569566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
24579566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsIndices));
24589566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsMatrices));
24599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numLeafIndices));
24609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafMatricesSec, &numLeafMatrices));
24619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numLeafIndices, &leafIndices, numLeafMatrices, &leafMatrices));
24629566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24639566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24649566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24659566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24669566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&matricesSF));
24679566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
24689566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rootIndices, rootMatrices));
24699566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootIndicesSec));
24709566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootMatricesSec));
247146bdb399SToby Isaac   }
247246bdb399SToby Isaac   /* count to preallocate */
24739566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
247446bdb399SToby Isaac   {
247546bdb399SToby Isaac     PetscInt       nGlobal;
247646bdb399SToby Isaac     PetscInt      *dnnz, *onnz;
2477b9a5774bSToby Isaac     PetscLayout    rowMap, colMap;
2478b9a5774bSToby Isaac     PetscInt       rowStart, rowEnd, colStart, colEnd;
24791c58ffc4SToby Isaac     PetscInt       maxDof;
24801c58ffc4SToby Isaac     PetscInt      *rowIndices;
24811c58ffc4SToby Isaac     DM             refTree;
24821c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
24831c58ffc4SToby Isaac     PetscScalar ***refPointFieldMats;
24841c58ffc4SToby Isaac     PetscSection   refConSec, refAnSec;
24850eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, maxConDof, maxColumns, leafStart, leafEnd;
24861c58ffc4SToby Isaac     PetscScalar   *pointWork;
248746bdb399SToby Isaac 
24889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine, &nGlobal));
24899566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nGlobal, &dnnz, nGlobal, &onnz));
24909566063dSJacob Faibussowitsch     PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
24919566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rowMap));
24929566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(colMap));
24939566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
24949566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
24959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
24969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafIndicesSec, &leafStart, &leafEnd));
24979566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
24980eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
249946bdb399SToby Isaac       PetscInt gDof, gcDof, gOff;
250046bdb399SToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
250146bdb399SToby Isaac       PetscInt matSize;
250221968bf8SToby Isaac       PetscInt i;
250346bdb399SToby Isaac 
25049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
25059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2506ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
25079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
250808401ef6SPierre Jolivet       PetscCheck(gOff >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I though having global dofs meant a non-negative offset");
25091dca8a05SBarry Smith       PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I thought the row map would constrain the global dofs");
25109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
25119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
251246bdb399SToby Isaac       numColIndices -= 2 * numFields;
251308401ef6SPierre Jolivet       PetscCheck(numColIndices > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "global fine dof with no dofs to interpolate from");
251446bdb399SToby Isaac       pInd              = &leafIndices[pIndOff];
251521968bf8SToby Isaac       offsets[0]        = 0;
251621968bf8SToby Isaac       offsetsCopy[0]    = 0;
251721968bf8SToby Isaac       newOffsets[0]     = 0;
251821968bf8SToby Isaac       newOffsetsCopy[0] = 0;
251946bdb399SToby Isaac       if (numFields) {
252021968bf8SToby Isaac         PetscInt f;
252146bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
252246bdb399SToby Isaac           PetscInt rowDof;
252346bdb399SToby Isaac 
25249566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
252521968bf8SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
252621968bf8SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
252721968bf8SToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
252821968bf8SToby Isaac           numD[f]            = 0;
252921968bf8SToby Isaac           numO[f]            = 0;
253046bdb399SToby Isaac         }
25319566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
253246bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
253321968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
253421968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
253546bdb399SToby Isaac 
253646bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
253746bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
253846bdb399SToby Isaac 
253946bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
254021968bf8SToby Isaac               numD[f]++;
25419371c9d4SSatish Balay             } else if (gInd >= 0) { /* negative means non-entry */
254221968bf8SToby Isaac               numO[f]++;
254346bdb399SToby Isaac             }
254446bdb399SToby Isaac           }
254546bdb399SToby Isaac         }
25469371c9d4SSatish Balay       } else {
25479566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
254821968bf8SToby Isaac         numD[0] = 0;
254921968bf8SToby Isaac         numO[0] = 0;
255046bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
255146bdb399SToby Isaac           PetscInt gInd = pInd[i];
255246bdb399SToby Isaac 
255346bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
255421968bf8SToby Isaac             numD[0]++;
25559371c9d4SSatish Balay           } else if (gInd >= 0) { /* negative means non-entry */
255621968bf8SToby Isaac             numO[0]++;
255746bdb399SToby Isaac           }
255846bdb399SToby Isaac         }
255946bdb399SToby Isaac       }
25609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
256146bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
256246bdb399SToby Isaac         PetscInt childId;
256346bdb399SToby Isaac 
256446bdb399SToby Isaac         childId = childIds[p - pStartF];
256521968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
256646bdb399SToby Isaac           if (numFields) {
2567b9a5774bSToby Isaac             PetscInt f;
2568b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
256921968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
257046bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
257121968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
257221968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
257346bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25741dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2575b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
25769371c9d4SSatish Balay                 } else if (gIndCoarse >= 0) { /* remote */
25771dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2578b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
25799371c9d4SSatish Balay                 } else { /* constrained */
258008401ef6SPierre Jolivet                   PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
258146bdb399SToby Isaac                 }
258246bdb399SToby Isaac               }
258346bdb399SToby Isaac             }
25849371c9d4SSatish Balay           } else {
2585b9a5774bSToby Isaac             PetscInt i;
2586b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
258746bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
258846bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
258946bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25901dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2591b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
25929371c9d4SSatish Balay               } else if (gIndCoarse >= 0) { /* remote */
25931dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2594b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
25959371c9d4SSatish Balay               } else { /* constrained */
259608401ef6SPierre Jolivet                 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
259746bdb399SToby Isaac               }
259846bdb399SToby Isaac             }
259946bdb399SToby Isaac           }
26009371c9d4SSatish Balay         } else { /* interpolate from all */
260146bdb399SToby Isaac           if (numFields) {
2602b9a5774bSToby Isaac             PetscInt f;
2603b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
260421968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
260546bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
260621968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
260746bdb399SToby Isaac                 if (gIndFine >= 0) {
26081dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2609b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2610b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
261146bdb399SToby Isaac                 }
261246bdb399SToby Isaac               }
261346bdb399SToby Isaac             }
26149371c9d4SSatish Balay           } else {
2615b9a5774bSToby Isaac             PetscInt i;
2616b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
261746bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
261846bdb399SToby Isaac               if (gIndFine >= 0) {
26191dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2620b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2621b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
262246bdb399SToby Isaac               }
262346bdb399SToby Isaac             }
262446bdb399SToby Isaac           }
262546bdb399SToby Isaac         }
26269371c9d4SSatish Balay       } else { /* interpolate from all */
262746bdb399SToby Isaac         if (numFields) {
2628b9a5774bSToby Isaac           PetscInt f;
2629b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
263021968bf8SToby Isaac             PetscInt numRows = offsets[f + 1] - offsets[f], row;
263146bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
263221968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
263346bdb399SToby Isaac               if (gIndFine >= 0) {
26341dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2635b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2636b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
263746bdb399SToby Isaac               }
263846bdb399SToby Isaac             }
263946bdb399SToby Isaac           }
26409371c9d4SSatish Balay         } else { /* every dof get a full row */
2641b9a5774bSToby Isaac           PetscInt i;
2642b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
264346bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
264446bdb399SToby Isaac             if (gIndFine >= 0) {
26451dca8a05SBarry Smith               PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2646b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2647b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
264846bdb399SToby Isaac             }
264946bdb399SToby Isaac           }
265046bdb399SToby Isaac         }
265146bdb399SToby Isaac       }
265246bdb399SToby Isaac     }
26539566063dSJacob Faibussowitsch     PetscCall(MatXAIJSetPreallocation(mat, 1, dnnz, onnz, NULL, NULL));
26549566063dSJacob Faibussowitsch     PetscCall(PetscFree2(dnnz, onnz));
265521968bf8SToby Isaac 
26569566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
26579566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
26589566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
26599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
26609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
26619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(refConSec, &maxConDof));
26629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(leafIndicesSec, &maxColumns));
26639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxConDof * maxColumns, &pointWork));
26640eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2665e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2666e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2667e44e4e7fSToby Isaac       PetscInt matSize;
2668e44e4e7fSToby Isaac       PetscInt childId;
2669e44e4e7fSToby Isaac 
26709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
26719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2672ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
2673e44e4e7fSToby Isaac       childId = childIds[p - pStartF];
26749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
26759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
26769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2677e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2678e44e4e7fSToby Isaac       pInd              = &leafIndices[pIndOff];
2679e44e4e7fSToby Isaac       offsets[0]        = 0;
2680e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2681e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2682e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2683e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2684e44e4e7fSToby Isaac       if (numFields) {
2685e44e4e7fSToby Isaac         PetscInt f;
2686e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2687e44e4e7fSToby Isaac           PetscInt rowDof;
2688e44e4e7fSToby Isaac 
26899566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2690e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2691e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2692e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2693e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2694e44e4e7fSToby Isaac         }
26959566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
26969371c9d4SSatish Balay       } else {
26979566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
26981c58ffc4SToby Isaac       }
26999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2700e44e4e7fSToby Isaac       if (!matSize) {      /* incoming matrix is identity */
2701e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2702e44e4e7fSToby Isaac           if (numFields) {
2703e44e4e7fSToby Isaac             PetscInt f;
2704e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2705e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
270648a46eb9SPierre Jolivet               for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[offsets[f] + row], pInd[newOffsets[f] + row], 1., INSERT_VALUES));
270721968bf8SToby Isaac             }
27089371c9d4SSatish Balay           } else {
2709e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
271048a46eb9SPierre Jolivet             for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[row], pInd[row], 1., INSERT_VALUES));
2711e44e4e7fSToby Isaac           }
27129371c9d4SSatish Balay         } else { /* interpolate from all */
2713e44e4e7fSToby Isaac           if (numFields) {
2714e44e4e7fSToby Isaac             PetscInt f;
2715e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2716e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f];
2717e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
27189566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], refPointFieldMats[childId - pRefStart][f], INSERT_VALUES));
2719e44e4e7fSToby Isaac             }
27209371c9d4SSatish Balay           } else {
27219566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, refPointFieldMats[childId - pRefStart][0], INSERT_VALUES));
2722e44e4e7fSToby Isaac           }
2723e44e4e7fSToby Isaac         }
27249371c9d4SSatish Balay       } else { /* interpolate from all */
2725e44e4e7fSToby Isaac         PetscInt     pMatOff;
2726e44e4e7fSToby Isaac         PetscScalar *pMat;
2727e44e4e7fSToby Isaac 
27289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafMatricesSec, p, &pMatOff));
2729e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2730e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2731e44e4e7fSToby Isaac           if (numFields) {
2732e44e4e7fSToby Isaac             PetscInt f, count;
2733e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2734e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2735e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2736e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2737e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2738e44e4e7fSToby Isaac 
27399566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], inMat, INSERT_VALUES));
2740e44e4e7fSToby Isaac               count += numCols * numInRows;
2741e44e4e7fSToby Isaac             }
27429371c9d4SSatish Balay           } else {
27439566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, pMat, INSERT_VALUES));
2744e44e4e7fSToby Isaac           }
27459371c9d4SSatish Balay         } else { /* multiply the incoming matrix by the child interpolation */
2746e44e4e7fSToby Isaac           if (numFields) {
2747e44e4e7fSToby Isaac             PetscInt f, count;
2748e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2749e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2750e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2751e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2752e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2753e44e4e7fSToby Isaac               PetscInt     i, j, k;
275408401ef6SPierre Jolivet               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2755e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2756e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2757e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2758ad540459SPierre Jolivet                   for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2759e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2760e44e4e7fSToby Isaac                 }
2761e44e4e7fSToby Isaac               }
27629566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], pointWork, INSERT_VALUES));
2763e44e4e7fSToby Isaac               count += numCols * numInRows;
2764e44e4e7fSToby Isaac             }
27659371c9d4SSatish Balay           } else { /* every dof gets a full row */
2766e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2767e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2768e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2769e44e4e7fSToby Isaac             PetscInt i, j, k;
277008401ef6SPierre Jolivet             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2771e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2772e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2773e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2774ad540459SPierre Jolivet                 for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2775e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2776e44e4e7fSToby Isaac               }
2777e44e4e7fSToby Isaac             }
27789566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, numRows, rowIndices, numCols, pInd, pointWork, INSERT_VALUES));
2779e44e4e7fSToby Isaac           }
2780e44e4e7fSToby Isaac         }
2781e44e4e7fSToby Isaac       }
2782e44e4e7fSToby Isaac     }
27839566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
27849566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
27859566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointWork));
2786e44e4e7fSToby Isaac   }
27879566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
27889566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
27899566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
27909566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafMatricesSec));
27919566063dSJacob Faibussowitsch   PetscCall(PetscFree2(leafIndices, leafMatrices));
27929566063dSJacob Faibussowitsch   PetscCall(PetscFree2(*(PetscInt ****)&perms, *(PetscScalar ****)&flips));
27939566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
27949566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
27956ecaa68aSToby Isaac   PetscFunctionReturn(0);
27966ecaa68aSToby Isaac }
2797154bca37SToby Isaac 
27988d2f55e7SToby Isaac /*
27998d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
28008d2f55e7SToby Isaac  *
28018d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
28028d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
28038d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
28048d2f55e7SToby Isaac  *       a_{i,j} = 0;
28058d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
28068d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
28078d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
28088d2f55e7SToby Isaac  */
2809d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
2810d71ae5a4SJacob Faibussowitsch {
28118d2f55e7SToby Isaac   PetscDS      ds;
28128d2f55e7SToby Isaac   PetscSection section, cSection;
28138d2f55e7SToby Isaac   DMLabel      canonical, depth;
28148d2f55e7SToby Isaac   Mat          cMat, mat;
28158d2f55e7SToby Isaac   PetscInt    *nnz;
28168d2f55e7SToby Isaac   PetscInt     f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
28178d2f55e7SToby Isaac   PetscInt     m, n;
28188d2f55e7SToby Isaac   PetscScalar *pointScalar;
28198d2f55e7SToby Isaac   PetscReal   *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
28208d2f55e7SToby Isaac 
28218d2f55e7SToby Isaac   PetscFunctionBegin;
28229566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &section));
28239566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(refTree, &dim));
28249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(dim, &v0, dim, &v0parent, dim, &vtmp, dim * dim, &J, dim * dim, &Jparent, dim * dim, &invJ));
28259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(dim, &pointScalar, dim, &pointRef));
28269566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
28279566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
28289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numSecFields));
28299566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "canonical", &canonical));
28309566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "depth", &depth));
28319566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSection, &cMat, NULL));
28329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
28339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
28349566063dSJacob Faibussowitsch   PetscCall(MatGetSize(cMat, &n, &m)); /* the injector has transpose sizes from the constraint matrix */
28358d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
28369566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(m, &nnz));
28378d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) { /* a point will have non-zeros if it is canonical, it has dofs, and its children have dofs */
28388d2f55e7SToby Isaac     const PetscInt *children;
28398d2f55e7SToby Isaac     PetscInt        numChildren;
28408d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28418d2f55e7SToby Isaac 
28428d2f55e7SToby Isaac     if (canonical) {
28438d2f55e7SToby Isaac       PetscInt pCanonical;
28449566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28458d2f55e7SToby Isaac       if (p != pCanonical) continue;
28468d2f55e7SToby Isaac     }
28479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28488d2f55e7SToby Isaac     if (!numChildren) continue;
28498d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28508d2f55e7SToby Isaac       PetscInt child = children[i];
28518d2f55e7SToby Isaac       PetscInt dof;
28528d2f55e7SToby Isaac 
28539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
28548d2f55e7SToby Isaac       numChildDof += dof;
28558d2f55e7SToby Isaac     }
28569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
28578d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
28588d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
28598d2f55e7SToby Isaac       PetscInt selfOff;
28608d2f55e7SToby Isaac 
28618d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
28628d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
28638d2f55e7SToby Isaac           PetscInt child = children[i];
28648d2f55e7SToby Isaac           PetscInt dof;
28658d2f55e7SToby Isaac 
28669566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
28678d2f55e7SToby Isaac           numChildDof += dof;
28688d2f55e7SToby Isaac         }
28699566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
28709566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
28719371c9d4SSatish Balay       } else {
28729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
28738d2f55e7SToby Isaac       }
2874ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) nnz[selfOff + i] = numChildDof;
28758d2f55e7SToby Isaac     }
28768d2f55e7SToby Isaac   }
28779566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(PETSC_COMM_SELF, m, n, m, n, -1, nnz, -1, NULL, &mat));
28789566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
28798d2f55e7SToby Isaac   /* Setp 2: compute entries */
28808d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
28818d2f55e7SToby Isaac     const PetscInt *children;
28828d2f55e7SToby Isaac     PetscInt        numChildren;
28838d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28848d2f55e7SToby Isaac 
28858d2f55e7SToby Isaac     /* same conditions about when entries occur */
28868d2f55e7SToby Isaac     if (canonical) {
28878d2f55e7SToby Isaac       PetscInt pCanonical;
28889566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28898d2f55e7SToby Isaac       if (p != pCanonical) continue;
28908d2f55e7SToby Isaac     }
28919566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28928d2f55e7SToby Isaac     if (!numChildren) continue;
28938d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28948d2f55e7SToby Isaac       PetscInt child = children[i];
28958d2f55e7SToby Isaac       PetscInt dof;
28968d2f55e7SToby Isaac 
28979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
28988d2f55e7SToby Isaac       numChildDof += dof;
28998d2f55e7SToby Isaac     }
29009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
29018d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
29028d2f55e7SToby Isaac 
29038d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
290459fc6756SToby Isaac       PetscInt        pI = -1, cI = -1;
290552a3aeb4SToby Isaac       PetscInt        selfOff, Nc, parentCell;
29068d2f55e7SToby Isaac       PetscInt        cellShapeOff;
29078d2f55e7SToby Isaac       PetscObject     disc;
29088d2f55e7SToby Isaac       PetscDualSpace  dsp;
29098d2f55e7SToby Isaac       PetscClassId    classId;
29108d2f55e7SToby Isaac       PetscScalar    *pointMat;
29113b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
29128d2f55e7SToby Isaac       PetscInt        pO = PETSC_MIN_INT;
29138d2f55e7SToby Isaac       const PetscInt *depthNumDof;
29148d2f55e7SToby Isaac 
29158d2f55e7SToby Isaac       if (numSecFields) {
29168d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
29178d2f55e7SToby Isaac           PetscInt child = children[i];
29188d2f55e7SToby Isaac           PetscInt dof;
29198d2f55e7SToby Isaac 
29209566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
29218d2f55e7SToby Isaac           numChildDof += dof;
29228d2f55e7SToby Isaac         }
29239566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
29249566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
29259371c9d4SSatish Balay       } else {
29269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
29278d2f55e7SToby Isaac       }
29288d2f55e7SToby Isaac 
29293b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
29308d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
29318d2f55e7SToby Isaac         parentCell = p;
29329371c9d4SSatish Balay       } else {
29338d2f55e7SToby Isaac         PetscInt *star = NULL;
29348d2f55e7SToby Isaac         PetscInt  numStar;
29358d2f55e7SToby Isaac 
29368d2f55e7SToby Isaac         parentCell = -1;
29379566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29388d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
29398d2f55e7SToby Isaac           PetscInt c = star[2 * i];
29408d2f55e7SToby Isaac 
29418d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
29428d2f55e7SToby Isaac             parentCell = c;
29438d2f55e7SToby Isaac             break;
29448d2f55e7SToby Isaac           }
29458d2f55e7SToby Isaac         }
29469566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29478d2f55e7SToby Isaac       }
2948a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
29499566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
29509566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc, &classId));
2951c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
29529566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
29539371c9d4SSatish Balay       } else if (classId == PETSCFV_CLASSID) {
29549566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace((PetscFV)disc, &dsp));
29559371c9d4SSatish Balay       } else {
29569b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported discretization object");
2957c5356c36SToby Isaac       }
29589566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumDof(dsp, &depthNumDof));
29599566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumComponents(dsp, &Nc));
29608d2f55e7SToby Isaac       {
29618d2f55e7SToby Isaac         PetscInt *closure = NULL;
29628d2f55e7SToby Isaac         PetscInt  numClosure;
29638d2f55e7SToby Isaac 
29649566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
296559fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
29668d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
29678d2f55e7SToby Isaac 
29688d2f55e7SToby Isaac           pO = closure[2 * i + 1];
296959fc6756SToby Isaac           if (point == p) {
297059fc6756SToby Isaac             pI = i;
297159fc6756SToby Isaac             break;
297259fc6756SToby Isaac           }
29739566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(depth, point, &pointDepth));
29748d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
29758d2f55e7SToby Isaac         }
29769566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
29778d2f55e7SToby Isaac       }
29788d2f55e7SToby Isaac 
29799566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
29809566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
298152a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
2982ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) matRows[i] = selfOff + i;
298352a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
29843b1c2a6aSToby Isaac       {
29853b1c2a6aSToby Isaac         PetscInt colOff = 0;
29863b1c2a6aSToby Isaac 
29873b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
29883b1c2a6aSToby Isaac           PetscInt child = children[i];
29893b1c2a6aSToby Isaac           PetscInt dof, off, j;
29903b1c2a6aSToby Isaac 
29913b1c2a6aSToby Isaac           if (numSecFields) {
29929566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSection, child, f, &dof));
29939566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(cSection, child, f, &off));
29949371c9d4SSatish Balay           } else {
29959566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(cSection, child, &dof));
29969566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(cSection, child, &off));
29973b1c2a6aSToby Isaac           }
29983b1c2a6aSToby Isaac 
2999ad540459SPierre Jolivet           for (j = 0; j < dof; j++) matCols[colOff++] = off + j;
30003b1c2a6aSToby Isaac         }
30013b1c2a6aSToby Isaac       }
30028d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
30038d2f55e7SToby Isaac         PetscFE              fe = (PetscFE)disc;
30048d2f55e7SToby Isaac         PetscInt             fSize;
300559fc6756SToby Isaac         const PetscInt    ***perms;
300659fc6756SToby Isaac         const PetscScalar ***flips;
300759fc6756SToby Isaac         const PetscInt      *pperms;
300859fc6756SToby Isaac 
30099566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &dsp));
30109566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetDimension(dsp, &fSize));
30119566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
301259fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
301352a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
30148d2f55e7SToby Isaac           PetscQuadrature  q;
301552a3aeb4SToby Isaac           PetscInt         dim, thisNc, numPoints, j, k;
30168d2f55e7SToby Isaac           const PetscReal *points;
30178d2f55e7SToby Isaac           const PetscReal *weights;
30188d2f55e7SToby Isaac           PetscInt        *closure = NULL;
30198d2f55e7SToby Isaac           PetscInt         numClosure;
302059fc6756SToby Isaac           PetscInt         iCell              = pperms ? pperms[i] : i;
302159fc6756SToby Isaac           PetscInt         parentCellShapeDof = cellShapeOff + iCell;
3022ef0bb6c7SMatthew G. Knepley           PetscTabulation  Tparent;
30238d2f55e7SToby Isaac 
30249566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(dsp, parentCellShapeDof, &q));
30259566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(q, &dim, &thisNc, &numPoints, &points, &weights));
302663a3b9bcSJacob Faibussowitsch           PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
30279566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe, 1, numPoints, points, 0, &Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
30283b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
30298d2f55e7SToby Isaac             PetscInt           childCell = -1;
303052a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3031c330f8ffSToby Isaac             const PetscReal    xi0[3]    = {-1., -1., -1.};
30328d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
30338d2f55e7SToby Isaac             const PetscScalar *point;
3034ef0bb6c7SMatthew G. Knepley             PetscTabulation    Tchild;
30358d2f55e7SToby Isaac             PetscInt           childCellShapeOff, pointMatOff;
30368d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
30378d2f55e7SToby Isaac             PetscInt d;
30388d2f55e7SToby Isaac 
3039ad540459SPierre Jolivet             for (d = 0; d < dim; d++) pointScalar[d] = points[dim * j + d];
30408d2f55e7SToby Isaac             point = pointScalar;
30418d2f55e7SToby Isaac #else
30428d2f55e7SToby Isaac             point = pointReal;
30438d2f55e7SToby Isaac #endif
30448d2f55e7SToby Isaac 
3045ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
30463b1c2a6aSToby Isaac 
30473b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
30488d2f55e7SToby Isaac               PetscInt  child = children[k];
30498d2f55e7SToby Isaac               PetscInt *star  = NULL;
30508d2f55e7SToby Isaac               PetscInt  numStar, s;
30518d2f55e7SToby Isaac 
30529566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30538d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
30548d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
30558d2f55e7SToby Isaac 
30568d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
30579566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(refTree, dim, point, c, &childCell));
30588d2f55e7SToby Isaac                 if (childCell >= 0) break;
30598d2f55e7SToby Isaac               }
30609566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30618d2f55e7SToby Isaac               if (childCell >= 0) break;
30628d2f55e7SToby Isaac             }
306308401ef6SPierre Jolivet             PetscCheck(childCell >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not locate quadrature point");
30649566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
30659566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3066c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3067c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
30688d2f55e7SToby Isaac 
30699566063dSJacob Faibussowitsch             PetscCall(PetscFECreateTabulation(fe, 1, 1, pointRef, 0, &Tchild));
30709566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
30713b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3072c5356c36SToby Isaac               PetscInt        child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
30738d2f55e7SToby Isaac               PetscInt        l;
307459fc6756SToby Isaac               const PetscInt *cperms;
30758d2f55e7SToby Isaac 
30769566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(depth, child, &childDepth));
30778d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
307859fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
30798d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
30808d2f55e7SToby Isaac                 PetscInt pointDepth;
30818d2f55e7SToby Isaac 
30828d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
308359fc6756SToby Isaac                 if (point == child) {
308459fc6756SToby Isaac                   cI = l;
308559fc6756SToby Isaac                   break;
308659fc6756SToby Isaac                 }
30879566063dSJacob Faibussowitsch                 PetscCall(DMLabelGetValue(depth, point, &pointDepth));
30888d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
30898d2f55e7SToby Isaac               }
30908d2f55e7SToby Isaac               if (l == numClosure) {
30918d2f55e7SToby Isaac                 pointMatOff += childDof;
30928d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
30938d2f55e7SToby Isaac               }
309459fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
30958d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
309659fc6756SToby Isaac                 PetscInt   lCell        = cperms ? cperms[l] : l;
309759fc6756SToby Isaac                 PetscInt   childCellDof = childCellShapeOff + lCell;
309852a3aeb4SToby Isaac                 PetscReal *childValAtPoint;
309952a3aeb4SToby Isaac                 PetscReal  val = 0.;
31008d2f55e7SToby Isaac 
3101ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
3102ad540459SPierre Jolivet                 for (m = 0; m < Nc; m++) val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
310352a3aeb4SToby Isaac 
310452a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
31058d2f55e7SToby Isaac               }
31068d2f55e7SToby Isaac               pointMatOff += childDof;
31078d2f55e7SToby Isaac             }
31089566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
31099566063dSJacob Faibussowitsch             PetscCall(PetscTabulationDestroy(&Tchild));
31108d2f55e7SToby Isaac           }
31119566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&Tparent));
31128d2f55e7SToby Isaac         }
31139371c9d4SSatish Balay       } else { /* just the volume-weighted averages of the children */
31143b1c2a6aSToby Isaac         PetscReal parentVol;
3115bfaa5bdcSToby Isaac         PetscInt  childCell;
31163b1c2a6aSToby Isaac 
31179566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3118bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
311952a3aeb4SToby Isaac           PetscInt  child = children[i], j;
31203b1c2a6aSToby Isaac           PetscReal childVol;
31213b1c2a6aSToby Isaac 
31223b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
31239566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
3124ad540459SPierre Jolivet           for (j = 0; j < Nc; j++) pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
3125bfaa5bdcSToby Isaac           childCell++;
31263b1c2a6aSToby Isaac         }
31278d2f55e7SToby Isaac       }
31283b1c2a6aSToby Isaac       /* Insert pointMat into mat */
31299566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, numSelfDof, matRows, numChildDof, matCols, pointMat, INSERT_VALUES));
31309566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
31319566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
31328d2f55e7SToby Isaac     }
31338d2f55e7SToby Isaac   }
31349566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJ));
31359566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointScalar, pointRef));
31369566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
31379566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
31388d2f55e7SToby Isaac   *inj = mat;
31398d2f55e7SToby Isaac   PetscFunctionReturn(0);
31408d2f55e7SToby Isaac }
31418d2f55e7SToby Isaac 
3142d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3143d71ae5a4SJacob Faibussowitsch {
3144f30e825dSToby Isaac   PetscDS        ds;
3145f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3146f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3147f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3148f30e825dSToby Isaac 
3149f30e825dSToby Isaac   PetscFunctionBegin;
31509566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
31519566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
31529566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
31539566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
31549566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
31559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
31569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
31579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
31589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof, &cols));
3159f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3160f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3161f30e825dSToby Isaac 
31629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
31639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
31649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3165f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3166f30e825dSToby Isaac 
31679566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFields, &refPointFieldMats[p - pRefStart]));
3168f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
316952a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3170f30e825dSToby Isaac 
3171f30e825dSToby Isaac       if (numFields > 1) {
31729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
31739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
31749371c9d4SSatish Balay       } else {
31759566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
31769566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
3177f30e825dSToby Isaac       }
3178f30e825dSToby Isaac 
3179ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
3180f30e825dSToby Isaac       numCols = 0;
3181f30e825dSToby Isaac       {
3182f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3183f30e825dSToby Isaac 
3184f30e825dSToby Isaac         if (numFields > 1) {
31859566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, parent, f, &aDof));
31869566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, parent, f, &aOff));
31879371c9d4SSatish Balay         } else {
31889566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, parent, &aDof));
31899566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, parent, &aOff));
3190f30e825dSToby Isaac         }
3191f30e825dSToby Isaac 
3192ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + j;
3193f30e825dSToby Isaac       }
31949566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
3195f30e825dSToby Isaac       /* transpose of constraint matrix */
31969566063dSJacob Faibussowitsch       PetscCall(MatGetValues(inj, numCols, cols, cDof, rows, refPointFieldMats[p - pRefStart][f]));
3197f30e825dSToby Isaac     }
3198f30e825dSToby Isaac   }
3199f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
32009566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
32019566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
3202f30e825dSToby Isaac   PetscFunctionReturn(0);
3203f30e825dSToby Isaac }
3204f30e825dSToby Isaac 
3205d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3206d71ae5a4SJacob Faibussowitsch {
3207f30e825dSToby Isaac   PetscDS        ds;
3208f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3209f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3210c6154584SToby Isaac   PetscSection   refConSec, refSection;
3211f30e825dSToby Isaac 
3212f30e825dSToby Isaac   PetscFunctionBegin;
3213f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3214f30e825dSToby Isaac   *childrenMats     = NULL;
32159566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
32169566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
32179566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
32189566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
32199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3220f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3221f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3222f30e825dSToby Isaac 
32239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
32249566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
32259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3226f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3227f30e825dSToby Isaac 
3228f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3229f30e825dSToby Isaac       PetscInt cDof;
3230f30e825dSToby Isaac 
3231f30e825dSToby Isaac       if (numFields > 1) {
32329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
32339371c9d4SSatish Balay       } else {
32349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3235f30e825dSToby Isaac       }
3236f30e825dSToby Isaac 
32379566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3238f30e825dSToby Isaac     }
32399566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3240f30e825dSToby Isaac   }
32419566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
3242f30e825dSToby Isaac   PetscFunctionReturn(0);
3243f30e825dSToby Isaac }
3244f30e825dSToby Isaac 
3245d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree, Mat *injRef)
3246d71ae5a4SJacob Faibussowitsch {
3247ebf164c7SToby Isaac   Mat         cMatRef;
32486148253fSToby Isaac   PetscObject injRefObj;
32498d2f55e7SToby Isaac 
3250154bca37SToby Isaac   PetscFunctionBegin;
32519566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, NULL, &cMatRef, NULL));
32529566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", &injRefObj));
3253ebf164c7SToby Isaac   *injRef = (Mat)injRefObj;
3254ebf164c7SToby Isaac   if (!*injRef) {
32559566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorReferenceTree(refTree, injRef));
32569566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", (PetscObject)*injRef));
3257ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
32589566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3259ebf164c7SToby Isaac   }
3260ebf164c7SToby Isaac   PetscFunctionReturn(0);
32616148253fSToby Isaac }
3262f30e825dSToby Isaac 
3263d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, const PetscInt *childIds, Vec fineVec, PetscInt numFields, PetscInt *offsets, PetscSection *rootMultiSec, PetscSection *multiLeafSec, PetscInt **gatheredIndices, PetscScalar **gatheredValues)
3264d71ae5a4SJacob Faibussowitsch {
3265c921d74cSToby Isaac   PetscInt        pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3266ebf164c7SToby Isaac   PetscSection    globalCoarse, globalFine;
3267ebf164c7SToby Isaac   PetscSection    localCoarse, localFine, leafIndicesSec;
3268c921d74cSToby Isaac   PetscSection    multiRootSec, rootIndicesSec;
3269c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3270c921d74cSToby Isaac   const PetscInt *rootDegrees;
3271c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3272ebf164c7SToby Isaac   PetscSF         coarseToFineEmbedded;
3273ebf164c7SToby Isaac 
3274ebf164c7SToby Isaac   PetscFunctionBegin;
32759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
32769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
32779566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
32789566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
32799566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
32809566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafIndicesSec, pStartF, pEndF));
32819566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
32828d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
32837e96bdafSToby Isaac     PetscInt        l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
32847e96bdafSToby Isaac     const PetscInt *leaves;
32858d2f55e7SToby Isaac 
32869566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
32877e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
32887e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
32899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
32909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
32918d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
32928d2f55e7SToby Isaac         numPointsWithDofs++;
3293f30e825dSToby Isaac 
32949566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localFine, p, &dof));
32959566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafIndicesSec, p, dof + 1));
32968d2f55e7SToby Isaac       }
32978d2f55e7SToby Isaac     }
32989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
32999566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafIndicesSec));
33009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numIndices));
33019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1), &leafInds));
33029566063dSJacob Faibussowitsch     if (gatheredValues) PetscCall(PetscMalloc1(numIndices, &leafVals));
33037e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
33047e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
33059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
33069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
33078d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3308f30e825dSToby Isaac         PetscInt     off, gOff;
3309f30e825dSToby Isaac         PetscInt    *pInd;
3310c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3311f30e825dSToby Isaac 
33127e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3313f30e825dSToby Isaac 
33149566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3315f30e825dSToby Isaac 
3316c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3317c921d74cSToby Isaac         if (gatheredValues) {
3318c921d74cSToby Isaac           PetscInt i;
3319c921d74cSToby Isaac 
3320c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3321c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3322c921d74cSToby Isaac         }
33239566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
3324f30e825dSToby Isaac 
3325f30e825dSToby Isaac         offsets[0] = 0;
3326f30e825dSToby Isaac         if (numFields) {
3327f30e825dSToby Isaac           PetscInt f;
3328f30e825dSToby Isaac 
3329f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3330f30e825dSToby Isaac             PetscInt fDof;
33319566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localFine, p, f, &fDof));
3332f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3333f30e825dSToby Isaac           }
33349566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
3335367003a6SStefano Zampini         } else {
33369566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
3337f30e825dSToby Isaac         }
33389566063dSJacob Faibussowitsch         if (gatheredValues) PetscCall(VecGetValues(fineVec, dof, pInd, pVal));
33398d2f55e7SToby Isaac       }
33408d2f55e7SToby Isaac     }
33419566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
33429566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
33438d2f55e7SToby Isaac   }
3344f30e825dSToby Isaac 
33459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
33469566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
33479566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3348f30e825dSToby Isaac 
33496148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
33506148253fSToby Isaac     MPI_Datatype threeInt;
33516148253fSToby Isaac     PetscMPIInt  rank;
33526148253fSToby Isaac     PetscInt(*parentNodeAndIdCoarse)[3];
33536148253fSToby Isaac     PetscInt(*parentNodeAndIdFine)[3];
33546148253fSToby Isaac     PetscInt           p, nleaves, nleavesToParents;
33556148253fSToby Isaac     PetscSF            pointSF, sfToParents;
33566148253fSToby Isaac     const PetscInt    *ilocal;
33576148253fSToby Isaac     const PetscSFNode *iremote;
33586148253fSToby Isaac     PetscSFNode       *iremoteToParents;
33596148253fSToby Isaac     PetscInt          *ilocalToParents;
33606148253fSToby Isaac 
33619566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse), &rank));
33629566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &threeInt));
33639566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&threeInt));
33649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEndC - pStartC, &parentNodeAndIdCoarse, pEndF - pStartF, &parentNodeAndIdFine));
33659566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(coarse, &pointSF));
33669566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, &iremote));
33676148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
33686148253fSToby Isaac       PetscInt parent, childId;
33699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(coarse, p, &parent, &childId));
33706148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
33716148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
33726148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
33736148253fSToby Isaac       if (nleaves > 0) {
33746148253fSToby Isaac         PetscInt leaf = -1;
33756148253fSToby Isaac 
33766148253fSToby Isaac         if (ilocal) {
33779566063dSJacob Faibussowitsch           PetscCall(PetscFindInt(parent, nleaves, ilocal, &leaf));
33789371c9d4SSatish Balay         } else {
33796148253fSToby Isaac           leaf = p - pStartC;
33806148253fSToby Isaac         }
33816148253fSToby Isaac         if (leaf >= 0) {
33826148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
33836148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
33846148253fSToby Isaac         }
33856148253fSToby Isaac       }
33866148253fSToby Isaac     }
33876148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
33886148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
33896148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
33906148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
33916148253fSToby Isaac     }
33929566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
33939566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
33946148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3395f30e825dSToby Isaac       PetscInt dof;
3396f30e825dSToby Isaac 
33979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &dof));
3398f30e825dSToby Isaac       if (dof) {
3399f30e825dSToby Isaac         PetscInt off;
3400f30e825dSToby Isaac 
34019566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3402c921d74cSToby Isaac         if (gatheredIndices) {
3403c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3404c921d74cSToby Isaac         } else if (gatheredValues) {
3405c921d74cSToby Isaac           leafVals[off] = (PetscScalar)PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3406c921d74cSToby Isaac         }
3407f30e825dSToby Isaac       }
3408ad540459SPierre Jolivet       if (parentNodeAndIdFine[p - pStartF][0] >= 0) nleavesToParents++;
34096148253fSToby Isaac     }
34109566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &ilocalToParents));
34119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &iremoteToParents));
34126148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
34136148253fSToby Isaac       if (parentNodeAndIdFine[p - pStartF][0] >= 0) {
34146148253fSToby Isaac         ilocalToParents[nleavesToParents]        = p - pStartF;
34156148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p - pStartF][0];
34166148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p - pStartF][1];
34176148253fSToby Isaac         nleavesToParents++;
34186148253fSToby Isaac       }
34196148253fSToby Isaac     }
34209566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse), &sfToParents));
34219566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(sfToParents, pEndC - pStartC, nleavesToParents, ilocalToParents, PETSC_OWN_POINTER, iremoteToParents, PETSC_OWN_POINTER));
34229566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34236148253fSToby Isaac 
34246148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
34256148253fSToby Isaac 
34269566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parentNodeAndIdCoarse, parentNodeAndIdFine));
34279566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&threeInt));
34286148253fSToby Isaac   }
3429f30e825dSToby Isaac 
34306148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
34316148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
34326148253fSToby Isaac     PetscSF  sfDofsOnly;
34336148253fSToby Isaac 
34346148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
34359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3437ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
34386148253fSToby Isaac     }
34399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
34406148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
34419566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34429566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3443ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = p - pStartC;
34446148253fSToby Isaac     }
34459566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
34469566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34479566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
34486148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
34496148253fSToby Isaac   }
3450f30e825dSToby Isaac 
34516148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
34529566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded, &rootDegrees));
34539566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded, &rootDegrees));
34549566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &multiRootSec));
34559566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(multiRootSec, pStartC, pEndC));
345648a46eb9SPierre Jolivet   for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionSetDof(multiRootSec, p, rootDegrees[p - pStartC]));
34579566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(multiRootSec));
34589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(multiRootSec, &numMulti));
34599566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
3460f30e825dSToby Isaac   { /* distribute the leaf section */
3461f30e825dSToby Isaac     PetscSF   multi, multiInv, indicesSF;
3462f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
34638d2f55e7SToby Isaac 
34649566063dSJacob Faibussowitsch     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded, &multi));
34659566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF(multi, &multiInv));
34669566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(multiInv, leafIndicesSec, &remoteOffsets, rootIndicesSec));
34679566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(multiInv, leafIndicesSec, remoteOffsets, rootIndicesSec, &indicesSF));
34689566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
34699566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&multiInv));
34709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
3471c921d74cSToby Isaac     if (gatheredIndices) {
34729566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootInds));
34739566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
34749566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3475c921d74cSToby Isaac     }
3476c921d74cSToby Isaac     if (gatheredValues) {
34779566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootVals));
34789566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
34799566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3480c921d74cSToby Isaac     }
34819566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
34828d2f55e7SToby Isaac   }
34839566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
34849566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafInds));
34859566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafVals));
34869566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3487c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3488c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3489c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3490c921d74cSToby Isaac   if (gatheredValues) *gatheredValues = rootVals;
3491ebf164c7SToby Isaac   PetscFunctionReturn(0);
3492ebf164c7SToby Isaac }
3493ebf164c7SToby Isaac 
3494d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3495d71ae5a4SJacob Faibussowitsch {
3496ebf164c7SToby Isaac   DM             refTree;
3497c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3498ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3499ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3500ebf164c7SToby Isaac   PetscSection   cSecRef;
3501277f51e8SBarry Smith   PetscInt      *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3502ebf164c7SToby Isaac   Mat            injRef;
3503c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3504ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3505ebf164c7SToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
3506ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3507ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3508ebf164c7SToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3509ebf164c7SToby Isaac 
3510ebf164c7SToby Isaac   PetscFunctionBegin;
3511ebf164c7SToby Isaac 
3512ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
35139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
35149566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
35159566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
35169566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
3517ebf164c7SToby Isaac 
35189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
35199566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
35209566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
35219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
35229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
35239566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
35249566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
35259566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
3526ebf164c7SToby Isaac   {
3527ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
35289566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
3529ebf164c7SToby Isaac   }
3530ebf164c7SToby Isaac 
35319566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, childIds, NULL, numFields, offsets, &multiRootSec, &rootIndicesSec, &rootIndices, NULL));
35328d2f55e7SToby Isaac 
35339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &parentIndices));
3534f30e825dSToby Isaac 
3535f30e825dSToby Isaac   /* count indices */
35369566063dSJacob Faibussowitsch   PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
35379566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
35389566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
35399566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
35409566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
35419566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(rowEnd - rowStart, &nnzD, rowEnd - rowStart, &nnzO));
3542f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3543f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
35448d2f55e7SToby Isaac 
35459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
35469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3547f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
35489566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
35498d2f55e7SToby Isaac 
35508d2f55e7SToby Isaac     rowOffsets[0]  = 0;
3551f30e825dSToby Isaac     offsetsCopy[0] = 0;
35528d2f55e7SToby Isaac     if (numFields) {
35538d2f55e7SToby Isaac       PetscInt f;
35548d2f55e7SToby Isaac 
3555f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3556f30e825dSToby Isaac         PetscInt fDof;
35579566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3558f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
35598d2f55e7SToby Isaac       }
35609566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3561367003a6SStefano Zampini     } else {
35629566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3563f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
35648d2f55e7SToby Isaac     }
3565f30e825dSToby Isaac 
35669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
35679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3568f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3569f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3570f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3571f30e825dSToby Isaac       const PetscInt *childIndices;
3572f30e825dSToby Isaac 
35739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
35749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3575f30e825dSToby Isaac       childId      = rootIndices[offset++];
3576f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3577f30e825dSToby Isaac       numIndices--;
3578f30e825dSToby Isaac 
3579f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3580f30e825dSToby Isaac         PetscInt i;
3581f30e825dSToby Isaac 
3582f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3583f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3584f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3585f30e825dSToby Isaac           if (rowIndex < 0) continue;
358608401ef6SPierre Jolivet           PetscCheck(colIndex >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unconstrained fine and constrained coarse");
3587a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3588f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
35899371c9d4SSatish Balay           } else {
3590f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3591f30e825dSToby Isaac           }
3592f30e825dSToby Isaac         }
35939371c9d4SSatish Balay       } else {
3594f30e825dSToby Isaac         PetscInt parentId, f, lim;
3595f30e825dSToby Isaac 
35969566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3597f30e825dSToby Isaac 
3598f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3599f30e825dSToby Isaac         offsets[0] = 0;
36008d2f55e7SToby Isaac         if (numFields) {
36018d2f55e7SToby Isaac           PetscInt f;
3602f30e825dSToby Isaac 
36038d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3604f30e825dSToby Isaac             PetscInt fDof;
36059566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3606f30e825dSToby Isaac 
3607f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
36088d2f55e7SToby Isaac           }
36099371c9d4SSatish Balay         } else {
3610f30e825dSToby Isaac           PetscInt cDof;
3611f30e825dSToby Isaac 
36129566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3613f30e825dSToby Isaac           offsets[1] = cDof;
3614f30e825dSToby Isaac         }
3615f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3616f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3617f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3618f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3619f30e825dSToby Isaac 
3620f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3621f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3622f30e825dSToby Isaac 
3623f30e825dSToby Isaac             if (colIndex < 0) continue;
3624f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3625f30e825dSToby Isaac               numD++;
36269371c9d4SSatish Balay             } else {
3627f30e825dSToby Isaac               numO++;
3628f30e825dSToby Isaac             }
3629f30e825dSToby Isaac           }
3630f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3631f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3632f30e825dSToby Isaac 
3633f30e825dSToby Isaac             if (rowIndex < 0) continue;
3634f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3635f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
36368d2f55e7SToby Isaac           }
36378d2f55e7SToby Isaac         }
36388d2f55e7SToby Isaac       }
3639f30e825dSToby Isaac     }
3640f30e825dSToby Isaac   }
3641f30e825dSToby Isaac   /* preallocate */
36429566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mat, 1, nnzD, nnzO, NULL, NULL));
36439566063dSJacob Faibussowitsch   PetscCall(PetscFree2(nnzD, nnzO));
3644f30e825dSToby Isaac   /* insert values */
36459566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3646f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3647f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3648f30e825dSToby Isaac 
36499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
36509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3651f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
36529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
3653f30e825dSToby Isaac 
3654f30e825dSToby Isaac     rowOffsets[0]  = 0;
3655f30e825dSToby Isaac     offsetsCopy[0] = 0;
36568d2f55e7SToby Isaac     if (numFields) {
36578d2f55e7SToby Isaac       PetscInt f;
3658f30e825dSToby Isaac 
36598d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3660f30e825dSToby Isaac         PetscInt fDof;
36619566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3662f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3663f30e825dSToby Isaac       }
36649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3665367003a6SStefano Zampini     } else {
36669566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3667f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3668f30e825dSToby Isaac     }
3669f30e825dSToby Isaac 
36709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
36719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3672f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3673f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3674f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3675f30e825dSToby Isaac       const PetscInt *childIndices;
3676f30e825dSToby Isaac 
36779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
36789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3679f30e825dSToby Isaac       childId      = rootIndices[offset++];
3680f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3681f30e825dSToby Isaac       numIndices--;
3682f30e825dSToby Isaac 
3683f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3684f30e825dSToby Isaac         PetscInt i;
3685f30e825dSToby Isaac 
368648a46eb9SPierre Jolivet         for (i = 0; i < numIndices; i++) PetscCall(MatSetValue(mat, parentIndices[i], childIndices[i], 1., INSERT_VALUES));
36879371c9d4SSatish Balay       } else {
3688f30e825dSToby Isaac         PetscInt parentId, f, lim;
36898d2f55e7SToby Isaac 
36909566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3691f30e825dSToby Isaac 
3692f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3693f30e825dSToby Isaac         offsets[0] = 0;
36948d2f55e7SToby Isaac         if (numFields) {
3695f30e825dSToby Isaac           PetscInt f;
36968d2f55e7SToby Isaac 
3697f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3698f30e825dSToby Isaac             PetscInt fDof;
36999566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3700f30e825dSToby Isaac 
3701f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
37028d2f55e7SToby Isaac           }
37039371c9d4SSatish Balay         } else {
3704f30e825dSToby Isaac           PetscInt cDof;
3705f30e825dSToby Isaac 
37069566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3707f30e825dSToby Isaac           offsets[1] = cDof;
37088d2f55e7SToby Isaac         }
3709f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3710f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3711f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3712f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3713f30e825dSToby Isaac 
37149566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat, rowOffsets[f + 1] - rowOffsets[f], rowIndices, offsets[f + 1] - offsets[f], colIndices, childMat, INSERT_VALUES));
37158d2f55e7SToby Isaac         }
37168d2f55e7SToby Isaac       }
37178d2f55e7SToby Isaac     }
37188d2f55e7SToby Isaac   }
37199566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
37209566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
37219566063dSJacob Faibussowitsch   PetscCall(PetscFree(parentIndices));
37229566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
37239566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootIndices));
37249566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
3725f30e825dSToby Isaac 
37269566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
37279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
3728154bca37SToby Isaac   PetscFunctionReturn(0);
3729154bca37SToby Isaac }
373038fc2455SToby Isaac 
3731d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3732d71ae5a4SJacob Faibussowitsch {
373362095d54SToby Isaac   PetscSF            coarseToFineEmbedded;
373462095d54SToby Isaac   PetscSection       globalCoarse, globalFine;
373562095d54SToby Isaac   PetscSection       localCoarse, localFine;
373662095d54SToby Isaac   PetscSection       aSec, cSec;
373762095d54SToby Isaac   PetscSection       rootValuesSec;
373862095d54SToby Isaac   PetscSection       leafValuesSec;
373962095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
374062095d54SToby Isaac   IS                 aIS;
374162095d54SToby Isaac   const PetscInt    *anchors;
374262095d54SToby Isaac   Mat                cMat;
374362095d54SToby Isaac   PetscInt           numFields;
3744412e9a14SMatthew G. Knepley   PetscInt           pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
374562095d54SToby Isaac   PetscInt           aStart, aEnd, cStart, cEnd;
374662095d54SToby Isaac   PetscInt          *maxChildIds;
374762095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
37480eb7e1eaSToby Isaac   PetscFV            fv = NULL;
37490eb7e1eaSToby Isaac   PetscInt           dim, numFVcomps = -1, fvField = -1;
37500eb7e1eaSToby Isaac   DM                 cellDM = NULL, gradDM = NULL;
37510eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
37520eb7e1eaSToby Isaac   const PetscScalar *gradArray     = NULL;
375362095d54SToby Isaac 
3754ebf164c7SToby Isaac   PetscFunctionBegin;
37559566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
37569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
37579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(coarse, 0, &cellStart, &cellEnd));
37589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
37599566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
37609566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(coarse, &dim));
376162095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3762e4a60869SToby Isaac     PetscInt        nleaves, l;
3763e4a60869SToby Isaac     const PetscInt *leaves;
376462095d54SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
376562095d54SToby Isaac 
37669566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
3767e4a60869SToby Isaac 
3768e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3769e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3770e4a60869SToby Isaac 
37719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3773ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
377462095d54SToby Isaac     }
37759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
37764833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
3777e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3778e4a60869SToby Isaac 
37799566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3781ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
378262095d54SToby Isaac     }
37839566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
37849566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
378562095d54SToby Isaac   }
378662095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
37879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
3788ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
37899566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
37909566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
379162095d54SToby Isaac 
37929566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
37939566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
379462095d54SToby Isaac 
37959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
37969566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
37979566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
379862095d54SToby Isaac 
37999566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
38009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
380162095d54SToby Isaac 
380262095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
38039566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootValuesSec));
38049566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootValuesSec, pStartC, pEndC));
38059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
380662095d54SToby Isaac   {
380762095d54SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
38089566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &newOffsets, maxFields, &newOffsetsCopy, maxFields, &rowOffsets, maxFields, &numD, maxFields, &numO));
380962095d54SToby Isaac   }
38100eb7e1eaSToby Isaac   if (grad) {
38110eb7e1eaSToby Isaac     PetscInt i;
38120eb7e1eaSToby Isaac 
38139566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeom, &cellDM));
38149566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeom, &cellGeomArray));
38159566063dSJacob Faibussowitsch     PetscCall(VecGetDM(grad, &gradDM));
38169566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(grad, &gradArray));
38170eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1, numFields); i++) {
38180eb7e1eaSToby Isaac       PetscObject  obj;
38190eb7e1eaSToby Isaac       PetscClassId id;
38200eb7e1eaSToby Isaac 
38219566063dSJacob Faibussowitsch       PetscCall(DMGetField(coarse, i, NULL, &obj));
38229566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
38230eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
38240eb7e1eaSToby Isaac         fv = (PetscFV)obj;
38259566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &numFVcomps));
38260eb7e1eaSToby Isaac         fvField = i;
38270eb7e1eaSToby Isaac         break;
38280eb7e1eaSToby Isaac       }
38290eb7e1eaSToby Isaac     }
38300eb7e1eaSToby Isaac   }
383162095d54SToby Isaac 
383262095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
383362095d54SToby Isaac     PetscInt dof;
383462095d54SToby Isaac     PetscInt maxChildId = maxChildIds[p - pStartC];
383562095d54SToby Isaac     PetscInt numValues  = 0;
383662095d54SToby Isaac 
38379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3838ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
383962095d54SToby Isaac     offsets[0]    = 0;
384062095d54SToby Isaac     newOffsets[0] = 0;
384162095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
384262095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
384362095d54SToby Isaac 
38449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
384562095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
384662095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
384762095d54SToby Isaac 
38489566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
384962095d54SToby Isaac         numValues += clDof;
385062095d54SToby Isaac       }
38519566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
38529371c9d4SSatish Balay     } else if (maxChildId == -1) {
38539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localCoarse, p, &numValues));
385462095d54SToby Isaac     }
385562095d54SToby Isaac     /* we will pack the column indices with the field offsets */
385678b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
38570eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
38580eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
38590eb7e1eaSToby Isaac     }
38609566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootValuesSec, p, numValues));
386162095d54SToby Isaac   }
38629566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootValuesSec));
386362095d54SToby Isaac   {
386462095d54SToby Isaac     PetscInt           numRootValues;
386562095d54SToby Isaac     const PetscScalar *coarseArray;
386662095d54SToby Isaac 
38679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootValuesSec, &numRootValues));
38689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRootValues, &rootValues));
38699566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecCoarseLocal, &coarseArray));
387062095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
387162095d54SToby Isaac       PetscInt     numValues;
387262095d54SToby Isaac       PetscInt     pValOff;
387362095d54SToby Isaac       PetscScalar *pVal;
387462095d54SToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
387562095d54SToby Isaac 
38769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootValuesSec, p, &numValues));
3877ad540459SPierre Jolivet       if (!numValues) continue;
38789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootValuesSec, p, &pValOff));
387962095d54SToby Isaac       pVal = &(rootValues[pValOff]);
388062095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
38810eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
38829566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(coarse, NULL, vecCoarseLocal, p, &closureSize, &pVal));
38830eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
3884193eb951SToby Isaac           PetscFVCellGeom *cg;
38856dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
38860eb7e1eaSToby Isaac           PetscInt         i;
38870eb7e1eaSToby Isaac 
38880eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
38890eb7e1eaSToby Isaac 
38909566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(cellDM, p, cellGeomArray, (void *)&cg));
38910eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
38920eb7e1eaSToby Isaac           pVal += dim;
38939566063dSJacob Faibussowitsch           PetscCall(DMPlexPointGlobalRead(gradDM, p, gradArray, (void *)&gradVals));
38940eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
38950eb7e1eaSToby Isaac         }
38969371c9d4SSatish Balay       } else if (maxChildId == -1) {
389778b7adb5SToby Isaac         PetscInt lDof, lOff, i;
389878b7adb5SToby Isaac 
38999566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, p, &lDof));
39009566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(localCoarse, p, &lOff));
390178b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
390278b7adb5SToby Isaac       }
390378b7adb5SToby Isaac     }
39049566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecCoarseLocal, &coarseArray));
39059566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
390662095d54SToby Isaac   }
390762095d54SToby Isaac   {
390862095d54SToby Isaac     PetscSF   valuesSF;
390962095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
391062095d54SToby Isaac 
39119566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafValuesSec));
39129566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootValuesSec, &remoteOffsetsValues, leafValuesSec));
39139566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootValuesSec, remoteOffsetsValues, leafValuesSec, &valuesSF));
39149566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
39159566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsValues));
39169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafValuesSec, &numLeafValues));
39179566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafValues, &leafValues));
39189566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39199566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39209566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&valuesSF));
39219566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootValues));
39229566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootValuesSec));
392362095d54SToby Isaac   }
39249566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
392562095d54SToby Isaac   {
392662095d54SToby Isaac     PetscInt       maxDof;
392762095d54SToby Isaac     PetscInt      *rowIndices;
392862095d54SToby Isaac     DM             refTree;
392962095d54SToby Isaac     PetscInt     **refPointFieldN;
393062095d54SToby Isaac     PetscScalar ***refPointFieldMats;
393162095d54SToby Isaac     PetscSection   refConSec, refAnSec;
39320eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, leafStart, leafEnd;
393362095d54SToby Isaac     PetscScalar   *pointWork;
393462095d54SToby Isaac 
39359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
39369566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
39379566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
39389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
39399566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(fine, refTree));
39409566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
39419566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
39429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
39439566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
39449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafValuesSec, &leafStart, &leafEnd));
39459566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSimplexOrBoxCells(fine, 0, &cellStart, &cellEnd));
39460eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
394762095d54SToby Isaac       PetscInt           gDof, gcDof, gOff, lDof;
394862095d54SToby Isaac       PetscInt           numValues, pValOff;
394962095d54SToby Isaac       PetscInt           childId;
395062095d54SToby Isaac       const PetscScalar *pVal;
39510eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
395262095d54SToby Isaac 
39539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
39549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localFine, p, &lDof));
39559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
3956ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
39579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
39589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafValuesSec, p, &numValues));
395962095d54SToby Isaac       if (!numValues) continue;
39609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafValuesSec, p, &pValOff));
396162095d54SToby Isaac       pVal              = &leafValues[pValOff];
396262095d54SToby Isaac       offsets[0]        = 0;
396362095d54SToby Isaac       offsetsCopy[0]    = 0;
396462095d54SToby Isaac       newOffsets[0]     = 0;
396562095d54SToby Isaac       newOffsetsCopy[0] = 0;
39664833aeb0SToby Isaac       childId           = cids[p - pStartF];
396762095d54SToby Isaac       if (numFields) {
396862095d54SToby Isaac         PetscInt f;
396962095d54SToby Isaac         for (f = 0; f < numFields; f++) {
397062095d54SToby Isaac           PetscInt rowDof;
397162095d54SToby Isaac 
39729566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
397362095d54SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
397462095d54SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
397562095d54SToby Isaac           /* TODO: closure indices */
39769f4e70e1SToby Isaac           newOffsets[f + 1] = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
397762095d54SToby Isaac         }
39789566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
39799371c9d4SSatish Balay       } else {
39804833aeb0SToby Isaac         offsets[0]    = 0;
39814833aeb0SToby Isaac         offsets[1]    = lDof;
39824833aeb0SToby Isaac         newOffsets[0] = 0;
39834833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
39849566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
398562095d54SToby Isaac       }
398662095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
39879566063dSJacob Faibussowitsch         PetscCall(VecSetValues(vecFine, numValues, rowIndices, pVal, INSERT_VALUES));
398862095d54SToby Isaac       } else {
398962095d54SToby Isaac         PetscInt f;
399062095d54SToby Isaac 
399178b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
399278b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
399378b7adb5SToby Isaac           fvGradData = &pVal[numValues];
399478b7adb5SToby Isaac         }
399562095d54SToby Isaac         for (f = 0; f < PetscMax(1, numFields); f++) {
399662095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
399762095d54SToby Isaac           PetscInt           numRows  = offsets[f + 1] - offsets[f];
399862095d54SToby Isaac           PetscInt           numCols  = newOffsets[f + 1] - newOffsets[f];
399962095d54SToby Isaac           const PetscScalar *cVal     = &pVal[newOffsets[f]];
400062095d54SToby Isaac           PetscScalar       *rVal     = &pointWork[offsets[f]];
400162095d54SToby Isaac           PetscInt           i, j;
400262095d54SToby Isaac 
4003708c7f19SToby Isaac #if 0
400463a3b9bcSJacob Faibussowitsch           PetscCall(PetscInfo(coarse,"childId %" PetscInt_FMT ", numRows %" PetscInt_FMT ", numCols %" PetscInt_FMT ", refPointFieldN %" PetscInt_FMT " maxDof %" PetscInt_FMT "\n",childId,numRows,numCols,refPointFieldN[childId - pRefStart][f], maxDof));
4005708c7f19SToby Isaac #endif
400662095d54SToby Isaac           for (i = 0; i < numRows; i++) {
400762095d54SToby Isaac             PetscScalar val = 0.;
4008ad540459SPierre Jolivet             for (j = 0; j < numCols; j++) val += childMat[i * numCols + j] * cVal[j];
400962095d54SToby Isaac             rVal[i] = val;
401062095d54SToby Isaac           }
40110eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
40120eb7e1eaSToby Isaac             PetscReal          centroid[3];
40130eb7e1eaSToby Isaac             PetscScalar        diff[3];
40140eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
40150eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
40160eb7e1eaSToby Isaac 
40179566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFVM(fine, p, NULL, centroid, NULL));
4018ad540459SPierre Jolivet             for (i = 0; i < dim; i++) diff[i] = centroid[i] - parentCentroid[i];
40190eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
40200eb7e1eaSToby Isaac               PetscScalar val = 0.;
40210eb7e1eaSToby Isaac 
4022ad540459SPierre Jolivet               for (j = 0; j < dim; j++) val += gradient[dim * i + j] * diff[j];
40230eb7e1eaSToby Isaac               rVal[i] += val;
40240eb7e1eaSToby Isaac             }
40250eb7e1eaSToby Isaac           }
40269566063dSJacob Faibussowitsch           PetscCall(VecSetValues(vecFine, numRows, &rowIndices[offsets[f]], rVal, INSERT_VALUES));
402762095d54SToby Isaac         }
402862095d54SToby Isaac       }
402962095d54SToby Isaac     }
40309566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
40319566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
40329566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
403362095d54SToby Isaac   }
40349566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafValues));
40359566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafValuesSec));
40369566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
40379566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
4038ebf164c7SToby Isaac   PetscFunctionReturn(0);
4039ebf164c7SToby Isaac }
4040ebf164c7SToby Isaac 
4041d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4042d71ae5a4SJacob Faibussowitsch {
4043c921d74cSToby Isaac   DM             refTree;
4044c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4045c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4046c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4047c921d74cSToby Isaac   PetscSection   cSecRef;
4048c921d74cSToby Isaac   PetscInt      *parentIndices, pRefStart, pRefEnd;
4049d3bc4906SToby Isaac   PetscScalar   *rootValues, *parentValues;
4050c921d74cSToby Isaac   Mat            injRef;
4051c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4052c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4053c921d74cSToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
4054c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4055c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4056c921d74cSToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4057c921d74cSToby Isaac 
4058ebf164c7SToby Isaac   PetscFunctionBegin;
4059c921d74cSToby Isaac 
4060c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
40619566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40629566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecCoarse, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
40649566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(coarse, refTree));
40659566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
40669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
40679566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
4068c921d74cSToby Isaac 
40699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
40709566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
40719566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
40729566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
40739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
40749566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
40759566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
40769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
4077c921d74cSToby Isaac   {
4078c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
40799566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
4080c921d74cSToby Isaac   }
4081c921d74cSToby Isaac 
40829566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, cids, vecFine, numFields, offsets, &multiRootSec, &rootIndicesSec, NULL, &rootValues));
4083c921d74cSToby Isaac 
40849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxDof, &parentIndices, maxDof, &parentValues));
4085c921d74cSToby Isaac 
4086c921d74cSToby Isaac   /* count indices */
40879566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecFine, &colMap));
40889566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecCoarse, &rowMap));
40899566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
40909566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
40919566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
40929566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
4093c921d74cSToby Isaac   /* insert values */
40949566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4095c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4096c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
409778b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4098c921d74cSToby Isaac 
40999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
41009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
4101c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
41029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localCoarse, p, &dof));
41039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
4104c921d74cSToby Isaac 
4105c921d74cSToby Isaac     rowOffsets[0]  = 0;
4106c921d74cSToby Isaac     offsetsCopy[0] = 0;
4107c921d74cSToby Isaac     if (numFields) {
4108c921d74cSToby Isaac       PetscInt f;
4109c921d74cSToby Isaac 
4110c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4111c921d74cSToby Isaac         PetscInt fDof;
41129566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
4113c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4114c921d74cSToby Isaac       }
41159566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
4116367003a6SStefano Zampini     } else {
41179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
4118c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4119c921d74cSToby Isaac     }
4120c921d74cSToby Isaac 
41219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
41229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
4123c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
41242f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4125c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4126c921d74cSToby Isaac       PetscInt           numIndices, childId, offset;
4127c921d74cSToby Isaac       const PetscScalar *childValues;
4128c921d74cSToby Isaac 
41299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
41309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
4131c921d74cSToby Isaac       childId     = (PetscInt)PetscRealPart(rootValues[offset++]);
4132c921d74cSToby Isaac       childValues = &rootValues[offset];
4133c921d74cSToby Isaac       numIndices--;
4134c921d74cSToby Isaac 
4135c921d74cSToby Isaac       if (childId == -2) { /* skip */
4136c921d74cSToby Isaac         continue;
4137c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
41382f65e181SToby Isaac         PetscInt m;
41392f65e181SToby Isaac 
414078b7adb5SToby Isaac         contribute = PETSC_TRUE;
41412f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4142beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4143d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4144d3bc4906SToby Isaac 
414578b7adb5SToby Isaac         contribute = PETSC_TRUE;
41469566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
4147d3bc4906SToby Isaac 
4148d3bc4906SToby Isaac         lim        = PetscMax(1, numFields);
4149d3bc4906SToby Isaac         offsets[0] = 0;
4150d3bc4906SToby Isaac         if (numFields) {
4151d3bc4906SToby Isaac           PetscInt f;
4152d3bc4906SToby Isaac 
4153d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4154d3bc4906SToby Isaac             PetscInt fDof;
41559566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
4156d3bc4906SToby Isaac 
4157d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4158d3bc4906SToby Isaac           }
41599371c9d4SSatish Balay         } else {
4160d3bc4906SToby Isaac           PetscInt cDof;
4161d3bc4906SToby Isaac 
41629566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
4163d3bc4906SToby Isaac           offsets[1] = cDof;
4164d3bc4906SToby Isaac         }
4165d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4166d3bc4906SToby Isaac           PetscScalar       *childMat = &childrenMats[childId - pRefStart][f][0];
4167d3bc4906SToby Isaac           PetscInt           n        = offsets[f + 1] - offsets[f];
4168e328ff09SToby Isaac           PetscInt           m        = rowOffsets[f + 1] - rowOffsets[f];
4169d3bc4906SToby Isaac           PetscInt           i, j;
4170d3bc4906SToby Isaac           const PetscScalar *colValues = &childValues[offsets[f]];
4171d3bc4906SToby Isaac 
4172e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4173d3bc4906SToby Isaac             PetscScalar val = 0.;
4174ad540459SPierre Jolivet             for (j = 0; j < n; j++) val += childMat[n * i + j] * colValues[j];
4175e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4176d3bc4906SToby Isaac           }
4177d3bc4906SToby Isaac         }
4178c921d74cSToby Isaac       }
4179c921d74cSToby Isaac     }
41809566063dSJacob Faibussowitsch     if (contribute) PetscCall(VecSetValues(vecCoarse, dof, parentIndices, parentValues, INSERT_VALUES));
4181c921d74cSToby Isaac   }
41829566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
41839566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
41849566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parentIndices, parentValues));
41859566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
41869566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootValues));
41879566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
4188ebf164c7SToby Isaac   PetscFunctionReturn(0);
4189ebf164c7SToby Isaac }
4190ebf164c7SToby Isaac 
4191ff1f73f7SToby Isaac /*@
4192ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4193ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4194ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4195ff1f73f7SToby Isaac 
4196*a1cb98faSBarry Smith   Collective on dmIn
4197ff1f73f7SToby Isaac 
4198ff1f73f7SToby Isaac   Input Parameters:
4199*a1cb98faSBarry Smith + dmIn        - The `DMPLEX` mesh for the input vector
4200ff1f73f7SToby Isaac . vecIn       - The input vector
4201ff1f73f7SToby Isaac . sfRefine    - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4202ff1f73f7SToby Isaac                 the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4203ff1f73f7SToby Isaac . sfCoarsen   - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4204ff1f73f7SToby Isaac                 the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4205ff1f73f7SToby Isaac . cidsRefine  - The childIds of the points in dmOut.  These childIds relate back to the reference tree: childid[j] = k implies
4206ff1f73f7SToby Isaac                 that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4207ff1f73f7SToby Isaac                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in dmOut is exactly
4208ff1f73f7SToby Isaac                 equivalent to its root in dmIn, so no interpolation is necessary.  childid[j] = -2 indicates that this
4209ff1f73f7SToby Isaac                 point j in dmOut is not a leaf of sfRefine.
4210ff1f73f7SToby Isaac . cidsCoarsen - The childIds of the points in dmIn.  These childIds relate back to the reference tree: childid[j] = k implies
4211ff1f73f7SToby Isaac                 that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4212ff1f73f7SToby Isaac                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4213ff1f73f7SToby Isaac . useBCs      - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4214ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4215ff1f73f7SToby Isaac 
4216ff1f73f7SToby Isaac   Output Parameters:
42178966356dSPierre Jolivet . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transferred
4218*a1cb98faSBarry Smith                 projection of vecIn from dmIn to dmOut.  Note that any field discretized with a `PetscFV` finite volume
4219ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4220ff1f73f7SToby Isaac                 coarse points to fine points.
4221ff1f73f7SToby Isaac 
4222ff1f73f7SToby Isaac   Level: developer
4223ff1f73f7SToby Isaac 
4224*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `Vec`, `PetscFV`, `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4225ff1f73f7SToby Isaac @*/
4226d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
4227d71ae5a4SJacob Faibussowitsch {
422838fc2455SToby Isaac   PetscFunctionBegin;
42299566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
4230ff1f73f7SToby Isaac   if (sfRefine) {
4231fbfa57b9SToby Isaac     Vec vecInLocal;
42320eb7e1eaSToby Isaac     DM  dmGrad   = NULL;
42330eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4234fbfa57b9SToby Isaac 
42359566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
42369566063dSJacob Faibussowitsch     PetscCall(VecSet(vecInLocal, 0.0));
42370eb7e1eaSToby Isaac     {
42380eb7e1eaSToby Isaac       PetscInt numFields, i;
42390eb7e1eaSToby Isaac 
42409566063dSJacob Faibussowitsch       PetscCall(DMGetNumFields(dmIn, &numFields));
42410eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
42420eb7e1eaSToby Isaac         PetscObject  obj;
42430eb7e1eaSToby Isaac         PetscClassId classid;
42440eb7e1eaSToby Isaac 
42459566063dSJacob Faibussowitsch         PetscCall(DMGetField(dmIn, i, NULL, &obj));
42469566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &classid));
42470eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
42489566063dSJacob Faibussowitsch           PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
42490eb7e1eaSToby Isaac           break;
42500eb7e1eaSToby Isaac         }
42510eb7e1eaSToby Isaac       }
42520eb7e1eaSToby Isaac     }
42531baa6e33SBarry Smith     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
42549566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42559566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42560eb7e1eaSToby Isaac     if (dmGrad) {
42579566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad, &grad));
42589566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
42590eb7e1eaSToby Isaac     }
42609566063dSJacob Faibussowitsch     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
42619566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
426248a46eb9SPierre Jolivet     if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
4263ebf164c7SToby Isaac   }
42641baa6e33SBarry Smith   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
42659566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(vecOut));
42669566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(vecOut));
426738fc2455SToby Isaac   PetscFunctionReturn(0);
426838fc2455SToby Isaac }
4269