xref: /petsc/src/dm/impls/plex/plextree.c (revision f4f49eeac7efa77fffa46b7ff95a3ed169f659ed)
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;
475878b19aaSToby Isaac   PetscInt     p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
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;
65866af876cSToby Isaac   PetscInt     aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
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));
799*f4f49eeaSPierre 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++) {
22396ecaa68aSToby Isaac       PetscInt     numRowIndices, numColIndices, matSize, dof;
2240f13f9184SToby Isaac       PetscInt     pIndOff, pMatOff, f;
22416ecaa68aSToby Isaac       PetscInt    *pInd;
22426ecaa68aSToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
22436ecaa68aSToby Isaac       PetscScalar *pMat       = NULL;
22446ecaa68aSToby Isaac 
22459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, p, &numColIndices));
2246ad540459SPierre Jolivet       if (!numColIndices) continue;
2247f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2248f13f9184SToby Isaac         offsets[f]        = 0;
2249f13f9184SToby Isaac         newOffsets[f]     = 0;
2250f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2251f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2252f13f9184SToby Isaac       }
22536ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
22549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, p, &pIndOff));
2255*f4f49eeaSPierre 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         PetscInt numRowIndices = matSize / numColIndices;
22666ecaa68aSToby Isaac 
22676ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
22686ecaa68aSToby Isaac           PetscInt numIndices, *indices;
22699566063dSJacob Faibussowitsch           PetscCall(DMPlexGetClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
227008401ef6SPierre Jolivet           PetscCheck(numIndices == numColIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "mismatching constraint indices calculations");
2271ad540459SPierre Jolivet           for (i = 0; i < numColIndices; i++) pInd[i] = indices[i];
22726ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
227346bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i + 1];
227446bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i + 1];
22756ecaa68aSToby Isaac           }
22769566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
22779371c9d4SSatish Balay         } else {
22786ecaa68aSToby Isaac           PetscInt     closureSize, *closure = NULL, cl;
22796ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
22806ecaa68aSToby Isaac           PetscInt     numPoints, *points;
22816ecaa68aSToby Isaac 
22829566063dSJacob Faibussowitsch           PetscCall(DMGetWorkArray(coarse, numRowIndices * numRowIndices, MPIU_SCALAR, &pMatIn));
22836ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
2284ad540459SPierre Jolivet             for (j = 0; j < numRowIndices; j++) pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
22856ecaa68aSToby Isaac           }
22869566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22874acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
22889566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
22899566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
22904acb8e1eSToby Isaac           }
22916ecaa68aSToby Isaac           if (numFields) {
22926ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
22936ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
22946ecaa68aSToby Isaac 
22956ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
22966ecaa68aSToby Isaac                 PetscInt fDof;
22976ecaa68aSToby Isaac 
22989566063dSJacob Faibussowitsch                 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &fDof));
22996ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
23006ecaa68aSToby Isaac               }
23016ecaa68aSToby Isaac             }
23026ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
23036ecaa68aSToby Isaac               offsets[f + 1] += offsets[f];
23046ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
23056ecaa68aSToby Isaac             }
23066ecaa68aSToby Isaac           }
23074acb8e1eSToby Isaac           /* TODO : flips here ? */
23086ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
23099566063dSJacob Faibussowitsch           PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, perms, pMatIn, &numPoints, NULL, &points, &pMatModified, newOffsets, PETSC_FALSE));
23104acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23119566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
23129566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
23134acb8e1eSToby Isaac           }
23144acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23159566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23169566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23174acb8e1eSToby Isaac           }
23186ecaa68aSToby Isaac           if (!numFields) {
2319ad540459SPierre Jolivet             for (i = 0; i < numRowIndices * numColIndices; i++) pMat[i] = pMatModified[i];
23209371c9d4SSatish Balay           } else {
2321f13f9184SToby Isaac             PetscInt i, j, count;
23226ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
23236ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f + 1]; i++) {
2324ad540459SPierre Jolivet                 for (j = newOffsets[f]; j < newOffsets[f + 1]; j++, count++) pMat[count] = pMatModified[i * numColIndices + j];
23256ecaa68aSToby Isaac               }
23266ecaa68aSToby Isaac             }
23276ecaa68aSToby Isaac           }
23289566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatModified));
23299566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
23309566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatIn));
23316ecaa68aSToby Isaac           if (numFields) {
233246bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
233346bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f + 1];
233446bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f + 1];
23356ecaa68aSToby Isaac             }
23364acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23374acb8e1eSToby Isaac               PetscInt globalOff, c = points[2 * cl];
23389566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23399566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
23406ecaa68aSToby Isaac             }
23416ecaa68aSToby Isaac           } else {
23424acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23434acb8e1eSToby Isaac               PetscInt        c    = points[2 * cl], globalOff;
23444acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
23454acb8e1eSToby Isaac 
23469566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23479566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
23486ecaa68aSToby Isaac             }
23496ecaa68aSToby Isaac           }
23504acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23519566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23529566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23534acb8e1eSToby Isaac           }
23549566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numPoints, MPIU_SCALAR, &points));
23556ecaa68aSToby Isaac         }
23569371c9d4SSatish Balay       } else if (matSize) {
23576ecaa68aSToby Isaac         PetscInt  cOff;
23586ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
23596ecaa68aSToby Isaac 
23606ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
236108401ef6SPierre Jolivet         PetscCheck(numRowIndices == dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Miscounted dofs");
23629566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
23639566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
23649566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, p, &cOff));
23659566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
23669566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
23676ecaa68aSToby Isaac         if (numFields) {
23686ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23696ecaa68aSToby Isaac             PetscInt fDof;
2370f13f9184SToby Isaac 
23719566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSec, p, f, &fDof));
23726ecaa68aSToby Isaac             offsets[f + 1] = fDof;
23736ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
23746ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
23759566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
23766ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
23776ecaa68aSToby Isaac             }
23786ecaa68aSToby Isaac           }
23796ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23806ecaa68aSToby Isaac             offsets[f + 1] += offsets[f];
23816ecaa68aSToby Isaac             offsetsCopy[f + 1] = offsets[f + 1];
23826ecaa68aSToby Isaac             newOffsets[f + 1] += newOffsets[f];
23836ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
23846ecaa68aSToby Isaac           }
23859566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, -1, NULL, rowIndices));
23866ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23876ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23889566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23899566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, -1, NULL, colIndices));
23906ecaa68aSToby Isaac           }
23919371c9d4SSatish Balay         } else {
23929566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, NULL, rowIndices));
23936ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23946ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23959566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23969566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, NULL, colIndices));
23976ecaa68aSToby Isaac           }
23986ecaa68aSToby Isaac         }
23996ecaa68aSToby Isaac         if (numFields) {
2400f13f9184SToby Isaac           PetscInt count, a;
2401f13f9184SToby Isaac 
24026ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
24036ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
24046ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
24059566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat, iSize, &rowIndices[offsets[f]], jSize, &colIndices[newOffsets[f]], &pMat[count]));
24066ecaa68aSToby Isaac             count += iSize * jSize;
240746bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
240846bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f + 1];
24096ecaa68aSToby Isaac           }
24106ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24116ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24126ecaa68aSToby Isaac             PetscInt gOff;
24139566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24149566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, -1, NULL, pInd));
24156ecaa68aSToby Isaac           }
24169371c9d4SSatish Balay         } else {
24176ecaa68aSToby Isaac           PetscInt a;
24189566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat, numRowIndices, rowIndices, numColIndices, colIndices, pMat));
24196ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24206ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24216ecaa68aSToby Isaac             PetscInt gOff;
24229566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24239566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, NULL, pInd));
24246ecaa68aSToby Isaac           }
24256ecaa68aSToby Isaac         }
24269566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
24279566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
24289371c9d4SSatish Balay       } else {
24296ecaa68aSToby Isaac         PetscInt gOff;
24306ecaa68aSToby Isaac 
24319566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
24326ecaa68aSToby Isaac         if (numFields) {
24336ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
24346ecaa68aSToby Isaac             PetscInt fDof;
24359566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
24366ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
24376ecaa68aSToby Isaac           }
24386ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
243946bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
244046bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f + 1];
24416ecaa68aSToby Isaac           }
24429566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2443367003a6SStefano Zampini         } else {
24449566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
24456ecaa68aSToby Isaac         }
24466ecaa68aSToby Isaac       }
24476ecaa68aSToby Isaac     }
24489566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
24496ecaa68aSToby Isaac   }
245046bdb399SToby Isaac   {
245146bdb399SToby Isaac     PetscSF   indicesSF, matricesSF;
245246bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
245346bdb399SToby Isaac 
24549566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
24559566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafMatricesSec));
24569566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootIndicesSec, &remoteOffsetsIndices, leafIndicesSec));
24579566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootMatricesSec, &remoteOffsetsMatrices, leafMatricesSec));
24589566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootIndicesSec, remoteOffsetsIndices, leafIndicesSec, &indicesSF));
24599566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootMatricesSec, remoteOffsetsMatrices, leafMatricesSec, &matricesSF));
24609566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
24619566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsIndices));
24629566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsMatrices));
24639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numLeafIndices));
24649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafMatricesSec, &numLeafMatrices));
24659566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numLeafIndices, &leafIndices, numLeafMatrices, &leafMatrices));
24669566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24679566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24689566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24699566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24709566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&matricesSF));
24719566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
24729566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rootIndices, rootMatrices));
24739566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootIndicesSec));
24749566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootMatricesSec));
247546bdb399SToby Isaac   }
247646bdb399SToby Isaac   /* count to preallocate */
24779566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
247846bdb399SToby Isaac   {
247946bdb399SToby Isaac     PetscInt       nGlobal;
248046bdb399SToby Isaac     PetscInt      *dnnz, *onnz;
2481b9a5774bSToby Isaac     PetscLayout    rowMap, colMap;
2482b9a5774bSToby Isaac     PetscInt       rowStart, rowEnd, colStart, colEnd;
24831c58ffc4SToby Isaac     PetscInt       maxDof;
24841c58ffc4SToby Isaac     PetscInt      *rowIndices;
24851c58ffc4SToby Isaac     DM             refTree;
24861c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
24871c58ffc4SToby Isaac     PetscScalar ***refPointFieldMats;
24881c58ffc4SToby Isaac     PetscSection   refConSec, refAnSec;
24890eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, maxConDof, maxColumns, leafStart, leafEnd;
24901c58ffc4SToby Isaac     PetscScalar   *pointWork;
249146bdb399SToby Isaac 
24929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine, &nGlobal));
24939566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nGlobal, &dnnz, nGlobal, &onnz));
24949566063dSJacob Faibussowitsch     PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
24959566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rowMap));
24969566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(colMap));
24979566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
24989566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
24999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
25009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafIndicesSec, &leafStart, &leafEnd));
25019566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
25020eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
250346bdb399SToby Isaac       PetscInt gDof, gcDof, gOff;
250446bdb399SToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
250546bdb399SToby Isaac       PetscInt matSize;
250621968bf8SToby Isaac       PetscInt i;
250746bdb399SToby Isaac 
25089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
25099566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2510ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
25119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
251208401ef6SPierre Jolivet       PetscCheck(gOff >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I though having global dofs meant a non-negative offset");
25131dca8a05SBarry Smith       PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I thought the row map would constrain the global dofs");
25149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
25159566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
251646bdb399SToby Isaac       numColIndices -= 2 * numFields;
251708401ef6SPierre Jolivet       PetscCheck(numColIndices > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "global fine dof with no dofs to interpolate from");
251846bdb399SToby Isaac       pInd              = &leafIndices[pIndOff];
251921968bf8SToby Isaac       offsets[0]        = 0;
252021968bf8SToby Isaac       offsetsCopy[0]    = 0;
252121968bf8SToby Isaac       newOffsets[0]     = 0;
252221968bf8SToby Isaac       newOffsetsCopy[0] = 0;
252346bdb399SToby Isaac       if (numFields) {
252421968bf8SToby Isaac         PetscInt f;
252546bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
252646bdb399SToby Isaac           PetscInt rowDof;
252746bdb399SToby Isaac 
25289566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
252921968bf8SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
253021968bf8SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
253121968bf8SToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
253221968bf8SToby Isaac           numD[f]            = 0;
253321968bf8SToby Isaac           numO[f]            = 0;
253446bdb399SToby Isaac         }
25359566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
253646bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
253721968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
253821968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
253946bdb399SToby Isaac 
254046bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
254146bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
254246bdb399SToby Isaac 
254346bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
254421968bf8SToby Isaac               numD[f]++;
25459371c9d4SSatish Balay             } else if (gInd >= 0) { /* negative means non-entry */
254621968bf8SToby Isaac               numO[f]++;
254746bdb399SToby Isaac             }
254846bdb399SToby Isaac           }
254946bdb399SToby Isaac         }
25509371c9d4SSatish Balay       } else {
25519566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
255221968bf8SToby Isaac         numD[0] = 0;
255321968bf8SToby Isaac         numO[0] = 0;
255446bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
255546bdb399SToby Isaac           PetscInt gInd = pInd[i];
255646bdb399SToby Isaac 
255746bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
255821968bf8SToby Isaac             numD[0]++;
25599371c9d4SSatish Balay           } else if (gInd >= 0) { /* negative means non-entry */
256021968bf8SToby Isaac             numO[0]++;
256146bdb399SToby Isaac           }
256246bdb399SToby Isaac         }
256346bdb399SToby Isaac       }
25649566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
256546bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
256646bdb399SToby Isaac         PetscInt childId;
256746bdb399SToby Isaac 
256846bdb399SToby Isaac         childId = childIds[p - pStartF];
256921968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
257046bdb399SToby Isaac           if (numFields) {
2571b9a5774bSToby Isaac             PetscInt f;
2572b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
257321968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
257446bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
257521968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
257621968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
257746bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25781dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2579b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
25809371c9d4SSatish Balay                 } else if (gIndCoarse >= 0) { /* remote */
25811dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2582b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
25839371c9d4SSatish Balay                 } else { /* constrained */
258408401ef6SPierre Jolivet                   PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
258546bdb399SToby Isaac                 }
258646bdb399SToby Isaac               }
258746bdb399SToby Isaac             }
25889371c9d4SSatish Balay           } else {
2589b9a5774bSToby Isaac             PetscInt i;
2590b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
259146bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
259246bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
259346bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25941dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2595b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
25969371c9d4SSatish Balay               } else if (gIndCoarse >= 0) { /* remote */
25971dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2598b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
25999371c9d4SSatish Balay               } else { /* constrained */
260008401ef6SPierre Jolivet                 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
260146bdb399SToby Isaac               }
260246bdb399SToby Isaac             }
260346bdb399SToby Isaac           }
26049371c9d4SSatish Balay         } else { /* interpolate from all */
260546bdb399SToby Isaac           if (numFields) {
2606b9a5774bSToby Isaac             PetscInt f;
2607b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
260821968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
260946bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
261021968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
261146bdb399SToby Isaac                 if (gIndFine >= 0) {
26121dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2613b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2614b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
261546bdb399SToby Isaac                 }
261646bdb399SToby Isaac               }
261746bdb399SToby Isaac             }
26189371c9d4SSatish Balay           } else {
2619b9a5774bSToby Isaac             PetscInt i;
2620b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
262146bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
262246bdb399SToby Isaac               if (gIndFine >= 0) {
26231dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2624b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2625b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
262646bdb399SToby Isaac               }
262746bdb399SToby Isaac             }
262846bdb399SToby Isaac           }
262946bdb399SToby Isaac         }
26309371c9d4SSatish Balay       } else { /* interpolate from all */
263146bdb399SToby Isaac         if (numFields) {
2632b9a5774bSToby Isaac           PetscInt f;
2633b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
263421968bf8SToby Isaac             PetscInt numRows = offsets[f + 1] - offsets[f], row;
263546bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
263621968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
263746bdb399SToby Isaac               if (gIndFine >= 0) {
26381dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2639b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2640b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
264146bdb399SToby Isaac               }
264246bdb399SToby Isaac             }
264346bdb399SToby Isaac           }
26449371c9d4SSatish Balay         } else { /* every dof get a full row */
2645b9a5774bSToby Isaac           PetscInt i;
2646b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
264746bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
264846bdb399SToby Isaac             if (gIndFine >= 0) {
26491dca8a05SBarry Smith               PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2650b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2651b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
265246bdb399SToby Isaac             }
265346bdb399SToby Isaac           }
265446bdb399SToby Isaac         }
265546bdb399SToby Isaac       }
265646bdb399SToby Isaac     }
26579566063dSJacob Faibussowitsch     PetscCall(MatXAIJSetPreallocation(mat, 1, dnnz, onnz, NULL, NULL));
26589566063dSJacob Faibussowitsch     PetscCall(PetscFree2(dnnz, onnz));
265921968bf8SToby Isaac 
26609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
2661d3a532e9SStefano Zampini     PetscCall(DMCopyDisc(fine, refTree));
2662d3a532e9SStefano Zampini     PetscCall(DMSetLocalSection(refTree, NULL));
2663d3a532e9SStefano Zampini     PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
26649566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
26659566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
26669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
26679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
26689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(refConSec, &maxConDof));
26699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(leafIndicesSec, &maxColumns));
26709566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxConDof * maxColumns, &pointWork));
26710eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2672e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2673e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2674e44e4e7fSToby Isaac       PetscInt matSize;
2675e44e4e7fSToby Isaac       PetscInt childId;
2676e44e4e7fSToby Isaac 
26779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
26789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2679ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
2680e44e4e7fSToby Isaac       childId = childIds[p - pStartF];
26819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
26829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
26839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2684e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2685e44e4e7fSToby Isaac       pInd              = &leafIndices[pIndOff];
2686e44e4e7fSToby Isaac       offsets[0]        = 0;
2687e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2688e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2689e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2690e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2691e44e4e7fSToby Isaac       if (numFields) {
2692e44e4e7fSToby Isaac         PetscInt f;
2693e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2694e44e4e7fSToby Isaac           PetscInt rowDof;
2695e44e4e7fSToby Isaac 
26969566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2697e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2698e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2699e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2700e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2701e44e4e7fSToby Isaac         }
27029566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
27039371c9d4SSatish Balay       } else {
27049566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
27051c58ffc4SToby Isaac       }
27069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2707e44e4e7fSToby Isaac       if (!matSize) {      /* incoming matrix is identity */
2708e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2709e44e4e7fSToby Isaac           if (numFields) {
2710e44e4e7fSToby Isaac             PetscInt f;
2711e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2712e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
271348a46eb9SPierre Jolivet               for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[offsets[f] + row], pInd[newOffsets[f] + row], 1., INSERT_VALUES));
271421968bf8SToby Isaac             }
27159371c9d4SSatish Balay           } else {
2716e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
271748a46eb9SPierre Jolivet             for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[row], pInd[row], 1., INSERT_VALUES));
2718e44e4e7fSToby Isaac           }
27199371c9d4SSatish Balay         } else { /* interpolate from all */
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];
2724e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
27259566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], refPointFieldMats[childId - pRefStart][f], INSERT_VALUES));
2726e44e4e7fSToby Isaac             }
27279371c9d4SSatish Balay           } else {
27289566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, refPointFieldMats[childId - pRefStart][0], INSERT_VALUES));
2729e44e4e7fSToby Isaac           }
2730e44e4e7fSToby Isaac         }
27319371c9d4SSatish Balay       } else { /* interpolate from all */
2732e44e4e7fSToby Isaac         PetscInt     pMatOff;
2733e44e4e7fSToby Isaac         PetscScalar *pMat;
2734e44e4e7fSToby Isaac 
27359566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafMatricesSec, p, &pMatOff));
2736e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2737e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2738e44e4e7fSToby Isaac           if (numFields) {
2739e44e4e7fSToby Isaac             PetscInt f, count;
2740e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2741e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2742e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2743e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2744e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2745e44e4e7fSToby Isaac 
27469566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], inMat, INSERT_VALUES));
2747e44e4e7fSToby Isaac               count += numCols * numInRows;
2748e44e4e7fSToby Isaac             }
27499371c9d4SSatish Balay           } else {
27509566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, pMat, INSERT_VALUES));
2751e44e4e7fSToby Isaac           }
27529371c9d4SSatish Balay         } else { /* multiply the incoming matrix by the child interpolation */
2753e44e4e7fSToby Isaac           if (numFields) {
2754e44e4e7fSToby Isaac             PetscInt f, count;
2755e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2756e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2757e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2758e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2759e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2760e44e4e7fSToby Isaac               PetscInt     i, j, k;
276108401ef6SPierre Jolivet               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2762e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2763e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2764e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2765ad540459SPierre Jolivet                   for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2766e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2767e44e4e7fSToby Isaac                 }
2768e44e4e7fSToby Isaac               }
27699566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], pointWork, INSERT_VALUES));
2770e44e4e7fSToby Isaac               count += numCols * numInRows;
2771e44e4e7fSToby Isaac             }
27729371c9d4SSatish Balay           } else { /* every dof gets a full row */
2773e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2774e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2775e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2776e44e4e7fSToby Isaac             PetscInt i, j, k;
277708401ef6SPierre Jolivet             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2778e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2779e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2780e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2781ad540459SPierre Jolivet                 for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2782e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2783e44e4e7fSToby Isaac               }
2784e44e4e7fSToby Isaac             }
27859566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, numRows, rowIndices, numCols, pInd, pointWork, INSERT_VALUES));
2786e44e4e7fSToby Isaac           }
2787e44e4e7fSToby Isaac         }
2788e44e4e7fSToby Isaac       }
2789e44e4e7fSToby Isaac     }
27909566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
27919566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
27929566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointWork));
2793e44e4e7fSToby Isaac   }
27949566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
27959566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
27969566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
27979566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafMatricesSec));
27989566063dSJacob Faibussowitsch   PetscCall(PetscFree2(leafIndices, leafMatrices));
27999566063dSJacob Faibussowitsch   PetscCall(PetscFree2(*(PetscInt ****)&perms, *(PetscScalar ****)&flips));
28009566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
28019566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
28023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28036ecaa68aSToby Isaac }
2804154bca37SToby Isaac 
28058d2f55e7SToby Isaac /*
28068d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
28078d2f55e7SToby Isaac  *
28088d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
28098d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
28108d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
28118d2f55e7SToby Isaac  *       a_{i,j} = 0;
28128d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
28138d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
28148d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
28158d2f55e7SToby Isaac  */
2816d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
2817d71ae5a4SJacob Faibussowitsch {
28188d2f55e7SToby Isaac   PetscDS      ds;
28198d2f55e7SToby Isaac   PetscSection section, cSection;
28208d2f55e7SToby Isaac   DMLabel      canonical, depth;
28218d2f55e7SToby Isaac   Mat          cMat, mat;
28228d2f55e7SToby Isaac   PetscInt    *nnz;
28238d2f55e7SToby Isaac   PetscInt     f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
28248d2f55e7SToby Isaac   PetscInt     m, n;
28258d2f55e7SToby Isaac   PetscScalar *pointScalar;
28268d2f55e7SToby Isaac   PetscReal   *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
28278d2f55e7SToby Isaac 
28288d2f55e7SToby Isaac   PetscFunctionBegin;
28299566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &section));
28309566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(refTree, &dim));
28319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(dim, &v0, dim, &v0parent, dim, &vtmp, dim * dim, &J, dim * dim, &Jparent, dim * dim, &invJ));
28329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(dim, &pointScalar, dim, &pointRef));
28339566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
28349566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
28359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numSecFields));
28369566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "canonical", &canonical));
28379566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "depth", &depth));
28389566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSection, &cMat, NULL));
28399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
28409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
28419566063dSJacob Faibussowitsch   PetscCall(MatGetSize(cMat, &n, &m)); /* the injector has transpose sizes from the constraint matrix */
28428d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
28439566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(m, &nnz));
28448d2f55e7SToby 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 */
28458d2f55e7SToby Isaac     const PetscInt *children;
28468d2f55e7SToby Isaac     PetscInt        numChildren;
28478d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28488d2f55e7SToby Isaac 
28498d2f55e7SToby Isaac     if (canonical) {
28508d2f55e7SToby Isaac       PetscInt pCanonical;
28519566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28528d2f55e7SToby Isaac       if (p != pCanonical) continue;
28538d2f55e7SToby Isaac     }
28549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28558d2f55e7SToby Isaac     if (!numChildren) continue;
28568d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28578d2f55e7SToby Isaac       PetscInt child = children[i];
28588d2f55e7SToby Isaac       PetscInt dof;
28598d2f55e7SToby Isaac 
28609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
28618d2f55e7SToby Isaac       numChildDof += dof;
28628d2f55e7SToby Isaac     }
28639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
28648d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
28658d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
28668d2f55e7SToby Isaac       PetscInt selfOff;
28678d2f55e7SToby Isaac 
28688d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
28698d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
28708d2f55e7SToby Isaac           PetscInt child = children[i];
28718d2f55e7SToby Isaac           PetscInt dof;
28728d2f55e7SToby Isaac 
28739566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
28748d2f55e7SToby Isaac           numChildDof += dof;
28758d2f55e7SToby Isaac         }
28769566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
28779566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
28789371c9d4SSatish Balay       } else {
28799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
28808d2f55e7SToby Isaac       }
2881ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) nnz[selfOff + i] = numChildDof;
28828d2f55e7SToby Isaac     }
28838d2f55e7SToby Isaac   }
28849566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(PETSC_COMM_SELF, m, n, m, n, -1, nnz, -1, NULL, &mat));
28859566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
28868d2f55e7SToby Isaac   /* Setp 2: compute entries */
28878d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
28888d2f55e7SToby Isaac     const PetscInt *children;
28898d2f55e7SToby Isaac     PetscInt        numChildren;
28908d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28918d2f55e7SToby Isaac 
28928d2f55e7SToby Isaac     /* same conditions about when entries occur */
28938d2f55e7SToby Isaac     if (canonical) {
28948d2f55e7SToby Isaac       PetscInt pCanonical;
28959566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28968d2f55e7SToby Isaac       if (p != pCanonical) continue;
28978d2f55e7SToby Isaac     }
28989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28998d2f55e7SToby Isaac     if (!numChildren) continue;
29008d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
29018d2f55e7SToby Isaac       PetscInt child = children[i];
29028d2f55e7SToby Isaac       PetscInt dof;
29038d2f55e7SToby Isaac 
29049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
29058d2f55e7SToby Isaac       numChildDof += dof;
29068d2f55e7SToby Isaac     }
29079566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
29088d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
29098d2f55e7SToby Isaac 
29108d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
291159fc6756SToby Isaac       PetscInt        pI = -1, cI = -1;
291252a3aeb4SToby Isaac       PetscInt        selfOff, Nc, parentCell;
29138d2f55e7SToby Isaac       PetscInt        cellShapeOff;
29148d2f55e7SToby Isaac       PetscObject     disc;
29158d2f55e7SToby Isaac       PetscDualSpace  dsp;
29168d2f55e7SToby Isaac       PetscClassId    classId;
29178d2f55e7SToby Isaac       PetscScalar    *pointMat;
29183b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
29198d2f55e7SToby Isaac       PetscInt        pO = PETSC_MIN_INT;
29208d2f55e7SToby Isaac       const PetscInt *depthNumDof;
29218d2f55e7SToby Isaac 
29228d2f55e7SToby Isaac       if (numSecFields) {
29238d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
29248d2f55e7SToby Isaac           PetscInt child = children[i];
29258d2f55e7SToby Isaac           PetscInt dof;
29268d2f55e7SToby Isaac 
29279566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
29288d2f55e7SToby Isaac           numChildDof += dof;
29298d2f55e7SToby Isaac         }
29309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
29319566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
29329371c9d4SSatish Balay       } else {
29339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
29348d2f55e7SToby Isaac       }
29358d2f55e7SToby Isaac 
29363b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
29378d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
29388d2f55e7SToby Isaac         parentCell = p;
29399371c9d4SSatish Balay       } else {
29408d2f55e7SToby Isaac         PetscInt *star = NULL;
29418d2f55e7SToby Isaac         PetscInt  numStar;
29428d2f55e7SToby Isaac 
29438d2f55e7SToby Isaac         parentCell = -1;
29449566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29458d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
29468d2f55e7SToby Isaac           PetscInt c = star[2 * i];
29478d2f55e7SToby Isaac 
29488d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
29498d2f55e7SToby Isaac             parentCell = c;
29508d2f55e7SToby Isaac             break;
29518d2f55e7SToby Isaac           }
29528d2f55e7SToby Isaac         }
29539566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29548d2f55e7SToby Isaac       }
2955a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
29569566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
29579566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc, &classId));
2958c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
29599566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
29609371c9d4SSatish Balay       } else if (classId == PETSCFV_CLASSID) {
29619566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace((PetscFV)disc, &dsp));
29629371c9d4SSatish Balay       } else {
29639b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported discretization object");
2964c5356c36SToby Isaac       }
29659566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumDof(dsp, &depthNumDof));
29669566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumComponents(dsp, &Nc));
29678d2f55e7SToby Isaac       {
29688d2f55e7SToby Isaac         PetscInt *closure = NULL;
29698d2f55e7SToby Isaac         PetscInt  numClosure;
29708d2f55e7SToby Isaac 
29719566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
297259fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
29738d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
29748d2f55e7SToby Isaac 
29758d2f55e7SToby Isaac           pO = closure[2 * i + 1];
297659fc6756SToby Isaac           if (point == p) {
297759fc6756SToby Isaac             pI = i;
297859fc6756SToby Isaac             break;
297959fc6756SToby Isaac           }
29809566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(depth, point, &pointDepth));
29818d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
29828d2f55e7SToby Isaac         }
29839566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
29848d2f55e7SToby Isaac       }
29858d2f55e7SToby Isaac 
29869566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
29879566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
298852a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
2989ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) matRows[i] = selfOff + i;
299052a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
29913b1c2a6aSToby Isaac       {
29923b1c2a6aSToby Isaac         PetscInt colOff = 0;
29933b1c2a6aSToby Isaac 
29943b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
29953b1c2a6aSToby Isaac           PetscInt child = children[i];
29963b1c2a6aSToby Isaac           PetscInt dof, off, j;
29973b1c2a6aSToby Isaac 
29983b1c2a6aSToby Isaac           if (numSecFields) {
29999566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSection, child, f, &dof));
30009566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(cSection, child, f, &off));
30019371c9d4SSatish Balay           } else {
30029566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(cSection, child, &dof));
30039566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(cSection, child, &off));
30043b1c2a6aSToby Isaac           }
30053b1c2a6aSToby Isaac 
3006ad540459SPierre Jolivet           for (j = 0; j < dof; j++) matCols[colOff++] = off + j;
30073b1c2a6aSToby Isaac         }
30083b1c2a6aSToby Isaac       }
30098d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
30108d2f55e7SToby Isaac         PetscFE              fe = (PetscFE)disc;
30118d2f55e7SToby Isaac         PetscInt             fSize;
301259fc6756SToby Isaac         const PetscInt    ***perms;
301359fc6756SToby Isaac         const PetscScalar ***flips;
301459fc6756SToby Isaac         const PetscInt      *pperms;
301559fc6756SToby Isaac 
30169566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &dsp));
30179566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetDimension(dsp, &fSize));
30189566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
301959fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
302052a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
30218d2f55e7SToby Isaac           PetscQuadrature  q;
302252a3aeb4SToby Isaac           PetscInt         dim, thisNc, numPoints, j, k;
30238d2f55e7SToby Isaac           const PetscReal *points;
30248d2f55e7SToby Isaac           const PetscReal *weights;
30258d2f55e7SToby Isaac           PetscInt        *closure = NULL;
30268d2f55e7SToby Isaac           PetscInt         numClosure;
302759fc6756SToby Isaac           PetscInt         iCell              = pperms ? pperms[i] : i;
302859fc6756SToby Isaac           PetscInt         parentCellShapeDof = cellShapeOff + iCell;
3029ef0bb6c7SMatthew G. Knepley           PetscTabulation  Tparent;
30308d2f55e7SToby Isaac 
30319566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(dsp, parentCellShapeDof, &q));
30329566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(q, &dim, &thisNc, &numPoints, &points, &weights));
303363a3b9bcSJacob Faibussowitsch           PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
30349566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe, 1, numPoints, points, 0, &Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
30353b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
30368d2f55e7SToby Isaac             PetscInt           childCell = -1;
303752a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3038c330f8ffSToby Isaac             const PetscReal    xi0[3]    = {-1., -1., -1.};
30398d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
30408d2f55e7SToby Isaac             const PetscScalar *point;
3041ef0bb6c7SMatthew G. Knepley             PetscTabulation    Tchild;
30428d2f55e7SToby Isaac             PetscInt           childCellShapeOff, pointMatOff;
30438d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
30448d2f55e7SToby Isaac             PetscInt d;
30458d2f55e7SToby Isaac 
3046ad540459SPierre Jolivet             for (d = 0; d < dim; d++) pointScalar[d] = points[dim * j + d];
30478d2f55e7SToby Isaac             point = pointScalar;
30488d2f55e7SToby Isaac #else
30498d2f55e7SToby Isaac             point = pointReal;
30508d2f55e7SToby Isaac #endif
30518d2f55e7SToby Isaac 
3052ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
30533b1c2a6aSToby Isaac 
30543b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
30558d2f55e7SToby Isaac               PetscInt  child = children[k];
30568d2f55e7SToby Isaac               PetscInt *star  = NULL;
30578d2f55e7SToby Isaac               PetscInt  numStar, s;
30588d2f55e7SToby Isaac 
30599566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30608d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
30618d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
30628d2f55e7SToby Isaac 
30638d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
30649566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(refTree, dim, point, c, &childCell));
30658d2f55e7SToby Isaac                 if (childCell >= 0) break;
30668d2f55e7SToby Isaac               }
30679566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30688d2f55e7SToby Isaac               if (childCell >= 0) break;
30698d2f55e7SToby Isaac             }
307008401ef6SPierre Jolivet             PetscCheck(childCell >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not locate quadrature point");
30719566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
30729566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3073c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3074c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
30758d2f55e7SToby Isaac 
30769566063dSJacob Faibussowitsch             PetscCall(PetscFECreateTabulation(fe, 1, 1, pointRef, 0, &Tchild));
30779566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
30783b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3079c5356c36SToby Isaac               PetscInt        child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
30808d2f55e7SToby Isaac               PetscInt        l;
308159fc6756SToby Isaac               const PetscInt *cperms;
30828d2f55e7SToby Isaac 
30839566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(depth, child, &childDepth));
30848d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
308559fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
30868d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
30878d2f55e7SToby Isaac                 PetscInt pointDepth;
30888d2f55e7SToby Isaac 
30898d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
309059fc6756SToby Isaac                 if (point == child) {
309159fc6756SToby Isaac                   cI = l;
309259fc6756SToby Isaac                   break;
309359fc6756SToby Isaac                 }
30949566063dSJacob Faibussowitsch                 PetscCall(DMLabelGetValue(depth, point, &pointDepth));
30958d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
30968d2f55e7SToby Isaac               }
30978d2f55e7SToby Isaac               if (l == numClosure) {
30988d2f55e7SToby Isaac                 pointMatOff += childDof;
30998d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
31008d2f55e7SToby Isaac               }
310159fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
31028d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
310359fc6756SToby Isaac                 PetscInt   lCell        = cperms ? cperms[l] : l;
310459fc6756SToby Isaac                 PetscInt   childCellDof = childCellShapeOff + lCell;
310552a3aeb4SToby Isaac                 PetscReal *childValAtPoint;
310652a3aeb4SToby Isaac                 PetscReal  val = 0.;
31078d2f55e7SToby Isaac 
3108ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
3109ad540459SPierre Jolivet                 for (m = 0; m < Nc; m++) val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
311052a3aeb4SToby Isaac 
311152a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
31128d2f55e7SToby Isaac               }
31138d2f55e7SToby Isaac               pointMatOff += childDof;
31148d2f55e7SToby Isaac             }
31159566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
31169566063dSJacob Faibussowitsch             PetscCall(PetscTabulationDestroy(&Tchild));
31178d2f55e7SToby Isaac           }
31189566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&Tparent));
31198d2f55e7SToby Isaac         }
31209371c9d4SSatish Balay       } else { /* just the volume-weighted averages of the children */
31213b1c2a6aSToby Isaac         PetscReal parentVol;
3122bfaa5bdcSToby Isaac         PetscInt  childCell;
31233b1c2a6aSToby Isaac 
31249566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3125bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
312652a3aeb4SToby Isaac           PetscInt  child = children[i], j;
31273b1c2a6aSToby Isaac           PetscReal childVol;
31283b1c2a6aSToby Isaac 
31293b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
31309566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
3131ad540459SPierre Jolivet           for (j = 0; j < Nc; j++) pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
3132bfaa5bdcSToby Isaac           childCell++;
31333b1c2a6aSToby Isaac         }
31348d2f55e7SToby Isaac       }
31353b1c2a6aSToby Isaac       /* Insert pointMat into mat */
31369566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, numSelfDof, matRows, numChildDof, matCols, pointMat, INSERT_VALUES));
31379566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
31389566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
31398d2f55e7SToby Isaac     }
31408d2f55e7SToby Isaac   }
31419566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJ));
31429566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointScalar, pointRef));
31439566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
31449566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
31458d2f55e7SToby Isaac   *inj = mat;
31463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31478d2f55e7SToby Isaac }
31488d2f55e7SToby Isaac 
3149d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3150d71ae5a4SJacob Faibussowitsch {
3151f30e825dSToby Isaac   PetscDS        ds;
3152f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3153f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3154f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3155f30e825dSToby Isaac 
3156f30e825dSToby Isaac   PetscFunctionBegin;
31579566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
31589566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
31599566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
31609566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
31619566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
31629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
31639566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
31649566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
31659566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof, &cols));
3166f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3167f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3168f30e825dSToby Isaac 
31699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
31709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
31719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3172f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3173f30e825dSToby Isaac 
31749566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFields, &refPointFieldMats[p - pRefStart]));
3175f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
317652a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3177f30e825dSToby Isaac 
3178f30e825dSToby Isaac       if (numFields > 1) {
31799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
31809566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
31819371c9d4SSatish Balay       } else {
31829566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
31839566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
3184f30e825dSToby Isaac       }
3185f30e825dSToby Isaac 
3186ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
3187f30e825dSToby Isaac       numCols = 0;
3188f30e825dSToby Isaac       {
3189f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3190f30e825dSToby Isaac 
3191f30e825dSToby Isaac         if (numFields > 1) {
31929566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, parent, f, &aDof));
31939566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, parent, f, &aOff));
31949371c9d4SSatish Balay         } else {
31959566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, parent, &aDof));
31969566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, parent, &aOff));
3197f30e825dSToby Isaac         }
3198f30e825dSToby Isaac 
3199ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + j;
3200f30e825dSToby Isaac       }
32019566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
3202f30e825dSToby Isaac       /* transpose of constraint matrix */
32039566063dSJacob Faibussowitsch       PetscCall(MatGetValues(inj, numCols, cols, cDof, rows, refPointFieldMats[p - pRefStart][f]));
3204f30e825dSToby Isaac     }
3205f30e825dSToby Isaac   }
3206f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
32079566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
32089566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
32093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3210f30e825dSToby Isaac }
3211f30e825dSToby Isaac 
3212d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3213d71ae5a4SJacob Faibussowitsch {
3214f30e825dSToby Isaac   PetscDS        ds;
3215f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3216f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3217c6154584SToby Isaac   PetscSection   refConSec, refSection;
3218f30e825dSToby Isaac 
3219f30e825dSToby Isaac   PetscFunctionBegin;
3220f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3221f30e825dSToby Isaac   *childrenMats     = NULL;
32229566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
32239566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
32249566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
32259566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
32269566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3227f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3228f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3229f30e825dSToby Isaac 
32309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
32319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
32329566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3233f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3234f30e825dSToby Isaac 
3235f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3236f30e825dSToby Isaac       PetscInt cDof;
3237f30e825dSToby Isaac 
3238f30e825dSToby Isaac       if (numFields > 1) {
32399566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
32409371c9d4SSatish Balay       } else {
32419566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3242f30e825dSToby Isaac       }
3243f30e825dSToby Isaac 
32449566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3245f30e825dSToby Isaac     }
32469566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3247f30e825dSToby Isaac   }
32489566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
32493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3250f30e825dSToby Isaac }
3251f30e825dSToby Isaac 
3252d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree, Mat *injRef)
3253d71ae5a4SJacob Faibussowitsch {
3254ebf164c7SToby Isaac   Mat         cMatRef;
32556148253fSToby Isaac   PetscObject injRefObj;
32568d2f55e7SToby Isaac 
3257154bca37SToby Isaac   PetscFunctionBegin;
32589566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, NULL, &cMatRef, NULL));
32599566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", &injRefObj));
3260ebf164c7SToby Isaac   *injRef = (Mat)injRefObj;
3261ebf164c7SToby Isaac   if (!*injRef) {
32629566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorReferenceTree(refTree, injRef));
32639566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", (PetscObject)*injRef));
3264ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
32659566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3266ebf164c7SToby Isaac   }
32673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32686148253fSToby Isaac }
3269f30e825dSToby Isaac 
3270d71ae5a4SJacob 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)
3271d71ae5a4SJacob Faibussowitsch {
3272c921d74cSToby Isaac   PetscInt        pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3273ebf164c7SToby Isaac   PetscSection    globalCoarse, globalFine;
3274ebf164c7SToby Isaac   PetscSection    localCoarse, localFine, leafIndicesSec;
3275c921d74cSToby Isaac   PetscSection    multiRootSec, rootIndicesSec;
3276c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3277c921d74cSToby Isaac   const PetscInt *rootDegrees;
3278c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3279ebf164c7SToby Isaac   PetscSF         coarseToFineEmbedded;
3280ebf164c7SToby Isaac 
3281ebf164c7SToby Isaac   PetscFunctionBegin;
32829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
32839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
32849566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
32859566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
32869566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
32879566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafIndicesSec, pStartF, pEndF));
32889566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
32898d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
32907e96bdafSToby Isaac     PetscInt        l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
32917e96bdafSToby Isaac     const PetscInt *leaves;
32928d2f55e7SToby Isaac 
32939566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
32947e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
32957e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
32969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
32979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
32988d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
32998d2f55e7SToby Isaac         numPointsWithDofs++;
3300f30e825dSToby Isaac 
33019566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localFine, p, &dof));
33029566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafIndicesSec, p, dof + 1));
33038d2f55e7SToby Isaac       }
33048d2f55e7SToby Isaac     }
33059566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
33069566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafIndicesSec));
33079566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numIndices));
33089566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1), &leafInds));
33099566063dSJacob Faibussowitsch     if (gatheredValues) PetscCall(PetscMalloc1(numIndices, &leafVals));
33107e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
33117e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
33129566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
33139566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
33148d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3315f30e825dSToby Isaac         PetscInt     off, gOff;
3316f30e825dSToby Isaac         PetscInt    *pInd;
3317c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3318f30e825dSToby Isaac 
33197e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3320f30e825dSToby Isaac 
33219566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3322f30e825dSToby Isaac 
3323c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3324c921d74cSToby Isaac         if (gatheredValues) {
3325c921d74cSToby Isaac           PetscInt i;
3326c921d74cSToby Isaac 
3327c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3328c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3329c921d74cSToby Isaac         }
33309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
3331f30e825dSToby Isaac 
3332f30e825dSToby Isaac         offsets[0] = 0;
3333f30e825dSToby Isaac         if (numFields) {
3334f30e825dSToby Isaac           PetscInt f;
3335f30e825dSToby Isaac 
3336f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3337f30e825dSToby Isaac             PetscInt fDof;
33389566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localFine, p, f, &fDof));
3339f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3340f30e825dSToby Isaac           }
33419566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
3342367003a6SStefano Zampini         } else {
33439566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
3344f30e825dSToby Isaac         }
33459566063dSJacob Faibussowitsch         if (gatheredValues) PetscCall(VecGetValues(fineVec, dof, pInd, pVal));
33468d2f55e7SToby Isaac       }
33478d2f55e7SToby Isaac     }
33489566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
33499566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
33508d2f55e7SToby Isaac   }
3351f30e825dSToby Isaac 
33529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
33539566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
33549566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3355f30e825dSToby Isaac 
33566148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
33576148253fSToby Isaac     MPI_Datatype threeInt;
33586148253fSToby Isaac     PetscMPIInt  rank;
33596148253fSToby Isaac     PetscInt(*parentNodeAndIdCoarse)[3];
33606148253fSToby Isaac     PetscInt(*parentNodeAndIdFine)[3];
33616148253fSToby Isaac     PetscInt           p, nleaves, nleavesToParents;
33626148253fSToby Isaac     PetscSF            pointSF, sfToParents;
33636148253fSToby Isaac     const PetscInt    *ilocal;
33646148253fSToby Isaac     const PetscSFNode *iremote;
33656148253fSToby Isaac     PetscSFNode       *iremoteToParents;
33666148253fSToby Isaac     PetscInt          *ilocalToParents;
33676148253fSToby Isaac 
33689566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse), &rank));
33699566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &threeInt));
33709566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&threeInt));
33719566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEndC - pStartC, &parentNodeAndIdCoarse, pEndF - pStartF, &parentNodeAndIdFine));
33729566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(coarse, &pointSF));
33739566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, &iremote));
33746148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
33756148253fSToby Isaac       PetscInt parent, childId;
33769566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(coarse, p, &parent, &childId));
33776148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
33786148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
33796148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
33806148253fSToby Isaac       if (nleaves > 0) {
33816148253fSToby Isaac         PetscInt leaf = -1;
33826148253fSToby Isaac 
33836148253fSToby Isaac         if (ilocal) {
33849566063dSJacob Faibussowitsch           PetscCall(PetscFindInt(parent, nleaves, ilocal, &leaf));
33859371c9d4SSatish Balay         } else {
33866148253fSToby Isaac           leaf = p - pStartC;
33876148253fSToby Isaac         }
33886148253fSToby Isaac         if (leaf >= 0) {
33896148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
33906148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
33916148253fSToby Isaac         }
33926148253fSToby Isaac       }
33936148253fSToby Isaac     }
33946148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
33956148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
33966148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
33976148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
33986148253fSToby Isaac     }
33999566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
34009566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
34016148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3402f30e825dSToby Isaac       PetscInt dof;
3403f30e825dSToby Isaac 
34049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &dof));
3405f30e825dSToby Isaac       if (dof) {
3406f30e825dSToby Isaac         PetscInt off;
3407f30e825dSToby Isaac 
34089566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3409c921d74cSToby Isaac         if (gatheredIndices) {
3410c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3411c921d74cSToby Isaac         } else if (gatheredValues) {
3412c921d74cSToby Isaac           leafVals[off] = (PetscScalar)PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3413c921d74cSToby Isaac         }
3414f30e825dSToby Isaac       }
3415ad540459SPierre Jolivet       if (parentNodeAndIdFine[p - pStartF][0] >= 0) nleavesToParents++;
34166148253fSToby Isaac     }
34179566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &ilocalToParents));
34189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &iremoteToParents));
34196148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
34206148253fSToby Isaac       if (parentNodeAndIdFine[p - pStartF][0] >= 0) {
34216148253fSToby Isaac         ilocalToParents[nleavesToParents]        = p - pStartF;
34226148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p - pStartF][0];
34236148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p - pStartF][1];
34246148253fSToby Isaac         nleavesToParents++;
34256148253fSToby Isaac       }
34266148253fSToby Isaac     }
34279566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse), &sfToParents));
34289566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(sfToParents, pEndC - pStartC, nleavesToParents, ilocalToParents, PETSC_OWN_POINTER, iremoteToParents, PETSC_OWN_POINTER));
34299566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34306148253fSToby Isaac 
34316148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
34326148253fSToby Isaac 
34339566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parentNodeAndIdCoarse, parentNodeAndIdFine));
34349566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&threeInt));
34356148253fSToby Isaac   }
3436f30e825dSToby Isaac 
34376148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
34386148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
34396148253fSToby Isaac     PetscSF  sfDofsOnly;
34406148253fSToby Isaac 
34416148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
34429566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34439566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3444ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
34456148253fSToby Isaac     }
34469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
34476148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
34489566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34499566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3450ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = p - pStartC;
34516148253fSToby Isaac     }
34529566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
34539566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34549566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
34556148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
34566148253fSToby Isaac   }
3457f30e825dSToby Isaac 
34586148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
34599566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded, &rootDegrees));
34609566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded, &rootDegrees));
34619566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &multiRootSec));
34629566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(multiRootSec, pStartC, pEndC));
346348a46eb9SPierre Jolivet   for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionSetDof(multiRootSec, p, rootDegrees[p - pStartC]));
34649566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(multiRootSec));
34659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(multiRootSec, &numMulti));
34669566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
3467f30e825dSToby Isaac   { /* distribute the leaf section */
3468f30e825dSToby Isaac     PetscSF   multi, multiInv, indicesSF;
3469f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
34708d2f55e7SToby Isaac 
34719566063dSJacob Faibussowitsch     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded, &multi));
34729566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF(multi, &multiInv));
34739566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(multiInv, leafIndicesSec, &remoteOffsets, rootIndicesSec));
34749566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(multiInv, leafIndicesSec, remoteOffsets, rootIndicesSec, &indicesSF));
34759566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
34769566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&multiInv));
34779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
3478c921d74cSToby Isaac     if (gatheredIndices) {
34799566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootInds));
34809566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
34819566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3482c921d74cSToby Isaac     }
3483c921d74cSToby Isaac     if (gatheredValues) {
34849566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootVals));
34859566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
34869566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3487c921d74cSToby Isaac     }
34889566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
34898d2f55e7SToby Isaac   }
34909566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
34919566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafInds));
34929566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafVals));
34939566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3494c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3495c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3496c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3497c921d74cSToby Isaac   if (gatheredValues) *gatheredValues = rootVals;
34983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3499ebf164c7SToby Isaac }
3500ebf164c7SToby Isaac 
3501d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3502d71ae5a4SJacob Faibussowitsch {
3503ebf164c7SToby Isaac   DM             refTree;
3504c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3505ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3506ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3507ebf164c7SToby Isaac   PetscSection   cSecRef;
3508277f51e8SBarry Smith   PetscInt      *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3509ebf164c7SToby Isaac   Mat            injRef;
3510c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3511ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3512ebf164c7SToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
3513ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3514ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3515ebf164c7SToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3516ebf164c7SToby Isaac 
3517ebf164c7SToby Isaac   PetscFunctionBegin;
3518ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
35199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
3520d3a532e9SStefano Zampini   PetscCall(DMCopyDisc(coarse, refTree));
3521d3a532e9SStefano Zampini   PetscCall(DMSetLocalSection(refTree, NULL));
3522d3a532e9SStefano Zampini   PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
35239566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
35249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
35259566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
3526ebf164c7SToby Isaac 
35279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
35289566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
35299566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
35309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
35319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
35329566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
35339566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
35349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
3535ebf164c7SToby Isaac   {
3536ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
35379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
3538ebf164c7SToby Isaac   }
3539ebf164c7SToby Isaac 
35409566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, childIds, NULL, numFields, offsets, &multiRootSec, &rootIndicesSec, &rootIndices, NULL));
35418d2f55e7SToby Isaac 
35429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &parentIndices));
3543f30e825dSToby Isaac 
3544f30e825dSToby Isaac   /* count indices */
35459566063dSJacob Faibussowitsch   PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
35469566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
35479566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
35489566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
35499566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
35509566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(rowEnd - rowStart, &nnzD, rowEnd - rowStart, &nnzO));
3551f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3552f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
35538d2f55e7SToby Isaac 
35549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
35559566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3556f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
35579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
35588d2f55e7SToby Isaac 
35598d2f55e7SToby Isaac     rowOffsets[0]  = 0;
3560f30e825dSToby Isaac     offsetsCopy[0] = 0;
35618d2f55e7SToby Isaac     if (numFields) {
35628d2f55e7SToby Isaac       PetscInt f;
35638d2f55e7SToby Isaac 
3564f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3565f30e825dSToby Isaac         PetscInt fDof;
35669566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3567f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
35688d2f55e7SToby Isaac       }
35699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3570367003a6SStefano Zampini     } else {
35719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3572f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
35738d2f55e7SToby Isaac     }
3574f30e825dSToby Isaac 
35759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
35769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3577f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3578f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3579f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3580f30e825dSToby Isaac       const PetscInt *childIndices;
3581f30e825dSToby Isaac 
35829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
35839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3584f30e825dSToby Isaac       childId      = rootIndices[offset++];
3585f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3586f30e825dSToby Isaac       numIndices--;
3587f30e825dSToby Isaac 
3588f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3589f30e825dSToby Isaac         PetscInt i;
3590f30e825dSToby Isaac 
3591f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3592f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3593f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3594f30e825dSToby Isaac           if (rowIndex < 0) continue;
359508401ef6SPierre Jolivet           PetscCheck(colIndex >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unconstrained fine and constrained coarse");
3596a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3597f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
35989371c9d4SSatish Balay           } else {
3599f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3600f30e825dSToby Isaac           }
3601f30e825dSToby Isaac         }
36029371c9d4SSatish Balay       } else {
3603f30e825dSToby Isaac         PetscInt parentId, f, lim;
3604f30e825dSToby Isaac 
36059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3606f30e825dSToby Isaac 
3607f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3608f30e825dSToby Isaac         offsets[0] = 0;
36098d2f55e7SToby Isaac         if (numFields) {
36108d2f55e7SToby Isaac           PetscInt f;
3611f30e825dSToby Isaac 
36128d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3613f30e825dSToby Isaac             PetscInt fDof;
36149566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3615f30e825dSToby Isaac 
3616f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
36178d2f55e7SToby Isaac           }
36189371c9d4SSatish Balay         } else {
3619f30e825dSToby Isaac           PetscInt cDof;
3620f30e825dSToby Isaac 
36219566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3622f30e825dSToby Isaac           offsets[1] = cDof;
3623f30e825dSToby Isaac         }
3624f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3625f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3626f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3627f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3628f30e825dSToby Isaac 
3629f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3630f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3631f30e825dSToby Isaac 
3632f30e825dSToby Isaac             if (colIndex < 0) continue;
3633f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3634f30e825dSToby Isaac               numD++;
36359371c9d4SSatish Balay             } else {
3636f30e825dSToby Isaac               numO++;
3637f30e825dSToby Isaac             }
3638f30e825dSToby Isaac           }
3639f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3640f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3641f30e825dSToby Isaac 
3642f30e825dSToby Isaac             if (rowIndex < 0) continue;
3643f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3644f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
36458d2f55e7SToby Isaac           }
36468d2f55e7SToby Isaac         }
36478d2f55e7SToby Isaac       }
3648f30e825dSToby Isaac     }
3649f30e825dSToby Isaac   }
3650f30e825dSToby Isaac   /* preallocate */
36519566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mat, 1, nnzD, nnzO, NULL, NULL));
36529566063dSJacob Faibussowitsch   PetscCall(PetscFree2(nnzD, nnzO));
3653f30e825dSToby Isaac   /* insert values */
36549566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3655f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3656f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3657f30e825dSToby Isaac 
36589566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
36599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3660f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
36619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
3662f30e825dSToby Isaac 
3663f30e825dSToby Isaac     rowOffsets[0]  = 0;
3664f30e825dSToby Isaac     offsetsCopy[0] = 0;
36658d2f55e7SToby Isaac     if (numFields) {
36668d2f55e7SToby Isaac       PetscInt f;
3667f30e825dSToby Isaac 
36688d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3669f30e825dSToby Isaac         PetscInt fDof;
36709566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3671f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3672f30e825dSToby Isaac       }
36739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3674367003a6SStefano Zampini     } else {
36759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3676f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3677f30e825dSToby Isaac     }
3678f30e825dSToby Isaac 
36799566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
36809566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3681f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3682f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3683f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3684f30e825dSToby Isaac       const PetscInt *childIndices;
3685f30e825dSToby Isaac 
36869566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
36879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3688f30e825dSToby Isaac       childId      = rootIndices[offset++];
3689f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3690f30e825dSToby Isaac       numIndices--;
3691f30e825dSToby Isaac 
3692f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3693f30e825dSToby Isaac         PetscInt i;
3694f30e825dSToby Isaac 
369548a46eb9SPierre Jolivet         for (i = 0; i < numIndices; i++) PetscCall(MatSetValue(mat, parentIndices[i], childIndices[i], 1., INSERT_VALUES));
36969371c9d4SSatish Balay       } else {
3697f30e825dSToby Isaac         PetscInt parentId, f, lim;
36988d2f55e7SToby Isaac 
36999566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3700f30e825dSToby Isaac 
3701f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3702f30e825dSToby Isaac         offsets[0] = 0;
37038d2f55e7SToby Isaac         if (numFields) {
3704f30e825dSToby Isaac           PetscInt f;
37058d2f55e7SToby Isaac 
3706f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3707f30e825dSToby Isaac             PetscInt fDof;
37089566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3709f30e825dSToby Isaac 
3710f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
37118d2f55e7SToby Isaac           }
37129371c9d4SSatish Balay         } else {
3713f30e825dSToby Isaac           PetscInt cDof;
3714f30e825dSToby Isaac 
37159566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3716f30e825dSToby Isaac           offsets[1] = cDof;
37178d2f55e7SToby Isaac         }
3718f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3719f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3720f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3721f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3722f30e825dSToby Isaac 
37239566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat, rowOffsets[f + 1] - rowOffsets[f], rowIndices, offsets[f + 1] - offsets[f], colIndices, childMat, INSERT_VALUES));
37248d2f55e7SToby Isaac         }
37258d2f55e7SToby Isaac       }
37268d2f55e7SToby Isaac     }
37278d2f55e7SToby Isaac   }
37289566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
37299566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
37309566063dSJacob Faibussowitsch   PetscCall(PetscFree(parentIndices));
37319566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
37329566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootIndices));
37339566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
3734f30e825dSToby Isaac 
37359566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
37369566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
37373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3738154bca37SToby Isaac }
373938fc2455SToby Isaac 
3740d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3741d71ae5a4SJacob Faibussowitsch {
374262095d54SToby Isaac   PetscSF            coarseToFineEmbedded;
374362095d54SToby Isaac   PetscSection       globalCoarse, globalFine;
374462095d54SToby Isaac   PetscSection       localCoarse, localFine;
374562095d54SToby Isaac   PetscSection       aSec, cSec;
374662095d54SToby Isaac   PetscSection       rootValuesSec;
374762095d54SToby Isaac   PetscSection       leafValuesSec;
374862095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
374962095d54SToby Isaac   IS                 aIS;
375062095d54SToby Isaac   const PetscInt    *anchors;
375162095d54SToby Isaac   Mat                cMat;
375262095d54SToby Isaac   PetscInt           numFields;
3753412e9a14SMatthew G. Knepley   PetscInt           pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
375462095d54SToby Isaac   PetscInt           aStart, aEnd, cStart, cEnd;
375562095d54SToby Isaac   PetscInt          *maxChildIds;
375662095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
37570eb7e1eaSToby Isaac   PetscFV            fv = NULL;
37580eb7e1eaSToby Isaac   PetscInt           dim, numFVcomps = -1, fvField = -1;
37590eb7e1eaSToby Isaac   DM                 cellDM = NULL, gradDM = NULL;
37600eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
37610eb7e1eaSToby Isaac   const PetscScalar *gradArray     = NULL;
376262095d54SToby Isaac 
3763ebf164c7SToby Isaac   PetscFunctionBegin;
37649566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
37659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
37669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(coarse, 0, &cellStart, &cellEnd));
37679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
37689566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
37699566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(coarse, &dim));
377062095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3771e4a60869SToby Isaac     PetscInt        nleaves, l;
3772e4a60869SToby Isaac     const PetscInt *leaves;
377362095d54SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
377462095d54SToby Isaac 
37759566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
3776e4a60869SToby Isaac 
3777e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3778e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3779e4a60869SToby Isaac 
37809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3782ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
378362095d54SToby Isaac     }
37849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
37854833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
3786e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3787e4a60869SToby Isaac 
37889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3790ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
379162095d54SToby Isaac     }
37929566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
37939566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
379462095d54SToby Isaac   }
379562095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
37969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
3797ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
37989566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
37999566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
380062095d54SToby Isaac 
38019566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
38029566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
380362095d54SToby Isaac 
38049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
38059566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
38069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
380762095d54SToby Isaac 
38089566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
38099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
381062095d54SToby Isaac 
381162095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
38129566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootValuesSec));
38139566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootValuesSec, pStartC, pEndC));
38149566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
381562095d54SToby Isaac   {
381662095d54SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
38179566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &newOffsets, maxFields, &newOffsetsCopy, maxFields, &rowOffsets, maxFields, &numD, maxFields, &numO));
381862095d54SToby Isaac   }
38190eb7e1eaSToby Isaac   if (grad) {
38200eb7e1eaSToby Isaac     PetscInt i;
38210eb7e1eaSToby Isaac 
38229566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeom, &cellDM));
38239566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeom, &cellGeomArray));
38249566063dSJacob Faibussowitsch     PetscCall(VecGetDM(grad, &gradDM));
38259566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(grad, &gradArray));
38260eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1, numFields); i++) {
38270eb7e1eaSToby Isaac       PetscObject  obj;
38280eb7e1eaSToby Isaac       PetscClassId id;
38290eb7e1eaSToby Isaac 
38309566063dSJacob Faibussowitsch       PetscCall(DMGetField(coarse, i, NULL, &obj));
38319566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
38320eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
38330eb7e1eaSToby Isaac         fv = (PetscFV)obj;
38349566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &numFVcomps));
38350eb7e1eaSToby Isaac         fvField = i;
38360eb7e1eaSToby Isaac         break;
38370eb7e1eaSToby Isaac       }
38380eb7e1eaSToby Isaac     }
38390eb7e1eaSToby Isaac   }
384062095d54SToby Isaac 
384162095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
384262095d54SToby Isaac     PetscInt dof;
384362095d54SToby Isaac     PetscInt maxChildId = maxChildIds[p - pStartC];
384462095d54SToby Isaac     PetscInt numValues  = 0;
384562095d54SToby Isaac 
38469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3847ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
384862095d54SToby Isaac     offsets[0]    = 0;
384962095d54SToby Isaac     newOffsets[0] = 0;
385062095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
385162095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
385262095d54SToby Isaac 
38539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
385462095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
385562095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
385662095d54SToby Isaac 
38579566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
385862095d54SToby Isaac         numValues += clDof;
385962095d54SToby Isaac       }
38609566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
38619371c9d4SSatish Balay     } else if (maxChildId == -1) {
38629566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localCoarse, p, &numValues));
386362095d54SToby Isaac     }
386462095d54SToby Isaac     /* we will pack the column indices with the field offsets */
386578b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
38660eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
38670eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
38680eb7e1eaSToby Isaac     }
38699566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootValuesSec, p, numValues));
387062095d54SToby Isaac   }
38719566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootValuesSec));
387262095d54SToby Isaac   {
387362095d54SToby Isaac     PetscInt           numRootValues;
387462095d54SToby Isaac     const PetscScalar *coarseArray;
387562095d54SToby Isaac 
38769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootValuesSec, &numRootValues));
38779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRootValues, &rootValues));
38789566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecCoarseLocal, &coarseArray));
387962095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
388062095d54SToby Isaac       PetscInt     numValues;
388162095d54SToby Isaac       PetscInt     pValOff;
388262095d54SToby Isaac       PetscScalar *pVal;
388362095d54SToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
388462095d54SToby Isaac 
38859566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootValuesSec, p, &numValues));
3886ad540459SPierre Jolivet       if (!numValues) continue;
38879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootValuesSec, p, &pValOff));
3888*f4f49eeaSPierre Jolivet       pVal = &rootValues[pValOff];
388962095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
38900eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
38919566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(coarse, NULL, vecCoarseLocal, p, &closureSize, &pVal));
38920eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
3893193eb951SToby Isaac           PetscFVCellGeom *cg;
38946dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
38950eb7e1eaSToby Isaac           PetscInt         i;
38960eb7e1eaSToby Isaac 
38970eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
38980eb7e1eaSToby Isaac 
38999566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(cellDM, p, cellGeomArray, (void *)&cg));
39000eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
39010eb7e1eaSToby Isaac           pVal += dim;
39029566063dSJacob Faibussowitsch           PetscCall(DMPlexPointGlobalRead(gradDM, p, gradArray, (void *)&gradVals));
39030eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
39040eb7e1eaSToby Isaac         }
39059371c9d4SSatish Balay       } else if (maxChildId == -1) {
390678b7adb5SToby Isaac         PetscInt lDof, lOff, i;
390778b7adb5SToby Isaac 
39089566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, p, &lDof));
39099566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(localCoarse, p, &lOff));
391078b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
391178b7adb5SToby Isaac       }
391278b7adb5SToby Isaac     }
39139566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecCoarseLocal, &coarseArray));
39149566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
391562095d54SToby Isaac   }
391662095d54SToby Isaac   {
391762095d54SToby Isaac     PetscSF   valuesSF;
391862095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
391962095d54SToby Isaac 
39209566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafValuesSec));
39219566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootValuesSec, &remoteOffsetsValues, leafValuesSec));
39229566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootValuesSec, remoteOffsetsValues, leafValuesSec, &valuesSF));
39239566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
39249566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsValues));
39259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafValuesSec, &numLeafValues));
39269566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafValues, &leafValues));
39279566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39289566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39299566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&valuesSF));
39309566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootValues));
39319566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootValuesSec));
393262095d54SToby Isaac   }
39339566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
393462095d54SToby Isaac   {
393562095d54SToby Isaac     PetscInt       maxDof;
393662095d54SToby Isaac     PetscInt      *rowIndices;
393762095d54SToby Isaac     DM             refTree;
393862095d54SToby Isaac     PetscInt     **refPointFieldN;
393962095d54SToby Isaac     PetscScalar ***refPointFieldMats;
394062095d54SToby Isaac     PetscSection   refConSec, refAnSec;
39410eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, leafStart, leafEnd;
394262095d54SToby Isaac     PetscScalar   *pointWork;
394362095d54SToby Isaac 
39449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
39459566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
39469566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
39479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
39489566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(fine, refTree));
39499566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
39509566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
39519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
39529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
39539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafValuesSec, &leafStart, &leafEnd));
39549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSimplexOrBoxCells(fine, 0, &cellStart, &cellEnd));
39550eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
395662095d54SToby Isaac       PetscInt           gDof, gcDof, gOff, lDof;
395762095d54SToby Isaac       PetscInt           numValues, pValOff;
395862095d54SToby Isaac       PetscInt           childId;
395962095d54SToby Isaac       const PetscScalar *pVal;
39600eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
396162095d54SToby Isaac 
39629566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
39639566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localFine, p, &lDof));
39649566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
3965ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
39669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
39679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafValuesSec, p, &numValues));
396862095d54SToby Isaac       if (!numValues) continue;
39699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafValuesSec, p, &pValOff));
397062095d54SToby Isaac       pVal              = &leafValues[pValOff];
397162095d54SToby Isaac       offsets[0]        = 0;
397262095d54SToby Isaac       offsetsCopy[0]    = 0;
397362095d54SToby Isaac       newOffsets[0]     = 0;
397462095d54SToby Isaac       newOffsetsCopy[0] = 0;
39754833aeb0SToby Isaac       childId           = cids[p - pStartF];
397662095d54SToby Isaac       if (numFields) {
397762095d54SToby Isaac         PetscInt f;
397862095d54SToby Isaac         for (f = 0; f < numFields; f++) {
397962095d54SToby Isaac           PetscInt rowDof;
398062095d54SToby Isaac 
39819566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
398262095d54SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
398362095d54SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
398462095d54SToby Isaac           /* TODO: closure indices */
39859f4e70e1SToby Isaac           newOffsets[f + 1] = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
398662095d54SToby Isaac         }
39879566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
39889371c9d4SSatish Balay       } else {
39894833aeb0SToby Isaac         offsets[0]    = 0;
39904833aeb0SToby Isaac         offsets[1]    = lDof;
39914833aeb0SToby Isaac         newOffsets[0] = 0;
39924833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
39939566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
399462095d54SToby Isaac       }
399562095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
39969566063dSJacob Faibussowitsch         PetscCall(VecSetValues(vecFine, numValues, rowIndices, pVal, INSERT_VALUES));
399762095d54SToby Isaac       } else {
399862095d54SToby Isaac         PetscInt f;
399962095d54SToby Isaac 
400078b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
400178b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
400278b7adb5SToby Isaac           fvGradData = &pVal[numValues];
400378b7adb5SToby Isaac         }
400462095d54SToby Isaac         for (f = 0; f < PetscMax(1, numFields); f++) {
400562095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
400662095d54SToby Isaac           PetscInt           numRows  = offsets[f + 1] - offsets[f];
400762095d54SToby Isaac           PetscInt           numCols  = newOffsets[f + 1] - newOffsets[f];
400862095d54SToby Isaac           const PetscScalar *cVal     = &pVal[newOffsets[f]];
400962095d54SToby Isaac           PetscScalar       *rVal     = &pointWork[offsets[f]];
401062095d54SToby Isaac           PetscInt           i, j;
401162095d54SToby Isaac 
4012708c7f19SToby Isaac #if 0
401363a3b9bcSJacob 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));
4014708c7f19SToby Isaac #endif
401562095d54SToby Isaac           for (i = 0; i < numRows; i++) {
401662095d54SToby Isaac             PetscScalar val = 0.;
4017ad540459SPierre Jolivet             for (j = 0; j < numCols; j++) val += childMat[i * numCols + j] * cVal[j];
401862095d54SToby Isaac             rVal[i] = val;
401962095d54SToby Isaac           }
40200eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
40210eb7e1eaSToby Isaac             PetscReal          centroid[3];
40220eb7e1eaSToby Isaac             PetscScalar        diff[3];
40230eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
40240eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
40250eb7e1eaSToby Isaac 
40269566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFVM(fine, p, NULL, centroid, NULL));
4027ad540459SPierre Jolivet             for (i = 0; i < dim; i++) diff[i] = centroid[i] - parentCentroid[i];
40280eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
40290eb7e1eaSToby Isaac               PetscScalar val = 0.;
40300eb7e1eaSToby Isaac 
4031ad540459SPierre Jolivet               for (j = 0; j < dim; j++) val += gradient[dim * i + j] * diff[j];
40320eb7e1eaSToby Isaac               rVal[i] += val;
40330eb7e1eaSToby Isaac             }
40340eb7e1eaSToby Isaac           }
40359566063dSJacob Faibussowitsch           PetscCall(VecSetValues(vecFine, numRows, &rowIndices[offsets[f]], rVal, INSERT_VALUES));
403662095d54SToby Isaac         }
403762095d54SToby Isaac       }
403862095d54SToby Isaac     }
40399566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
40409566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
40419566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
404262095d54SToby Isaac   }
40439566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafValues));
40449566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafValuesSec));
40459566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
40469566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
40473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4048ebf164c7SToby Isaac }
4049ebf164c7SToby Isaac 
4050d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4051d71ae5a4SJacob Faibussowitsch {
4052c921d74cSToby Isaac   DM             refTree;
4053c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4054c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4055c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4056c921d74cSToby Isaac   PetscSection   cSecRef;
4057c921d74cSToby Isaac   PetscInt      *parentIndices, pRefStart, pRefEnd;
4058d3bc4906SToby Isaac   PetscScalar   *rootValues, *parentValues;
4059c921d74cSToby Isaac   Mat            injRef;
4060c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4061c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4062c921d74cSToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
4063c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4064c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4065c921d74cSToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4066c921d74cSToby Isaac 
4067ebf164c7SToby Isaac   PetscFunctionBegin;
4068c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
40699566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40709566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecCoarse, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40719566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
40729566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(coarse, refTree));
40739566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
40749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
40759566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
4076c921d74cSToby Isaac 
40779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
40789566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
40799566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
40809566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
40819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
40829566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
40839566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
40849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
4085c921d74cSToby Isaac   {
4086c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
40879566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
4088c921d74cSToby Isaac   }
4089c921d74cSToby Isaac 
40909566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, cids, vecFine, numFields, offsets, &multiRootSec, &rootIndicesSec, NULL, &rootValues));
4091c921d74cSToby Isaac 
40929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxDof, &parentIndices, maxDof, &parentValues));
4093c921d74cSToby Isaac 
4094c921d74cSToby Isaac   /* count indices */
40959566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecFine, &colMap));
40969566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecCoarse, &rowMap));
40979566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
40989566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
40999566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
41009566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
4101c921d74cSToby Isaac   /* insert values */
41029566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4103c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4104c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
410578b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4106c921d74cSToby Isaac 
41079566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
41089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
4109c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
41109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localCoarse, p, &dof));
41119566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
4112c921d74cSToby Isaac 
4113c921d74cSToby Isaac     rowOffsets[0]  = 0;
4114c921d74cSToby Isaac     offsetsCopy[0] = 0;
4115c921d74cSToby Isaac     if (numFields) {
4116c921d74cSToby Isaac       PetscInt f;
4117c921d74cSToby Isaac 
4118c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4119c921d74cSToby Isaac         PetscInt fDof;
41209566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
4121c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4122c921d74cSToby Isaac       }
41239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
4124367003a6SStefano Zampini     } else {
41259566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
4126c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4127c921d74cSToby Isaac     }
4128c921d74cSToby Isaac 
41299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
41309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
4131c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
41322f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4133c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4134c921d74cSToby Isaac       PetscInt           numIndices, childId, offset;
4135c921d74cSToby Isaac       const PetscScalar *childValues;
4136c921d74cSToby Isaac 
41379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
41389566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
4139c921d74cSToby Isaac       childId     = (PetscInt)PetscRealPart(rootValues[offset++]);
4140c921d74cSToby Isaac       childValues = &rootValues[offset];
4141c921d74cSToby Isaac       numIndices--;
4142c921d74cSToby Isaac 
4143c921d74cSToby Isaac       if (childId == -2) { /* skip */
4144c921d74cSToby Isaac         continue;
4145c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
41462f65e181SToby Isaac         PetscInt m;
41472f65e181SToby Isaac 
414878b7adb5SToby Isaac         contribute = PETSC_TRUE;
41492f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4150beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4151d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4152d3bc4906SToby Isaac 
415378b7adb5SToby Isaac         contribute = PETSC_TRUE;
41549566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
4155d3bc4906SToby Isaac 
4156d3bc4906SToby Isaac         lim        = PetscMax(1, numFields);
4157d3bc4906SToby Isaac         offsets[0] = 0;
4158d3bc4906SToby Isaac         if (numFields) {
4159d3bc4906SToby Isaac           PetscInt f;
4160d3bc4906SToby Isaac 
4161d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4162d3bc4906SToby Isaac             PetscInt fDof;
41639566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
4164d3bc4906SToby Isaac 
4165d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4166d3bc4906SToby Isaac           }
41679371c9d4SSatish Balay         } else {
4168d3bc4906SToby Isaac           PetscInt cDof;
4169d3bc4906SToby Isaac 
41709566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
4171d3bc4906SToby Isaac           offsets[1] = cDof;
4172d3bc4906SToby Isaac         }
4173d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4174d3bc4906SToby Isaac           PetscScalar       *childMat = &childrenMats[childId - pRefStart][f][0];
4175d3bc4906SToby Isaac           PetscInt           n        = offsets[f + 1] - offsets[f];
4176e328ff09SToby Isaac           PetscInt           m        = rowOffsets[f + 1] - rowOffsets[f];
4177d3bc4906SToby Isaac           PetscInt           i, j;
4178d3bc4906SToby Isaac           const PetscScalar *colValues = &childValues[offsets[f]];
4179d3bc4906SToby Isaac 
4180e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4181d3bc4906SToby Isaac             PetscScalar val = 0.;
4182ad540459SPierre Jolivet             for (j = 0; j < n; j++) val += childMat[n * i + j] * colValues[j];
4183e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4184d3bc4906SToby Isaac           }
4185d3bc4906SToby Isaac         }
4186c921d74cSToby Isaac       }
4187c921d74cSToby Isaac     }
41889566063dSJacob Faibussowitsch     if (contribute) PetscCall(VecSetValues(vecCoarse, dof, parentIndices, parentValues, INSERT_VALUES));
4189c921d74cSToby Isaac   }
41909566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
41919566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
41929566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parentIndices, parentValues));
41939566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
41949566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootValues));
41959566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
41963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4197ebf164c7SToby Isaac }
4198ebf164c7SToby Isaac 
4199ff1f73f7SToby Isaac /*@
4200ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4201ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4202ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4203ff1f73f7SToby Isaac 
420420f4b53cSBarry Smith   Collective
4205ff1f73f7SToby Isaac 
4206ff1f73f7SToby Isaac   Input Parameters:
4207a1cb98faSBarry Smith + dmIn        - The `DMPLEX` mesh for the input vector
420820f4b53cSBarry Smith . dmOut       - The second `DMPLEX` mesh
4209ff1f73f7SToby Isaac . vecIn       - The input vector
421020f4b53cSBarry Smith . sfRefine    - A star forest indicating points in the mesh `dmIn` (roots in the star forest) that are parents to points in
421120f4b53cSBarry Smith                 the mesh `dmOut` (leaves in the star forest), i.e. where `dmOut` is more refined than `dmIn`
421220f4b53cSBarry Smith . sfCoarsen   - A star forest indicating points in the mesh `dmOut` (roots in the star forest) that are parents to points in
421320f4b53cSBarry Smith                 the mesh `dmIn` (leaves in the star forest), i.e. where `dmOut` is more coarsened than `dmIn`
421420f4b53cSBarry Smith . cidsRefine  - The childIds of the points in `dmOut`.  These childIds relate back to the reference tree: childid[j] = k implies
421520f4b53cSBarry Smith                 that mesh point j of `dmOut` was refined from a point in `dmIn` just as the mesh point k in the reference
421620f4b53cSBarry Smith                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in `dmOut` is exactly
421720f4b53cSBarry Smith                 equivalent to its root in `dmIn`, so no interpolation is necessary.  childid[j] = -2 indicates that this
421820f4b53cSBarry Smith                 point j in `dmOut` is not a leaf of `sfRefine`.
421920f4b53cSBarry Smith . cidsCoarsen - The childIds of the points in `dmIn`.  These childIds relate back to the reference tree: childid[j] = k implies
422020f4b53cSBarry Smith                 that mesh point j of dmIn coarsens to a point in `dmOut` just as the mesh point k in the reference
422120f4b53cSBarry Smith                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in `dmOut` is not a leaf in `sfCoarsen`.
422220f4b53cSBarry Smith . useBCs      - `PETSC_TRUE` indicates that boundary values should be inserted into `vecIn` before transfer.
4223ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4224ff1f73f7SToby Isaac 
42252fe279fdSBarry Smith   Output Parameter:
42268966356dSPierre Jolivet . vecOut - Using interpolation and injection operators calculated on the reference tree, the transferred
422720f4b53cSBarry Smith                 projection of `vecIn` from `dmIn` to `dmOut`.  Note that any field discretized with a `PetscFV` finite volume
4228ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4229ff1f73f7SToby Isaac                 coarse points to fine points.
4230ff1f73f7SToby Isaac 
4231ff1f73f7SToby Isaac   Level: developer
4232ff1f73f7SToby Isaac 
42331cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSF`, `Vec`, `PetscFV`, `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4234ff1f73f7SToby Isaac @*/
4235d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
4236d71ae5a4SJacob Faibussowitsch {
423738fc2455SToby Isaac   PetscFunctionBegin;
42389566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
4239ff1f73f7SToby Isaac   if (sfRefine) {
4240fbfa57b9SToby Isaac     Vec vecInLocal;
42410eb7e1eaSToby Isaac     DM  dmGrad   = NULL;
42420eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4243fbfa57b9SToby Isaac 
42449566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
42459566063dSJacob Faibussowitsch     PetscCall(VecSet(vecInLocal, 0.0));
42460eb7e1eaSToby Isaac     {
42470eb7e1eaSToby Isaac       PetscInt numFields, i;
42480eb7e1eaSToby Isaac 
42499566063dSJacob Faibussowitsch       PetscCall(DMGetNumFields(dmIn, &numFields));
42500eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
42510eb7e1eaSToby Isaac         PetscObject  obj;
42520eb7e1eaSToby Isaac         PetscClassId classid;
42530eb7e1eaSToby Isaac 
42549566063dSJacob Faibussowitsch         PetscCall(DMGetField(dmIn, i, NULL, &obj));
42559566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &classid));
42560eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
42579566063dSJacob Faibussowitsch           PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
42580eb7e1eaSToby Isaac           break;
42590eb7e1eaSToby Isaac         }
42600eb7e1eaSToby Isaac       }
42610eb7e1eaSToby Isaac     }
42621baa6e33SBarry Smith     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
42639566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42649566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42650eb7e1eaSToby Isaac     if (dmGrad) {
42669566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad, &grad));
42679566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
42680eb7e1eaSToby Isaac     }
42699566063dSJacob Faibussowitsch     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
42709566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
427148a46eb9SPierre Jolivet     if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
4272ebf164c7SToby Isaac   }
42731baa6e33SBarry Smith   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
42749566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(vecOut));
42759566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(vecOut));
42763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
427738fc2455SToby Isaac }
4278