xref: /petsc/src/dm/impls/plex/plextree.c (revision 1690c2ae071c7584458d4e437df7b47bc4686b3c)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2af0996ceSBarry Smith #include <petsc/private/isimpl.h>
3af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
4d6a7ad0dSToby Isaac #include <petscsf.h>
50c37af3bSToby Isaac #include <petscds.h>
6d6a7ad0dSToby Isaac 
70e3d61c9SBarry Smith /* hierarchy routines */
8d6a7ad0dSToby Isaac 
9d6a7ad0dSToby Isaac /*@
10d6a7ad0dSToby Isaac   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
11d6a7ad0dSToby Isaac 
1220f4b53cSBarry Smith   Not Collective
13d6a7ad0dSToby Isaac 
14d6a7ad0dSToby Isaac   Input Parameters:
15a1cb98faSBarry Smith + dm  - The `DMPLEX` object
16a1cb98faSBarry Smith - ref - The reference tree `DMPLEX` object
17d6a7ad0dSToby Isaac 
180b7167a0SToby Isaac   Level: intermediate
19d6a7ad0dSToby Isaac 
201cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`,`DMPlexGetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
21d6a7ad0dSToby Isaac @*/
22d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
23d71ae5a4SJacob Faibussowitsch {
24d6a7ad0dSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
25d6a7ad0dSToby Isaac 
26d6a7ad0dSToby Isaac   PetscFunctionBegin;
27d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28ad540459SPierre Jolivet   if (ref) PetscValidHeaderSpecific(ref, DM_CLASSID, 2);
299566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)ref));
309566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
31d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33d6a7ad0dSToby Isaac }
34d6a7ad0dSToby Isaac 
35d6a7ad0dSToby Isaac /*@
36d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
37d6a7ad0dSToby Isaac 
3820f4b53cSBarry Smith   Not Collective
39d6a7ad0dSToby Isaac 
402fe279fdSBarry Smith   Input Parameter:
41a1cb98faSBarry Smith . dm - The `DMPLEX` object
42d6a7ad0dSToby Isaac 
432fe279fdSBarry Smith   Output Parameter:
44a1cb98faSBarry Smith . ref - The reference tree `DMPLEX` object
45d6a7ad0dSToby Isaac 
460b7167a0SToby Isaac   Level: intermediate
47d6a7ad0dSToby Isaac 
48d3a532e9SStefano Zampini   Developer Notes:
49d3a532e9SStefano Zampini   The reference tree is shallow copied during `DMClone()`, thus it is may be shared by different `DM`s.
50d3a532e9SStefano Zampini   It is not a topological-only object, since some parts of the library use its local section to compute
51d3a532e9SStefano Zampini   interpolation and injection matrices. This may lead to unexpected failures during those calls.
52d3a532e9SStefano Zampini 
531cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
54d6a7ad0dSToby Isaac @*/
55d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
56d71ae5a4SJacob Faibussowitsch {
57d6a7ad0dSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
58d6a7ad0dSToby Isaac 
59d6a7ad0dSToby Isaac   PetscFunctionBegin;
60d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
614f572ea9SToby Isaac   PetscAssertPointer(ref, 2);
62d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64d6a7ad0dSToby Isaac }
65d6a7ad0dSToby Isaac 
66d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
67d71ae5a4SJacob Faibussowitsch {
68dcbd3bf7SToby Isaac   PetscInt coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
69dcbd3bf7SToby Isaac 
70dcbd3bf7SToby Isaac   PetscFunctionBegin;
71dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
72dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
73dcbd3bf7SToby Isaac     if (childB) *childB = childA;
743ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
75dcbd3bf7SToby Isaac   }
76dcbd3bf7SToby Isaac   for (dim = 0; dim < 3; dim++) {
779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, dim, &dStart, &dEnd));
78ad540459SPierre Jolivet     if (parent >= dStart && parent <= dEnd) break;
79dcbd3bf7SToby Isaac   }
8063a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot perform child symmetry for %" PetscInt_FMT "-cells", dim);
8128b400f6SJacob Faibussowitsch   PetscCheck(dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "A vertex has no children");
82dcbd3bf7SToby Isaac   if (childA < dStart || childA >= dEnd) {
83dcbd3bf7SToby Isaac     /* this is a lower-dimensional child: bootstrap */
84dcbd3bf7SToby Isaac     PetscInt        size, i, sA = -1, sB, sOrientB, sConeSize;
85dcbd3bf7SToby Isaac     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
86dcbd3bf7SToby Isaac 
879566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, childA, &size));
889566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, childA, &supp));
89dcbd3bf7SToby Isaac 
90dcbd3bf7SToby Isaac     /* find a point sA in supp(childA) that has the same parent */
91dcbd3bf7SToby Isaac     for (i = 0; i < size; i++) {
92dcbd3bf7SToby Isaac       PetscInt sParent;
93dcbd3bf7SToby Isaac 
94dcbd3bf7SToby Isaac       sA = supp[i];
95dcbd3bf7SToby Isaac       if (sA == parent) continue;
969566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, sA, &sParent, NULL));
97ad540459SPierre Jolivet       if (sParent == parent) break;
98dcbd3bf7SToby Isaac     }
9908401ef6SPierre Jolivet     PetscCheck(i != size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "could not find support in children");
100dcbd3bf7SToby Isaac     /* find out which point sB is in an equivalent position to sA under
101dcbd3bf7SToby Isaac      * parentOrientB */
1029566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildSymmetry_Default(dm, parent, parentOrientA, 0, sA, parentOrientB, &sOrientB, &sB));
1039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, sA, &sConeSize));
1049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sA, &coneA));
1059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sB, &coneB));
1069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sA, &oA));
1079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sB, &oB));
108dcbd3bf7SToby Isaac     /* step through the cone of sA in natural order */
109dcbd3bf7SToby Isaac     for (i = 0; i < sConeSize; i++) {
110dcbd3bf7SToby Isaac       if (coneA[i] == childA) {
111dcbd3bf7SToby Isaac         /* if childA is at position i in coneA,
112dcbd3bf7SToby Isaac          * then we want the point that is at sOrientB*i in coneB */
113dcbd3bf7SToby Isaac         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize - (sOrientB + 1) - i) % sConeSize);
114dcbd3bf7SToby Isaac         if (childB) *childB = coneB[j];
115dcbd3bf7SToby Isaac         if (childOrientB) {
116b5a892a1SMatthew G. Knepley           DMPolytopeType ct;
117dcbd3bf7SToby Isaac           PetscInt       oBtrue;
118dcbd3bf7SToby Isaac 
1199566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, childA, &coneSize));
120dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
1211dca8a05SBarry Smith           PetscCheck(coneSize == 0 || coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected a vertex or an edge");
122b5a892a1SMatthew G. Knepley           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
123dcbd3bf7SToby Isaac           /* we may have to flip an edge */
124b5a892a1SMatthew G. Knepley           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientation(ct, -1, oB[j]);
125b5a892a1SMatthew G. Knepley           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
126b5a892a1SMatthew G. Knepley           ABswap        = DihedralSwap(coneSize, DMPolytopeConvertNewOrientation_Internal(ct, oA[i]), oBtrue);
127dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
128dcbd3bf7SToby Isaac         }
129dcbd3bf7SToby Isaac         break;
130dcbd3bf7SToby Isaac       }
131dcbd3bf7SToby Isaac     }
13208401ef6SPierre Jolivet     PetscCheck(i != sConeSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "support cone mismatch");
1333ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
134dcbd3bf7SToby Isaac   }
135dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
1369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
137dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
138dcbd3bf7SToby Isaac   if (dim == 2) {
139dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
140dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
141dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
142dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
143dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
144dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
145947b95d8SBarry Smith   } else {
146dcbd3bf7SToby Isaac     ABswapVert = ABswap;
147dcbd3bf7SToby Isaac   }
148dcbd3bf7SToby Isaac   if (childB) {
149dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
150dcbd3bf7SToby Isaac     PetscInt        p, posA = -1, numChildren, i;
151dcbd3bf7SToby Isaac     const PetscInt *children;
152dcbd3bf7SToby Isaac 
153dcbd3bf7SToby Isaac     /* count which position the child is in */
1549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, parent, &numChildren, &children));
155dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
156dcbd3bf7SToby Isaac       p = children[i];
157dcbd3bf7SToby Isaac       if (p == childA) {
158dcbd3bf7SToby Isaac         posA = i;
159dcbd3bf7SToby Isaac         break;
160dcbd3bf7SToby Isaac       }
161dcbd3bf7SToby Isaac     }
162dcbd3bf7SToby Isaac     if (posA >= coneSize) {
163dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
164dcbd3bf7SToby Isaac        * is invariant */
1651dca8a05SBarry Smith       PetscCheck(dim == 2 && posA == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Expected a middle triangle, got something else");
166dcbd3bf7SToby Isaac       *childB = childA;
1679371c9d4SSatish Balay     } else {
168dcbd3bf7SToby Isaac       /* figure out position B by applying ABswapVert */
169dcbd3bf7SToby Isaac       PetscInt posB;
170dcbd3bf7SToby Isaac 
171dcbd3bf7SToby Isaac       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize - (ABswapVert + 1) - posA) % coneSize);
172dcbd3bf7SToby Isaac       if (childB) *childB = children[posB];
173dcbd3bf7SToby Isaac     }
174dcbd3bf7SToby Isaac   }
175dcbd3bf7SToby Isaac   if (childOrientB) *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
1763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
177dcbd3bf7SToby Isaac }
178dcbd3bf7SToby Isaac 
179dcbd3bf7SToby Isaac /*@
180dcbd3bf7SToby Isaac   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
181dcbd3bf7SToby Isaac 
182dcbd3bf7SToby Isaac   Input Parameters:
183a1cb98faSBarry Smith + dm            - the reference tree `DMPLEX` object
184dcbd3bf7SToby Isaac . parent        - the parent point
185dcbd3bf7SToby Isaac . parentOrientA - the reference orientation for describing the parent
186dcbd3bf7SToby Isaac . childOrientA  - the reference orientation for describing the child
187dcbd3bf7SToby Isaac . childA        - the reference childID for describing the child
188dcbd3bf7SToby Isaac - parentOrientB - the new orientation for describing the parent
189dcbd3bf7SToby Isaac 
190dcbd3bf7SToby Isaac   Output Parameters:
19120f4b53cSBarry Smith + childOrientB - if not `NULL`, set to the new orientation for describing the child
19220f4b53cSBarry Smith - childB       - if not `NULL`, the new childID for describing the child
193dcbd3bf7SToby Isaac 
194dcbd3bf7SToby Isaac   Level: developer
195dcbd3bf7SToby Isaac 
1961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetReferenceTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetTree()`
197dcbd3bf7SToby Isaac @*/
198d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
199d71ae5a4SJacob Faibussowitsch {
200dcbd3bf7SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
201dcbd3bf7SToby Isaac 
202dcbd3bf7SToby Isaac   PetscFunctionBegin;
203dcbd3bf7SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20428b400f6SJacob Faibussowitsch   PetscCheck(mesh->getchildsymmetry, PETSC_COMM_SELF, PETSC_ERR_SUP, "DMPlexReferenceTreeGetChildSymmetry not implemented");
2059566063dSJacob Faibussowitsch   PetscCall(mesh->getchildsymmetry(dm, parent, parentOrientA, childOrientA, childA, parentOrientB, childOrientB, childB));
2063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
207dcbd3bf7SToby Isaac }
208dcbd3bf7SToby Isaac 
209776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM, PetscSection, PetscInt *, PetscInt *, PetscBool, PetscBool);
210f9f063d4SToby Isaac 
211d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
212d71ae5a4SJacob Faibussowitsch {
213f2c1aa1dSLisandro Dalcin   PetscFunctionBegin;
2149566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_TRUE, PETSC_FALSE));
2153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
216f2c1aa1dSLisandro Dalcin }
217f2c1aa1dSLisandro Dalcin 
218d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
219d71ae5a4SJacob Faibussowitsch {
2200e2cc29aSToby Isaac   MPI_Comm     comm;
2210e2cc29aSToby Isaac   PetscInt     dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
222da43764aSToby Isaac   PetscInt    *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
223da43764aSToby Isaac   DMLabel      identity, identityRef;
22410f7e118SToby Isaac   PetscSection unionSection, unionConeSection, parentSection;
225da43764aSToby Isaac   PetscScalar *unionCoords;
226da43764aSToby Isaac   IS           perm;
227da43764aSToby Isaac 
228da43764aSToby Isaac   PetscFunctionBegin;
2290e2cc29aSToby Isaac   comm = PetscObjectComm((PetscObject)K);
2309566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(K, &dim));
2319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
2329566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, labelName, &identity));
2339566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(Kref, labelName, &identityRef));
2349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(Kref, &pRefStart, &pRefEnd));
2359566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionSection));
2369566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart)));
237da43764aSToby Isaac   /* count points that will go in the union */
23848a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; p++) PetscCall(PetscSectionSetDof(unionSection, p - pStart, 1));
239da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
240da43764aSToby Isaac     PetscInt q, qSize;
2419566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(identityRef, p, &q));
2429566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(identityRef, q, &qSize));
24348a46eb9SPierre Jolivet     if (qSize > 1) PetscCall(PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1));
244da43764aSToby Isaac   }
2459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart, &permvals));
246da43764aSToby Isaac   offset = 0;
247da43764aSToby Isaac   /* stratify points in the union by topological dimension */
248da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
249da43764aSToby Isaac     PetscInt cStart, cEnd, c;
250da43764aSToby Isaac 
2519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, &cEnd));
252ad540459SPierre Jolivet     for (c = cStart; c < cEnd; c++) permvals[offset++] = c;
253da43764aSToby Isaac 
2549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd));
255ad540459SPierre Jolivet     for (c = cStart; c < cEnd; c++) permvals[offset++] = c + (pEnd - pStart);
256da43764aSToby Isaac   }
2579566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm));
2589566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetPermutation(unionSection, perm));
2599566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionSection));
2609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionSection, &numUnionPoints));
2619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numUnionPoints, &coneSizes, dim + 1, &numDimPoints));
262da43764aSToby Isaac   /* count dimension points */
263da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
264da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
2659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, NULL));
2669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff));
267da43764aSToby Isaac     if (d < dim) {
2689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d + 1, &cStart, NULL));
2699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff2));
2709371c9d4SSatish Balay     } else {
271da43764aSToby Isaac       cOff2 = numUnionPoints;
272da43764aSToby Isaac     }
273da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
274da43764aSToby Isaac   }
2759566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionConeSection));
2769566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(unionConeSection, 0, numUnionPoints));
277da43764aSToby Isaac   /* count the cones in the union */
278da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
279da43764aSToby Isaac     PetscInt dof, uOff;
280da43764aSToby Isaac 
2819566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
2829566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
2839566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
284da43764aSToby Isaac     coneSizes[uOff] = dof;
285da43764aSToby Isaac   }
286da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
287da43764aSToby Isaac     PetscInt dof, uDof, uOff;
288da43764aSToby Isaac 
2899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
2909566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
2919566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
292da43764aSToby Isaac     if (uDof) {
2939566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
294da43764aSToby Isaac       coneSizes[uOff] = dof;
295da43764aSToby Isaac     }
296da43764aSToby Isaac   }
2979566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionConeSection));
2989566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionConeSection, &numCones));
2999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numCones, &unionCones, numCones, &unionOrientations));
300da43764aSToby Isaac   /* write the cones in the union */
301da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
302da43764aSToby Isaac     PetscInt        dof, uOff, c, cOff;
303da43764aSToby Isaac     const PetscInt *cone, *orientation;
304da43764aSToby Isaac 
3059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
3069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(K, p, &cone));
3079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(K, p, &orientation));
3089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
3099566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
310da43764aSToby Isaac     for (c = 0; c < dof; c++) {
311da43764aSToby Isaac       PetscInt e, eOff;
312da43764aSToby Isaac       e = cone[c];
3139566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
314da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
315da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
316da43764aSToby Isaac     }
317da43764aSToby Isaac   }
318da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
319da43764aSToby Isaac     PetscInt        dof, uDof, uOff, c, cOff;
320da43764aSToby Isaac     const PetscInt *cone, *orientation;
321da43764aSToby Isaac 
3229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
3239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(Kref, p, &cone));
3249566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(Kref, p, &orientation));
3259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
327da43764aSToby Isaac     if (uDof) {
3289566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
329da43764aSToby Isaac       for (c = 0; c < dof; c++) {
330da43764aSToby Isaac         PetscInt e, eOff, eDof;
331da43764aSToby Isaac 
332da43764aSToby Isaac         e = cone[c];
3339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart), &eDof));
334da43764aSToby Isaac         if (eDof) {
3359566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff));
3369371c9d4SSatish Balay         } else {
3379566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(identityRef, e, &e));
3389566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
339da43764aSToby Isaac         }
340da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
341da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
342da43764aSToby Isaac       }
343da43764aSToby Isaac     }
344da43764aSToby Isaac   }
345da43764aSToby Isaac   /* get the coordinates */
346da43764aSToby Isaac   {
347da43764aSToby Isaac     PetscInt     vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
348da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
349da43764aSToby Isaac     Vec          KcoordsVec, KrefCoordsVec;
350da43764aSToby Isaac     PetscScalar *Kcoords;
351da43764aSToby Isaac 
3529566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(K, &KcoordsSec));
3539566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(K, &KcoordsVec));
3549566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(Kref, &KrefCoordsSec));
3559566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(Kref, &KrefCoordsVec));
356da43764aSToby Isaac 
357da43764aSToby Isaac     numVerts = numDimPoints[0];
3589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numVerts * dim, &unionCoords));
3599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(K, 0, &vStart, &vEnd));
360da43764aSToby Isaac 
361da43764aSToby Isaac     offset = 0;
362da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
3639566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, v - pStart, &vOff));
3649566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords));
365ad540459SPierre Jolivet       for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
366da43764aSToby Isaac       offset++;
367da43764aSToby Isaac     }
3689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(Kref, 0, &vRefStart, &vRefEnd));
369da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
3709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(unionSection, v - pRefStart + (pEnd - pStart), &vDof));
3719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, v - pRefStart + (pEnd - pStart), &vOff));
3729566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords));
373da43764aSToby Isaac       if (vDof) {
374ad540459SPierre Jolivet         for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
375da43764aSToby Isaac         offset++;
376da43764aSToby Isaac       }
377da43764aSToby Isaac     }
378da43764aSToby Isaac   }
3799566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, ref));
3809566063dSJacob Faibussowitsch   PetscCall(DMSetType(*ref, DMPLEX));
3819566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ref, dim));
3829566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromDAG(*ref, dim, numDimPoints, coneSizes, unionCones, unionOrientations, unionCoords));
38310f7e118SToby Isaac   /* set the tree */
3849566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &parentSection));
3859566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(parentSection, 0, numUnionPoints));
38610f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
38710f7e118SToby Isaac     PetscInt uDof, uOff;
38810f7e118SToby Isaac 
3899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3909566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
3911baa6e33SBarry Smith     if (uDof) PetscCall(PetscSectionSetDof(parentSection, uOff, 1));
39210f7e118SToby Isaac   }
3939566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(parentSection));
3949566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection, &parentSize));
3959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(parentSize, &parents, parentSize, &childIDs));
39610f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
39710f7e118SToby Isaac     PetscInt uDof, uOff;
39810f7e118SToby Isaac 
3999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
4009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
40110f7e118SToby Isaac     if (uDof) {
40210f7e118SToby Isaac       PetscInt pOff, parent, parentU;
4039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(parentSection, uOff, &pOff));
4049566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(identityRef, p, &parent));
4059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, parent - pStart, &parentU));
40610f7e118SToby Isaac       parents[pOff]  = parentU;
40710f7e118SToby Isaac       childIDs[pOff] = uOff;
40810f7e118SToby Isaac     }
40910f7e118SToby Isaac   }
4109566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_SetTree(*ref, parentSection, parents, childIDs));
4119566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
4129566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parents, childIDs));
41310f7e118SToby Isaac 
414da43764aSToby Isaac   /* clean up */
4159566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionSection));
4169566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionConeSection));
4179566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&perm));
4189566063dSJacob Faibussowitsch   PetscCall(PetscFree(unionCoords));
4199566063dSJacob Faibussowitsch   PetscCall(PetscFree2(unionCones, unionOrientations));
4209566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coneSizes, numDimPoints));
4213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4220e2cc29aSToby Isaac }
4230e2cc29aSToby Isaac 
4240e2cc29aSToby Isaac /*@
4250e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4260e2cc29aSToby Isaac 
427d083f849SBarry Smith   Collective
4280e2cc29aSToby Isaac 
4290e2cc29aSToby Isaac   Input Parameters:
4300e2cc29aSToby Isaac + comm    - the MPI communicator
4310e2cc29aSToby Isaac . dim     - the spatial dimension
4320e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4330e2cc29aSToby Isaac 
4342fe279fdSBarry Smith   Output Parameter:
435a1cb98faSBarry Smith . ref - the reference tree `DMPLEX` object
4360e2cc29aSToby Isaac 
4370e2cc29aSToby Isaac   Level: intermediate
4380e2cc29aSToby Isaac 
439db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`
4400e2cc29aSToby Isaac @*/
441d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
442d71ae5a4SJacob Faibussowitsch {
4430e2cc29aSToby Isaac   DM_Plex *mesh;
4440e2cc29aSToby Isaac   DM       K, Kref;
4450e2cc29aSToby Isaac   PetscInt p, pStart, pEnd;
4460e2cc29aSToby Isaac   DMLabel  identity;
4470e2cc29aSToby Isaac 
4480e2cc29aSToby Isaac   PetscFunctionBegin;
4490e2cc29aSToby Isaac #if 1
4500e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4510e2cc29aSToby Isaac #endif
4520e2cc29aSToby Isaac   /* create a reference element */
4539566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K));
4549566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(K, "identity"));
4559566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, "identity", &identity));
4569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
45748a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; p++) PetscCall(DMLabelSetValue(identity, p, p));
4580e2cc29aSToby Isaac   /* refine it */
4599566063dSJacob Faibussowitsch   PetscCall(DMRefine(K, comm, &Kref));
4600e2cc29aSToby Isaac 
4610e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4620e2cc29aSToby Isaac    * points that appear in both */
4639566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref));
4640e2cc29aSToby Isaac   mesh                   = (DM_Plex *)(*ref)->data;
4650e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
4669566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&K));
4679566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&Kref));
4683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
469da43764aSToby Isaac }
470da43764aSToby Isaac 
471d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
472d71ae5a4SJacob Faibussowitsch {
473878b19aaSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
474878b19aaSToby Isaac   PetscSection childSec, pSec;
475*1690c2aeSBarry Smith   PetscInt     p, pSize, cSize, parMax = PETSC_INT_MIN, parMin = PETSC_INT_MAX;
476878b19aaSToby Isaac   PetscInt    *offsets, *children, pStart, pEnd;
477878b19aaSToby Isaac 
478878b19aaSToby Isaac   PetscFunctionBegin;
479878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4809566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
4819566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
482878b19aaSToby Isaac   pSec = mesh->parentSection;
4833ba16761SJacob Faibussowitsch   if (!pSec) PetscFunctionReturn(PETSC_SUCCESS);
4849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(pSec, &pSize));
485878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
486878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
487878b19aaSToby Isaac 
488878b19aaSToby Isaac     parMax = PetscMax(parMax, par + 1);
489878b19aaSToby Isaac     parMin = PetscMin(parMin, par);
490878b19aaSToby Isaac   }
491878b19aaSToby Isaac   if (parMin > parMax) {
492878b19aaSToby Isaac     parMin = -1;
493878b19aaSToby Isaac     parMax = -1;
494878b19aaSToby Isaac   }
4959566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)pSec), &childSec));
4969566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(childSec, parMin, parMax));
497878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
498878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
499878b19aaSToby Isaac 
5009566063dSJacob Faibussowitsch     PetscCall(PetscSectionAddDof(childSec, par, 1));
501878b19aaSToby Isaac   }
5029566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(childSec));
5039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(childSec, &cSize));
5049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cSize, &children));
5059566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(parMax - parMin, &offsets));
5069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(pSec, &pStart, &pEnd));
507878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
508878b19aaSToby Isaac     PetscInt dof, off, i;
509878b19aaSToby Isaac 
5109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pSec, p, &dof));
5119566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(pSec, p, &off));
512878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
513878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
514878b19aaSToby Isaac 
5159566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec, par, &cOff));
516878b19aaSToby Isaac       children[cOff + offsets[par - parMin]++] = p;
517878b19aaSToby Isaac     }
518878b19aaSToby Isaac   }
519878b19aaSToby Isaac   mesh->childSection = childSec;
520878b19aaSToby Isaac   mesh->children     = children;
5219566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
5223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
523878b19aaSToby Isaac }
524878b19aaSToby Isaac 
525d71ae5a4SJacob Faibussowitsch static PetscErrorCode AnchorsFlatten(PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
526d71ae5a4SJacob Faibussowitsch {
5276dd5a8c8SToby Isaac   PetscInt        pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5286dd5a8c8SToby Isaac   const PetscInt *vals;
5296dd5a8c8SToby Isaac   PetscSection    secNew;
5306dd5a8c8SToby Isaac   PetscBool       anyNew, globalAnyNew;
5316dd5a8c8SToby Isaac   PetscBool       compress;
5326dd5a8c8SToby Isaac 
5336dd5a8c8SToby Isaac   PetscFunctionBegin;
5349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
5359566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is, &size));
5369566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is, &vals));
5379566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secNew));
5389566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(secNew, pStart, pEnd));
5396dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5406dd5a8c8SToby Isaac     PetscInt dof;
5416dd5a8c8SToby Isaac 
5426dd5a8c8SToby Isaac     p = vals[i];
5436dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
5456dd5a8c8SToby Isaac     if (dof) break;
5466dd5a8c8SToby Isaac   }
5476dd5a8c8SToby Isaac   if (i == size) {
5489566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5496dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5506dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5516dd5a8c8SToby Isaac     sizeNew  = 0;
5529371c9d4SSatish Balay   } else {
5536dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5546dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5556dd5a8c8SToby Isaac       PetscInt dof, off;
5566dd5a8c8SToby Isaac 
5579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5596dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5606dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5616dd5a8c8SToby Isaac 
56248a46eb9SPierre Jolivet         if (q >= pStart && q < pEnd) PetscCall(PetscSectionGetDof(section, q, &qDof));
5631baa6e33SBarry Smith         if (qDof) PetscCall(PetscSectionAddDof(secNew, p, qDof));
56448a46eb9SPierre Jolivet         else PetscCall(PetscSectionAddDof(secNew, p, 1));
5656dd5a8c8SToby Isaac       }
5666dd5a8c8SToby Isaac     }
5679566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(secNew, &sizeNew));
5699566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sizeNew, &valsNew));
5706dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5716dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5726dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
5736dd5a8c8SToby Isaac 
5749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(secNew, p, &dofNew));
5779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(secNew, p, &offNew));
5786dd5a8c8SToby Isaac       count = 0;
5796dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5806dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
5816dd5a8c8SToby Isaac 
5826dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5839566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, q, &qDof));
5849566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, q, &qOff));
5856dd5a8c8SToby Isaac         }
5866dd5a8c8SToby Isaac         if (qDof) {
5876dd5a8c8SToby Isaac           PetscInt oldCount = count;
5886dd5a8c8SToby Isaac 
5896dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
5906dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
5916dd5a8c8SToby Isaac 
5926dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
593ad540459SPierre Jolivet               if (valsNew[offNew + k] == r) break;
5946dd5a8c8SToby Isaac             }
595ad540459SPierre Jolivet             if (k == oldCount) valsNew[offNew + count++] = r;
5966dd5a8c8SToby Isaac           }
5979371c9d4SSatish Balay         } else {
5986dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
5996dd5a8c8SToby Isaac 
6006dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
601ad540459SPierre Jolivet             if (valsNew[offNew + k] == q) break;
6026dd5a8c8SToby Isaac           }
603ad540459SPierre Jolivet           if (k == oldCount) valsNew[offNew + count++] = q;
6046dd5a8c8SToby Isaac         }
6056dd5a8c8SToby Isaac       }
6066dd5a8c8SToby Isaac       if (count < dofNew) {
6079566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secNew, p, count));
6086dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6096dd5a8c8SToby Isaac       }
6106dd5a8c8SToby Isaac     }
6116dd5a8c8SToby Isaac   }
6129566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is, &vals));
6131c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&anyNew, &globalAnyNew, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
6146dd5a8c8SToby Isaac   if (!globalAnyNew) {
6159566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secNew));
6166dd5a8c8SToby Isaac     *sectionNew = NULL;
6176dd5a8c8SToby Isaac     *isNew      = NULL;
6189371c9d4SSatish Balay   } else {
6196dd5a8c8SToby Isaac     PetscBool globalCompress;
6206dd5a8c8SToby Isaac 
6211c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&compress, &globalCompress, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
6226dd5a8c8SToby Isaac     if (compress) {
6236dd5a8c8SToby Isaac       PetscSection secComp;
6246dd5a8c8SToby Isaac       PetscInt    *valsComp = NULL;
6256dd5a8c8SToby Isaac 
6269566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secComp));
6279566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetChart(secComp, pStart, pEnd));
6286dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6296dd5a8c8SToby Isaac         PetscInt dof;
6306dd5a8c8SToby Isaac 
6319566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6329566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secComp, p, dof));
6336dd5a8c8SToby Isaac       }
6349566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetUp(secComp));
6359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(secComp, &sizeNew));
6369566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(sizeNew, &valsComp));
6376dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6386dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6396dd5a8c8SToby Isaac 
6409566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6419566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secNew, p, &off));
6429566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secComp, p, &offNew));
643ad540459SPierre Jolivet         for (j = 0; j < dof; j++) valsComp[offNew + j] = valsNew[off + j];
6446dd5a8c8SToby Isaac       }
6459566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&secNew));
6466dd5a8c8SToby Isaac       secNew = secComp;
6479566063dSJacob Faibussowitsch       PetscCall(PetscFree(valsNew));
6486dd5a8c8SToby Isaac       valsNew = valsComp;
6496dd5a8c8SToby Isaac     }
6509566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), sizeNew, valsNew, PETSC_OWN_POINTER, isNew));
6516dd5a8c8SToby Isaac   }
6523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6536dd5a8c8SToby Isaac }
6546dd5a8c8SToby Isaac 
655d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
656d71ae5a4SJacob Faibussowitsch {
65766af876cSToby Isaac   PetscInt     p, pStart, pEnd, *anchors, size;
658*1690c2aeSBarry Smith   PetscInt     aMin = PETSC_INT_MAX, aMax = PETSC_INT_MIN;
65966af876cSToby Isaac   PetscSection aSec;
660f9f063d4SToby Isaac   DMLabel      canonLabel;
66166af876cSToby Isaac   IS           aIS;
66266af876cSToby Isaac 
66366af876cSToby Isaac   PetscFunctionBegin;
66466af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
6669566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "canonical", &canonLabel));
66766af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
66866af876cSToby Isaac     PetscInt parent;
66966af876cSToby Isaac 
670f9f063d4SToby Isaac     if (canonLabel) {
671f9f063d4SToby Isaac       PetscInt canon;
672f9f063d4SToby Isaac 
6739566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
674f9f063d4SToby Isaac       if (p != canon) continue;
675f9f063d4SToby Isaac     }
6769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
67766af876cSToby Isaac     if (parent != p) {
67866af876cSToby Isaac       aMin = PetscMin(aMin, p);
67966af876cSToby Isaac       aMax = PetscMax(aMax, p + 1);
68066af876cSToby Isaac     }
68166af876cSToby Isaac   }
68266af876cSToby Isaac   if (aMin > aMax) {
68366af876cSToby Isaac     aMin = -1;
68466af876cSToby Isaac     aMax = -1;
68566af876cSToby Isaac   }
6869566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &aSec));
6879566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(aSec, aMin, aMax));
68866af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
68966af876cSToby Isaac     PetscInt parent, ancestor = p;
69066af876cSToby Isaac 
691f9f063d4SToby Isaac     if (canonLabel) {
692f9f063d4SToby Isaac       PetscInt canon;
693f9f063d4SToby Isaac 
6949566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
695f9f063d4SToby Isaac       if (p != canon) continue;
696f9f063d4SToby Isaac     }
6979566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
69866af876cSToby Isaac     while (parent != ancestor) {
69966af876cSToby Isaac       ancestor = parent;
7009566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
70166af876cSToby Isaac     }
70266af876cSToby Isaac     if (ancestor != p) {
70366af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
70466af876cSToby Isaac 
7059566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
7069566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(aSec, p, closureSize));
7079566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
70866af876cSToby Isaac     }
70966af876cSToby Isaac   }
7109566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(aSec));
7119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(aSec, &size));
7129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &anchors));
71366af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
71466af876cSToby Isaac     PetscInt parent, ancestor = p;
71566af876cSToby Isaac 
716f9f063d4SToby Isaac     if (canonLabel) {
717f9f063d4SToby Isaac       PetscInt canon;
718f9f063d4SToby Isaac 
7199566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
720f9f063d4SToby Isaac       if (p != canon) continue;
721f9f063d4SToby Isaac     }
7229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
72366af876cSToby Isaac     while (parent != ancestor) {
72466af876cSToby Isaac       ancestor = parent;
7259566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
72666af876cSToby Isaac     }
72766af876cSToby Isaac     if (ancestor != p) {
72866af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
72966af876cSToby Isaac 
7309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
73166af876cSToby Isaac 
7329566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
733ad540459SPierre Jolivet       for (j = 0; j < closureSize; j++) anchors[aOff + j] = closure[2 * j];
7349566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
73566af876cSToby Isaac     }
73666af876cSToby Isaac   }
7379566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, anchors, PETSC_OWN_POINTER, &aIS));
7386dd5a8c8SToby Isaac   {
7396dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7406dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7416dd5a8c8SToby Isaac 
7429566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aSec));
7439566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aIS));
7446dd5a8c8SToby Isaac     while (aSecNew) {
7459566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&aSec));
7469566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&aIS));
7476dd5a8c8SToby Isaac       aSec    = aSecNew;
7486dd5a8c8SToby Isaac       aIS     = aISNew;
7496dd5a8c8SToby Isaac       aSecNew = NULL;
7506dd5a8c8SToby Isaac       aISNew  = NULL;
7519566063dSJacob Faibussowitsch       PetscCall(AnchorsFlatten(aSec, aIS, &aSecNew, &aISNew));
7526dd5a8c8SToby Isaac     }
7536dd5a8c8SToby Isaac   }
7549566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm, aSec, aIS));
7559566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&aSec));
7569566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&aIS));
7573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
75866af876cSToby Isaac }
75966af876cSToby Isaac 
760d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTrueSupportSize(DM dm, PetscInt p, PetscInt *dof, PetscInt *numTrueSupp)
761d71ae5a4SJacob Faibussowitsch {
7626461c1adSToby Isaac   PetscFunctionBegin;
7636461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
7646461c1adSToby Isaac     PetscInt        i, alldof;
7656461c1adSToby Isaac     const PetscInt *supp;
7666461c1adSToby Isaac     PetscInt        count = 0;
7676461c1adSToby Isaac 
7689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &alldof));
7699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &supp));
7706461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
7716461c1adSToby Isaac       PetscInt        q = supp[i], numCones, j;
7726461c1adSToby Isaac       const PetscInt *cone;
7736461c1adSToby Isaac 
7749566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, q, &numCones));
7759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, q, &cone));
7766461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
7776461c1adSToby Isaac         if (cone[j] == p) break;
7786461c1adSToby Isaac       }
7796461c1adSToby Isaac       if (j < numCones) count++;
7806461c1adSToby Isaac     }
7816461c1adSToby Isaac     numTrueSupp[p] = count;
7826461c1adSToby Isaac   }
7836461c1adSToby Isaac   *dof = numTrueSupp[p];
7843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7856461c1adSToby Isaac }
7866461c1adSToby Isaac 
787d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
788d71ae5a4SJacob Faibussowitsch {
789776742edSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
790776742edSToby Isaac   PetscSection newSupportSection;
791776742edSToby Isaac   PetscInt     newSize, *newSupports, pStart, pEnd, p, d, depth;
7926461c1adSToby Isaac   PetscInt    *numTrueSupp;
793776742edSToby Isaac   PetscInt    *offsets;
794776742edSToby Isaac 
795776742edSToby Isaac   PetscFunctionBegin;
796776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
797776742edSToby Isaac   /* symmetrize the hierarchy */
7989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
799f4f49eeaSPierre Jolivet   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)mesh->supportSection), &newSupportSection));
8009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8019566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSupportSection, pStart, pEnd));
8029566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd, &offsets));
8039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd, &numTrueSupp));
8046461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8056461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
806776742edSToby Isaac    * parent(q) */
807776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
809776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
810776742edSToby Isaac       PetscInt dof, q, qdof, parent;
811776742edSToby Isaac 
8129566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTrueSupportSize(dm, p, &dof, numTrueSupp));
8139566063dSJacob Faibussowitsch       PetscCall(PetscSectionAddDof(newSupportSection, p, dof));
814776742edSToby Isaac       q = p;
8159566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
816776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
817776742edSToby Isaac         q = parent;
818776742edSToby Isaac 
8199566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTrueSupportSize(dm, q, &qdof, numTrueSupp));
8209566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection, p, qdof));
8219566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection, q, dof));
8229566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
823776742edSToby Isaac       }
824776742edSToby Isaac     }
825776742edSToby Isaac   }
8269566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSupportSection));
8279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSupportSection, &newSize));
8289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(newSize, &newSupports));
829776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
831776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
832776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
833776742edSToby Isaac 
8349566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
8359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
8369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(newSupportSection, p, &newDof));
8379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(newSupportSection, p, &newOff));
838776742edSToby Isaac       for (i = 0; i < dof; i++) {
8396461c1adSToby Isaac         PetscInt        numCones, j;
8406461c1adSToby Isaac         const PetscInt *cone;
8416461c1adSToby Isaac         PetscInt        q = mesh->supports[off + i];
8426461c1adSToby Isaac 
8439566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, q, &numCones));
8449566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, q, &cone));
8456461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8466461c1adSToby Isaac           if (cone[j] == p) break;
8476461c1adSToby Isaac         }
8486461c1adSToby Isaac         if (j < numCones) newSupports[newOff + offsets[p]++] = q;
849776742edSToby Isaac       }
850776742edSToby Isaac 
851776742edSToby Isaac       q = p;
8529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
853776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
854776742edSToby Isaac         q = parent;
8559566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->supportSection, q, &qdof));
8569566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &qoff));
8579566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(newSupportSection, q, &newqOff));
858776742edSToby Isaac         for (i = 0; i < qdof; i++) {
8596461c1adSToby Isaac           PetscInt        numCones, j;
8606461c1adSToby Isaac           const PetscInt *cone;
8616461c1adSToby Isaac           PetscInt        r = mesh->supports[qoff + i];
8626461c1adSToby Isaac 
8639566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
8649566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, r, &cone));
8656461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
8666461c1adSToby Isaac             if (cone[j] == q) break;
8676461c1adSToby Isaac           }
8686461c1adSToby Isaac           if (j < numCones) newSupports[newOff + offsets[p]++] = r;
869776742edSToby Isaac         }
870776742edSToby Isaac         for (i = 0; i < dof; i++) {
8716461c1adSToby Isaac           PetscInt        numCones, j;
8726461c1adSToby Isaac           const PetscInt *cone;
8736461c1adSToby Isaac           PetscInt        r = mesh->supports[off + i];
8746461c1adSToby Isaac 
8759566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
8769566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, r, &cone));
8776461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
8786461c1adSToby Isaac             if (cone[j] == p) break;
8796461c1adSToby Isaac           }
8806461c1adSToby Isaac           if (j < numCones) newSupports[newqOff + offsets[q]++] = r;
881776742edSToby Isaac         }
8829566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
883776742edSToby Isaac       }
884776742edSToby Isaac     }
885776742edSToby Isaac   }
8869566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
887776742edSToby Isaac   mesh->supportSection = newSupportSection;
8889566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
889776742edSToby Isaac   mesh->supports = newSupports;
8909566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
8919566063dSJacob Faibussowitsch   PetscCall(PetscFree(numTrueSupp));
8923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
893776742edSToby Isaac }
894776742edSToby Isaac 
895f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM, PetscSection, PetscSection, Mat);
896f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM, PetscSection, PetscSection, Mat);
897f7c74593SToby Isaac 
898d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
899d71ae5a4SJacob Faibussowitsch {
900f9f063d4SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
901f9f063d4SToby Isaac   DM       refTree;
902f9f063d4SToby Isaac   PetscInt size;
903f9f063d4SToby Isaac 
904f9f063d4SToby Isaac   PetscFunctionBegin;
905f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
906f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
9079566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)parentSection));
9089566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
909f9f063d4SToby Isaac   mesh->parentSection = parentSection;
9109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection, &size));
911f9f063d4SToby Isaac   if (parents != mesh->parents) {
9129566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->parents));
9139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->parents));
9149566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->parents, parents, size));
915f9f063d4SToby Isaac   }
916f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
9179566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->childIDs));
9189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->childIDs));
9199566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->childIDs, childIDs, size));
920f9f063d4SToby Isaac   }
9219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
922f9f063d4SToby Isaac   if (refTree) {
923f9f063d4SToby Isaac     DMLabel canonLabel;
924f9f063d4SToby Isaac 
9259566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(refTree, "canonical", &canonLabel));
926f9f063d4SToby Isaac     if (canonLabel) {
927f9f063d4SToby Isaac       PetscInt i;
928f9f063d4SToby Isaac 
929f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
930f9f063d4SToby Isaac         PetscInt canon;
9319566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon));
932ad540459SPierre Jolivet         if (canon >= 0) mesh->childIDs[i] = canon;
933f9f063d4SToby Isaac       }
934f9f063d4SToby Isaac     }
935f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
9366e0288c8SStefano Zampini   } else {
937f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
938f9f063d4SToby Isaac   }
9399566063dSJacob Faibussowitsch   PetscCall(DMPlexTreeSymmetrize(dm));
940f9f063d4SToby Isaac   if (computeCanonical) {
941f9f063d4SToby Isaac     PetscInt d, dim;
942f9f063d4SToby Isaac 
943f9f063d4SToby Isaac     /* add the canonical label */
9449566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
9459566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "canonical"));
946f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
947f9f063d4SToby Isaac       PetscInt        p, dStart, dEnd, canon = -1, cNumChildren;
948f9f063d4SToby Isaac       const PetscInt *cChildren;
949f9f063d4SToby Isaac 
9509566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
951f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
9529566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, p, &cNumChildren, &cChildren));
953f9f063d4SToby Isaac         if (cNumChildren) {
954f9f063d4SToby Isaac           canon = p;
955f9f063d4SToby Isaac           break;
956f9f063d4SToby Isaac         }
957f9f063d4SToby Isaac       }
958f9f063d4SToby Isaac       if (canon == -1) continue;
959f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
960f9f063d4SToby Isaac         PetscInt        numChildren, i;
961f9f063d4SToby Isaac         const PetscInt *children;
962f9f063d4SToby Isaac 
9639566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, p, &numChildren, &children));
964f9f063d4SToby Isaac         if (numChildren) {
96563a3b9bcSJacob 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);
9669566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "canonical", p, canon));
96748a46eb9SPierre Jolivet           for (i = 0; i < numChildren; i++) PetscCall(DMSetLabelValue(dm, "canonical", children[i], cChildren[i]));
968f9f063d4SToby Isaac         }
969f9f063d4SToby Isaac       }
970f9f063d4SToby Isaac     }
971f9f063d4SToby Isaac   }
9721baa6e33SBarry Smith   if (exchangeSupports) PetscCall(DMPlexTreeExchangeSupports(dm));
973f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
974f7c74593SToby Isaac   /* reset anchors */
9759566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm, NULL, NULL));
9763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
977f9f063d4SToby Isaac }
978f9f063d4SToby Isaac 
9790b7167a0SToby Isaac /*@
9800b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
981aaa8cc7dSPierre Jolivet   the point-to-point constraints determined by the tree: a point is constrained to the points in the closure of its
9820b7167a0SToby Isaac   tree root.
9830b7167a0SToby Isaac 
98420f4b53cSBarry Smith   Collective
9850b7167a0SToby Isaac 
9860b7167a0SToby Isaac   Input Parameters:
987a1cb98faSBarry Smith + dm            - the `DMPLEX` object
9880b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
9890b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
9900b7167a0SToby Isaac . parents       - a list of the point parents; copied, can be destroyed
9910b7167a0SToby Isaac - childIDs      - identifies the relationship of the child point to the parent point; if there is a reference tree, then
9920b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
9930b7167a0SToby Isaac 
9940b7167a0SToby Isaac   Level: intermediate
9950b7167a0SToby Isaac 
9961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
9970b7167a0SToby Isaac @*/
998d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
999d71ae5a4SJacob Faibussowitsch {
10000b7167a0SToby Isaac   PetscFunctionBegin;
10019566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_FALSE, PETSC_TRUE));
10023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10030b7167a0SToby Isaac }
10040b7167a0SToby Isaac 
1005b2f41788SToby Isaac /*@
1006b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
100720f4b53cSBarry Smith   Collective
1008b2f41788SToby Isaac 
1009f899ff85SJose E. Roman   Input Parameter:
1010a1cb98faSBarry Smith . dm - the `DMPLEX` object
1011b2f41788SToby Isaac 
1012b2f41788SToby Isaac   Output Parameters:
1013b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1014b2f41788SToby Isaac                   offset indexes the parent and childID list
1015b2f41788SToby Isaac . parents       - a list of the point parents
1016b2f41788SToby Isaac . childIDs      - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1017b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1018b2f41788SToby Isaac . childSection  - the inverse of the parent section
1019b2f41788SToby Isaac - children      - a list of the point children
1020b2f41788SToby Isaac 
1021b2f41788SToby Isaac   Level: intermediate
1022b2f41788SToby Isaac 
10231cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`,`DMPlexSetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
1024b2f41788SToby Isaac @*/
1025d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1026d71ae5a4SJacob Faibussowitsch {
1027b2f41788SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
1028b2f41788SToby Isaac 
1029b2f41788SToby Isaac   PetscFunctionBegin;
1030b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1031b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1032b2f41788SToby Isaac   if (parents) *parents = mesh->parents;
1033b2f41788SToby Isaac   if (childIDs) *childIDs = mesh->childIDs;
1034b2f41788SToby Isaac   if (childSection) *childSection = mesh->childSection;
1035b2f41788SToby Isaac   if (children) *children = mesh->children;
10363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1037b2f41788SToby Isaac }
1038b2f41788SToby Isaac 
1039d961a43aSToby Isaac /*@
1040eaf898f9SPatrick Sanan   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)
1041d961a43aSToby Isaac 
1042d961a43aSToby Isaac   Input Parameters:
1043a1cb98faSBarry Smith + dm    - the `DMPLEX` object
1044d961a43aSToby Isaac - point - the query point
1045d961a43aSToby Isaac 
1046d961a43aSToby Isaac   Output Parameters:
104720f4b53cSBarry Smith + parent  - if not `NULL`, set to the parent of the point, or the point itself if the point does not have a parent
104820f4b53cSBarry Smith - childID - if not `NULL`, set to the child ID of the point with respect to its parent, or 0 if the point
1049d961a43aSToby Isaac             does not have a parent
1050d961a43aSToby Isaac 
1051d961a43aSToby Isaac   Level: intermediate
1052d961a43aSToby Isaac 
10531cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeChildren()`
1054d961a43aSToby Isaac @*/
1055d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1056d71ae5a4SJacob Faibussowitsch {
1057d961a43aSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
1058d961a43aSToby Isaac   PetscSection pSec;
1059d961a43aSToby Isaac 
1060d961a43aSToby Isaac   PetscFunctionBegin;
1061d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1062d961a43aSToby Isaac   pSec = mesh->parentSection;
1063d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1064d961a43aSToby Isaac     PetscInt dof;
1065d961a43aSToby Isaac 
10669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pSec, point, &dof));
1067d961a43aSToby Isaac     if (dof) {
1068d961a43aSToby Isaac       PetscInt off;
1069d961a43aSToby Isaac 
10709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(pSec, point, &off));
1071d961a43aSToby Isaac       if (parent) *parent = mesh->parents[off];
1072d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
10733ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
1074d961a43aSToby Isaac     }
1075d961a43aSToby Isaac   }
1076ad540459SPierre Jolivet   if (parent) *parent = point;
1077ad540459SPierre Jolivet   if (childID) *childID = 0;
10783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1079d961a43aSToby Isaac }
1080d961a43aSToby Isaac 
1081d961a43aSToby Isaac /*@C
1082eaf898f9SPatrick Sanan   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)
1083d961a43aSToby Isaac 
1084d961a43aSToby Isaac   Input Parameters:
1085a1cb98faSBarry Smith + dm    - the `DMPLEX` object
1086d961a43aSToby Isaac - point - the query point
1087d961a43aSToby Isaac 
1088d961a43aSToby Isaac   Output Parameters:
108920f4b53cSBarry Smith + numChildren - if not `NULL`, set to the number of children
109020f4b53cSBarry Smith - children    - if not `NULL`, set to a list children, or set to `NULL` if the point has no children
1091d961a43aSToby Isaac 
1092d961a43aSToby Isaac   Level: intermediate
1093d961a43aSToby Isaac 
10941cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeParent()`
1095d961a43aSToby Isaac @*/
1096d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1097d71ae5a4SJacob Faibussowitsch {
1098d961a43aSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
1099d961a43aSToby Isaac   PetscSection childSec;
1100d961a43aSToby Isaac   PetscInt     dof = 0;
1101d961a43aSToby Isaac 
1102d961a43aSToby Isaac   PetscFunctionBegin;
1103d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1104d961a43aSToby Isaac   childSec = mesh->childSection;
110548a46eb9SPierre Jolivet   if (childSec && point >= childSec->pStart && point < childSec->pEnd) PetscCall(PetscSectionGetDof(childSec, point, &dof));
1106d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1107d961a43aSToby Isaac   if (children) {
1108d961a43aSToby Isaac     if (dof) {
1109d961a43aSToby Isaac       PetscInt off;
1110d961a43aSToby Isaac 
11119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec, point, &off));
1112d961a43aSToby Isaac       *children = &mesh->children[off];
11139371c9d4SSatish Balay     } else {
1114d961a43aSToby Isaac       *children = NULL;
1115d961a43aSToby Isaac     }
1116d961a43aSToby Isaac   }
11173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1118d961a43aSToby Isaac }
11190c37af3bSToby Isaac 
1120d71ae5a4SJacob 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)
1121d71ae5a4SJacob Faibussowitsch {
112252a3aeb4SToby Isaac   PetscInt f, b, p, c, offset, qPoints;
1123b3a4bf2aSToby Isaac 
1124b3a4bf2aSToby Isaac   PetscFunctionBegin;
11259566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(space, nPoints, points, work, NULL, NULL));
112652a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
112752a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
112852a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1129b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1130b3a4bf2aSToby Isaac 
113152a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
1132ad540459SPierre Jolivet         for (c = 0; c < nComps; c++) val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
113352a3aeb4SToby Isaac       }
11349566063dSJacob Faibussowitsch       PetscCall(MatSetValue(basisAtPoints, b, f, val, INSERT_VALUES));
1135b3a4bf2aSToby Isaac     }
1136b3a4bf2aSToby Isaac     offset += qPoints;
1137b3a4bf2aSToby Isaac   }
11389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(basisAtPoints, MAT_FINAL_ASSEMBLY));
11399566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(basisAtPoints, MAT_FINAL_ASSEMBLY));
11403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1141b3a4bf2aSToby Isaac }
1142b3a4bf2aSToby Isaac 
1143d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
1144d71ae5a4SJacob Faibussowitsch {
11450c37af3bSToby Isaac   PetscDS         ds;
11460c37af3bSToby Isaac   PetscInt        spdim;
11470c37af3bSToby Isaac   PetscInt        numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
11480c37af3bSToby Isaac   const PetscInt *anchors;
1149f7c74593SToby Isaac   PetscSection    aSec;
11500c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
11510c37af3bSToby Isaac   IS              aIS;
11520c37af3bSToby Isaac 
11530c37af3bSToby Isaac   PetscFunctionBegin;
11549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
11559566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
11569566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
11579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
11589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
11599566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
11609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &conStart, &conEnd));
11619566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &spdim));
11629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(spdim, &v0, spdim, &v0parent, spdim, &vtmp, spdim * spdim, &J, spdim * spdim, &Jparent, spdim * spdim, &invJparent));
11630c37af3bSToby Isaac 
11640c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
11650dd1b1feSToby Isaac     PetscObject          disc;
11660dd1b1feSToby Isaac     PetscClassId         id;
1167b3a4bf2aSToby Isaac     PetscSpace           bspace;
1168b3a4bf2aSToby Isaac     PetscDualSpace       dspace;
11699c3cf19fSMatthew G. Knepley     PetscInt             i, j, k, nPoints, Nc, offset;
117052a3aeb4SToby Isaac     PetscInt             fSize, maxDof;
1171b3a4bf2aSToby Isaac     PetscReal           *weights, *pointsRef, *pointsReal, *work;
11721683a169SBarry Smith     PetscScalar         *scwork;
11731683a169SBarry Smith     const PetscScalar   *X;
11742c44ad04SToby Isaac     PetscInt            *sizes, *workIndRow, *workIndCol;
11750c37af3bSToby Isaac     Mat                  Amat, Bmat, Xmat;
11762c44ad04SToby Isaac     const PetscInt      *numDof = NULL;
1177085f0adfSToby Isaac     const PetscInt    ***perms  = NULL;
1178085f0adfSToby Isaac     const PetscScalar ***flips  = NULL;
11790c37af3bSToby Isaac 
11809566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(ds, f, &disc));
11819566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(disc, &id));
11820dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1183b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE)disc;
1184b3a4bf2aSToby Isaac 
11859566063dSJacob Faibussowitsch       PetscCall(PetscFEGetBasisSpace(fe, &bspace));
11869566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(fe, &dspace));
11879566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
11889566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
11899371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
1190b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV)disc;
1191b3a4bf2aSToby Isaac 
11929566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
11939566063dSJacob Faibussowitsch       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)fv), &bspace));
11949566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetType(bspace, PETSCSPACEPOLYNOMIAL));
11959566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetDegree(bspace, 0, PETSC_DETERMINE));
11969566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumComponents(bspace, Nc));
11979566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumVariables(bspace, spdim));
11989566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(bspace));
11999566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &dspace));
12009566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
12019371c9d4SSatish Balay     } else SETERRQ(PetscObjectComm(disc), PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
12029566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetNumDof(dspace, &numDof));
1203ad540459SPierre Jolivet     for (i = 0, maxDof = 0; i <= spdim; i++) maxDof = PetscMax(maxDof, numDof[i]);
12049566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSymmetries(dspace, &perms, &flips));
12050dd1b1feSToby Isaac 
12069566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &Amat));
12079566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Amat, fSize, fSize, fSize, fSize));
12089566063dSJacob Faibussowitsch     PetscCall(MatSetType(Amat, MATSEQDENSE));
12099566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Amat));
12109566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Bmat));
12119566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Xmat));
12120c37af3bSToby Isaac     nPoints = 0;
12130c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
121452a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
12150c37af3bSToby Isaac       PetscQuadrature quad;
12160c37af3bSToby Isaac 
12179566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
12189566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, &thisNc, &qPoints, NULL, NULL));
121963a3b9bcSJacob Faibussowitsch       PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
12200c37af3bSToby Isaac       nPoints += qPoints;
12210c37af3bSToby Isaac     }
12229566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(fSize, &sizes, nPoints * Nc, &weights, spdim * nPoints, &pointsRef, spdim * nPoints, &pointsReal, nPoints * fSize * Nc, &work, maxDof, &workIndRow, maxDof, &workIndCol));
12239566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof * maxDof, &scwork));
12240c37af3bSToby Isaac     offset = 0;
12250c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12260c37af3bSToby Isaac       PetscInt         qPoints;
12270c37af3bSToby Isaac       const PetscReal *p, *w;
12280c37af3bSToby Isaac       PetscQuadrature  quad;
12290c37af3bSToby Isaac 
12309566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
12319566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &qPoints, &p, &w));
12329566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(weights + Nc * offset, w, Nc * qPoints));
12339566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pointsRef + spdim * offset, p, spdim * qPoints));
1234b3a4bf2aSToby Isaac       sizes[i] = qPoints;
12350c37af3bSToby Isaac       offset += qPoints;
12360c37af3bSToby Isaac     }
12379566063dSJacob Faibussowitsch     PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsRef, weights, work, Amat));
12389566063dSJacob Faibussowitsch     PetscCall(MatLUFactor(Amat, NULL, NULL, NULL));
12390c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
12400c37af3bSToby Isaac       PetscInt  parent;
12410c37af3bSToby Isaac       PetscInt  closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
12420c37af3bSToby Isaac       PetscInt *childOffsets, *parentOffsets;
12430c37af3bSToby Isaac 
12449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, c, &parent, NULL));
12450c37af3bSToby Isaac       if (parent == c) continue;
12469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12470c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12480c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12490c37af3bSToby Isaac         PetscInt conDof;
12500c37af3bSToby Isaac 
12510c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1252085f0adfSToby Isaac         if (numFields) {
12539566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
12549371c9d4SSatish Balay         } else {
12559566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
12560c37af3bSToby Isaac         }
12570c37af3bSToby Isaac         if (conDof) break;
12580c37af3bSToby Isaac       }
12590c37af3bSToby Isaac       if (i == closureSize) {
12609566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12610c37af3bSToby Isaac         continue;
12620c37af3bSToby Isaac       }
12630c37af3bSToby Isaac 
12649566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ));
12659566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent));
12660c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1267c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
1268c330f8ffSToby Isaac 
1269c330f8ffSToby Isaac         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i * spdim], vtmp);
1270c330f8ffSToby Isaac         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i * spdim]);
12710c37af3bSToby Isaac       }
12729566063dSJacob Faibussowitsch       PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsReal, weights, work, Bmat));
12739566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(Amat, Bmat, Xmat));
12749566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Xmat, &X));
12759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
12769566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(closureSize + 1, &childOffsets, closureSizeP + 1, &parentOffsets));
12770c37af3bSToby Isaac       childOffsets[0] = 0;
12780c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12790c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12800c37af3bSToby Isaac         PetscInt dof;
12810c37af3bSToby Isaac 
1282085f0adfSToby Isaac         if (numFields) {
12839566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12849371c9d4SSatish Balay         } else {
12859566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12860c37af3bSToby Isaac         }
128752a3aeb4SToby Isaac         childOffsets[i + 1] = childOffsets[i] + dof;
12880c37af3bSToby Isaac       }
12890c37af3bSToby Isaac       parentOffsets[0] = 0;
12900c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
12910c37af3bSToby Isaac         PetscInt p = closureP[2 * i];
12920c37af3bSToby Isaac         PetscInt dof;
12930c37af3bSToby Isaac 
1294085f0adfSToby Isaac         if (numFields) {
12959566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12969371c9d4SSatish Balay         } else {
12979566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12980c37af3bSToby Isaac         }
129952a3aeb4SToby Isaac         parentOffsets[i + 1] = parentOffsets[i] + dof;
13000c37af3bSToby Isaac       }
13010c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13022c44ad04SToby Isaac         PetscInt           conDof, conOff, aDof, aOff, nWork;
13030c37af3bSToby Isaac         PetscInt           p = closure[2 * i];
13040c37af3bSToby Isaac         PetscInt           o = closure[2 * i + 1];
1305085f0adfSToby Isaac         const PetscInt    *perm;
1306085f0adfSToby Isaac         const PetscScalar *flip;
13070c37af3bSToby Isaac 
13080c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1309085f0adfSToby Isaac         if (numFields) {
13109566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
13119566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &conOff));
13129371c9d4SSatish Balay         } else {
13139566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
13149566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(cSec, p, &conOff));
13150c37af3bSToby Isaac         }
13160c37af3bSToby Isaac         if (!conDof) continue;
1317085f0adfSToby Isaac         perm = (perms && perms[i]) ? perms[i][o] : NULL;
1318085f0adfSToby Isaac         flip = (flips && flips[i]) ? flips[i][o] : NULL;
13199566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
13209566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
13212c44ad04SToby Isaac         nWork = childOffsets[i + 1] - childOffsets[i];
13220c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
13230c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
13240c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
13250c37af3bSToby Isaac 
1326085f0adfSToby Isaac           if (numFields) {
13279566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aSecDof));
13289566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aSecOff));
13299371c9d4SSatish Balay           } else {
13309566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, a, &aSecDof));
13319566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, a, &aSecOff));
13320c37af3bSToby Isaac           }
13330c37af3bSToby Isaac           if (!aSecDof) continue;
13340c37af3bSToby Isaac 
13350c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
13360c37af3bSToby Isaac             PetscInt q  = closureP[2 * j];
13370c37af3bSToby Isaac             PetscInt oq = closureP[2 * j + 1];
13382c44ad04SToby Isaac 
13392c44ad04SToby Isaac             if (q == a) {
134052a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1341085f0adfSToby Isaac               const PetscInt    *permP;
1342085f0adfSToby Isaac               const PetscScalar *flipP;
1343085f0adfSToby Isaac 
1344085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1345085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
13462c44ad04SToby Isaac               nWorkP = parentOffsets[j + 1] - parentOffsets[j];
13472c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
13481683a169SBarry Smith                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
13492c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
13502c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
1351ad540459SPierre Jolivet                 for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
13522c44ad04SToby Isaac               }
1353ad540459SPierre Jolivet               for (r = 0; r < nWork; r++) workIndRow[perm ? perm[r] : r] = conOff + r;
1354ad540459SPierre Jolivet               for (s = 0; s < nWorkP; s++) workIndCol[permP ? permP[s] : s] = aSecOff + s;
13552c44ad04SToby Isaac               if (flip) {
13562c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1357ad540459SPierre Jolivet                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flip[r];
13582c44ad04SToby Isaac                 }
13592c44ad04SToby Isaac               }
13602c44ad04SToby Isaac               if (flipP) {
13612c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1362ad540459SPierre Jolivet                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flipP[s];
13632c44ad04SToby Isaac                 }
13642c44ad04SToby Isaac               }
13659566063dSJacob Faibussowitsch               PetscCall(MatSetValues(cMat, nWork, workIndRow, nWorkP, workIndCol, scwork, INSERT_VALUES));
13662c44ad04SToby Isaac               break;
13670c37af3bSToby Isaac             }
13680c37af3bSToby Isaac           }
13690c37af3bSToby Isaac         }
13700c37af3bSToby Isaac       }
13719566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Xmat, &X));
13729566063dSJacob Faibussowitsch       PetscCall(PetscFree2(childOffsets, parentOffsets));
13739566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
13749566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
13750c37af3bSToby Isaac     }
13769566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Amat));
13779566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Bmat));
13789566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Xmat));
13799566063dSJacob Faibussowitsch     PetscCall(PetscFree(scwork));
13809566063dSJacob Faibussowitsch     PetscCall(PetscFree7(sizes, weights, pointsRef, pointsReal, work, workIndRow, workIndCol));
138148a46eb9SPierre Jolivet     if (id == PETSCFV_CLASSID) PetscCall(PetscSpaceDestroy(&bspace));
13820c37af3bSToby Isaac   }
13839566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
13849566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
13859566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJparent));
13869566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
13873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13880c37af3bSToby Isaac }
138995a0b26dSToby Isaac 
1390d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1391d71ae5a4SJacob Faibussowitsch {
1392f7c74593SToby Isaac   Mat                 refCmat;
139321968bf8SToby Isaac   PetscDS             ds;
1394085f0adfSToby Isaac   PetscInt            numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
139521968bf8SToby Isaac   PetscScalar      ***refPointFieldMats;
139621968bf8SToby Isaac   PetscSection        refConSec, refAnSec, refSection;
139721968bf8SToby Isaac   IS                  refAnIS;
139821968bf8SToby Isaac   const PetscInt     *refAnchors;
1399085f0adfSToby Isaac   const PetscInt    **perms;
1400085f0adfSToby Isaac   const PetscScalar **flips;
140195a0b26dSToby Isaac 
140295a0b26dSToby Isaac   PetscFunctionBegin;
14039566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
14049566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1405085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
14069566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
14079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
14089566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(refAnIS, &refAnchors));
14099566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
14109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
14119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
14129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldN));
14139566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
14149566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
14159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
14169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxAnDof, &cols));
141795a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
141895a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
141995a0b26dSToby Isaac 
14209566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
14219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
142295a0b26dSToby Isaac     if (!pDof || parent == p) continue;
142395a0b26dSToby Isaac 
14249566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxFields, &refPointFieldMats[p - pRefStart]));
14259566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(maxFields, &refPointFieldN[p - pRefStart]));
14269566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
1427085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1428085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
142995a0b26dSToby Isaac 
1430085f0adfSToby Isaac       if (f < numFields) {
14319566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
14329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
14339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1434085f0adfSToby Isaac       } else {
14359566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
14369566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
14379566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetPointSyms(refSection, closureSize, closure, &perms, &flips));
143895a0b26dSToby Isaac       }
143995a0b26dSToby Isaac 
1440ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
144195a0b26dSToby Isaac       numCols = 0;
144295a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
144395a0b26dSToby Isaac         PetscInt        q = closure[2 * i];
144495a0b26dSToby Isaac         PetscInt        aDof, aOff, j;
1445085f0adfSToby Isaac         const PetscInt *perm = perms ? perms[i] : NULL;
144695a0b26dSToby Isaac 
1447085f0adfSToby Isaac         if (numFields) {
14489566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14499566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14509371c9d4SSatish Balay         } else {
14519566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14529566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
145395a0b26dSToby Isaac         }
145495a0b26dSToby Isaac 
1455ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + (perm ? perm[j] : j);
145695a0b26dSToby Isaac       }
145795a0b26dSToby Isaac       refPointFieldN[p - pRefStart][f] = numCols;
14589566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
14599566063dSJacob Faibussowitsch       PetscCall(MatGetValues(refCmat, cDof, rows, numCols, cols, refPointFieldMats[p - pRefStart][f]));
1460085f0adfSToby Isaac       if (flips) {
1461085f0adfSToby Isaac         PetscInt colOff = 0;
1462085f0adfSToby Isaac 
1463085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1464085f0adfSToby Isaac           PetscInt           q = closure[2 * i];
1465085f0adfSToby Isaac           PetscInt           aDof, aOff, j;
1466085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1467085f0adfSToby Isaac 
1468085f0adfSToby Isaac           if (numFields) {
14699566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14709566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14719371c9d4SSatish Balay           } else {
14729566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14739566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
1474085f0adfSToby Isaac           }
1475085f0adfSToby Isaac           if (flip) {
1476085f0adfSToby Isaac             PetscInt k;
1477085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1478ad540459SPierre Jolivet               for (j = 0; j < aDof; j++) refPointFieldMats[p - pRefStart][f][k * numCols + colOff + j] *= flip[j];
1479085f0adfSToby Isaac             }
1480085f0adfSToby Isaac           }
1481085f0adfSToby Isaac           colOff += aDof;
1482085f0adfSToby Isaac         }
1483085f0adfSToby Isaac       }
1484085f0adfSToby Isaac       if (numFields) {
14859566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestoreFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1486085f0adfSToby Isaac       } else {
14879566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestorePointSyms(refSection, closureSize, closure, &perms, &flips));
1488085f0adfSToby Isaac       }
148995a0b26dSToby Isaac     }
14909566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
149195a0b26dSToby Isaac   }
149221968bf8SToby Isaac   *childrenMats = refPointFieldMats;
149321968bf8SToby Isaac   *childrenN    = refPointFieldN;
14949566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(refAnIS, &refAnchors));
14959566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
14969566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
14973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
149821968bf8SToby Isaac }
149921968bf8SToby Isaac 
1500d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1501d71ae5a4SJacob Faibussowitsch {
150221968bf8SToby Isaac   PetscDS        ds;
150321968bf8SToby Isaac   PetscInt     **refPointFieldN;
150421968bf8SToby Isaac   PetscScalar ***refPointFieldMats;
1505085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
150621968bf8SToby Isaac   PetscSection   refConSec;
150721968bf8SToby Isaac 
150821968bf8SToby Isaac   PetscFunctionBegin;
150921968bf8SToby Isaac   refPointFieldN    = *childrenN;
151021968bf8SToby Isaac   *childrenN        = NULL;
151121968bf8SToby Isaac   refPointFieldMats = *childrenMats;
151221968bf8SToby Isaac   *childrenMats     = NULL;
15139566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
15149566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1515367003a6SStefano Zampini   maxFields = PetscMax(1, numFields);
15169566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
15179566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
151821968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
151921968bf8SToby Isaac     PetscInt parent, pDof;
152021968bf8SToby Isaac 
15219566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
15229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
152321968bf8SToby Isaac     if (!pDof || parent == p) continue;
152421968bf8SToby Isaac 
1525085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
152621968bf8SToby Isaac       PetscInt cDof;
152721968bf8SToby Isaac 
1528085f0adfSToby Isaac       if (numFields) {
15299566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
15309371c9d4SSatish Balay       } else {
15319566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
153221968bf8SToby Isaac       }
153321968bf8SToby Isaac 
15349566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
153521968bf8SToby Isaac     }
15369566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
15379566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldN[p - pRefStart]));
153821968bf8SToby Isaac   }
15399566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
15409566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldN));
15413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
154221968bf8SToby Isaac }
154321968bf8SToby Isaac 
1544d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
1545d71ae5a4SJacob Faibussowitsch {
154621968bf8SToby Isaac   DM              refTree;
154721968bf8SToby Isaac   PetscDS         ds;
154821968bf8SToby Isaac   Mat             refCmat;
1549085f0adfSToby Isaac   PetscInt        numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
155021968bf8SToby Isaac   PetscScalar  ***refPointFieldMats, *pointWork;
155121968bf8SToby Isaac   PetscSection    refConSec, refAnSec, anSec;
155221968bf8SToby Isaac   IS              refAnIS, anIS;
155321968bf8SToby Isaac   const PetscInt *anchors;
155421968bf8SToby Isaac 
155521968bf8SToby Isaac   PetscFunctionBegin;
155621968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
15579566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
15589566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1559085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
15609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
15619566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, refTree));
1562c77c71ffSToby Isaac   PetscCall(DMSetLocalSection(refTree, NULL));
1563c77c71ffSToby Isaac   PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
15649566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
15659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
15669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anSec, &anIS));
15679566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(anIS, &anchors));
15689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
15699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(conSec, &conStart, &conEnd));
15709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
15719566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
15729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof * maxAnDof, &pointWork));
157321968bf8SToby Isaac 
157421968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
15759566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
157695a0b26dSToby Isaac 
157795a0b26dSToby Isaac   /* step 2: compute the preorder */
15789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
15799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(pEnd - pStart, &perm, pEnd - pStart, &iperm));
158095a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
158195a0b26dSToby Isaac     perm[p - pStart]  = p;
158295a0b26dSToby Isaac     iperm[p - pStart] = p - pStart;
158395a0b26dSToby Isaac   }
158495a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
158595a0b26dSToby Isaac     PetscInt point = perm[p];
158695a0b26dSToby Isaac     PetscInt parent;
158795a0b26dSToby Isaac 
15889566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
158995a0b26dSToby Isaac     if (parent == point) {
159095a0b26dSToby Isaac       p++;
15919371c9d4SSatish Balay     } else {
159295a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
159395a0b26dSToby Isaac 
15949566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
159595a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
159695a0b26dSToby Isaac         PetscInt q = closure[2 * i];
159795a0b26dSToby Isaac         if (iperm[q - pStart] > iperm[point - pStart]) {
159895a0b26dSToby Isaac           /* swap */
159995a0b26dSToby Isaac           perm[p]                 = q;
160095a0b26dSToby Isaac           perm[iperm[q - pStart]] = point;
160195a0b26dSToby Isaac           iperm[point - pStart]   = iperm[q - pStart];
160295a0b26dSToby Isaac           iperm[q - pStart]       = p;
160395a0b26dSToby Isaac           break;
160495a0b26dSToby Isaac         }
160595a0b26dSToby Isaac       }
160695a0b26dSToby Isaac       size = closureSize;
16079566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1608ad540459SPierre Jolivet       if (i == size) p++;
160995a0b26dSToby Isaac     }
161095a0b26dSToby Isaac   }
161195a0b26dSToby Isaac 
161295a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
161395a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
161495a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
161595a0b26dSToby Isaac    * values outside of the Mat first.
161695a0b26dSToby Isaac    */
161795a0b26dSToby Isaac   {
161895a0b26dSToby Isaac     PetscInt        nRows, row, nnz;
161995a0b26dSToby Isaac     PetscBool       done;
1620cd6fc93eSToby Isaac     PetscInt        secStart, secEnd;
162195a0b26dSToby Isaac     const PetscInt *ia, *ja;
162295a0b26dSToby Isaac     PetscScalar    *vals;
162395a0b26dSToby Isaac 
1624cd6fc93eSToby Isaac     PetscCall(PetscSectionGetChart(section, &secStart, &secEnd));
16259566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
162628b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not get RowIJ of constraint matrix");
162795a0b26dSToby Isaac     nnz = ia[nRows];
162895a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
162995a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
16309566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vals));
163195a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
163295a0b26dSToby Isaac       PetscInt parent, childid, closureSize, *closure = NULL;
163395a0b26dSToby Isaac       PetscInt point = perm[p], pointDof;
163495a0b26dSToby Isaac 
16359566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, point, &parent, &childid));
163695a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
16379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(conSec, point, &pointDof));
163895a0b26dSToby Isaac       if (!pointDof) continue;
16399566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1640085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1641085f0adfSToby Isaac         PetscInt            cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
164295a0b26dSToby Isaac         PetscScalar        *pointMat;
1643085f0adfSToby Isaac         const PetscInt    **perms;
1644085f0adfSToby Isaac         const PetscScalar **flips;
164595a0b26dSToby Isaac 
1646085f0adfSToby Isaac         if (numFields) {
16479566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(conSec, point, f, &cDof));
16489566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(conSec, point, f, &cOff));
16499371c9d4SSatish Balay         } else {
16509566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(conSec, point, &cDof));
16519566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(conSec, point, &cOff));
165295a0b26dSToby Isaac         }
165395a0b26dSToby Isaac         if (!cDof) continue;
16549566063dSJacob Faibussowitsch         if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
16559566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetPointSyms(section, closureSize, closure, &perms, &flips));
165695a0b26dSToby Isaac 
165795a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
165876bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
165995a0b26dSToby Isaac           for (r = 0; r < cDof; r++) {
166095a0b26dSToby Isaac             if (cDof > 1 && r) {
166163a3b9bcSJacob 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]));
166295a0b26dSToby Isaac             }
166395a0b26dSToby Isaac           }
166476bd3646SJed Brown         }
166595a0b26dSToby Isaac         /* zero rows */
1666ad540459SPierre Jolivet         for (i = ia[cOff]; i < ia[cOff + cDof]; i++) vals[i] = 0.;
166795a0b26dSToby Isaac         matOffset   = ia[cOff];
166895a0b26dSToby Isaac         numFillCols = ia[cOff + 1] - matOffset;
166995a0b26dSToby Isaac         pointMat    = refPointFieldMats[childid - pRefStart][f];
167095a0b26dSToby Isaac         numCols     = refPointFieldN[childid - pRefStart][f];
167195a0b26dSToby Isaac         offset      = 0;
167295a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
167395a0b26dSToby Isaac           PetscInt           q = closure[2 * i];
167495a0b26dSToby Isaac           PetscInt           aDof, aOff, j, k, qConDof, qConOff;
1675085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1676085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
167795a0b26dSToby Isaac 
167895a0b26dSToby Isaac           qConDof = qConOff = 0;
1679cd6fc93eSToby Isaac           if (q < secStart || q >= secEnd) continue;
1680085f0adfSToby Isaac           if (numFields) {
16819566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, q, f, &aDof));
16829566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, q, f, &aOff));
168395a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16849566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(conSec, q, f, &qConDof));
16859566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldOffset(conSec, q, f, &qConOff));
168695a0b26dSToby Isaac             }
16879371c9d4SSatish Balay           } else {
16889566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, q, &aDof));
16899566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, q, &aOff));
169095a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16919566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(conSec, q, &qConDof));
16929566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(conSec, q, &qConOff));
169395a0b26dSToby Isaac             }
169495a0b26dSToby Isaac           }
169595a0b26dSToby Isaac           if (!aDof) continue;
169695a0b26dSToby Isaac           if (qConDof) {
169795a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
169895a0b26dSToby Isaac              * be filled, thanks to preordering */
169995a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
170095a0b26dSToby Isaac             PetscInt aMatOffset   = ia[qConOff];
170195a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
170295a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
170395a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
170495a0b26dSToby Isaac                 PetscScalar inVal = 0;
170595a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1706085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
170795a0b26dSToby Isaac 
1708085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
170995a0b26dSToby Isaac                 }
171095a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
171195a0b26dSToby Isaac               }
171295a0b26dSToby Isaac             }
171395a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
171495a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
171595a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
171695a0b26dSToby Isaac               for (; k < numFillCols; k++) {
1717ad540459SPierre Jolivet                 if (ja[matOffset + k] == col) break;
171895a0b26dSToby Isaac               }
171963a3b9bcSJacob Faibussowitsch               PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, col);
1720ad540459SPierre Jolivet               for (r = 0; r < cDof; r++) vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
172195a0b26dSToby Isaac             }
17229371c9d4SSatish Balay           } else {
172395a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
172495a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
1725ad540459SPierre Jolivet               if (ja[matOffset + k] == aOff) break;
172695a0b26dSToby Isaac             }
172763a3b9bcSJacob Faibussowitsch             PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, aOff);
172895a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1729085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1730085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1731085f0adfSToby Isaac 
1732085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
173395a0b26dSToby Isaac               }
173495a0b26dSToby Isaac             }
173595a0b26dSToby Isaac           }
173695a0b26dSToby Isaac           offset += aDof;
173795a0b26dSToby Isaac         }
1738085f0adfSToby Isaac         if (numFields) {
17399566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestoreFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
1740085f0adfSToby Isaac         } else {
17419566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestorePointSyms(section, closureSize, closure, &perms, &flips));
1742085f0adfSToby Isaac         }
174395a0b26dSToby Isaac       }
17449566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
174595a0b26dSToby Isaac     }
174648a46eb9SPierre 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));
17479566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
174828b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not restore RowIJ of constraint matrix");
17499566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
17509566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
17519566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
175295a0b26dSToby Isaac   }
175395a0b26dSToby Isaac 
175495a0b26dSToby Isaac   /* clean up */
17559566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(anIS, &anchors));
17569566063dSJacob Faibussowitsch   PetscCall(PetscFree2(perm, iperm));
17579566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointWork));
17589566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
17593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
176095a0b26dSToby Isaac }
176195a0b26dSToby Isaac 
17626f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
17636f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
1764d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTreeRefineCell(DM dm, PetscInt cell, DM *ncdm)
1765d71ae5a4SJacob Faibussowitsch {
17666f5f1567SToby Isaac   DM           K;
1767420f55faSMatthew G. Knepley   PetscMPIInt  rank;
17686f5f1567SToby Isaac   PetscInt     dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
17696f5f1567SToby Isaac   PetscInt     numNewCones, *newConeSizes, *newCones, *newOrientations;
17706f5f1567SToby Isaac   PetscInt    *Kembedding;
17716f5f1567SToby Isaac   PetscInt    *cellClosure = NULL, nc;
17726f5f1567SToby Isaac   PetscScalar *newVertexCoords;
17736f5f1567SToby Isaac   PetscInt     numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
17746f5f1567SToby Isaac   PetscSection parentSection;
17756f5f1567SToby Isaac 
17766f5f1567SToby Isaac   PetscFunctionBegin;
17779566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
17789566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
17799566063dSJacob Faibussowitsch   PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
17809566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ncdm, dim));
17816f5f1567SToby Isaac 
17829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
17839566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &parentSection));
17849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &K));
17856858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
1786dd400576SPatrick Sanan   if (rank == 0) {
17876f5f1567SToby Isaac     /* compute the new charts */
17889566063dSJacob Faibussowitsch     PetscCall(PetscMalloc5(dim + 1, &pNewCount, dim + 1, &pNewStart, dim + 1, &pNewEnd, dim + 1, &pOldStart, dim + 1, &pOldEnd));
17896f5f1567SToby Isaac     offset = 0;
17906f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
17916f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
17926f5f1567SToby Isaac 
17936f5f1567SToby Isaac       pNewStart[d] = offset;
17949566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, d, &pOldStart[d], &pOldEnd[d]));
17959566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
17966f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
17976f5f1567SToby Isaac       /* adding the new points */
17986f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
17996f5f1567SToby Isaac       if (!d) {
18006f5f1567SToby Isaac         /* removing the cell */
18016f5f1567SToby Isaac         pNewCount[d]--;
18026f5f1567SToby Isaac       }
18036f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18046f5f1567SToby Isaac         PetscInt parent;
18059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &parent, NULL));
18066f5f1567SToby Isaac         if (parent == k) {
18076f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
18086f5f1567SToby Isaac           pNewCount[d]--;
18096f5f1567SToby Isaac         }
18106f5f1567SToby Isaac       }
18116f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
18126f5f1567SToby Isaac       offset     = pNewEnd[d];
18136f5f1567SToby Isaac     }
18141dca8a05SBarry 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]);
18156f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
18169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
18176f5f1567SToby Isaac 
18189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pNewEnd[dim], &newConeSizes));
18196f5f1567SToby Isaac     {
1820b5a892a1SMatthew G. Knepley       DMPolytopeType pct, qct;
18216f5f1567SToby Isaac       PetscInt       kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
18226f5f1567SToby Isaac 
18239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetChart(K, &kStart, &kEnd));
18249566063dSJacob Faibussowitsch       PetscCall(PetscMalloc4(kEnd - kStart, &Kembedding, kEnd - kStart, &perm, kEnd - kStart, &iperm, kEnd - kStart, &preOrient));
18256f5f1567SToby Isaac 
18266f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18276f5f1567SToby Isaac         perm[k - kStart]      = k;
18286f5f1567SToby Isaac         iperm[k - kStart]     = k - kStart;
18296f5f1567SToby Isaac         preOrient[k - kStart] = 0;
18306f5f1567SToby Isaac       }
18316f5f1567SToby Isaac 
18329566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18336f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
18346f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2 * j + 1];
18356f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2 * j + 1];
18366f5f1567SToby Isaac         PetscInt p, q;
18376f5f1567SToby Isaac 
18386f5f1567SToby Isaac         p = closureK[2 * j];
18396f5f1567SToby Isaac         q = cellClosure[2 * j];
18409566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(K, p, &pct));
18419566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, q, &qct));
18426f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
1843ad540459SPierre Jolivet           if (q >= pOldStart[d] && q < pOldEnd[d]) Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
18446f5f1567SToby Isaac         }
1845b5a892a1SMatthew G. Knepley         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1846b5a892a1SMatthew G. Knepley         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
18476f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
18486f5f1567SToby Isaac           PetscInt        numChildren, i;
18496f5f1567SToby Isaac           const PetscInt *children;
18506f5f1567SToby Isaac 
18519566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(K, p, &numChildren, &children));
18526f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
18536f5f1567SToby Isaac             PetscInt kPerm, oPerm;
18546f5f1567SToby Isaac 
18556f5f1567SToby Isaac             k = children[i];
18569566063dSJacob Faibussowitsch             PetscCall(DMPlexReferenceTreeGetChildSymmetry(K, p, parentOrientA, 0, k, parentOrientB, &oPerm, &kPerm));
18576f5f1567SToby Isaac             /* perm = what refTree position I'm in */
18586f5f1567SToby Isaac             perm[kPerm - kStart] = k;
18596f5f1567SToby Isaac             /* iperm = who is at this position */
18606f5f1567SToby Isaac             iperm[k - kStart]         = kPerm - kStart;
18616f5f1567SToby Isaac             preOrient[kPerm - kStart] = oPerm;
18626f5f1567SToby Isaac           }
18636f5f1567SToby Isaac         }
18646f5f1567SToby Isaac       }
18659566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18666f5f1567SToby Isaac     }
18679566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, 0, pNewEnd[dim]));
18686f5f1567SToby Isaac     offset      = 0;
18696f5f1567SToby Isaac     numNewCones = 0;
18706f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18716f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
18726f5f1567SToby Isaac       PetscInt p;
18736f5f1567SToby Isaac       PetscInt size;
18746f5f1567SToby Isaac 
18756f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
18766f5f1567SToby Isaac         /* skip cell 0 */
18776f5f1567SToby Isaac         if (p == cell) continue;
18786f5f1567SToby Isaac         /* old cones to new cones */
18799566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
18806f5f1567SToby Isaac         newConeSizes[offset++] = size;
18816f5f1567SToby Isaac         numNewCones += size;
18826f5f1567SToby Isaac       }
18836f5f1567SToby Isaac 
18849566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
18856f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18866f5f1567SToby Isaac         PetscInt kParent;
18876f5f1567SToby Isaac 
18889566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
18896f5f1567SToby Isaac         if (kParent != k) {
18906f5f1567SToby Isaac           Kembedding[k] = offset;
18919566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
18926f5f1567SToby Isaac           newConeSizes[offset++] = size;
18936f5f1567SToby Isaac           numNewCones += size;
189448a46eb9SPierre Jolivet           if (kParent != 0) PetscCall(PetscSectionSetDof(parentSection, Kembedding[k], 1));
18956f5f1567SToby Isaac         }
18966f5f1567SToby Isaac       }
18976f5f1567SToby Isaac     }
18986f5f1567SToby Isaac 
18999566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
19009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(parentSection, &numPointsWithParents));
19019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numNewCones, &newCones, numNewCones, &newOrientations));
19029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPointsWithParents, &parents, numPointsWithParents, &childIDs));
19036f5f1567SToby Isaac 
19046f5f1567SToby Isaac     /* fill new cones */
19056f5f1567SToby Isaac     offset = 0;
19066f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19076f5f1567SToby Isaac       PetscInt        kStart, kEnd, k, l;
19086f5f1567SToby Isaac       PetscInt        p;
19096f5f1567SToby Isaac       PetscInt        size;
19106f5f1567SToby Isaac       const PetscInt *cone, *orientation;
19116f5f1567SToby Isaac 
19126f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19136f5f1567SToby Isaac         /* skip cell 0 */
19146f5f1567SToby Isaac         if (p == cell) continue;
19156f5f1567SToby Isaac         /* old cones to new cones */
19169566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
19179566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
19189566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeOrientation(dm, p, &orientation));
19196f5f1567SToby Isaac         for (l = 0; l < size; l++) {
19206f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
19216f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
19226f5f1567SToby Isaac         }
19236f5f1567SToby Isaac       }
19246f5f1567SToby Isaac 
19259566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
19266f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19276f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
19286f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
19296f5f1567SToby Isaac 
19309566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
19316f5f1567SToby Isaac         if (kParent != k) {
19326f5f1567SToby Isaac           /* embed new cones */
19339566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
19349566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(K, kPerm, &cone));
19359566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeOrientation(K, kPerm, &orientation));
19366f5f1567SToby Isaac           for (l = 0; l < size; l++) {
19376f5f1567SToby Isaac             PetscInt       q, m = (preO >= 0) ? ((preO + l) % size) : ((size - (preO + 1) - l) % size);
19386f5f1567SToby Isaac             PetscInt       newO, lSize, oTrue;
1939b5a892a1SMatthew G. Knepley             DMPolytopeType ct = DM_NUM_POLYTOPES;
19406f5f1567SToby Isaac 
19416f5f1567SToby Isaac             q                = iperm[cone[m]];
19426f5f1567SToby Isaac             newCones[offset] = Kembedding[q];
19439566063dSJacob Faibussowitsch             PetscCall(DMPlexGetConeSize(K, q, &lSize));
1944b5a892a1SMatthew G. Knepley             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
1945b5a892a1SMatthew G. Knepley             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
1946b5a892a1SMatthew G. Knepley             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
19476f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
19486f5f1567SToby Isaac             newO                      = DihedralCompose(lSize, oTrue, preOrient[q]);
1949b5a892a1SMatthew G. Knepley             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
19506f5f1567SToby Isaac           }
19516f5f1567SToby Isaac           if (kParent != 0) {
19526f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
19539566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(parentSection, Kembedding[k], &pOffset));
19546f5f1567SToby Isaac             parents[pOffset]  = newPoint;
19556f5f1567SToby Isaac             childIDs[pOffset] = k;
19566f5f1567SToby Isaac           }
19576f5f1567SToby Isaac         }
19586f5f1567SToby Isaac       }
19596f5f1567SToby Isaac     }
19606f5f1567SToby Isaac 
19619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(dim * (pNewEnd[dim] - pNewStart[dim]), &newVertexCoords));
19626f5f1567SToby Isaac 
19636f5f1567SToby Isaac     /* fill coordinates */
19646f5f1567SToby Isaac     offset = 0;
19656f5f1567SToby Isaac     {
1966d90620a3SMatthew G. Knepley       PetscInt     kStart, kEnd, l;
19676f5f1567SToby Isaac       PetscSection vSection;
19686f5f1567SToby Isaac       PetscInt     v;
19696f5f1567SToby Isaac       Vec          coords;
19706f5f1567SToby Isaac       PetscScalar *coordvals;
19716f5f1567SToby Isaac       PetscInt     dof, off;
1972c111c6b7SMatthew G. Knepley       PetscReal    v0[3], J[9], detJ;
19736f5f1567SToby Isaac 
197476bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
1975d90620a3SMatthew G. Knepley         PetscInt k;
19769566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(K, 0, &kStart, &kEnd));
19776f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
19789566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
197963a3b9bcSJacob Faibussowitsch           PetscCheck(detJ > 0., PETSC_COMM_SELF, PETSC_ERR_PLIB, "reference tree cell %" PetscInt_FMT " has bad determinant", k);
19806f5f1567SToby Isaac         }
1981d90620a3SMatthew G. Knepley       }
19829566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
19839566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &vSection));
19849566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coords));
19859566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19866f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
19879566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(vSection, v, &dof));
19889566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(vSection, v, &off));
1989ad540459SPierre Jolivet         for (l = 0; l < dof; l++) newVertexCoords[offset++] = coordvals[off + l];
19906f5f1567SToby Isaac       }
19919566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
19926f5f1567SToby Isaac 
19939566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(K, &vSection));
19949566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(K, &coords));
19959566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19969566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(K, 0, &kStart, &kEnd));
19976f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
19989bc368c7SMatthew G. Knepley         PetscReal       coord[3], newCoord[3];
19996f5f1567SToby Isaac         PetscInt        vPerm = perm[v];
20006f5f1567SToby Isaac         PetscInt        kParent;
2001c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
20026f5f1567SToby Isaac 
20039566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, v, &kParent, NULL));
20046f5f1567SToby Isaac         if (kParent != v) {
20056f5f1567SToby Isaac           /* this is a new vertex */
20069566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(vSection, vPerm, &off));
20079bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off + l]);
2008367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
20099bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset + l] = newCoord[l];
20106f5f1567SToby Isaac           offset += dim;
20116f5f1567SToby Isaac         }
20126f5f1567SToby Isaac       }
20139566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
20146f5f1567SToby Isaac     }
20156f5f1567SToby Isaac 
20166f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
20176f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
20186f5f1567SToby Isaac       PetscInt tmp;
20196f5f1567SToby Isaac 
20206f5f1567SToby Isaac       tmp                = pNewCount[d];
20216f5f1567SToby Isaac       pNewCount[d]       = pNewCount[dim - d];
20226f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
20236f5f1567SToby Isaac     }
20246f5f1567SToby Isaac 
20259566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, pNewCount, newConeSizes, newCones, newOrientations, newVertexCoords));
20269566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20279566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, parents, childIDs));
20286f5f1567SToby Isaac 
20296f5f1567SToby Isaac     /* clean up */
20309566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
20319566063dSJacob Faibussowitsch     PetscCall(PetscFree5(pNewCount, pNewStart, pNewEnd, pOldStart, pOldEnd));
20329566063dSJacob Faibussowitsch     PetscCall(PetscFree(newConeSizes));
20339566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCones, newOrientations));
20349566063dSJacob Faibussowitsch     PetscCall(PetscFree(newVertexCoords));
20359566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parents, childIDs));
20369566063dSJacob Faibussowitsch     PetscCall(PetscFree4(Kembedding, perm, iperm, preOrient));
20379371c9d4SSatish Balay   } else {
20386f5f1567SToby Isaac     PetscInt     p, counts[4];
20396f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
20406f5f1567SToby Isaac     Vec          coordVec;
20416f5f1567SToby Isaac     PetscScalar *coords;
20426f5f1567SToby Isaac 
20436f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20446f5f1567SToby Isaac       PetscInt dStart, dEnd;
20456f5f1567SToby Isaac 
20469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
20476f5f1567SToby Isaac       counts[d] = dEnd - dStart;
20486f5f1567SToby Isaac     }
20499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEnd - pStart, &coneSizes));
205048a46eb9SPierre Jolivet     for (p = pStart; p < pEnd; p++) PetscCall(DMPlexGetConeSize(dm, p, &coneSizes[p - pStart]));
20519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCones(dm, &cones));
20529566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientations(dm, &orientations));
20539566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordVec));
20549566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordVec, &coords));
20556f5f1567SToby Isaac 
20569566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
20579566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
20589566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, counts, coneSizes, cones, orientations, NULL));
20599566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20609566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, NULL, NULL));
20619566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordVec, &coords));
20626f5f1567SToby Isaac   }
20639566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
20643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20656f5f1567SToby Isaac }
20666ecaa68aSToby Isaac 
2067d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
2068d71ae5a4SJacob Faibussowitsch {
20696ecaa68aSToby Isaac   PetscSF              coarseToFineEmbedded;
20706ecaa68aSToby Isaac   PetscSection         globalCoarse, globalFine;
20716ecaa68aSToby Isaac   PetscSection         localCoarse, localFine;
20726ecaa68aSToby Isaac   PetscSection         aSec, cSec;
20736ecaa68aSToby Isaac   PetscSection         rootIndicesSec, rootMatricesSec;
207446bdb399SToby Isaac   PetscSection         leafIndicesSec, leafMatricesSec;
207546bdb399SToby Isaac   PetscInt            *rootIndices, *leafIndices;
207646bdb399SToby Isaac   PetscScalar         *rootMatrices, *leafMatrices;
20776ecaa68aSToby Isaac   IS                   aIS;
20786ecaa68aSToby Isaac   const PetscInt      *anchors;
20796ecaa68aSToby Isaac   Mat                  cMat;
20804acb8e1eSToby Isaac   PetscInt             numFields, maxFields;
20816ecaa68aSToby Isaac   PetscInt             pStartC, pEndC, pStartF, pEndF, p;
20826ecaa68aSToby Isaac   PetscInt             aStart, aEnd, cStart, cEnd;
20831c58ffc4SToby Isaac   PetscInt            *maxChildIds;
2084e44e4e7fSToby Isaac   PetscInt            *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
20854acb8e1eSToby Isaac   const PetscInt    ***perms;
20864acb8e1eSToby Isaac   const PetscScalar ***flips;
20876ecaa68aSToby Isaac 
20886ecaa68aSToby Isaac   PetscFunctionBegin;
20899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
20909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
20919566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
20926ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
209389698031SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
209489698031SToby Isaac     const PetscInt *leaves;
20956ecaa68aSToby Isaac 
20969566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
209789698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
209889698031SToby Isaac       p = leaves ? leaves[l] : l;
20999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
21009566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2101ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
21026ecaa68aSToby Isaac     }
21039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
21047cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
210589698031SToby Isaac       p = leaves ? leaves[l] : l;
21069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
21079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2108ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
21096ecaa68aSToby Isaac     }
21109566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
21119566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
21126ecaa68aSToby Isaac   }
21136ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
21149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
2115ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
211657168dbeSPierre Jolivet   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211757168dbeSPierre Jolivet   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211846bdb399SToby Isaac 
21199566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
21209566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
212146bdb399SToby Isaac 
21229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
21239566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
21249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
212546bdb399SToby Isaac 
21269566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
21279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
212846bdb399SToby Isaac 
212946bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
21309566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
21319566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootMatricesSec));
21329566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootIndicesSec, pStartC, pEndC));
21339566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootMatricesSec, pStartC, pEndC));
21349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
2135713c1c5dSToby Isaac   maxFields = PetscMax(1, numFields);
21369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc7(maxFields + 1, &offsets, maxFields + 1, &offsetsCopy, maxFields + 1, &newOffsets, maxFields + 1, &newOffsetsCopy, maxFields + 1, &rowOffsets, maxFields + 1, &numD, maxFields + 1, &numO));
21379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxFields + 1, (PetscInt ****)&perms, maxFields + 1, (PetscScalar ****)&flips));
21389566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)perms, (maxFields + 1) * sizeof(const PetscInt **)));
21399566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)flips, (maxFields + 1) * sizeof(const PetscScalar **)));
214046bdb399SToby Isaac 
214146bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
21428d2f55e7SToby Isaac     PetscInt dof, matSize = 0;
21436ecaa68aSToby Isaac     PetscInt aDof          = 0;
21446ecaa68aSToby Isaac     PetscInt cDof          = 0;
21456ecaa68aSToby Isaac     PetscInt maxChildId    = maxChildIds[p - pStartC];
21466ecaa68aSToby Isaac     PetscInt numRowIndices = 0;
21476ecaa68aSToby Isaac     PetscInt numColIndices = 0;
2148f13f9184SToby Isaac     PetscInt f;
21496ecaa68aSToby Isaac 
21509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2151ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
215248a46eb9SPierre Jolivet     if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof));
215348a46eb9SPierre Jolivet     if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(cSec, p, &cDof));
2154f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2155f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
21566ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2157f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
21586ecaa68aSToby Isaac 
21599566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
216046bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
21616ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
21626ecaa68aSToby Isaac 
21639566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
21646ecaa68aSToby Isaac         numRowIndices += clDof;
21656ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21669566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &clDof));
21676ecaa68aSToby Isaac           offsets[f + 1] += clDof;
21686ecaa68aSToby Isaac         }
21696ecaa68aSToby Isaac       }
21706ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
21716ecaa68aSToby Isaac         offsets[f + 1] += offsets[f];
21726ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
21736ecaa68aSToby Isaac       }
217446bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
21759566063dSJacob Faibussowitsch       PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, NULL, NULL, NULL, &numColIndices, NULL, NULL, newOffsets, PETSC_FALSE));
21769566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
21776ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
21786ecaa68aSToby Isaac         numColIndices = numRowIndices;
21796ecaa68aSToby Isaac         matSize       = 0;
21809371c9d4SSatish Balay       } else if (numFields) { /* we send one submat for each field: sum their sizes */
21816ecaa68aSToby Isaac         matSize = 0;
21826ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21836ecaa68aSToby Isaac           PetscInt numRow, numCol;
21846ecaa68aSToby Isaac 
21856ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2186f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
21876ecaa68aSToby Isaac           matSize += numRow * numCol;
21886ecaa68aSToby Isaac         }
21899371c9d4SSatish Balay       } else {
21906ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
21916ecaa68aSToby Isaac       }
2192f13f9184SToby Isaac     } else if (maxChildId == -1) {
21938d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2194f13f9184SToby Isaac         PetscInt aOff, a;
21956ecaa68aSToby Isaac 
21969566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
21976ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21986ecaa68aSToby Isaac           PetscInt fDof;
21996ecaa68aSToby Isaac 
22009566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
220121968bf8SToby Isaac           offsets[f + 1] = fDof;
22026ecaa68aSToby Isaac         }
22036ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
22046ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
22056ecaa68aSToby Isaac 
22069566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(localCoarse, anchor, &aLocalDof));
22076ecaa68aSToby Isaac           numColIndices += aLocalDof;
22086ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
22096ecaa68aSToby Isaac             PetscInt fDof;
22106ecaa68aSToby Isaac 
22119566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
221221968bf8SToby Isaac             newOffsets[f + 1] += fDof;
22136ecaa68aSToby Isaac           }
22146ecaa68aSToby Isaac         }
22156ecaa68aSToby Isaac         if (numFields) {
22166ecaa68aSToby Isaac           matSize = 0;
2217ad540459SPierre Jolivet           for (f = 0; f < numFields; f++) matSize += offsets[f + 1] * newOffsets[f + 1];
22189371c9d4SSatish Balay         } else {
22196ecaa68aSToby Isaac           matSize = numColIndices * dof;
22206ecaa68aSToby Isaac         }
22219371c9d4SSatish Balay       } else { /* no children, and no constraints on dofs: just get the global indices */
22226ecaa68aSToby Isaac         numColIndices = dof;
22236ecaa68aSToby Isaac         matSize       = 0;
22246ecaa68aSToby Isaac       }
22258d2f55e7SToby Isaac     }
222646bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
22279566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootIndicesSec, p, numColIndices ? numColIndices + 2 * numFields : 0));
22289566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootMatricesSec, p, matSize));
22296ecaa68aSToby Isaac   }
22309566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootIndicesSec));
22319566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootMatricesSec));
22326ecaa68aSToby Isaac   {
22336ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
22346ecaa68aSToby Isaac 
22359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
22369566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootMatricesSec, &numRootMatrices));
22379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numRootIndices, &rootIndices, numRootMatrices, &rootMatrices));
22386ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
22397853b79dSToby Isaac       PetscInt     numRowIndices = 0, numColIndices, matSize, dof;
2240f13f9184SToby Isaac       PetscInt     pIndOff, pMatOff, f;
22416ecaa68aSToby Isaac       PetscInt    *pInd;
22426ecaa68aSToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
22436ecaa68aSToby Isaac       PetscScalar *pMat       = NULL;
22446ecaa68aSToby Isaac 
22459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, p, &numColIndices));
2246ad540459SPierre Jolivet       if (!numColIndices) continue;
2247f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2248f13f9184SToby Isaac         offsets[f]        = 0;
2249f13f9184SToby Isaac         newOffsets[f]     = 0;
2250f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2251f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2252f13f9184SToby Isaac       }
22536ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
22549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, p, &pIndOff));
2255f4f49eeaSPierre Jolivet       pInd = &rootIndices[pIndOff];
22569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootMatricesSec, p, &matSize));
22576ecaa68aSToby Isaac       if (matSize) {
22589566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootMatricesSec, p, &pMatOff));
22596ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
22606ecaa68aSToby Isaac       }
22619566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2262ad540459SPierre Jolivet       if (dof < 0) dof = -(dof + 1);
22636ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
22646ecaa68aSToby Isaac         PetscInt i, j;
22656ecaa68aSToby Isaac 
22667853b79dSToby Isaac         if (matSize == 0) { /* don't need to calculate the mat, just the indices */
22676ecaa68aSToby Isaac           PetscInt numIndices, *indices;
22689566063dSJacob Faibussowitsch           PetscCall(DMPlexGetClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
226908401ef6SPierre Jolivet           PetscCheck(numIndices == numColIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "mismatching constraint indices calculations");
2270ad540459SPierre Jolivet           for (i = 0; i < numColIndices; i++) pInd[i] = indices[i];
22716ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
227246bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i + 1];
227346bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i + 1];
22746ecaa68aSToby Isaac           }
22759566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
22769371c9d4SSatish Balay         } else {
22776ecaa68aSToby Isaac           PetscInt     closureSize, *closure = NULL, cl;
22786ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
22796ecaa68aSToby Isaac           PetscInt     numPoints, *points;
22806ecaa68aSToby Isaac 
22817853b79dSToby Isaac           {
22827853b79dSToby Isaac             PetscInt *closure = NULL, closureSize, cl;
22837853b79dSToby Isaac 
22847853b79dSToby Isaac             PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22857853b79dSToby Isaac             for (cl = 0; cl < closureSize; cl++) { /* get the closure */
22867853b79dSToby Isaac               PetscInt c = closure[2 * cl], clDof;
22877853b79dSToby Isaac 
22887853b79dSToby Isaac               PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
22897853b79dSToby Isaac               numRowIndices += clDof;
22907853b79dSToby Isaac             }
22917853b79dSToby Isaac             PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22927853b79dSToby Isaac           }
22937853b79dSToby Isaac 
22949566063dSJacob Faibussowitsch           PetscCall(DMGetWorkArray(coarse, numRowIndices * numRowIndices, MPIU_SCALAR, &pMatIn));
22956ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
2296ad540459SPierre Jolivet             for (j = 0; j < numRowIndices; j++) pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
22976ecaa68aSToby Isaac           }
22989566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22994acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23009566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
23019566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
23024acb8e1eSToby Isaac           }
23036ecaa68aSToby Isaac           if (numFields) {
23046ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
23056ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
23066ecaa68aSToby Isaac 
23076ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
23086ecaa68aSToby Isaac                 PetscInt fDof;
23096ecaa68aSToby Isaac 
23109566063dSJacob Faibussowitsch                 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &fDof));
23116ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
23126ecaa68aSToby Isaac               }
23136ecaa68aSToby Isaac             }
23146ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
23156ecaa68aSToby Isaac               offsets[f + 1] += offsets[f];
23166ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
23176ecaa68aSToby Isaac             }
23186ecaa68aSToby Isaac           }
23194acb8e1eSToby Isaac           /* TODO : flips here ? */
23206ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
23219566063dSJacob Faibussowitsch           PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, perms, pMatIn, &numPoints, NULL, &points, &pMatModified, newOffsets, PETSC_FALSE));
23224acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23239566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
23249566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
23254acb8e1eSToby Isaac           }
23264acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23279566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23289566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23294acb8e1eSToby Isaac           }
23306ecaa68aSToby Isaac           if (!numFields) {
2331ad540459SPierre Jolivet             for (i = 0; i < numRowIndices * numColIndices; i++) pMat[i] = pMatModified[i];
23329371c9d4SSatish Balay           } else {
2333f13f9184SToby Isaac             PetscInt i, j, count;
23346ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
23356ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f + 1]; i++) {
2336ad540459SPierre Jolivet                 for (j = newOffsets[f]; j < newOffsets[f + 1]; j++, count++) pMat[count] = pMatModified[i * numColIndices + j];
23376ecaa68aSToby Isaac               }
23386ecaa68aSToby Isaac             }
23396ecaa68aSToby Isaac           }
23409566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatModified));
23419566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
23429566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatIn));
23436ecaa68aSToby Isaac           if (numFields) {
234446bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
234546bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f + 1];
234646bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f + 1];
23476ecaa68aSToby Isaac             }
23484acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23494acb8e1eSToby Isaac               PetscInt globalOff, c = points[2 * cl];
23509566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23519566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
23526ecaa68aSToby Isaac             }
23536ecaa68aSToby Isaac           } else {
23544acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23554acb8e1eSToby Isaac               PetscInt        c    = points[2 * cl], globalOff;
23564acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
23574acb8e1eSToby Isaac 
23589566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23599566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
23606ecaa68aSToby Isaac             }
23616ecaa68aSToby Isaac           }
23624acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23639566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23649566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23654acb8e1eSToby Isaac           }
23669566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numPoints, MPIU_SCALAR, &points));
23676ecaa68aSToby Isaac         }
23689371c9d4SSatish Balay       } else if (matSize) {
23696ecaa68aSToby Isaac         PetscInt  cOff;
23707853b79dSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof = 0, aOff;
23716ecaa68aSToby Isaac 
23727853b79dSToby Isaac         numRowIndices = dof;
23739566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
23749566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
23759566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, p, &cOff));
23769566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
23779566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
23786ecaa68aSToby Isaac         if (numFields) {
23796ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23806ecaa68aSToby Isaac             PetscInt fDof;
2381f13f9184SToby Isaac 
23829566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSec, p, f, &fDof));
23836ecaa68aSToby Isaac             offsets[f + 1] = fDof;
23846ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
23856ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
23869566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
23876ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
23886ecaa68aSToby Isaac             }
23896ecaa68aSToby Isaac           }
23906ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23916ecaa68aSToby Isaac             offsets[f + 1] += offsets[f];
23926ecaa68aSToby Isaac             offsetsCopy[f + 1] = offsets[f + 1];
23936ecaa68aSToby Isaac             newOffsets[f + 1] += newOffsets[f];
23946ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
23956ecaa68aSToby Isaac           }
23969566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, -1, NULL, rowIndices));
23976ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23986ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23999566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
24009566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, -1, NULL, colIndices));
24016ecaa68aSToby Isaac           }
24029371c9d4SSatish Balay         } else {
24039566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, NULL, rowIndices));
24046ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24056ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
24069566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
24079566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, NULL, colIndices));
24086ecaa68aSToby Isaac           }
24096ecaa68aSToby Isaac         }
24106ecaa68aSToby Isaac         if (numFields) {
2411f13f9184SToby Isaac           PetscInt count, a;
2412f13f9184SToby Isaac 
24136ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
24146ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
24156ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
24169566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat, iSize, &rowIndices[offsets[f]], jSize, &colIndices[newOffsets[f]], &pMat[count]));
24176ecaa68aSToby Isaac             count += iSize * jSize;
241846bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
241946bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f + 1];
24206ecaa68aSToby Isaac           }
24216ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24226ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24236ecaa68aSToby Isaac             PetscInt gOff;
24249566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24259566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, -1, NULL, pInd));
24266ecaa68aSToby Isaac           }
24279371c9d4SSatish Balay         } else {
24286ecaa68aSToby Isaac           PetscInt a;
24299566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat, numRowIndices, rowIndices, numColIndices, colIndices, pMat));
24306ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24316ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24326ecaa68aSToby Isaac             PetscInt gOff;
24339566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24349566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, NULL, pInd));
24356ecaa68aSToby Isaac           }
24366ecaa68aSToby Isaac         }
24379566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
24389566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
24399371c9d4SSatish Balay       } else {
24406ecaa68aSToby Isaac         PetscInt gOff;
24416ecaa68aSToby Isaac 
24429566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
24436ecaa68aSToby Isaac         if (numFields) {
24446ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
24456ecaa68aSToby Isaac             PetscInt fDof;
24469566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
24476ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
24486ecaa68aSToby Isaac           }
24496ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
245046bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
245146bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f + 1];
24526ecaa68aSToby Isaac           }
24539566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2454367003a6SStefano Zampini         } else {
24559566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
24566ecaa68aSToby Isaac         }
24576ecaa68aSToby Isaac       }
24586ecaa68aSToby Isaac     }
24599566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
24606ecaa68aSToby Isaac   }
246146bdb399SToby Isaac   {
246246bdb399SToby Isaac     PetscSF   indicesSF, matricesSF;
246346bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
246446bdb399SToby Isaac 
24659566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
24669566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafMatricesSec));
24679566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootIndicesSec, &remoteOffsetsIndices, leafIndicesSec));
24689566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootMatricesSec, &remoteOffsetsMatrices, leafMatricesSec));
24699566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootIndicesSec, remoteOffsetsIndices, leafIndicesSec, &indicesSF));
24709566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootMatricesSec, remoteOffsetsMatrices, leafMatricesSec, &matricesSF));
24719566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
24729566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsIndices));
24739566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsMatrices));
24749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numLeafIndices));
24759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafMatricesSec, &numLeafMatrices));
24769566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numLeafIndices, &leafIndices, numLeafMatrices, &leafMatrices));
24779566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24789566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24799566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24809566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24819566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&matricesSF));
24829566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
24839566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rootIndices, rootMatrices));
24849566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootIndicesSec));
24859566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootMatricesSec));
248646bdb399SToby Isaac   }
248746bdb399SToby Isaac   /* count to preallocate */
24889566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
248946bdb399SToby Isaac   {
249046bdb399SToby Isaac     PetscInt       nGlobal;
249146bdb399SToby Isaac     PetscInt      *dnnz, *onnz;
2492b9a5774bSToby Isaac     PetscLayout    rowMap, colMap;
2493b9a5774bSToby Isaac     PetscInt       rowStart, rowEnd, colStart, colEnd;
24941c58ffc4SToby Isaac     PetscInt       maxDof;
24951c58ffc4SToby Isaac     PetscInt      *rowIndices;
24961c58ffc4SToby Isaac     DM             refTree;
24971c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
24981c58ffc4SToby Isaac     PetscScalar ***refPointFieldMats;
24991c58ffc4SToby Isaac     PetscSection   refConSec, refAnSec;
25000eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, maxConDof, maxColumns, leafStart, leafEnd;
25011c58ffc4SToby Isaac     PetscScalar   *pointWork;
250246bdb399SToby Isaac 
25039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine, &nGlobal));
25049566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nGlobal, &dnnz, nGlobal, &onnz));
25059566063dSJacob Faibussowitsch     PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
25069566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rowMap));
25079566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(colMap));
25089566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
25099566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
25109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
25119566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafIndicesSec, &leafStart, &leafEnd));
25129566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
25130eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
251446bdb399SToby Isaac       PetscInt gDof, gcDof, gOff;
251546bdb399SToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
251646bdb399SToby Isaac       PetscInt matSize;
251721968bf8SToby Isaac       PetscInt i;
251846bdb399SToby Isaac 
25199566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
25209566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2521ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
25229566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
252308401ef6SPierre Jolivet       PetscCheck(gOff >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I though having global dofs meant a non-negative offset");
25241dca8a05SBarry Smith       PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I thought the row map would constrain the global dofs");
25259566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
25269566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
252746bdb399SToby Isaac       numColIndices -= 2 * numFields;
252808401ef6SPierre Jolivet       PetscCheck(numColIndices > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "global fine dof with no dofs to interpolate from");
252946bdb399SToby Isaac       pInd              = &leafIndices[pIndOff];
253021968bf8SToby Isaac       offsets[0]        = 0;
253121968bf8SToby Isaac       offsetsCopy[0]    = 0;
253221968bf8SToby Isaac       newOffsets[0]     = 0;
253321968bf8SToby Isaac       newOffsetsCopy[0] = 0;
253446bdb399SToby Isaac       if (numFields) {
253521968bf8SToby Isaac         PetscInt f;
253646bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
253746bdb399SToby Isaac           PetscInt rowDof;
253846bdb399SToby Isaac 
25399566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
254021968bf8SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
254121968bf8SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
254221968bf8SToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
254321968bf8SToby Isaac           numD[f]            = 0;
254421968bf8SToby Isaac           numO[f]            = 0;
254546bdb399SToby Isaac         }
25469566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
254746bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
254821968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
254921968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
255046bdb399SToby Isaac 
255146bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
255246bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
255346bdb399SToby Isaac 
255446bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
255521968bf8SToby Isaac               numD[f]++;
25569371c9d4SSatish Balay             } else if (gInd >= 0) { /* negative means non-entry */
255721968bf8SToby Isaac               numO[f]++;
255846bdb399SToby Isaac             }
255946bdb399SToby Isaac           }
256046bdb399SToby Isaac         }
25619371c9d4SSatish Balay       } else {
25629566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
256321968bf8SToby Isaac         numD[0] = 0;
256421968bf8SToby Isaac         numO[0] = 0;
256546bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
256646bdb399SToby Isaac           PetscInt gInd = pInd[i];
256746bdb399SToby Isaac 
256846bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
256921968bf8SToby Isaac             numD[0]++;
25709371c9d4SSatish Balay           } else if (gInd >= 0) { /* negative means non-entry */
257121968bf8SToby Isaac             numO[0]++;
257246bdb399SToby Isaac           }
257346bdb399SToby Isaac         }
257446bdb399SToby Isaac       }
25759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
257646bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
257746bdb399SToby Isaac         PetscInt childId;
257846bdb399SToby Isaac 
257946bdb399SToby Isaac         childId = childIds[p - pStartF];
258021968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
258146bdb399SToby Isaac           if (numFields) {
2582b9a5774bSToby Isaac             PetscInt f;
2583b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
258421968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
258546bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
258621968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
258721968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
258846bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25891dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2590b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
25919371c9d4SSatish Balay                 } else if (gIndCoarse >= 0) { /* remote */
25921dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2593b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
25949371c9d4SSatish Balay                 } else { /* constrained */
259508401ef6SPierre Jolivet                   PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
259646bdb399SToby Isaac                 }
259746bdb399SToby Isaac               }
259846bdb399SToby Isaac             }
25999371c9d4SSatish Balay           } else {
2600b9a5774bSToby Isaac             PetscInt i;
2601b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
260246bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
260346bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
260446bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
26051dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2606b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
26079371c9d4SSatish Balay               } else if (gIndCoarse >= 0) { /* remote */
26081dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2609b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
26109371c9d4SSatish Balay               } else { /* constrained */
261108401ef6SPierre Jolivet                 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
261246bdb399SToby Isaac               }
261346bdb399SToby Isaac             }
261446bdb399SToby Isaac           }
26159371c9d4SSatish Balay         } else { /* interpolate from all */
261646bdb399SToby Isaac           if (numFields) {
2617b9a5774bSToby Isaac             PetscInt f;
2618b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
261921968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
262046bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
262121968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
262246bdb399SToby Isaac                 if (gIndFine >= 0) {
26231dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2624b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2625b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
262646bdb399SToby Isaac                 }
262746bdb399SToby Isaac               }
262846bdb399SToby Isaac             }
26299371c9d4SSatish Balay           } else {
2630b9a5774bSToby Isaac             PetscInt i;
2631b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
263246bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
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[0];
2636b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
263746bdb399SToby Isaac               }
263846bdb399SToby Isaac             }
263946bdb399SToby Isaac           }
264046bdb399SToby Isaac         }
26419371c9d4SSatish Balay       } else { /* interpolate from all */
264246bdb399SToby Isaac         if (numFields) {
2643b9a5774bSToby Isaac           PetscInt f;
2644b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
264521968bf8SToby Isaac             PetscInt numRows = offsets[f + 1] - offsets[f], row;
264646bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
264721968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
264846bdb399SToby Isaac               if (gIndFine >= 0) {
26491dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2650b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2651b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
265246bdb399SToby Isaac               }
265346bdb399SToby Isaac             }
265446bdb399SToby Isaac           }
26559371c9d4SSatish Balay         } else { /* every dof get a full row */
2656b9a5774bSToby Isaac           PetscInt i;
2657b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
265846bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
265946bdb399SToby Isaac             if (gIndFine >= 0) {
26601dca8a05SBarry Smith               PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2661b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2662b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
266346bdb399SToby Isaac             }
266446bdb399SToby Isaac           }
266546bdb399SToby Isaac         }
266646bdb399SToby Isaac       }
266746bdb399SToby Isaac     }
26689566063dSJacob Faibussowitsch     PetscCall(MatXAIJSetPreallocation(mat, 1, dnnz, onnz, NULL, NULL));
26699566063dSJacob Faibussowitsch     PetscCall(PetscFree2(dnnz, onnz));
267021968bf8SToby Isaac 
26719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
2672d3a532e9SStefano Zampini     PetscCall(DMCopyDisc(fine, refTree));
2673d3a532e9SStefano Zampini     PetscCall(DMSetLocalSection(refTree, NULL));
2674d3a532e9SStefano Zampini     PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
26759566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
26769566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
26779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
26789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
26799566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(refConSec, &maxConDof));
26809566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(leafIndicesSec, &maxColumns));
26819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxConDof * maxColumns, &pointWork));
26820eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2683e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2684e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2685e44e4e7fSToby Isaac       PetscInt matSize;
2686e44e4e7fSToby Isaac       PetscInt childId;
2687e44e4e7fSToby Isaac 
26889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
26899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2690ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
2691e44e4e7fSToby Isaac       childId = childIds[p - pStartF];
26929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
26939566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
26949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2695e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2696e44e4e7fSToby Isaac       pInd              = &leafIndices[pIndOff];
2697e44e4e7fSToby Isaac       offsets[0]        = 0;
2698e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2699e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2700e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2701e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2702e44e4e7fSToby Isaac       if (numFields) {
2703e44e4e7fSToby Isaac         PetscInt f;
2704e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2705e44e4e7fSToby Isaac           PetscInt rowDof;
2706e44e4e7fSToby Isaac 
27079566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2708e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2709e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2710e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2711e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2712e44e4e7fSToby Isaac         }
27139566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
27149371c9d4SSatish Balay       } else {
27159566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
27161c58ffc4SToby Isaac       }
27179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2718e44e4e7fSToby Isaac       if (!matSize) {      /* incoming matrix is identity */
2719e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2720e44e4e7fSToby Isaac           if (numFields) {
2721e44e4e7fSToby Isaac             PetscInt f;
2722e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2723e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
272448a46eb9SPierre Jolivet               for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[offsets[f] + row], pInd[newOffsets[f] + row], 1., INSERT_VALUES));
272521968bf8SToby Isaac             }
27269371c9d4SSatish Balay           } else {
2727e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
272848a46eb9SPierre Jolivet             for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[row], pInd[row], 1., INSERT_VALUES));
2729e44e4e7fSToby Isaac           }
27309371c9d4SSatish Balay         } else { /* interpolate from all */
2731e44e4e7fSToby Isaac           if (numFields) {
2732e44e4e7fSToby Isaac             PetscInt f;
2733e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2734e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f];
2735e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
27369566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], refPointFieldMats[childId - pRefStart][f], INSERT_VALUES));
2737e44e4e7fSToby Isaac             }
27389371c9d4SSatish Balay           } else {
27399566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, refPointFieldMats[childId - pRefStart][0], INSERT_VALUES));
2740e44e4e7fSToby Isaac           }
2741e44e4e7fSToby Isaac         }
27429371c9d4SSatish Balay       } else { /* interpolate from all */
2743e44e4e7fSToby Isaac         PetscInt     pMatOff;
2744e44e4e7fSToby Isaac         PetscScalar *pMat;
2745e44e4e7fSToby Isaac 
27469566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafMatricesSec, p, &pMatOff));
2747e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2748e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2749e44e4e7fSToby Isaac           if (numFields) {
2750e44e4e7fSToby Isaac             PetscInt f, count;
2751e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2752e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2753e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2754e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2755e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2756e44e4e7fSToby Isaac 
27579566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], inMat, INSERT_VALUES));
2758e44e4e7fSToby Isaac               count += numCols * numInRows;
2759e44e4e7fSToby Isaac             }
27609371c9d4SSatish Balay           } else {
27619566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, pMat, INSERT_VALUES));
2762e44e4e7fSToby Isaac           }
27639371c9d4SSatish Balay         } else { /* multiply the incoming matrix by the child interpolation */
2764e44e4e7fSToby Isaac           if (numFields) {
2765e44e4e7fSToby Isaac             PetscInt f, count;
2766e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2767e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2768e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2769e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2770e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2771e44e4e7fSToby Isaac               PetscInt     i, j, k;
277208401ef6SPierre Jolivet               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2773e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2774e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2775e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2776ad540459SPierre Jolivet                   for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2777e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2778e44e4e7fSToby Isaac                 }
2779e44e4e7fSToby Isaac               }
27809566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], pointWork, INSERT_VALUES));
2781e44e4e7fSToby Isaac               count += numCols * numInRows;
2782e44e4e7fSToby Isaac             }
27839371c9d4SSatish Balay           } else { /* every dof gets a full row */
2784e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2785e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2786e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2787e44e4e7fSToby Isaac             PetscInt i, j, k;
278808401ef6SPierre Jolivet             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2789e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2790e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2791e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2792ad540459SPierre Jolivet                 for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2793e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2794e44e4e7fSToby Isaac               }
2795e44e4e7fSToby Isaac             }
27969566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, numRows, rowIndices, numCols, pInd, pointWork, INSERT_VALUES));
2797e44e4e7fSToby Isaac           }
2798e44e4e7fSToby Isaac         }
2799e44e4e7fSToby Isaac       }
2800e44e4e7fSToby Isaac     }
28019566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
28029566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
28039566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointWork));
2804e44e4e7fSToby Isaac   }
28059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
28069566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
28079566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
28089566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafMatricesSec));
28099566063dSJacob Faibussowitsch   PetscCall(PetscFree2(leafIndices, leafMatrices));
28109566063dSJacob Faibussowitsch   PetscCall(PetscFree2(*(PetscInt ****)&perms, *(PetscScalar ****)&flips));
28119566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
28129566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
28133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28146ecaa68aSToby Isaac }
2815154bca37SToby Isaac 
28168d2f55e7SToby Isaac /*
28178d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
28188d2f55e7SToby Isaac  *
28198d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
28208d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
28218d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
28228d2f55e7SToby Isaac  *       a_{i,j} = 0;
28238d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
28248d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
28258d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
28268d2f55e7SToby Isaac  */
2827d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
2828d71ae5a4SJacob Faibussowitsch {
28298d2f55e7SToby Isaac   PetscDS      ds;
28308d2f55e7SToby Isaac   PetscSection section, cSection;
28318d2f55e7SToby Isaac   DMLabel      canonical, depth;
28328d2f55e7SToby Isaac   Mat          cMat, mat;
28338d2f55e7SToby Isaac   PetscInt    *nnz;
28348d2f55e7SToby Isaac   PetscInt     f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
28358d2f55e7SToby Isaac   PetscInt     m, n;
28368d2f55e7SToby Isaac   PetscScalar *pointScalar;
28378d2f55e7SToby Isaac   PetscReal   *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
28388d2f55e7SToby Isaac 
28398d2f55e7SToby Isaac   PetscFunctionBegin;
28409566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &section));
28419566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(refTree, &dim));
28429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(dim, &v0, dim, &v0parent, dim, &vtmp, dim * dim, &J, dim * dim, &Jparent, dim * dim, &invJ));
28439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(dim, &pointScalar, dim, &pointRef));
28449566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
28459566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
28469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numSecFields));
28479566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "canonical", &canonical));
28489566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "depth", &depth));
28499566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSection, &cMat, NULL));
28509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
28519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
28529566063dSJacob Faibussowitsch   PetscCall(MatGetSize(cMat, &n, &m)); /* the injector has transpose sizes from the constraint matrix */
28538d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
28549566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(m, &nnz));
28558d2f55e7SToby 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 */
28568d2f55e7SToby Isaac     const PetscInt *children;
28578d2f55e7SToby Isaac     PetscInt        numChildren;
28588d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28598d2f55e7SToby Isaac 
28608d2f55e7SToby Isaac     if (canonical) {
28618d2f55e7SToby Isaac       PetscInt pCanonical;
28629566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28638d2f55e7SToby Isaac       if (p != pCanonical) continue;
28648d2f55e7SToby Isaac     }
28659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28668d2f55e7SToby Isaac     if (!numChildren) continue;
28678d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28688d2f55e7SToby Isaac       PetscInt child = children[i];
28698d2f55e7SToby Isaac       PetscInt dof;
28708d2f55e7SToby Isaac 
28719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
28728d2f55e7SToby Isaac       numChildDof += dof;
28738d2f55e7SToby Isaac     }
28749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
28758d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
28768d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
28778d2f55e7SToby Isaac       PetscInt selfOff;
28788d2f55e7SToby Isaac 
28798d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
28808d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
28818d2f55e7SToby Isaac           PetscInt child = children[i];
28828d2f55e7SToby Isaac           PetscInt dof;
28838d2f55e7SToby Isaac 
28849566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
28858d2f55e7SToby Isaac           numChildDof += dof;
28868d2f55e7SToby Isaac         }
28879566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
28889566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
28899371c9d4SSatish Balay       } else {
28909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
28918d2f55e7SToby Isaac       }
2892ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) nnz[selfOff + i] = numChildDof;
28938d2f55e7SToby Isaac     }
28948d2f55e7SToby Isaac   }
28959566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(PETSC_COMM_SELF, m, n, m, n, -1, nnz, -1, NULL, &mat));
28969566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
28978d2f55e7SToby Isaac   /* Setp 2: compute entries */
28988d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
28998d2f55e7SToby Isaac     const PetscInt *children;
29008d2f55e7SToby Isaac     PetscInt        numChildren;
29018d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
29028d2f55e7SToby Isaac 
29038d2f55e7SToby Isaac     /* same conditions about when entries occur */
29048d2f55e7SToby Isaac     if (canonical) {
29058d2f55e7SToby Isaac       PetscInt pCanonical;
29069566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
29078d2f55e7SToby Isaac       if (p != pCanonical) continue;
29088d2f55e7SToby Isaac     }
29099566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
29108d2f55e7SToby Isaac     if (!numChildren) continue;
29118d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
29128d2f55e7SToby Isaac       PetscInt child = children[i];
29138d2f55e7SToby Isaac       PetscInt dof;
29148d2f55e7SToby Isaac 
29159566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
29168d2f55e7SToby Isaac       numChildDof += dof;
29178d2f55e7SToby Isaac     }
29189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
29198d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
29208d2f55e7SToby Isaac 
29218d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
292259fc6756SToby Isaac       PetscInt        pI = -1, cI = -1;
292352a3aeb4SToby Isaac       PetscInt        selfOff, Nc, parentCell;
29248d2f55e7SToby Isaac       PetscInt        cellShapeOff;
29258d2f55e7SToby Isaac       PetscObject     disc;
29268d2f55e7SToby Isaac       PetscDualSpace  dsp;
29278d2f55e7SToby Isaac       PetscClassId    classId;
29288d2f55e7SToby Isaac       PetscScalar    *pointMat;
29293b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
2930*1690c2aeSBarry Smith       PetscInt        pO = PETSC_INT_MIN;
29318d2f55e7SToby Isaac       const PetscInt *depthNumDof;
29328d2f55e7SToby Isaac 
29338d2f55e7SToby Isaac       if (numSecFields) {
29348d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
29358d2f55e7SToby Isaac           PetscInt child = children[i];
29368d2f55e7SToby Isaac           PetscInt dof;
29378d2f55e7SToby Isaac 
29389566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
29398d2f55e7SToby Isaac           numChildDof += dof;
29408d2f55e7SToby Isaac         }
29419566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
29429566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
29439371c9d4SSatish Balay       } else {
29449566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
29458d2f55e7SToby Isaac       }
29468d2f55e7SToby Isaac 
29473b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
29488d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
29498d2f55e7SToby Isaac         parentCell = p;
29509371c9d4SSatish Balay       } else {
29518d2f55e7SToby Isaac         PetscInt *star = NULL;
29528d2f55e7SToby Isaac         PetscInt  numStar;
29538d2f55e7SToby Isaac 
29548d2f55e7SToby Isaac         parentCell = -1;
29559566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29568d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
29578d2f55e7SToby Isaac           PetscInt c = star[2 * i];
29588d2f55e7SToby Isaac 
29598d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
29608d2f55e7SToby Isaac             parentCell = c;
29618d2f55e7SToby Isaac             break;
29628d2f55e7SToby Isaac           }
29638d2f55e7SToby Isaac         }
29649566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29658d2f55e7SToby Isaac       }
2966a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
29679566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
29689566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc, &classId));
2969c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
29709566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
29719371c9d4SSatish Balay       } else if (classId == PETSCFV_CLASSID) {
29729566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace((PetscFV)disc, &dsp));
29739371c9d4SSatish Balay       } else {
29749b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported discretization object");
2975c5356c36SToby Isaac       }
29769566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumDof(dsp, &depthNumDof));
29779566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumComponents(dsp, &Nc));
29788d2f55e7SToby Isaac       {
29798d2f55e7SToby Isaac         PetscInt *closure = NULL;
29808d2f55e7SToby Isaac         PetscInt  numClosure;
29818d2f55e7SToby Isaac 
29829566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
298359fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
29848d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
29858d2f55e7SToby Isaac 
29868d2f55e7SToby Isaac           pO = closure[2 * i + 1];
298759fc6756SToby Isaac           if (point == p) {
298859fc6756SToby Isaac             pI = i;
298959fc6756SToby Isaac             break;
299059fc6756SToby Isaac           }
29919566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(depth, point, &pointDepth));
29928d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
29938d2f55e7SToby Isaac         }
29949566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
29958d2f55e7SToby Isaac       }
29968d2f55e7SToby Isaac 
29979566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
29989566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
299952a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
3000ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) matRows[i] = selfOff + i;
300152a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
30023b1c2a6aSToby Isaac       {
30033b1c2a6aSToby Isaac         PetscInt colOff = 0;
30043b1c2a6aSToby Isaac 
30053b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
30063b1c2a6aSToby Isaac           PetscInt child = children[i];
30073b1c2a6aSToby Isaac           PetscInt dof, off, j;
30083b1c2a6aSToby Isaac 
30093b1c2a6aSToby Isaac           if (numSecFields) {
30109566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSection, child, f, &dof));
30119566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(cSection, child, f, &off));
30129371c9d4SSatish Balay           } else {
30139566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(cSection, child, &dof));
30149566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(cSection, child, &off));
30153b1c2a6aSToby Isaac           }
30163b1c2a6aSToby Isaac 
3017ad540459SPierre Jolivet           for (j = 0; j < dof; j++) matCols[colOff++] = off + j;
30183b1c2a6aSToby Isaac         }
30193b1c2a6aSToby Isaac       }
30208d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
30218d2f55e7SToby Isaac         PetscFE              fe = (PetscFE)disc;
30228d2f55e7SToby Isaac         PetscInt             fSize;
302359fc6756SToby Isaac         const PetscInt    ***perms;
302459fc6756SToby Isaac         const PetscScalar ***flips;
302559fc6756SToby Isaac         const PetscInt      *pperms;
302659fc6756SToby Isaac 
30279566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &dsp));
30289566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetDimension(dsp, &fSize));
30299566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
303059fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
303152a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
30328d2f55e7SToby Isaac           PetscQuadrature  q;
303352a3aeb4SToby Isaac           PetscInt         dim, thisNc, numPoints, j, k;
30348d2f55e7SToby Isaac           const PetscReal *points;
30358d2f55e7SToby Isaac           const PetscReal *weights;
30368d2f55e7SToby Isaac           PetscInt        *closure = NULL;
30378d2f55e7SToby Isaac           PetscInt         numClosure;
303859fc6756SToby Isaac           PetscInt         iCell              = pperms ? pperms[i] : i;
303959fc6756SToby Isaac           PetscInt         parentCellShapeDof = cellShapeOff + iCell;
3040ef0bb6c7SMatthew G. Knepley           PetscTabulation  Tparent;
30418d2f55e7SToby Isaac 
30429566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(dsp, parentCellShapeDof, &q));
30439566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(q, &dim, &thisNc, &numPoints, &points, &weights));
304463a3b9bcSJacob Faibussowitsch           PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
30459566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe, 1, numPoints, points, 0, &Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
30463b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
30478d2f55e7SToby Isaac             PetscInt           childCell = -1;
304852a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3049c330f8ffSToby Isaac             const PetscReal    xi0[3]    = {-1., -1., -1.};
30508d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
30518d2f55e7SToby Isaac             const PetscScalar *point;
3052ef0bb6c7SMatthew G. Knepley             PetscTabulation    Tchild;
30538d2f55e7SToby Isaac             PetscInt           childCellShapeOff, pointMatOff;
30548d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
30558d2f55e7SToby Isaac             PetscInt d;
30568d2f55e7SToby Isaac 
3057ad540459SPierre Jolivet             for (d = 0; d < dim; d++) pointScalar[d] = points[dim * j + d];
30588d2f55e7SToby Isaac             point = pointScalar;
30598d2f55e7SToby Isaac #else
30608d2f55e7SToby Isaac             point = pointReal;
30618d2f55e7SToby Isaac #endif
30628d2f55e7SToby Isaac 
3063ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
30643b1c2a6aSToby Isaac 
30653b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
30668d2f55e7SToby Isaac               PetscInt  child = children[k];
30678d2f55e7SToby Isaac               PetscInt *star  = NULL;
30688d2f55e7SToby Isaac               PetscInt  numStar, s;
30698d2f55e7SToby Isaac 
30709566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30718d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
30728d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
30738d2f55e7SToby Isaac 
30748d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
30759566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(refTree, dim, point, c, &childCell));
30768d2f55e7SToby Isaac                 if (childCell >= 0) break;
30778d2f55e7SToby Isaac               }
30789566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30798d2f55e7SToby Isaac               if (childCell >= 0) break;
30808d2f55e7SToby Isaac             }
308108401ef6SPierre Jolivet             PetscCheck(childCell >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not locate quadrature point");
30829566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
30839566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3084c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3085c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
30868d2f55e7SToby Isaac 
30879566063dSJacob Faibussowitsch             PetscCall(PetscFECreateTabulation(fe, 1, 1, pointRef, 0, &Tchild));
30889566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
30893b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3090*1690c2aeSBarry Smith               PetscInt        child = children[k], childDepth, childDof, childO = PETSC_INT_MIN;
30918d2f55e7SToby Isaac               PetscInt        l;
309259fc6756SToby Isaac               const PetscInt *cperms;
30938d2f55e7SToby Isaac 
30949566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(depth, child, &childDepth));
30958d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
309659fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
30978d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
30988d2f55e7SToby Isaac                 PetscInt pointDepth;
30998d2f55e7SToby Isaac 
31008d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
310159fc6756SToby Isaac                 if (point == child) {
310259fc6756SToby Isaac                   cI = l;
310359fc6756SToby Isaac                   break;
310459fc6756SToby Isaac                 }
31059566063dSJacob Faibussowitsch                 PetscCall(DMLabelGetValue(depth, point, &pointDepth));
31068d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
31078d2f55e7SToby Isaac               }
31088d2f55e7SToby Isaac               if (l == numClosure) {
31098d2f55e7SToby Isaac                 pointMatOff += childDof;
31108d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
31118d2f55e7SToby Isaac               }
311259fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
31138d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
311459fc6756SToby Isaac                 PetscInt   lCell        = cperms ? cperms[l] : l;
311559fc6756SToby Isaac                 PetscInt   childCellDof = childCellShapeOff + lCell;
311652a3aeb4SToby Isaac                 PetscReal *childValAtPoint;
311752a3aeb4SToby Isaac                 PetscReal  val = 0.;
31188d2f55e7SToby Isaac 
3119ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
3120ad540459SPierre Jolivet                 for (m = 0; m < Nc; m++) val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
312152a3aeb4SToby Isaac 
312252a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
31238d2f55e7SToby Isaac               }
31248d2f55e7SToby Isaac               pointMatOff += childDof;
31258d2f55e7SToby Isaac             }
31269566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
31279566063dSJacob Faibussowitsch             PetscCall(PetscTabulationDestroy(&Tchild));
31288d2f55e7SToby Isaac           }
31299566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&Tparent));
31308d2f55e7SToby Isaac         }
31319371c9d4SSatish Balay       } else { /* just the volume-weighted averages of the children */
31323b1c2a6aSToby Isaac         PetscReal parentVol;
3133bfaa5bdcSToby Isaac         PetscInt  childCell;
31343b1c2a6aSToby Isaac 
31359566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3136bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
313752a3aeb4SToby Isaac           PetscInt  child = children[i], j;
31383b1c2a6aSToby Isaac           PetscReal childVol;
31393b1c2a6aSToby Isaac 
31403b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
31419566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
3142ad540459SPierre Jolivet           for (j = 0; j < Nc; j++) pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
3143bfaa5bdcSToby Isaac           childCell++;
31443b1c2a6aSToby Isaac         }
31458d2f55e7SToby Isaac       }
31463b1c2a6aSToby Isaac       /* Insert pointMat into mat */
31479566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, numSelfDof, matRows, numChildDof, matCols, pointMat, INSERT_VALUES));
31489566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
31499566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
31508d2f55e7SToby Isaac     }
31518d2f55e7SToby Isaac   }
31529566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJ));
31539566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointScalar, pointRef));
31549566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
31559566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
31568d2f55e7SToby Isaac   *inj = mat;
31573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31588d2f55e7SToby Isaac }
31598d2f55e7SToby Isaac 
3160d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3161d71ae5a4SJacob Faibussowitsch {
3162f30e825dSToby Isaac   PetscDS        ds;
3163f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3164f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3165f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3166f30e825dSToby Isaac 
3167f30e825dSToby Isaac   PetscFunctionBegin;
31689566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
31699566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
31709566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
31719566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
31729566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
31739566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
31749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
31759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
31769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof, &cols));
3177f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3178f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3179f30e825dSToby Isaac 
31809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
31819566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
31829566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3183f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3184f30e825dSToby Isaac 
31859566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFields, &refPointFieldMats[p - pRefStart]));
3186f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
318752a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3188f30e825dSToby Isaac 
3189f30e825dSToby Isaac       if (numFields > 1) {
31909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
31919566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
31929371c9d4SSatish Balay       } else {
31939566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
31949566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
3195f30e825dSToby Isaac       }
3196f30e825dSToby Isaac 
3197ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
3198f30e825dSToby Isaac       numCols = 0;
3199f30e825dSToby Isaac       {
3200f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3201f30e825dSToby Isaac 
3202f30e825dSToby Isaac         if (numFields > 1) {
32039566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, parent, f, &aDof));
32049566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, parent, f, &aOff));
32059371c9d4SSatish Balay         } else {
32069566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, parent, &aDof));
32079566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, parent, &aOff));
3208f30e825dSToby Isaac         }
3209f30e825dSToby Isaac 
3210ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + j;
3211f30e825dSToby Isaac       }
32129566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
3213f30e825dSToby Isaac       /* transpose of constraint matrix */
32149566063dSJacob Faibussowitsch       PetscCall(MatGetValues(inj, numCols, cols, cDof, rows, refPointFieldMats[p - pRefStart][f]));
3215f30e825dSToby Isaac     }
3216f30e825dSToby Isaac   }
3217f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
32189566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
32199566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
32203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3221f30e825dSToby Isaac }
3222f30e825dSToby Isaac 
3223d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3224d71ae5a4SJacob Faibussowitsch {
3225f30e825dSToby Isaac   PetscDS        ds;
3226f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3227f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3228c6154584SToby Isaac   PetscSection   refConSec, refSection;
3229f30e825dSToby Isaac 
3230f30e825dSToby Isaac   PetscFunctionBegin;
3231f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3232f30e825dSToby Isaac   *childrenMats     = NULL;
32339566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
32349566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
32359566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
32369566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
32379566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3238f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3239f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3240f30e825dSToby Isaac 
32419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
32429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
32439566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3244f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3245f30e825dSToby Isaac 
3246f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3247f30e825dSToby Isaac       PetscInt cDof;
3248f30e825dSToby Isaac 
3249f30e825dSToby Isaac       if (numFields > 1) {
32509566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
32519371c9d4SSatish Balay       } else {
32529566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3253f30e825dSToby Isaac       }
3254f30e825dSToby Isaac 
32559566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3256f30e825dSToby Isaac     }
32579566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3258f30e825dSToby Isaac   }
32599566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
32603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3261f30e825dSToby Isaac }
3262f30e825dSToby Isaac 
3263d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree, Mat *injRef)
3264d71ae5a4SJacob Faibussowitsch {
3265ebf164c7SToby Isaac   Mat         cMatRef;
32666148253fSToby Isaac   PetscObject injRefObj;
32678d2f55e7SToby Isaac 
3268154bca37SToby Isaac   PetscFunctionBegin;
32699566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, NULL, &cMatRef, NULL));
32709566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", &injRefObj));
3271ebf164c7SToby Isaac   *injRef = (Mat)injRefObj;
3272ebf164c7SToby Isaac   if (!*injRef) {
32739566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorReferenceTree(refTree, injRef));
32749566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", (PetscObject)*injRef));
3275ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
32769566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3277ebf164c7SToby Isaac   }
32783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32796148253fSToby Isaac }
3280f30e825dSToby Isaac 
3281d71ae5a4SJacob 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)
3282d71ae5a4SJacob Faibussowitsch {
3283c921d74cSToby Isaac   PetscInt        pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3284ebf164c7SToby Isaac   PetscSection    globalCoarse, globalFine;
3285ebf164c7SToby Isaac   PetscSection    localCoarse, localFine, leafIndicesSec;
3286c921d74cSToby Isaac   PetscSection    multiRootSec, rootIndicesSec;
3287c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3288c921d74cSToby Isaac   const PetscInt *rootDegrees;
3289c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3290ebf164c7SToby Isaac   PetscSF         coarseToFineEmbedded;
3291ebf164c7SToby Isaac 
3292ebf164c7SToby Isaac   PetscFunctionBegin;
32939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
32949566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
32959566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
32969566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
32979566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
32989566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafIndicesSec, pStartF, pEndF));
32999566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
33008d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
33017e96bdafSToby Isaac     PetscInt        l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
33027e96bdafSToby Isaac     const PetscInt *leaves;
33038d2f55e7SToby Isaac 
33049566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
33057e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
33067e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
33079566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
33089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
33098d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
33108d2f55e7SToby Isaac         numPointsWithDofs++;
3311f30e825dSToby Isaac 
33129566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localFine, p, &dof));
33139566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafIndicesSec, p, dof + 1));
33148d2f55e7SToby Isaac       }
33158d2f55e7SToby Isaac     }
33169566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
33179566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafIndicesSec));
33189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numIndices));
33199566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1), &leafInds));
33209566063dSJacob Faibussowitsch     if (gatheredValues) PetscCall(PetscMalloc1(numIndices, &leafVals));
33217e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
33227e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
33239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
33249566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
33258d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3326f30e825dSToby Isaac         PetscInt     off, gOff;
3327f30e825dSToby Isaac         PetscInt    *pInd;
3328c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3329f30e825dSToby Isaac 
33307e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3331f30e825dSToby Isaac 
33329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3333f30e825dSToby Isaac 
3334c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3335c921d74cSToby Isaac         if (gatheredValues) {
3336c921d74cSToby Isaac           PetscInt i;
3337c921d74cSToby Isaac 
3338c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3339c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3340c921d74cSToby Isaac         }
33419566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
3342f30e825dSToby Isaac 
3343f30e825dSToby Isaac         offsets[0] = 0;
3344f30e825dSToby Isaac         if (numFields) {
3345f30e825dSToby Isaac           PetscInt f;
3346f30e825dSToby Isaac 
3347f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3348f30e825dSToby Isaac             PetscInt fDof;
33499566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localFine, p, f, &fDof));
3350f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3351f30e825dSToby Isaac           }
33529566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
3353367003a6SStefano Zampini         } else {
33549566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
3355f30e825dSToby Isaac         }
33569566063dSJacob Faibussowitsch         if (gatheredValues) PetscCall(VecGetValues(fineVec, dof, pInd, pVal));
33578d2f55e7SToby Isaac       }
33588d2f55e7SToby Isaac     }
33599566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
33609566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
33618d2f55e7SToby Isaac   }
3362f30e825dSToby Isaac 
33639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
33649566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
33659566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3366f30e825dSToby Isaac 
33676148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
33686148253fSToby Isaac     MPI_Datatype threeInt;
33696148253fSToby Isaac     PetscMPIInt  rank;
33706148253fSToby Isaac     PetscInt(*parentNodeAndIdCoarse)[3];
33716148253fSToby Isaac     PetscInt(*parentNodeAndIdFine)[3];
33726148253fSToby Isaac     PetscInt           p, nleaves, nleavesToParents;
33736148253fSToby Isaac     PetscSF            pointSF, sfToParents;
33746148253fSToby Isaac     const PetscInt    *ilocal;
33756148253fSToby Isaac     const PetscSFNode *iremote;
33766148253fSToby Isaac     PetscSFNode       *iremoteToParents;
33776148253fSToby Isaac     PetscInt          *ilocalToParents;
33786148253fSToby Isaac 
33799566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse), &rank));
33809566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &threeInt));
33819566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&threeInt));
33829566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEndC - pStartC, &parentNodeAndIdCoarse, pEndF - pStartF, &parentNodeAndIdFine));
33839566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(coarse, &pointSF));
33849566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, &iremote));
33856148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
33866148253fSToby Isaac       PetscInt parent, childId;
33879566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(coarse, p, &parent, &childId));
33886148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
33896148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
33906148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
33916148253fSToby Isaac       if (nleaves > 0) {
33926148253fSToby Isaac         PetscInt leaf = -1;
33936148253fSToby Isaac 
33946148253fSToby Isaac         if (ilocal) {
33959566063dSJacob Faibussowitsch           PetscCall(PetscFindInt(parent, nleaves, ilocal, &leaf));
33969371c9d4SSatish Balay         } else {
33976148253fSToby Isaac           leaf = p - pStartC;
33986148253fSToby Isaac         }
33996148253fSToby Isaac         if (leaf >= 0) {
34006148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
34016148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
34026148253fSToby Isaac         }
34036148253fSToby Isaac       }
34046148253fSToby Isaac     }
34056148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
34066148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
34076148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
34086148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
34096148253fSToby Isaac     }
34109566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
34119566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
34126148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3413f30e825dSToby Isaac       PetscInt dof;
3414f30e825dSToby Isaac 
34159566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &dof));
3416f30e825dSToby Isaac       if (dof) {
3417f30e825dSToby Isaac         PetscInt off;
3418f30e825dSToby Isaac 
34199566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3420c921d74cSToby Isaac         if (gatheredIndices) {
3421c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3422c921d74cSToby Isaac         } else if (gatheredValues) {
3423c921d74cSToby Isaac           leafVals[off] = (PetscScalar)PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3424c921d74cSToby Isaac         }
3425f30e825dSToby Isaac       }
3426ad540459SPierre Jolivet       if (parentNodeAndIdFine[p - pStartF][0] >= 0) nleavesToParents++;
34276148253fSToby Isaac     }
34289566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &ilocalToParents));
34299566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &iremoteToParents));
34306148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
34316148253fSToby Isaac       if (parentNodeAndIdFine[p - pStartF][0] >= 0) {
34326148253fSToby Isaac         ilocalToParents[nleavesToParents] = p - pStartF;
34336497c311SBarry Smith         // FIXME PetscCall(PetscMPIIntCast(parentNodeAndIdFine[p - pStartF][0],&iremoteToParents[nleavesToParents].rank));
34346497c311SBarry Smith         iremoteToParents[nleavesToParents].rank  = (PetscMPIInt)parentNodeAndIdFine[p - pStartF][0];
34356148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p - pStartF][1];
34366148253fSToby Isaac         nleavesToParents++;
34376148253fSToby Isaac       }
34386148253fSToby Isaac     }
34399566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse), &sfToParents));
34409566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(sfToParents, pEndC - pStartC, nleavesToParents, ilocalToParents, PETSC_OWN_POINTER, iremoteToParents, PETSC_OWN_POINTER));
34419566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34426148253fSToby Isaac 
34436148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
34446148253fSToby Isaac 
34459566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parentNodeAndIdCoarse, parentNodeAndIdFine));
34469566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&threeInt));
34476148253fSToby Isaac   }
3448f30e825dSToby Isaac 
34496148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
34506148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
34516148253fSToby Isaac     PetscSF  sfDofsOnly;
34526148253fSToby Isaac 
34536148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
34549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3456ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
34576148253fSToby Isaac     }
34589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
34596148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
34609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34619566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3462ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = p - pStartC;
34636148253fSToby Isaac     }
34649566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
34659566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34669566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
34676148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
34686148253fSToby Isaac   }
3469f30e825dSToby Isaac 
34706148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
34719566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded, &rootDegrees));
34729566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded, &rootDegrees));
34739566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &multiRootSec));
34749566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(multiRootSec, pStartC, pEndC));
347548a46eb9SPierre Jolivet   for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionSetDof(multiRootSec, p, rootDegrees[p - pStartC]));
34769566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(multiRootSec));
34779566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(multiRootSec, &numMulti));
34789566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
3479f30e825dSToby Isaac   { /* distribute the leaf section */
3480f30e825dSToby Isaac     PetscSF   multi, multiInv, indicesSF;
3481f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
34828d2f55e7SToby Isaac 
34839566063dSJacob Faibussowitsch     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded, &multi));
34849566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF(multi, &multiInv));
34859566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(multiInv, leafIndicesSec, &remoteOffsets, rootIndicesSec));
34869566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(multiInv, leafIndicesSec, remoteOffsets, rootIndicesSec, &indicesSF));
34879566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
34889566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&multiInv));
34899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
3490c921d74cSToby Isaac     if (gatheredIndices) {
34919566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootInds));
34929566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
34939566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3494c921d74cSToby Isaac     }
3495c921d74cSToby Isaac     if (gatheredValues) {
34969566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootVals));
34979566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
34989566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3499c921d74cSToby Isaac     }
35009566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
35018d2f55e7SToby Isaac   }
35029566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
35039566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafInds));
35049566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafVals));
35059566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3506c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3507c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3508c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3509c921d74cSToby Isaac   if (gatheredValues) *gatheredValues = rootVals;
35103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3511ebf164c7SToby Isaac }
3512ebf164c7SToby Isaac 
3513d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3514d71ae5a4SJacob Faibussowitsch {
3515ebf164c7SToby Isaac   DM             refTree;
3516c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3517ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3518ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3519ebf164c7SToby Isaac   PetscSection   cSecRef;
3520277f51e8SBarry Smith   PetscInt      *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3521ebf164c7SToby Isaac   Mat            injRef;
3522c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3523ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3524ebf164c7SToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
3525ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3526ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3527ebf164c7SToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3528ebf164c7SToby Isaac 
3529ebf164c7SToby Isaac   PetscFunctionBegin;
3530ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
35319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
3532d3a532e9SStefano Zampini   PetscCall(DMCopyDisc(coarse, refTree));
3533d3a532e9SStefano Zampini   PetscCall(DMSetLocalSection(refTree, NULL));
3534d3a532e9SStefano Zampini   PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
35359566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
35369566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
35379566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
3538ebf164c7SToby Isaac 
35399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
35409566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
35419566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
35429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
35439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
35449566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
35459566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
35469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
3547ebf164c7SToby Isaac   {
3548ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
35499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
3550ebf164c7SToby Isaac   }
3551ebf164c7SToby Isaac 
35529566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, childIds, NULL, numFields, offsets, &multiRootSec, &rootIndicesSec, &rootIndices, NULL));
35538d2f55e7SToby Isaac 
35549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &parentIndices));
3555f30e825dSToby Isaac 
3556f30e825dSToby Isaac   /* count indices */
35579566063dSJacob Faibussowitsch   PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
35589566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
35599566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
35609566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
35619566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
35629566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(rowEnd - rowStart, &nnzD, rowEnd - rowStart, &nnzO));
3563f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3564f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
35658d2f55e7SToby Isaac 
35669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
35679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3568f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
35699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
35708d2f55e7SToby Isaac 
35718d2f55e7SToby Isaac     rowOffsets[0]  = 0;
3572f30e825dSToby Isaac     offsetsCopy[0] = 0;
35738d2f55e7SToby Isaac     if (numFields) {
35748d2f55e7SToby Isaac       PetscInt f;
35758d2f55e7SToby Isaac 
3576f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3577f30e825dSToby Isaac         PetscInt fDof;
35789566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3579f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
35808d2f55e7SToby Isaac       }
35819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3582367003a6SStefano Zampini     } else {
35839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3584f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
35858d2f55e7SToby Isaac     }
3586f30e825dSToby Isaac 
35879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
35889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3589f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3590f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3591f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3592f30e825dSToby Isaac       const PetscInt *childIndices;
3593f30e825dSToby Isaac 
35949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
35959566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3596f30e825dSToby Isaac       childId      = rootIndices[offset++];
3597f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3598f30e825dSToby Isaac       numIndices--;
3599f30e825dSToby Isaac 
3600f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3601f30e825dSToby Isaac         PetscInt i;
3602f30e825dSToby Isaac 
3603f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3604f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3605f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3606f30e825dSToby Isaac           if (rowIndex < 0) continue;
360708401ef6SPierre Jolivet           PetscCheck(colIndex >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unconstrained fine and constrained coarse");
3608a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3609f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
36109371c9d4SSatish Balay           } else {
3611f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3612f30e825dSToby Isaac           }
3613f30e825dSToby Isaac         }
36149371c9d4SSatish Balay       } else {
3615f30e825dSToby Isaac         PetscInt parentId, f, lim;
3616f30e825dSToby Isaac 
36179566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3618f30e825dSToby Isaac 
3619f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3620f30e825dSToby Isaac         offsets[0] = 0;
36218d2f55e7SToby Isaac         if (numFields) {
36228d2f55e7SToby Isaac           PetscInt f;
3623f30e825dSToby Isaac 
36248d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3625f30e825dSToby Isaac             PetscInt fDof;
36269566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3627f30e825dSToby Isaac 
3628f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
36298d2f55e7SToby Isaac           }
36309371c9d4SSatish Balay         } else {
3631f30e825dSToby Isaac           PetscInt cDof;
3632f30e825dSToby Isaac 
36339566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3634f30e825dSToby Isaac           offsets[1] = cDof;
3635f30e825dSToby Isaac         }
3636f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3637f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3638f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3639f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3640f30e825dSToby Isaac 
3641f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3642f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3643f30e825dSToby Isaac 
3644f30e825dSToby Isaac             if (colIndex < 0) continue;
3645f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3646f30e825dSToby Isaac               numD++;
36479371c9d4SSatish Balay             } else {
3648f30e825dSToby Isaac               numO++;
3649f30e825dSToby Isaac             }
3650f30e825dSToby Isaac           }
3651f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3652f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3653f30e825dSToby Isaac 
3654f30e825dSToby Isaac             if (rowIndex < 0) continue;
3655f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3656f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
36578d2f55e7SToby Isaac           }
36588d2f55e7SToby Isaac         }
36598d2f55e7SToby Isaac       }
3660f30e825dSToby Isaac     }
3661f30e825dSToby Isaac   }
3662f30e825dSToby Isaac   /* preallocate */
36639566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mat, 1, nnzD, nnzO, NULL, NULL));
36649566063dSJacob Faibussowitsch   PetscCall(PetscFree2(nnzD, nnzO));
3665f30e825dSToby Isaac   /* insert values */
36669566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3667f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3668f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3669f30e825dSToby Isaac 
36709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
36719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3672f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
36739566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
3674f30e825dSToby Isaac 
3675f30e825dSToby Isaac     rowOffsets[0]  = 0;
3676f30e825dSToby Isaac     offsetsCopy[0] = 0;
36778d2f55e7SToby Isaac     if (numFields) {
36788d2f55e7SToby Isaac       PetscInt f;
3679f30e825dSToby Isaac 
36808d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3681f30e825dSToby Isaac         PetscInt fDof;
36829566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3683f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3684f30e825dSToby Isaac       }
36859566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3686367003a6SStefano Zampini     } else {
36879566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3688f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3689f30e825dSToby Isaac     }
3690f30e825dSToby Isaac 
36919566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
36929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3693f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3694f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3695f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3696f30e825dSToby Isaac       const PetscInt *childIndices;
3697f30e825dSToby Isaac 
36989566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
36999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3700f30e825dSToby Isaac       childId      = rootIndices[offset++];
3701f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3702f30e825dSToby Isaac       numIndices--;
3703f30e825dSToby Isaac 
3704f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3705f30e825dSToby Isaac         PetscInt i;
3706f30e825dSToby Isaac 
370748a46eb9SPierre Jolivet         for (i = 0; i < numIndices; i++) PetscCall(MatSetValue(mat, parentIndices[i], childIndices[i], 1., INSERT_VALUES));
37089371c9d4SSatish Balay       } else {
3709f30e825dSToby Isaac         PetscInt parentId, f, lim;
37108d2f55e7SToby Isaac 
37119566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3712f30e825dSToby Isaac 
3713f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3714f30e825dSToby Isaac         offsets[0] = 0;
37158d2f55e7SToby Isaac         if (numFields) {
3716f30e825dSToby Isaac           PetscInt f;
37178d2f55e7SToby Isaac 
3718f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3719f30e825dSToby Isaac             PetscInt fDof;
37209566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3721f30e825dSToby Isaac 
3722f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
37238d2f55e7SToby Isaac           }
37249371c9d4SSatish Balay         } else {
3725f30e825dSToby Isaac           PetscInt cDof;
3726f30e825dSToby Isaac 
37279566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3728f30e825dSToby Isaac           offsets[1] = cDof;
37298d2f55e7SToby Isaac         }
3730f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3731f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3732f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3733f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3734f30e825dSToby Isaac 
37359566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat, rowOffsets[f + 1] - rowOffsets[f], rowIndices, offsets[f + 1] - offsets[f], colIndices, childMat, INSERT_VALUES));
37368d2f55e7SToby Isaac         }
37378d2f55e7SToby Isaac       }
37388d2f55e7SToby Isaac     }
37398d2f55e7SToby Isaac   }
37409566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
37419566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
37429566063dSJacob Faibussowitsch   PetscCall(PetscFree(parentIndices));
37439566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
37449566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootIndices));
37459566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
3746f30e825dSToby Isaac 
37479566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
37489566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
37493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3750154bca37SToby Isaac }
375138fc2455SToby Isaac 
3752d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3753d71ae5a4SJacob Faibussowitsch {
375462095d54SToby Isaac   PetscSF            coarseToFineEmbedded;
375562095d54SToby Isaac   PetscSection       globalCoarse, globalFine;
375662095d54SToby Isaac   PetscSection       localCoarse, localFine;
375762095d54SToby Isaac   PetscSection       aSec, cSec;
375862095d54SToby Isaac   PetscSection       rootValuesSec;
375962095d54SToby Isaac   PetscSection       leafValuesSec;
376062095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
376162095d54SToby Isaac   IS                 aIS;
376262095d54SToby Isaac   const PetscInt    *anchors;
376362095d54SToby Isaac   Mat                cMat;
376462095d54SToby Isaac   PetscInt           numFields;
3765412e9a14SMatthew G. Knepley   PetscInt           pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
376662095d54SToby Isaac   PetscInt           aStart, aEnd, cStart, cEnd;
376762095d54SToby Isaac   PetscInt          *maxChildIds;
376862095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
37690eb7e1eaSToby Isaac   PetscFV            fv = NULL;
37700eb7e1eaSToby Isaac   PetscInt           dim, numFVcomps = -1, fvField = -1;
37710eb7e1eaSToby Isaac   DM                 cellDM = NULL, gradDM = NULL;
37720eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
37730eb7e1eaSToby Isaac   const PetscScalar *gradArray     = NULL;
377462095d54SToby Isaac 
3775ebf164c7SToby Isaac   PetscFunctionBegin;
37769566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
37779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
37789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(coarse, 0, &cellStart, &cellEnd));
37799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
37809566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
37819566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(coarse, &dim));
378262095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3783e4a60869SToby Isaac     PetscInt        nleaves, l;
3784e4a60869SToby Isaac     const PetscInt *leaves;
378562095d54SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
378662095d54SToby Isaac 
37879566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
3788e4a60869SToby Isaac 
3789e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3790e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3791e4a60869SToby Isaac 
37929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37939566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3794ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
379562095d54SToby Isaac     }
37969566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
37974833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
3798e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3799e4a60869SToby Isaac 
38009566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
38019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3802ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
380362095d54SToby Isaac     }
38049566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
38059566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
380662095d54SToby Isaac   }
380762095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
38089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
3809ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
38109566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
38119566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
381262095d54SToby Isaac 
38139566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
38149566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
381562095d54SToby Isaac 
38169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
38179566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
38189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
381962095d54SToby Isaac 
38209566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
38219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
382262095d54SToby Isaac 
382362095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
38249566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootValuesSec));
38259566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootValuesSec, pStartC, pEndC));
38269566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
382762095d54SToby Isaac   {
382862095d54SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
38299566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &newOffsets, maxFields, &newOffsetsCopy, maxFields, &rowOffsets, maxFields, &numD, maxFields, &numO));
383062095d54SToby Isaac   }
38310eb7e1eaSToby Isaac   if (grad) {
38320eb7e1eaSToby Isaac     PetscInt i;
38330eb7e1eaSToby Isaac 
38349566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeom, &cellDM));
38359566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeom, &cellGeomArray));
38369566063dSJacob Faibussowitsch     PetscCall(VecGetDM(grad, &gradDM));
38379566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(grad, &gradArray));
38380eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1, numFields); i++) {
38390eb7e1eaSToby Isaac       PetscObject  obj;
38400eb7e1eaSToby Isaac       PetscClassId id;
38410eb7e1eaSToby Isaac 
38429566063dSJacob Faibussowitsch       PetscCall(DMGetField(coarse, i, NULL, &obj));
38439566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
38440eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
38450eb7e1eaSToby Isaac         fv = (PetscFV)obj;
38469566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &numFVcomps));
38470eb7e1eaSToby Isaac         fvField = i;
38480eb7e1eaSToby Isaac         break;
38490eb7e1eaSToby Isaac       }
38500eb7e1eaSToby Isaac     }
38510eb7e1eaSToby Isaac   }
385262095d54SToby Isaac 
385362095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
385462095d54SToby Isaac     PetscInt dof;
385562095d54SToby Isaac     PetscInt maxChildId = maxChildIds[p - pStartC];
385662095d54SToby Isaac     PetscInt numValues  = 0;
385762095d54SToby Isaac 
38589566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3859ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
386062095d54SToby Isaac     offsets[0]    = 0;
386162095d54SToby Isaac     newOffsets[0] = 0;
386262095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
386362095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
386462095d54SToby Isaac 
38659566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
386662095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
386762095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
386862095d54SToby Isaac 
38699566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
387062095d54SToby Isaac         numValues += clDof;
387162095d54SToby Isaac       }
38729566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
38739371c9d4SSatish Balay     } else if (maxChildId == -1) {
38749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localCoarse, p, &numValues));
387562095d54SToby Isaac     }
387662095d54SToby Isaac     /* we will pack the column indices with the field offsets */
387778b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
38780eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
38790eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
38800eb7e1eaSToby Isaac     }
38819566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootValuesSec, p, numValues));
388262095d54SToby Isaac   }
38839566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootValuesSec));
388462095d54SToby Isaac   {
388562095d54SToby Isaac     PetscInt           numRootValues;
388662095d54SToby Isaac     const PetscScalar *coarseArray;
388762095d54SToby Isaac 
38889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootValuesSec, &numRootValues));
38899566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRootValues, &rootValues));
38909566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecCoarseLocal, &coarseArray));
389162095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
389262095d54SToby Isaac       PetscInt     numValues;
389362095d54SToby Isaac       PetscInt     pValOff;
389462095d54SToby Isaac       PetscScalar *pVal;
389562095d54SToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
389662095d54SToby Isaac 
38979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootValuesSec, p, &numValues));
3898ad540459SPierre Jolivet       if (!numValues) continue;
38999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootValuesSec, p, &pValOff));
3900f4f49eeaSPierre Jolivet       pVal = &rootValues[pValOff];
390162095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
39020eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
39039566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(coarse, NULL, vecCoarseLocal, p, &closureSize, &pVal));
39040eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
3905193eb951SToby Isaac           PetscFVCellGeom *cg;
39066dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
39070eb7e1eaSToby Isaac           PetscInt         i;
39080eb7e1eaSToby Isaac 
39090eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
39100eb7e1eaSToby Isaac 
39119566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(cellDM, p, cellGeomArray, (void *)&cg));
39120eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
39130eb7e1eaSToby Isaac           pVal += dim;
39149566063dSJacob Faibussowitsch           PetscCall(DMPlexPointGlobalRead(gradDM, p, gradArray, (void *)&gradVals));
39150eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
39160eb7e1eaSToby Isaac         }
39179371c9d4SSatish Balay       } else if (maxChildId == -1) {
391878b7adb5SToby Isaac         PetscInt lDof, lOff, i;
391978b7adb5SToby Isaac 
39209566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, p, &lDof));
39219566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(localCoarse, p, &lOff));
392278b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
392378b7adb5SToby Isaac       }
392478b7adb5SToby Isaac     }
39259566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecCoarseLocal, &coarseArray));
39269566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
392762095d54SToby Isaac   }
392862095d54SToby Isaac   {
392962095d54SToby Isaac     PetscSF   valuesSF;
393062095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
393162095d54SToby Isaac 
39329566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafValuesSec));
39339566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootValuesSec, &remoteOffsetsValues, leafValuesSec));
39349566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootValuesSec, remoteOffsetsValues, leafValuesSec, &valuesSF));
39359566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
39369566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsValues));
39379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafValuesSec, &numLeafValues));
39389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafValues, &leafValues));
39399566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39409566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39419566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&valuesSF));
39429566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootValues));
39439566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootValuesSec));
394462095d54SToby Isaac   }
39459566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
394662095d54SToby Isaac   {
394762095d54SToby Isaac     PetscInt       maxDof;
394862095d54SToby Isaac     PetscInt      *rowIndices;
394962095d54SToby Isaac     DM             refTree;
395062095d54SToby Isaac     PetscInt     **refPointFieldN;
395162095d54SToby Isaac     PetscScalar ***refPointFieldMats;
395262095d54SToby Isaac     PetscSection   refConSec, refAnSec;
39530eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, leafStart, leafEnd;
395462095d54SToby Isaac     PetscScalar   *pointWork;
395562095d54SToby Isaac 
39569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
39579566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
39589566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
39599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
39609566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(fine, refTree));
39619566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
39629566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
39639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
39649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
39659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafValuesSec, &leafStart, &leafEnd));
39669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSimplexOrBoxCells(fine, 0, &cellStart, &cellEnd));
39670eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
396862095d54SToby Isaac       PetscInt           gDof, gcDof, gOff, lDof;
396962095d54SToby Isaac       PetscInt           numValues, pValOff;
397062095d54SToby Isaac       PetscInt           childId;
397162095d54SToby Isaac       const PetscScalar *pVal;
39720eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
397362095d54SToby Isaac 
39749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
39759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localFine, p, &lDof));
39769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
3977ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
39789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
39799566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafValuesSec, p, &numValues));
398062095d54SToby Isaac       if (!numValues) continue;
39819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafValuesSec, p, &pValOff));
398262095d54SToby Isaac       pVal              = &leafValues[pValOff];
398362095d54SToby Isaac       offsets[0]        = 0;
398462095d54SToby Isaac       offsetsCopy[0]    = 0;
398562095d54SToby Isaac       newOffsets[0]     = 0;
398662095d54SToby Isaac       newOffsetsCopy[0] = 0;
39874833aeb0SToby Isaac       childId           = cids[p - pStartF];
398862095d54SToby Isaac       if (numFields) {
398962095d54SToby Isaac         PetscInt f;
399062095d54SToby Isaac         for (f = 0; f < numFields; f++) {
399162095d54SToby Isaac           PetscInt rowDof;
399262095d54SToby Isaac 
39939566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
399462095d54SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
399562095d54SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
399662095d54SToby Isaac           /* TODO: closure indices */
39979f4e70e1SToby Isaac           newOffsets[f + 1] = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
399862095d54SToby Isaac         }
39999566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
40009371c9d4SSatish Balay       } else {
40014833aeb0SToby Isaac         offsets[0]    = 0;
40024833aeb0SToby Isaac         offsets[1]    = lDof;
40034833aeb0SToby Isaac         newOffsets[0] = 0;
40044833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
40059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
400662095d54SToby Isaac       }
400762095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
40089566063dSJacob Faibussowitsch         PetscCall(VecSetValues(vecFine, numValues, rowIndices, pVal, INSERT_VALUES));
400962095d54SToby Isaac       } else {
401062095d54SToby Isaac         PetscInt f;
401162095d54SToby Isaac 
401278b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
401378b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
401478b7adb5SToby Isaac           fvGradData = &pVal[numValues];
401578b7adb5SToby Isaac         }
401662095d54SToby Isaac         for (f = 0; f < PetscMax(1, numFields); f++) {
401762095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
401862095d54SToby Isaac           PetscInt           numRows  = offsets[f + 1] - offsets[f];
401962095d54SToby Isaac           PetscInt           numCols  = newOffsets[f + 1] - newOffsets[f];
402062095d54SToby Isaac           const PetscScalar *cVal     = &pVal[newOffsets[f]];
402162095d54SToby Isaac           PetscScalar       *rVal     = &pointWork[offsets[f]];
402262095d54SToby Isaac           PetscInt           i, j;
402362095d54SToby Isaac 
4024708c7f19SToby Isaac #if 0
402563a3b9bcSJacob 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));
4026708c7f19SToby Isaac #endif
402762095d54SToby Isaac           for (i = 0; i < numRows; i++) {
402862095d54SToby Isaac             PetscScalar val = 0.;
4029ad540459SPierre Jolivet             for (j = 0; j < numCols; j++) val += childMat[i * numCols + j] * cVal[j];
403062095d54SToby Isaac             rVal[i] = val;
403162095d54SToby Isaac           }
40320eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
40330eb7e1eaSToby Isaac             PetscReal          centroid[3];
40340eb7e1eaSToby Isaac             PetscScalar        diff[3];
40350eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
40360eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
40370eb7e1eaSToby Isaac 
40389566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFVM(fine, p, NULL, centroid, NULL));
4039ad540459SPierre Jolivet             for (i = 0; i < dim; i++) diff[i] = centroid[i] - parentCentroid[i];
40400eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
40410eb7e1eaSToby Isaac               PetscScalar val = 0.;
40420eb7e1eaSToby Isaac 
4043ad540459SPierre Jolivet               for (j = 0; j < dim; j++) val += gradient[dim * i + j] * diff[j];
40440eb7e1eaSToby Isaac               rVal[i] += val;
40450eb7e1eaSToby Isaac             }
40460eb7e1eaSToby Isaac           }
40479566063dSJacob Faibussowitsch           PetscCall(VecSetValues(vecFine, numRows, &rowIndices[offsets[f]], rVal, INSERT_VALUES));
404862095d54SToby Isaac         }
404962095d54SToby Isaac       }
405062095d54SToby Isaac     }
40519566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
40529566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
40539566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
405462095d54SToby Isaac   }
40559566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafValues));
40569566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafValuesSec));
40579566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
40589566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
40593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4060ebf164c7SToby Isaac }
4061ebf164c7SToby Isaac 
4062d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4063d71ae5a4SJacob Faibussowitsch {
4064c921d74cSToby Isaac   DM             refTree;
4065c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4066c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4067c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4068c921d74cSToby Isaac   PetscSection   cSecRef;
4069c921d74cSToby Isaac   PetscInt      *parentIndices, pRefStart, pRefEnd;
4070d3bc4906SToby Isaac   PetscScalar   *rootValues, *parentValues;
4071c921d74cSToby Isaac   Mat            injRef;
4072c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4073c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4074c921d74cSToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
4075c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4076c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4077c921d74cSToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4078c921d74cSToby Isaac 
4079ebf164c7SToby Isaac   PetscFunctionBegin;
4080c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
40819566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40829566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecCoarse, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
40849566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(coarse, refTree));
40859566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
40869566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
40879566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
4088c921d74cSToby Isaac 
40899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
40909566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
40919566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
40929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
40939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
40949566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
40959566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
40969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
4097c921d74cSToby Isaac   {
4098c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
40999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
4100c921d74cSToby Isaac   }
4101c921d74cSToby Isaac 
41029566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, cids, vecFine, numFields, offsets, &multiRootSec, &rootIndicesSec, NULL, &rootValues));
4103c921d74cSToby Isaac 
41049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxDof, &parentIndices, maxDof, &parentValues));
4105c921d74cSToby Isaac 
4106c921d74cSToby Isaac   /* count indices */
41079566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecFine, &colMap));
41089566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecCoarse, &rowMap));
41099566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
41109566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
41119566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
41129566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
4113c921d74cSToby Isaac   /* insert values */
41149566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4115c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4116c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
411778b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4118c921d74cSToby Isaac 
41199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
41209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
4121c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
41229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localCoarse, p, &dof));
41239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
4124c921d74cSToby Isaac 
4125c921d74cSToby Isaac     rowOffsets[0]  = 0;
4126c921d74cSToby Isaac     offsetsCopy[0] = 0;
4127c921d74cSToby Isaac     if (numFields) {
4128c921d74cSToby Isaac       PetscInt f;
4129c921d74cSToby Isaac 
4130c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4131c921d74cSToby Isaac         PetscInt fDof;
41329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
4133c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4134c921d74cSToby Isaac       }
41359566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
4136367003a6SStefano Zampini     } else {
41379566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
4138c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4139c921d74cSToby Isaac     }
4140c921d74cSToby Isaac 
41419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
41429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
4143c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
41442f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4145c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4146c921d74cSToby Isaac       PetscInt           numIndices, childId, offset;
4147c921d74cSToby Isaac       const PetscScalar *childValues;
4148c921d74cSToby Isaac 
41499566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
41509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
4151c921d74cSToby Isaac       childId     = (PetscInt)PetscRealPart(rootValues[offset++]);
4152c921d74cSToby Isaac       childValues = &rootValues[offset];
4153c921d74cSToby Isaac       numIndices--;
4154c921d74cSToby Isaac 
4155c921d74cSToby Isaac       if (childId == -2) { /* skip */
4156c921d74cSToby Isaac         continue;
4157c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
41582f65e181SToby Isaac         PetscInt m;
41592f65e181SToby Isaac 
416078b7adb5SToby Isaac         contribute = PETSC_TRUE;
41612f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4162beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4163d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4164d3bc4906SToby Isaac 
416578b7adb5SToby Isaac         contribute = PETSC_TRUE;
41669566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
4167d3bc4906SToby Isaac 
4168d3bc4906SToby Isaac         lim        = PetscMax(1, numFields);
4169d3bc4906SToby Isaac         offsets[0] = 0;
4170d3bc4906SToby Isaac         if (numFields) {
4171d3bc4906SToby Isaac           PetscInt f;
4172d3bc4906SToby Isaac 
4173d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4174d3bc4906SToby Isaac             PetscInt fDof;
41759566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
4176d3bc4906SToby Isaac 
4177d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4178d3bc4906SToby Isaac           }
41799371c9d4SSatish Balay         } else {
4180d3bc4906SToby Isaac           PetscInt cDof;
4181d3bc4906SToby Isaac 
41829566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
4183d3bc4906SToby Isaac           offsets[1] = cDof;
4184d3bc4906SToby Isaac         }
4185d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4186d3bc4906SToby Isaac           PetscScalar       *childMat = &childrenMats[childId - pRefStart][f][0];
4187d3bc4906SToby Isaac           PetscInt           n        = offsets[f + 1] - offsets[f];
4188e328ff09SToby Isaac           PetscInt           m        = rowOffsets[f + 1] - rowOffsets[f];
4189d3bc4906SToby Isaac           PetscInt           i, j;
4190d3bc4906SToby Isaac           const PetscScalar *colValues = &childValues[offsets[f]];
4191d3bc4906SToby Isaac 
4192e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4193d3bc4906SToby Isaac             PetscScalar val = 0.;
4194ad540459SPierre Jolivet             for (j = 0; j < n; j++) val += childMat[n * i + j] * colValues[j];
4195e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4196d3bc4906SToby Isaac           }
4197d3bc4906SToby Isaac         }
4198c921d74cSToby Isaac       }
4199c921d74cSToby Isaac     }
42009566063dSJacob Faibussowitsch     if (contribute) PetscCall(VecSetValues(vecCoarse, dof, parentIndices, parentValues, INSERT_VALUES));
4201c921d74cSToby Isaac   }
42029566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
42039566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
42049566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parentIndices, parentValues));
42059566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
42069566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootValues));
42079566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
42083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4209ebf164c7SToby Isaac }
4210ebf164c7SToby Isaac 
4211ff1f73f7SToby Isaac /*@
4212ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4213ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4214ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4215ff1f73f7SToby Isaac 
421620f4b53cSBarry Smith   Collective
4217ff1f73f7SToby Isaac 
4218ff1f73f7SToby Isaac   Input Parameters:
4219a1cb98faSBarry Smith + dmIn        - The `DMPLEX` mesh for the input vector
422020f4b53cSBarry Smith . dmOut       - The second `DMPLEX` mesh
4221ff1f73f7SToby Isaac . vecIn       - The input vector
422220f4b53cSBarry Smith . sfRefine    - A star forest indicating points in the mesh `dmIn` (roots in the star forest) that are parents to points in
422320f4b53cSBarry Smith                 the mesh `dmOut` (leaves in the star forest), i.e. where `dmOut` is more refined than `dmIn`
422420f4b53cSBarry Smith . sfCoarsen   - A star forest indicating points in the mesh `dmOut` (roots in the star forest) that are parents to points in
422520f4b53cSBarry Smith                 the mesh `dmIn` (leaves in the star forest), i.e. where `dmOut` is more coarsened than `dmIn`
422620f4b53cSBarry Smith . cidsRefine  - The childIds of the points in `dmOut`.  These childIds relate back to the reference tree: childid[j] = k implies
422720f4b53cSBarry Smith                 that mesh point j of `dmOut` was refined from a point in `dmIn` just as the mesh point k in the reference
422820f4b53cSBarry Smith                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in `dmOut` is exactly
422920f4b53cSBarry Smith                 equivalent to its root in `dmIn`, so no interpolation is necessary.  childid[j] = -2 indicates that this
423020f4b53cSBarry Smith                 point j in `dmOut` is not a leaf of `sfRefine`.
423120f4b53cSBarry Smith . cidsCoarsen - The childIds of the points in `dmIn`.  These childIds relate back to the reference tree: childid[j] = k implies
423220f4b53cSBarry Smith                 that mesh point j of dmIn coarsens to a point in `dmOut` just as the mesh point k in the reference
423320f4b53cSBarry Smith                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in `dmOut` is not a leaf in `sfCoarsen`.
423420f4b53cSBarry Smith . useBCs      - `PETSC_TRUE` indicates that boundary values should be inserted into `vecIn` before transfer.
4235ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4236ff1f73f7SToby Isaac 
42372fe279fdSBarry Smith   Output Parameter:
42388966356dSPierre Jolivet . vecOut - Using interpolation and injection operators calculated on the reference tree, the transferred
423920f4b53cSBarry Smith                 projection of `vecIn` from `dmIn` to `dmOut`.  Note that any field discretized with a `PetscFV` finite volume
4240ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4241ff1f73f7SToby Isaac                 coarse points to fine points.
4242ff1f73f7SToby Isaac 
4243ff1f73f7SToby Isaac   Level: developer
4244ff1f73f7SToby Isaac 
42451cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSF`, `Vec`, `PetscFV`, `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4246ff1f73f7SToby Isaac @*/
4247d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
4248d71ae5a4SJacob Faibussowitsch {
424938fc2455SToby Isaac   PetscFunctionBegin;
42509566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
4251ff1f73f7SToby Isaac   if (sfRefine) {
4252fbfa57b9SToby Isaac     Vec vecInLocal;
42530eb7e1eaSToby Isaac     DM  dmGrad   = NULL;
42540eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4255fbfa57b9SToby Isaac 
42569566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
42579566063dSJacob Faibussowitsch     PetscCall(VecSet(vecInLocal, 0.0));
42580eb7e1eaSToby Isaac     {
42590eb7e1eaSToby Isaac       PetscInt numFields, i;
42600eb7e1eaSToby Isaac 
42619566063dSJacob Faibussowitsch       PetscCall(DMGetNumFields(dmIn, &numFields));
42620eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
42630eb7e1eaSToby Isaac         PetscObject  obj;
42640eb7e1eaSToby Isaac         PetscClassId classid;
42650eb7e1eaSToby Isaac 
42669566063dSJacob Faibussowitsch         PetscCall(DMGetField(dmIn, i, NULL, &obj));
42679566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &classid));
42680eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
42699566063dSJacob Faibussowitsch           PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
42700eb7e1eaSToby Isaac           break;
42710eb7e1eaSToby Isaac         }
42720eb7e1eaSToby Isaac       }
42730eb7e1eaSToby Isaac     }
42741baa6e33SBarry Smith     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
42759566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42769566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42770eb7e1eaSToby Isaac     if (dmGrad) {
42789566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad, &grad));
42799566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
42800eb7e1eaSToby Isaac     }
42819566063dSJacob Faibussowitsch     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
42829566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
428348a46eb9SPierre Jolivet     if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
4284ebf164c7SToby Isaac   }
42851baa6e33SBarry Smith   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
42869566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(vecOut));
42879566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(vecOut));
42883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
428938fc2455SToby Isaac }
4290