xref: /petsc/src/dm/impls/plex/plextree.c (revision 08401ef684002a709c6d3db98a0c9f54a8bcf1ec)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2af0996ceSBarry Smith #include <petsc/private/isimpl.h>
3af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
4d6a7ad0dSToby Isaac #include <petscsf.h>
50c37af3bSToby Isaac #include <petscds.h>
6d6a7ad0dSToby Isaac 
70e3d61c9SBarry Smith /* hierarchy routines */
8d6a7ad0dSToby Isaac 
9d6a7ad0dSToby Isaac /*@
10d6a7ad0dSToby Isaac   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
11d6a7ad0dSToby Isaac 
12d6a7ad0dSToby Isaac   Not collective
13d6a7ad0dSToby Isaac 
14d6a7ad0dSToby Isaac   Input Parameters:
15d6a7ad0dSToby Isaac + dm - The DMPlex object
16d6a7ad0dSToby Isaac - ref - The reference tree DMPlex object
17d6a7ad0dSToby Isaac 
180b7167a0SToby Isaac   Level: intermediate
19d6a7ad0dSToby Isaac 
20da43764aSToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexCreateDefaultReferenceTree()
21d6a7ad0dSToby Isaac @*/
22d6a7ad0dSToby Isaac PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
23d6a7ad0dSToby Isaac {
24d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
25d6a7ad0dSToby Isaac 
26d6a7ad0dSToby Isaac   PetscFunctionBegin;
27d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2847a1df27SMatthew G. Knepley   if (ref) {PetscValidHeaderSpecific(ref, DM_CLASSID, 2);}
299566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)ref));
309566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
31d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
32d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
33d6a7ad0dSToby Isaac }
34d6a7ad0dSToby Isaac 
35d6a7ad0dSToby Isaac /*@
36d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
37d6a7ad0dSToby Isaac 
38d6a7ad0dSToby Isaac   Not collective
39d6a7ad0dSToby Isaac 
40d6a7ad0dSToby Isaac   Input Parameters:
41d6a7ad0dSToby Isaac . dm - The DMPlex object
42d6a7ad0dSToby Isaac 
437a7aea1fSJed Brown   Output Parameters:
44d6a7ad0dSToby Isaac . ref - The reference tree DMPlex object
45d6a7ad0dSToby Isaac 
460b7167a0SToby Isaac   Level: intermediate
47d6a7ad0dSToby Isaac 
48da43764aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexCreateDefaultReferenceTree()
49d6a7ad0dSToby Isaac @*/
50d6a7ad0dSToby Isaac PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
51d6a7ad0dSToby Isaac {
52d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
53d6a7ad0dSToby Isaac 
54d6a7ad0dSToby Isaac   PetscFunctionBegin;
55d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
56d6a7ad0dSToby Isaac   PetscValidPointer(ref,2);
57d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
58d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
59d6a7ad0dSToby Isaac }
60d6a7ad0dSToby Isaac 
61dcbd3bf7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
62dcbd3bf7SToby Isaac {
63dcbd3bf7SToby Isaac   PetscInt       coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
64dcbd3bf7SToby Isaac 
65dcbd3bf7SToby Isaac   PetscFunctionBegin;
66dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
67dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
68dcbd3bf7SToby Isaac     if (childB) *childB = childA;
69dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
70dcbd3bf7SToby Isaac   }
71dcbd3bf7SToby Isaac   for (dim = 0; dim < 3; dim++) {
729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd));
73dcbd3bf7SToby Isaac     if (parent >= dStart && parent <= dEnd) {
74dcbd3bf7SToby Isaac       break;
75dcbd3bf7SToby Isaac     }
76dcbd3bf7SToby Isaac   }
77*08401ef6SPierre Jolivet   PetscCheck(dim <= 2,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim);
7828b400f6SJacob Faibussowitsch   PetscCheck(dim,PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
79dcbd3bf7SToby Isaac   if (childA < dStart || childA >= dEnd) {
80dcbd3bf7SToby Isaac     /* this is a lower-dimensional child: bootstrap */
81dcbd3bf7SToby Isaac     PetscInt size, i, sA = -1, sB, sOrientB, sConeSize;
82dcbd3bf7SToby Isaac     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
83dcbd3bf7SToby Isaac 
849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm,childA,&size));
859566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm,childA,&supp));
86dcbd3bf7SToby Isaac 
87dcbd3bf7SToby Isaac     /* find a point sA in supp(childA) that has the same parent */
88dcbd3bf7SToby Isaac     for (i = 0; i < size; i++) {
89dcbd3bf7SToby Isaac       PetscInt sParent;
90dcbd3bf7SToby Isaac 
91dcbd3bf7SToby Isaac       sA   = supp[i];
92dcbd3bf7SToby Isaac       if (sA == parent) continue;
939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,sA,&sParent,NULL));
94dcbd3bf7SToby Isaac       if (sParent == parent) {
95dcbd3bf7SToby Isaac         break;
96dcbd3bf7SToby Isaac       }
97dcbd3bf7SToby Isaac     }
98*08401ef6SPierre Jolivet     PetscCheck(i != size,PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
99dcbd3bf7SToby Isaac     /* find out which point sB is in an equivalent position to sA under
100dcbd3bf7SToby Isaac      * parentOrientB */
1019566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildSymmetry_Default(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB));
1029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm,sA,&sConeSize));
1039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm,sA,&coneA));
1049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm,sB,&coneB));
1059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm,sA,&oA));
1069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm,sB,&oB));
107dcbd3bf7SToby Isaac     /* step through the cone of sA in natural order */
108dcbd3bf7SToby Isaac     for (i = 0; i < sConeSize; i++) {
109dcbd3bf7SToby Isaac       if (coneA[i] == childA) {
110dcbd3bf7SToby Isaac         /* if childA is at position i in coneA,
111dcbd3bf7SToby Isaac          * then we want the point that is at sOrientB*i in coneB */
112dcbd3bf7SToby Isaac         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
113dcbd3bf7SToby Isaac         if (childB) *childB = coneB[j];
114dcbd3bf7SToby Isaac         if (childOrientB) {
115b5a892a1SMatthew G. Knepley           DMPolytopeType ct;
116dcbd3bf7SToby Isaac           PetscInt       oBtrue;
117dcbd3bf7SToby Isaac 
1189566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm,childA,&coneSize));
119dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
1202c71b3e2SJacob Faibussowitsch           PetscCheckFalse(coneSize != 0 && coneSize != 2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
121b5a892a1SMatthew G. Knepley           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
122dcbd3bf7SToby Isaac           /* we may have to flip an edge */
123b5a892a1SMatthew G. Knepley           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientation(ct, -1, oB[j]);
124b5a892a1SMatthew G. Knepley           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
125b5a892a1SMatthew G. Knepley           ABswap        = DihedralSwap(coneSize,DMPolytopeConvertNewOrientation_Internal(ct, oA[i]),oBtrue);
126dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
127dcbd3bf7SToby Isaac         }
128dcbd3bf7SToby Isaac         break;
129dcbd3bf7SToby Isaac       }
130dcbd3bf7SToby Isaac     }
131*08401ef6SPierre Jolivet     PetscCheck(i != sConeSize,PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
132dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
133dcbd3bf7SToby Isaac   }
134dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
1359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm,parent,&coneSize));
136dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
137dcbd3bf7SToby Isaac   if (dim == 2) {
138dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
139dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
140dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
141dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
142dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
143dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
144947b95d8SBarry Smith   } else {
145dcbd3bf7SToby Isaac     ABswapVert = ABswap;
146dcbd3bf7SToby Isaac   }
147dcbd3bf7SToby Isaac   if (childB) {
148dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
149dcbd3bf7SToby Isaac     PetscInt p, posA = -1, numChildren, i;
150dcbd3bf7SToby Isaac     const PetscInt *children;
151dcbd3bf7SToby Isaac 
152dcbd3bf7SToby Isaac     /* count which position the child is in */
1539566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm,parent,&numChildren,&children));
154dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
155dcbd3bf7SToby Isaac       p = children[i];
156dcbd3bf7SToby Isaac       if (p == childA) {
157dcbd3bf7SToby Isaac         posA = i;
158dcbd3bf7SToby Isaac         break;
159dcbd3bf7SToby Isaac       }
160dcbd3bf7SToby Isaac     }
161dcbd3bf7SToby Isaac     if (posA >= coneSize) {
162dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
163dcbd3bf7SToby Isaac        * is invariant */
1642c71b3e2SJacob Faibussowitsch       PetscCheckFalse(dim != 2 || posA != 3,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Expected a middle triangle, got something else");
165dcbd3bf7SToby Isaac       *childB = childA;
166dcbd3bf7SToby Isaac     }
167dcbd3bf7SToby Isaac     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);
176dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
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:
183dcbd3bf7SToby Isaac + 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:
191dcbd3bf7SToby Isaac + childOrientB - if not NULL, set to the new oreintation for describing the child
192ff1f73f7SToby Isaac - childB - if not NULL, the new childID for describing the child
193dcbd3bf7SToby Isaac 
194dcbd3bf7SToby Isaac   Level: developer
195dcbd3bf7SToby Isaac 
196dcbd3bf7SToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexSetReferenceTree(), DMPlexSetTree()
197dcbd3bf7SToby Isaac @*/
198dcbd3bf7SToby Isaac PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
199dcbd3bf7SToby Isaac {
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));
206dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
207dcbd3bf7SToby Isaac }
208dcbd3bf7SToby Isaac 
209776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM,PetscSection,PetscInt*,PetscInt*,PetscBool,PetscBool);
210f9f063d4SToby Isaac 
211f2c1aa1dSLisandro Dalcin PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
212f2c1aa1dSLisandro Dalcin {
213f2c1aa1dSLisandro Dalcin   PetscFunctionBegin;
2149566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_TRUE,PETSC_FALSE));
215f2c1aa1dSLisandro Dalcin   PetscFunctionReturn(0);
216f2c1aa1dSLisandro Dalcin }
217f2c1aa1dSLisandro Dalcin 
2180e2cc29aSToby Isaac PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
219da43764aSToby Isaac {
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 */
238da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
2399566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(unionSection, p - pStart, 1));
240da43764aSToby Isaac   }
241da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
242da43764aSToby Isaac     PetscInt q, qSize;
2439566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(identityRef, p, &q));
2449566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(identityRef, q, &qSize));
245da43764aSToby Isaac     if (qSize > 1) {
2469566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1));
247da43764aSToby Isaac     }
248da43764aSToby Isaac   }
2499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart,&permvals));
250da43764aSToby Isaac   offset = 0;
251da43764aSToby Isaac   /* stratify points in the union by topological dimension */
252da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
253da43764aSToby Isaac     PetscInt cStart, cEnd, c;
254da43764aSToby Isaac 
2559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, &cEnd));
256da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
257da43764aSToby Isaac       permvals[offset++] = c;
258da43764aSToby Isaac     }
259da43764aSToby Isaac 
2609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd));
261da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
262da43764aSToby Isaac       permvals[offset++] = c + (pEnd - pStart);
263da43764aSToby Isaac     }
264da43764aSToby Isaac   }
2659566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm));
2669566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetPermutation(unionSection,perm));
2679566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionSection));
2689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionSection,&numUnionPoints));
2699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numUnionPoints,&coneSizes,dim+1,&numDimPoints));
270da43764aSToby Isaac   /* count dimension points */
271da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
272da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
2739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K,d,&cStart,NULL));
2749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection,cStart-pStart,&cOff));
275da43764aSToby Isaac     if (d < dim) {
2769566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K,d+1,&cStart,NULL));
2779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection,cStart-pStart,&cOff2));
278da43764aSToby Isaac     }
279da43764aSToby Isaac     else {
280da43764aSToby Isaac       cOff2 = numUnionPoints;
281da43764aSToby Isaac     }
282da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
283da43764aSToby Isaac   }
2849566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionConeSection));
2859566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(unionConeSection, 0, numUnionPoints));
286da43764aSToby Isaac   /* count the cones in the union */
287da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
288da43764aSToby Isaac     PetscInt dof, uOff;
289da43764aSToby Isaac 
2909566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
2919566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart,&uOff));
2929566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
293da43764aSToby Isaac     coneSizes[uOff] = dof;
294da43764aSToby Isaac   }
295da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
296da43764aSToby Isaac     PetscInt dof, uDof, uOff;
297da43764aSToby Isaac 
2989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
2999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
3009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
301da43764aSToby Isaac     if (uDof) {
3029566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
303da43764aSToby Isaac       coneSizes[uOff] = dof;
304da43764aSToby Isaac     }
305da43764aSToby Isaac   }
3069566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionConeSection));
3079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionConeSection,&numCones));
3089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numCones,&unionCones,numCones,&unionOrientations));
309da43764aSToby Isaac   /* write the cones in the union */
310da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
311da43764aSToby Isaac     PetscInt dof, uOff, c, cOff;
312da43764aSToby Isaac     const PetscInt *cone, *orientation;
313da43764aSToby Isaac 
3149566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
3159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(K, p, &cone));
3169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(K, p, &orientation));
3179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart,&uOff));
3189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionConeSection,uOff,&cOff));
319da43764aSToby Isaac     for (c = 0; c < dof; c++) {
320da43764aSToby Isaac       PetscInt e, eOff;
321da43764aSToby Isaac       e                           = cone[c];
3229566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
323da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
324da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
325da43764aSToby Isaac     }
326da43764aSToby Isaac   }
327da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
328da43764aSToby Isaac     PetscInt dof, uDof, uOff, c, cOff;
329da43764aSToby Isaac     const PetscInt *cone, *orientation;
330da43764aSToby Isaac 
3319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
3329566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(Kref, p, &cone));
3339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(Kref, p, &orientation));
3349566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
3359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
336da43764aSToby Isaac     if (uDof) {
3379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionConeSection,uOff,&cOff));
338da43764aSToby Isaac       for (c = 0; c < dof; c++) {
339da43764aSToby Isaac         PetscInt e, eOff, eDof;
340da43764aSToby Isaac 
341da43764aSToby Isaac         e    = cone[c];
3429566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart),&eDof));
343da43764aSToby Isaac         if (eDof) {
3449566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff));
345da43764aSToby Isaac         }
346da43764aSToby Isaac         else {
3479566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(identityRef, e, &e));
3489566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
349da43764aSToby Isaac         }
350da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
351da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
352da43764aSToby Isaac       }
353da43764aSToby Isaac     }
354da43764aSToby Isaac   }
355da43764aSToby Isaac   /* get the coordinates */
356da43764aSToby Isaac   {
357da43764aSToby Isaac     PetscInt     vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
358da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
359da43764aSToby Isaac     Vec          KcoordsVec, KrefCoordsVec;
360da43764aSToby Isaac     PetscScalar *Kcoords;
361da43764aSToby Isaac 
3629566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(K, &KcoordsSec));
3639566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(K, &KcoordsVec));
3649566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(Kref, &KrefCoordsSec));
3659566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(Kref, &KrefCoordsVec));
366da43764aSToby Isaac 
367da43764aSToby Isaac     numVerts = numDimPoints[0];
3689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numVerts * dim,&unionCoords));
3699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(K,0,&vStart,&vEnd));
370da43764aSToby Isaac 
371da43764aSToby Isaac     offset = 0;
372da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
3739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection,v - pStart,&vOff));
3749566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords));
375da43764aSToby Isaac       for (d = 0; d < dim; d++) {
376da43764aSToby Isaac         unionCoords[offset * dim + d] = Kcoords[d];
377da43764aSToby Isaac       }
378da43764aSToby Isaac       offset++;
379da43764aSToby Isaac     }
3809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(Kref,0,&vRefStart,&vRefEnd));
381da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
3829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(unionSection,v - pRefStart + (pEnd - pStart),&vDof));
3839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection,v - pRefStart + (pEnd - pStart),&vOff));
3849566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords));
385da43764aSToby Isaac       if (vDof) {
386da43764aSToby Isaac         for (d = 0; d < dim; d++) {
387da43764aSToby Isaac           unionCoords[offset * dim + d] = Kcoords[d];
388da43764aSToby Isaac         }
389da43764aSToby Isaac         offset++;
390da43764aSToby Isaac       }
391da43764aSToby Isaac     }
392da43764aSToby Isaac   }
3939566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm,ref));
3949566063dSJacob Faibussowitsch   PetscCall(DMSetType(*ref,DMPLEX));
3959566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ref,dim));
3969566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromDAG(*ref,dim,numDimPoints,coneSizes,unionCones,unionOrientations,unionCoords));
39710f7e118SToby Isaac   /* set the tree */
3989566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm,&parentSection));
3999566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(parentSection,0,numUnionPoints));
40010f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
40110f7e118SToby Isaac     PetscInt uDof, uOff;
40210f7e118SToby Isaac 
4039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
4049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
40510f7e118SToby Isaac     if (uDof) {
4069566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(parentSection,uOff,1));
40710f7e118SToby Isaac     }
40810f7e118SToby Isaac   }
4099566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(parentSection));
4109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection,&parentSize));
4119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(parentSize,&parents,parentSize,&childIDs));
41210f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
41310f7e118SToby Isaac     PetscInt uDof, uOff;
41410f7e118SToby Isaac 
4159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
4169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
41710f7e118SToby Isaac     if (uDof) {
41810f7e118SToby Isaac       PetscInt pOff, parent, parentU;
4199566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(parentSection,uOff,&pOff));
4209566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(identityRef,p,&parent));
4219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, parent - pStart,&parentU));
42210f7e118SToby Isaac       parents[pOff] = parentU;
42310f7e118SToby Isaac       childIDs[pOff] = uOff;
42410f7e118SToby Isaac     }
42510f7e118SToby Isaac   }
4269566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_SetTree(*ref,parentSection,parents,childIDs));
4279566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
4289566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parents,childIDs));
42910f7e118SToby Isaac 
430da43764aSToby Isaac   /* clean up */
4319566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionSection));
4329566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionConeSection));
4339566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&perm));
4349566063dSJacob Faibussowitsch   PetscCall(PetscFree(unionCoords));
4359566063dSJacob Faibussowitsch   PetscCall(PetscFree2(unionCones,unionOrientations));
4369566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coneSizes,numDimPoints));
4370e2cc29aSToby Isaac   PetscFunctionReturn(0);
4380e2cc29aSToby Isaac }
4390e2cc29aSToby Isaac 
4400e2cc29aSToby Isaac /*@
4410e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4420e2cc29aSToby Isaac 
443d083f849SBarry Smith   Collective
4440e2cc29aSToby Isaac 
4450e2cc29aSToby Isaac   Input Parameters:
4460e2cc29aSToby Isaac + comm    - the MPI communicator
4470e2cc29aSToby Isaac . dim     - the spatial dimension
4480e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4490e2cc29aSToby Isaac 
4500e2cc29aSToby Isaac   Output Parameters:
4510e2cc29aSToby Isaac . ref     - the reference tree DMPlex object
4520e2cc29aSToby Isaac 
4530e2cc29aSToby Isaac   Level: intermediate
4540e2cc29aSToby Isaac 
4550e2cc29aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree()
4560e2cc29aSToby Isaac @*/
4570e2cc29aSToby Isaac PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
4580e2cc29aSToby Isaac {
4590e2cc29aSToby Isaac   DM_Plex       *mesh;
4600e2cc29aSToby Isaac   DM             K, Kref;
4610e2cc29aSToby Isaac   PetscInt       p, pStart, pEnd;
4620e2cc29aSToby Isaac   DMLabel        identity;
4630e2cc29aSToby Isaac 
4640e2cc29aSToby Isaac   PetscFunctionBegin;
4650e2cc29aSToby Isaac #if 1
4660e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4670e2cc29aSToby Isaac #endif
4680e2cc29aSToby Isaac   /* create a reference element */
4699566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K));
4709566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(K, "identity"));
4719566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, "identity", &identity));
4729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
4730e2cc29aSToby Isaac   for (p = pStart; p < pEnd; p++) {
4749566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(identity, p, p));
4750e2cc29aSToby Isaac   }
4760e2cc29aSToby Isaac   /* refine it */
4779566063dSJacob Faibussowitsch   PetscCall(DMRefine(K,comm,&Kref));
4780e2cc29aSToby Isaac 
4790e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4800e2cc29aSToby Isaac    * points that appear in both */
4819566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref));
4820e2cc29aSToby Isaac   mesh = (DM_Plex *) (*ref)->data;
4830e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
4849566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&K));
4859566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&Kref));
486da43764aSToby Isaac   PetscFunctionReturn(0);
487da43764aSToby Isaac }
488da43764aSToby Isaac 
489878b19aaSToby Isaac static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
490878b19aaSToby Isaac {
491878b19aaSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
492878b19aaSToby Isaac   PetscSection   childSec, pSec;
493878b19aaSToby Isaac   PetscInt       p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
494878b19aaSToby Isaac   PetscInt       *offsets, *children, pStart, pEnd;
495878b19aaSToby Isaac 
496878b19aaSToby Isaac   PetscFunctionBegin;
497878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4989566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
4999566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
500878b19aaSToby Isaac   pSec = mesh->parentSection;
501878b19aaSToby Isaac   if (!pSec) PetscFunctionReturn(0);
5029566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(pSec,&pSize));
503878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
504878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
505878b19aaSToby Isaac 
506878b19aaSToby Isaac     parMax = PetscMax(parMax,par+1);
507878b19aaSToby Isaac     parMin = PetscMin(parMin,par);
508878b19aaSToby Isaac   }
509878b19aaSToby Isaac   if (parMin > parMax) {
510878b19aaSToby Isaac     parMin = -1;
511878b19aaSToby Isaac     parMax = -1;
512878b19aaSToby Isaac   }
5139566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)pSec),&childSec));
5149566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(childSec,parMin,parMax));
515878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
516878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
517878b19aaSToby Isaac 
5189566063dSJacob Faibussowitsch     PetscCall(PetscSectionAddDof(childSec,par,1));
519878b19aaSToby Isaac   }
5209566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(childSec));
5219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(childSec,&cSize));
5229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cSize,&children));
5239566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(parMax-parMin,&offsets));
5249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(pSec,&pStart,&pEnd));
525878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
526878b19aaSToby Isaac     PetscInt dof, off, i;
527878b19aaSToby Isaac 
5289566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pSec,p,&dof));
5299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(pSec,p,&off));
530878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
531878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
532878b19aaSToby Isaac 
5339566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec,par,&cOff));
534878b19aaSToby Isaac       children[cOff + offsets[par-parMin]++] = p;
535878b19aaSToby Isaac     }
536878b19aaSToby Isaac   }
537878b19aaSToby Isaac   mesh->childSection = childSec;
538878b19aaSToby Isaac   mesh->children = children;
5399566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
540878b19aaSToby Isaac   PetscFunctionReturn(0);
541878b19aaSToby Isaac }
542878b19aaSToby Isaac 
5436dd5a8c8SToby Isaac static PetscErrorCode AnchorsFlatten (PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
5446dd5a8c8SToby Isaac {
5456dd5a8c8SToby Isaac   PetscInt       pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5466dd5a8c8SToby Isaac   const PetscInt *vals;
5476dd5a8c8SToby Isaac   PetscSection   secNew;
5486dd5a8c8SToby Isaac   PetscBool      anyNew, globalAnyNew;
5496dd5a8c8SToby Isaac   PetscBool      compress;
5506dd5a8c8SToby Isaac 
5516dd5a8c8SToby Isaac   PetscFunctionBegin;
5529566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section,&pStart,&pEnd));
5539566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is,&size));
5549566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is,&vals));
5559566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section),&secNew));
5569566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(secNew,pStart,pEnd));
5576dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5586dd5a8c8SToby Isaac     PetscInt dof;
5596dd5a8c8SToby Isaac 
5606dd5a8c8SToby Isaac     p = vals[i];
5616dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
5636dd5a8c8SToby Isaac     if (dof) break;
5646dd5a8c8SToby Isaac   }
5656dd5a8c8SToby Isaac   if (i == size) {
5669566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5676dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5686dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5696dd5a8c8SToby Isaac     sizeNew  = 0;
5706dd5a8c8SToby Isaac   }
5716dd5a8c8SToby Isaac   else {
5726dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5736dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5746dd5a8c8SToby Isaac       PetscInt dof, off;
5756dd5a8c8SToby Isaac 
5769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5786dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5796dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5806dd5a8c8SToby Isaac 
5816dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5829566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, q, &qDof));
5836dd5a8c8SToby Isaac         }
5846dd5a8c8SToby Isaac         if (qDof) {
5859566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(secNew, p, qDof));
5866dd5a8c8SToby Isaac         }
5876dd5a8c8SToby Isaac         else {
5889566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(secNew, p, 1));
5896dd5a8c8SToby Isaac         }
5906dd5a8c8SToby Isaac       }
5916dd5a8c8SToby Isaac     }
5929566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5939566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(secNew,&sizeNew));
5949566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sizeNew,&valsNew));
5956dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5966dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5976dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
5986dd5a8c8SToby Isaac 
5999566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
6009566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
6019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(secNew, p, &dofNew));
6029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(secNew, p, &offNew));
6036dd5a8c8SToby Isaac       count = 0;
6046dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
6056dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
6066dd5a8c8SToby Isaac 
6076dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
6089566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, q, &qDof));
6099566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, q, &qOff));
6106dd5a8c8SToby Isaac         }
6116dd5a8c8SToby Isaac         if (qDof) {
6126dd5a8c8SToby Isaac           PetscInt oldCount = count;
6136dd5a8c8SToby Isaac 
6146dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
6156dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
6166dd5a8c8SToby Isaac 
6176dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
6186dd5a8c8SToby Isaac               if (valsNew[offNew + k] == r) {
6196dd5a8c8SToby Isaac                 break;
6206dd5a8c8SToby Isaac               }
6216dd5a8c8SToby Isaac             }
6226dd5a8c8SToby Isaac             if (k == oldCount) {
6236dd5a8c8SToby Isaac               valsNew[offNew + count++] = r;
6246dd5a8c8SToby Isaac             }
6256dd5a8c8SToby Isaac           }
6266dd5a8c8SToby Isaac         }
6276dd5a8c8SToby Isaac         else {
6286dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
6296dd5a8c8SToby Isaac 
6306dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
6316dd5a8c8SToby Isaac             if (valsNew[offNew + k] == q) {
6326dd5a8c8SToby Isaac               break;
6336dd5a8c8SToby Isaac             }
6346dd5a8c8SToby Isaac           }
6356dd5a8c8SToby Isaac           if (k == oldCount) {
6366dd5a8c8SToby Isaac             valsNew[offNew + count++] = q;
6376dd5a8c8SToby Isaac           }
6386dd5a8c8SToby Isaac         }
6396dd5a8c8SToby Isaac       }
6406dd5a8c8SToby Isaac       if (count < dofNew) {
6419566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secNew, p, count));
6426dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6436dd5a8c8SToby Isaac       }
6446dd5a8c8SToby Isaac     }
6456dd5a8c8SToby Isaac   }
6469566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is,&vals));
6471c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&anyNew,&globalAnyNew,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew)));
6486dd5a8c8SToby Isaac   if (!globalAnyNew) {
6499566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secNew));
6506dd5a8c8SToby Isaac     *sectionNew = NULL;
6516dd5a8c8SToby Isaac     *isNew = NULL;
6526dd5a8c8SToby Isaac   }
6536dd5a8c8SToby Isaac   else {
6546dd5a8c8SToby Isaac     PetscBool globalCompress;
6556dd5a8c8SToby Isaac 
6561c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&compress,&globalCompress,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew)));
6576dd5a8c8SToby Isaac     if (compress) {
6586dd5a8c8SToby Isaac       PetscSection secComp;
6596dd5a8c8SToby Isaac       PetscInt *valsComp = NULL;
6606dd5a8c8SToby Isaac 
6619566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section),&secComp));
6629566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetChart(secComp,pStart,pEnd));
6636dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6646dd5a8c8SToby Isaac         PetscInt dof;
6656dd5a8c8SToby Isaac 
6669566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6679566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secComp, p, dof));
6686dd5a8c8SToby Isaac       }
6699566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetUp(secComp));
6709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(secComp,&sizeNew));
6719566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(sizeNew,&valsComp));
6726dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6736dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6746dd5a8c8SToby Isaac 
6759566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6769566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secNew, p, &off));
6779566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secComp, p, &offNew));
6786dd5a8c8SToby Isaac         for (j = 0; j < dof; j++) {
6796dd5a8c8SToby Isaac           valsComp[offNew + j] = valsNew[off + j];
6806dd5a8c8SToby Isaac         }
6816dd5a8c8SToby Isaac       }
6829566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&secNew));
6836dd5a8c8SToby Isaac       secNew  = secComp;
6849566063dSJacob Faibussowitsch       PetscCall(PetscFree(valsNew));
6856dd5a8c8SToby Isaac       valsNew = valsComp;
6866dd5a8c8SToby Isaac     }
6879566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is),sizeNew,valsNew,PETSC_OWN_POINTER,isNew));
6886dd5a8c8SToby Isaac   }
6896dd5a8c8SToby Isaac   PetscFunctionReturn(0);
6906dd5a8c8SToby Isaac }
6916dd5a8c8SToby Isaac 
692f7c74593SToby Isaac static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
69366af876cSToby Isaac {
69466af876cSToby Isaac   PetscInt       p, pStart, pEnd, *anchors, size;
69566af876cSToby Isaac   PetscInt       aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
69666af876cSToby Isaac   PetscSection   aSec;
697f9f063d4SToby Isaac   DMLabel        canonLabel;
69866af876cSToby Isaac   IS             aIS;
69966af876cSToby Isaac 
70066af876cSToby Isaac   PetscFunctionBegin;
70166af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm,&pStart,&pEnd));
7039566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm,"canonical",&canonLabel));
70466af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
70566af876cSToby Isaac     PetscInt parent;
70666af876cSToby Isaac 
707f9f063d4SToby Isaac     if (canonLabel) {
708f9f063d4SToby Isaac       PetscInt canon;
709f9f063d4SToby Isaac 
7109566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel,p,&canon));
711f9f063d4SToby Isaac       if (p != canon) continue;
712f9f063d4SToby Isaac     }
7139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm,p,&parent,NULL));
71466af876cSToby Isaac     if (parent != p) {
71566af876cSToby Isaac       aMin = PetscMin(aMin,p);
71666af876cSToby Isaac       aMax = PetscMax(aMax,p+1);
71766af876cSToby Isaac     }
71866af876cSToby Isaac   }
71966af876cSToby Isaac   if (aMin > aMax) {
72066af876cSToby Isaac     aMin = -1;
72166af876cSToby Isaac     aMax = -1;
72266af876cSToby Isaac   }
7239566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&aSec));
7249566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(aSec,aMin,aMax));
72566af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
72666af876cSToby Isaac     PetscInt parent, ancestor = p;
72766af876cSToby Isaac 
728f9f063d4SToby Isaac     if (canonLabel) {
729f9f063d4SToby Isaac       PetscInt canon;
730f9f063d4SToby Isaac 
7319566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel,p,&canon));
732f9f063d4SToby Isaac       if (p != canon) continue;
733f9f063d4SToby Isaac     }
7349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm,p,&parent,NULL));
73566af876cSToby Isaac     while (parent != ancestor) {
73666af876cSToby Isaac       ancestor = parent;
7379566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,ancestor,&parent,NULL));
73866af876cSToby Isaac     }
73966af876cSToby Isaac     if (ancestor != p) {
74066af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
74166af876cSToby Isaac 
7429566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
7439566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(aSec,p,closureSize));
7449566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
74566af876cSToby Isaac     }
74666af876cSToby Isaac   }
7479566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(aSec));
7489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(aSec,&size));
7499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size,&anchors));
75066af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
75166af876cSToby Isaac     PetscInt parent, ancestor = p;
75266af876cSToby Isaac 
753f9f063d4SToby Isaac     if (canonLabel) {
754f9f063d4SToby Isaac       PetscInt canon;
755f9f063d4SToby Isaac 
7569566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel,p,&canon));
757f9f063d4SToby Isaac       if (p != canon) continue;
758f9f063d4SToby Isaac     }
7599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm,p,&parent,NULL));
76066af876cSToby Isaac     while (parent != ancestor) {
76166af876cSToby Isaac       ancestor = parent;
7629566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,ancestor,&parent,NULL));
76366af876cSToby Isaac     }
76466af876cSToby Isaac     if (ancestor != p) {
76566af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
76666af876cSToby Isaac 
7679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(aSec,p,&aOff));
76866af876cSToby Isaac 
7699566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
77066af876cSToby Isaac       for (j = 0; j < closureSize; j++) {
77166af876cSToby Isaac         anchors[aOff + j] = closure[2*j];
77266af876cSToby Isaac       }
7739566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
77466af876cSToby Isaac     }
77566af876cSToby Isaac   }
7769566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF,size,anchors,PETSC_OWN_POINTER,&aIS));
7776dd5a8c8SToby Isaac   {
7786dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7796dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7806dd5a8c8SToby Isaac 
7819566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aSec));
7829566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aIS));
7836dd5a8c8SToby Isaac     while (aSecNew) {
7849566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&aSec));
7859566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&aIS));
7866dd5a8c8SToby Isaac       aSec    = aSecNew;
7876dd5a8c8SToby Isaac       aIS     = aISNew;
7886dd5a8c8SToby Isaac       aSecNew = NULL;
7896dd5a8c8SToby Isaac       aISNew  = NULL;
7909566063dSJacob Faibussowitsch       PetscCall(AnchorsFlatten(aSec,aIS,&aSecNew,&aISNew));
7916dd5a8c8SToby Isaac     }
7926dd5a8c8SToby Isaac   }
7939566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm,aSec,aIS));
7949566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&aSec));
7959566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&aIS));
79666af876cSToby Isaac   PetscFunctionReturn(0);
79766af876cSToby Isaac }
79866af876cSToby Isaac 
7996461c1adSToby Isaac static PetscErrorCode DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt *dof,PetscInt *numTrueSupp)
8006461c1adSToby Isaac {
8016461c1adSToby Isaac   PetscFunctionBegin;
8026461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
8036461c1adSToby Isaac     PetscInt i, alldof;
8046461c1adSToby Isaac     const PetscInt *supp;
8056461c1adSToby Isaac     PetscInt count = 0;
8066461c1adSToby Isaac 
8079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm,p,&alldof));
8089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm,p,&supp));
8096461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
8106461c1adSToby Isaac       PetscInt q = supp[i], numCones, j;
8116461c1adSToby Isaac       const PetscInt *cone;
8126461c1adSToby Isaac 
8139566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm,q,&numCones));
8149566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm,q,&cone));
8156461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
8166461c1adSToby Isaac         if (cone[j] == p) break;
8176461c1adSToby Isaac       }
8186461c1adSToby Isaac       if (j < numCones) count++;
8196461c1adSToby Isaac     }
8206461c1adSToby Isaac     numTrueSupp[p] = count;
8216461c1adSToby Isaac   }
8226461c1adSToby Isaac   *dof = numTrueSupp[p];
8236461c1adSToby Isaac   PetscFunctionReturn(0);
8246461c1adSToby Isaac }
8256461c1adSToby Isaac 
826776742edSToby Isaac static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
827776742edSToby Isaac {
828776742edSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
829776742edSToby Isaac   PetscSection   newSupportSection;
830776742edSToby Isaac   PetscInt       newSize, *newSupports, pStart, pEnd, p, d, depth;
8316461c1adSToby Isaac   PetscInt       *numTrueSupp;
832776742edSToby Isaac   PetscInt       *offsets;
833776742edSToby Isaac 
834776742edSToby Isaac   PetscFunctionBegin;
835776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
836776742edSToby Isaac   /* symmetrize the hierarchy */
8379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm,&depth));
8389566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)),&newSupportSection));
8399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm,&pStart,&pEnd));
8409566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSupportSection,pStart,pEnd));
8419566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd,&offsets));
8429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd,&numTrueSupp));
8436461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8446461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
845776742edSToby Isaac    * parent(q) */
846776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm,d,&pStart,&pEnd));
848776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
849776742edSToby Isaac       PetscInt dof, q, qdof, parent;
850776742edSToby Isaac 
8519566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTrueSupportSize(dm,p,&dof,numTrueSupp));
8529566063dSJacob Faibussowitsch       PetscCall(PetscSectionAddDof(newSupportSection, p, dof));
853776742edSToby Isaac       q    = p;
8549566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,q,&parent,NULL));
855776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
856776742edSToby Isaac         q = parent;
857776742edSToby Isaac 
8589566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTrueSupportSize(dm,q,&qdof,numTrueSupp));
8599566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection,p,qdof));
8609566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection,q,dof));
8619566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm,q,&parent,NULL));
862776742edSToby Isaac       }
863776742edSToby Isaac     }
864776742edSToby Isaac   }
8659566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSupportSection));
8669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSupportSection,&newSize));
8679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(newSize,&newSupports));
868776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm,d,&pStart,&pEnd));
870776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
871776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
872776742edSToby Isaac 
8739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
8749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
8759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(newSupportSection, p, &newDof));
8769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(newSupportSection, p, &newOff));
877776742edSToby Isaac       for (i = 0; i < dof; i++) {
8786461c1adSToby Isaac         PetscInt numCones, j;
8796461c1adSToby Isaac         const PetscInt *cone;
8806461c1adSToby Isaac         PetscInt q = mesh->supports[off + i];
8816461c1adSToby Isaac 
8829566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm,q,&numCones));
8839566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm,q,&cone));
8846461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8856461c1adSToby Isaac           if (cone[j] == p) break;
8866461c1adSToby Isaac         }
8876461c1adSToby Isaac         if (j < numCones) newSupports[newOff+offsets[p]++] = q;
888776742edSToby Isaac       }
889776742edSToby Isaac 
890776742edSToby Isaac       q    = p;
8919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,q,&parent,NULL));
892776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
893776742edSToby Isaac         q = parent;
8949566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->supportSection, q, &qdof));
8959566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &qoff));
8969566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(newSupportSection, q, &newqOff));
897776742edSToby Isaac         for (i = 0; i < qdof; i++) {
8986461c1adSToby Isaac           PetscInt numCones, j;
8996461c1adSToby Isaac           const PetscInt *cone;
9006461c1adSToby Isaac           PetscInt r = mesh->supports[qoff + i];
9016461c1adSToby Isaac 
9029566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm,r,&numCones));
9039566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm,r,&cone));
9046461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9056461c1adSToby Isaac             if (cone[j] == q) break;
9066461c1adSToby Isaac           }
9076461c1adSToby Isaac           if (j < numCones) newSupports[newOff+offsets[p]++] = r;
908776742edSToby Isaac         }
909776742edSToby Isaac         for (i = 0; i < dof; i++) {
9106461c1adSToby Isaac           PetscInt numCones, j;
9116461c1adSToby Isaac           const PetscInt *cone;
9126461c1adSToby Isaac           PetscInt r = mesh->supports[off + i];
9136461c1adSToby Isaac 
9149566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm,r,&numCones));
9159566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm,r,&cone));
9166461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9176461c1adSToby Isaac             if (cone[j] == p) break;
9186461c1adSToby Isaac           }
9196461c1adSToby Isaac           if (j < numCones) newSupports[newqOff+offsets[q]++] = r;
920776742edSToby Isaac         }
9219566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm,q,&parent,NULL));
922776742edSToby Isaac       }
923776742edSToby Isaac     }
924776742edSToby Isaac   }
9259566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
926776742edSToby Isaac   mesh->supportSection = newSupportSection;
9279566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
928776742edSToby Isaac   mesh->supports = newSupports;
9299566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
9309566063dSJacob Faibussowitsch   PetscCall(PetscFree(numTrueSupp));
931776742edSToby Isaac 
932776742edSToby Isaac   PetscFunctionReturn(0);
933776742edSToby Isaac }
934776742edSToby Isaac 
935f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM,PetscSection,PetscSection,Mat);
936f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM,PetscSection,PetscSection,Mat);
937f7c74593SToby Isaac 
938776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
939f9f063d4SToby Isaac {
940f9f063d4SToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
941f9f063d4SToby Isaac   DM             refTree;
942f9f063d4SToby Isaac   PetscInt       size;
943f9f063d4SToby Isaac 
944f9f063d4SToby Isaac   PetscFunctionBegin;
945f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
946f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
9479566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)parentSection));
9489566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
949f9f063d4SToby Isaac   mesh->parentSection = parentSection;
9509566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection,&size));
951f9f063d4SToby Isaac   if (parents != mesh->parents) {
9529566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->parents));
9539566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size,&mesh->parents));
9549566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->parents, parents, size));
955f9f063d4SToby Isaac   }
956f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
9579566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->childIDs));
9589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size,&mesh->childIDs));
9599566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->childIDs, childIDs, size));
960f9f063d4SToby Isaac   }
9619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm,&refTree));
962f9f063d4SToby Isaac   if (refTree) {
963f9f063d4SToby Isaac     DMLabel canonLabel;
964f9f063d4SToby Isaac 
9659566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(refTree,"canonical",&canonLabel));
966f9f063d4SToby Isaac     if (canonLabel) {
967f9f063d4SToby Isaac       PetscInt i;
968f9f063d4SToby Isaac 
969f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
970f9f063d4SToby Isaac         PetscInt canon;
9719566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon));
972f9f063d4SToby Isaac         if (canon >= 0) {
973f9f063d4SToby Isaac           mesh->childIDs[i] = canon;
974f9f063d4SToby Isaac         }
975f9f063d4SToby Isaac       }
976f9f063d4SToby Isaac     }
977f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
9786e0288c8SStefano Zampini   } else {
979f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
980f9f063d4SToby Isaac   }
9819566063dSJacob Faibussowitsch   PetscCall(DMPlexTreeSymmetrize(dm));
982f9f063d4SToby Isaac   if (computeCanonical) {
983f9f063d4SToby Isaac     PetscInt d, dim;
984f9f063d4SToby Isaac 
985f9f063d4SToby Isaac     /* add the canonical label */
9869566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm,&dim));
9879566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm,"canonical"));
988f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
989f9f063d4SToby Isaac       PetscInt p, dStart, dEnd, canon = -1, cNumChildren;
990f9f063d4SToby Isaac       const PetscInt *cChildren;
991f9f063d4SToby Isaac 
9929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm,d,&dStart,&dEnd));
993f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
9949566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm,p,&cNumChildren,&cChildren));
995f9f063d4SToby Isaac         if (cNumChildren) {
996f9f063d4SToby Isaac           canon = p;
997f9f063d4SToby Isaac           break;
998f9f063d4SToby Isaac         }
999f9f063d4SToby Isaac       }
1000f9f063d4SToby Isaac       if (canon == -1) continue;
1001f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1002f9f063d4SToby Isaac         PetscInt numChildren, i;
1003f9f063d4SToby Isaac         const PetscInt *children;
1004f9f063d4SToby Isaac 
10059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm,p,&numChildren,&children));
1006f9f063d4SToby Isaac         if (numChildren) {
1007*08401ef6SPierre Jolivet           PetscCheck(numChildren == cNumChildren,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"All parent points in a stratum should have the same number of children: %d != %d", numChildren, cNumChildren);
10089566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm,"canonical",p,canon));
1009f9f063d4SToby Isaac           for (i = 0; i < numChildren; i++) {
10109566063dSJacob Faibussowitsch             PetscCall(DMSetLabelValue(dm,"canonical",children[i],cChildren[i]));
1011f9f063d4SToby Isaac           }
1012f9f063d4SToby Isaac         }
1013f9f063d4SToby Isaac       }
1014f9f063d4SToby Isaac     }
1015f9f063d4SToby Isaac   }
1016776742edSToby Isaac   if (exchangeSupports) {
10179566063dSJacob Faibussowitsch     PetscCall(DMPlexTreeExchangeSupports(dm));
1018776742edSToby Isaac   }
1019f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
1020f7c74593SToby Isaac   /* reset anchors */
10219566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm,NULL,NULL));
1022f9f063d4SToby Isaac   PetscFunctionReturn(0);
1023f9f063d4SToby Isaac }
1024f9f063d4SToby Isaac 
10250b7167a0SToby Isaac /*@
10260b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
10270b7167a0SToby Isaac   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
10280b7167a0SToby Isaac   tree root.
10290b7167a0SToby Isaac 
10300b7167a0SToby Isaac   Collective on dm
10310b7167a0SToby Isaac 
10320b7167a0SToby Isaac   Input Parameters:
10330b7167a0SToby Isaac + dm - the DMPlex object
10340b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
10350b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
10360b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
10370b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
10380b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
10390b7167a0SToby Isaac 
10400b7167a0SToby Isaac   Level: intermediate
10410b7167a0SToby Isaac 
1042a17985deSToby Isaac .seealso: DMPlexGetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
10430b7167a0SToby Isaac @*/
1044b2f41788SToby Isaac PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
10450b7167a0SToby Isaac {
10460b7167a0SToby Isaac   PetscFunctionBegin;
10479566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_FALSE,PETSC_TRUE));
10480b7167a0SToby Isaac   PetscFunctionReturn(0);
10490b7167a0SToby Isaac }
10500b7167a0SToby Isaac 
1051b2f41788SToby Isaac /*@
1052b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1053b2f41788SToby Isaac   Collective on dm
1054b2f41788SToby Isaac 
1055f899ff85SJose E. Roman   Input Parameter:
1056b2f41788SToby Isaac . dm - the DMPlex object
1057b2f41788SToby Isaac 
1058b2f41788SToby Isaac   Output Parameters:
1059b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1060b2f41788SToby Isaac                   offset indexes the parent and childID list
1061b2f41788SToby Isaac . parents - a list of the point parents
1062b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1063b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1064b2f41788SToby Isaac . childSection - the inverse of the parent section
1065b2f41788SToby Isaac - children - a list of the point children
1066b2f41788SToby Isaac 
1067b2f41788SToby Isaac   Level: intermediate
1068b2f41788SToby Isaac 
1069a17985deSToby Isaac .seealso: DMPlexSetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
1070b2f41788SToby Isaac @*/
1071b2f41788SToby Isaac PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1072b2f41788SToby Isaac {
1073b2f41788SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
1074b2f41788SToby Isaac 
1075b2f41788SToby Isaac   PetscFunctionBegin;
1076b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1077b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1078b2f41788SToby Isaac   if (parents)       *parents       = mesh->parents;
1079b2f41788SToby Isaac   if (childIDs)      *childIDs      = mesh->childIDs;
1080b2f41788SToby Isaac   if (childSection)  *childSection  = mesh->childSection;
1081b2f41788SToby Isaac   if (children)      *children      = mesh->children;
1082b2f41788SToby Isaac   PetscFunctionReturn(0);
1083b2f41788SToby Isaac }
1084b2f41788SToby Isaac 
1085d961a43aSToby Isaac /*@
1086eaf898f9SPatrick Sanan   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)
1087d961a43aSToby Isaac 
1088d961a43aSToby Isaac   Input Parameters:
1089d961a43aSToby Isaac + dm - the DMPlex object
1090d961a43aSToby Isaac - point - the query point
1091d961a43aSToby Isaac 
1092d961a43aSToby Isaac   Output Parameters:
1093d961a43aSToby Isaac + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1094d961a43aSToby Isaac - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point
1095d961a43aSToby Isaac             does not have a parent
1096d961a43aSToby Isaac 
1097d961a43aSToby Isaac   Level: intermediate
1098d961a43aSToby Isaac 
1099d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeChildren()
1100d961a43aSToby Isaac @*/
1101d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1102d961a43aSToby Isaac {
1103d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1104d961a43aSToby Isaac   PetscSection   pSec;
1105d961a43aSToby Isaac 
1106d961a43aSToby Isaac   PetscFunctionBegin;
1107d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1108d961a43aSToby Isaac   pSec = mesh->parentSection;
1109d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1110d961a43aSToby Isaac     PetscInt dof;
1111d961a43aSToby Isaac 
11129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof (pSec, point, &dof));
1113d961a43aSToby Isaac     if (dof) {
1114d961a43aSToby Isaac       PetscInt off;
1115d961a43aSToby Isaac 
11169566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset (pSec, point, &off));
1117d961a43aSToby Isaac       if (parent)  *parent = mesh->parents[off];
1118d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
1119d961a43aSToby Isaac       PetscFunctionReturn(0);
1120d961a43aSToby Isaac     }
1121d961a43aSToby Isaac   }
1122d961a43aSToby Isaac   if (parent) {
1123d961a43aSToby Isaac     *parent = point;
1124d961a43aSToby Isaac   }
1125d961a43aSToby Isaac   if (childID) {
1126d961a43aSToby Isaac     *childID = 0;
1127d961a43aSToby Isaac   }
1128d961a43aSToby Isaac   PetscFunctionReturn(0);
1129d961a43aSToby Isaac }
1130d961a43aSToby Isaac 
1131d961a43aSToby Isaac /*@C
1132eaf898f9SPatrick Sanan   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)
1133d961a43aSToby Isaac 
1134d961a43aSToby Isaac   Input Parameters:
1135d961a43aSToby Isaac + dm - the DMPlex object
1136d961a43aSToby Isaac - point - the query point
1137d961a43aSToby Isaac 
1138d961a43aSToby Isaac   Output Parameters:
1139d961a43aSToby Isaac + numChildren - if not NULL, set to the number of children
1140d961a43aSToby Isaac - children - if not NULL, set to a list children, or set to NULL if the point has no children
1141d961a43aSToby Isaac 
1142d961a43aSToby Isaac   Level: intermediate
1143d961a43aSToby Isaac 
1144d961a43aSToby Isaac   Fortran Notes:
1145d961a43aSToby Isaac   Since it returns an array, this routine is only available in Fortran 90, and you must
1146d961a43aSToby Isaac   include petsc.h90 in your code.
1147d961a43aSToby Isaac 
1148d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeParent()
1149d961a43aSToby Isaac @*/
1150d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1151d961a43aSToby Isaac {
1152d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1153d961a43aSToby Isaac   PetscSection   childSec;
1154d961a43aSToby Isaac   PetscInt       dof = 0;
1155d961a43aSToby Isaac 
1156d961a43aSToby Isaac   PetscFunctionBegin;
1157d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1158d961a43aSToby Isaac   childSec = mesh->childSection;
1159d961a43aSToby Isaac   if (childSec && point >= childSec->pStart && point < childSec->pEnd) {
11609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof (childSec, point, &dof));
1161d961a43aSToby Isaac   }
1162d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1163d961a43aSToby Isaac   if (children) {
1164d961a43aSToby Isaac     if (dof) {
1165d961a43aSToby Isaac       PetscInt off;
1166d961a43aSToby Isaac 
11679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset (childSec, point, &off));
1168d961a43aSToby Isaac       *children = &mesh->children[off];
1169d961a43aSToby Isaac     }
1170d961a43aSToby Isaac     else {
1171d961a43aSToby Isaac       *children = NULL;
1172d961a43aSToby Isaac     }
1173d961a43aSToby Isaac   }
1174d961a43aSToby Isaac   PetscFunctionReturn(0);
1175d961a43aSToby Isaac }
11760c37af3bSToby Isaac 
117752a3aeb4SToby Isaac 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)
1178b3a4bf2aSToby Isaac {
117952a3aeb4SToby Isaac   PetscInt       f, b, p, c, offset, qPoints;
1180b3a4bf2aSToby Isaac 
1181b3a4bf2aSToby Isaac   PetscFunctionBegin;
11829566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(space,nPoints,points,work,NULL,NULL));
118352a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
118452a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
118552a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1186b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1187b3a4bf2aSToby Isaac 
118852a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
118952a3aeb4SToby Isaac         for (c = 0; c < nComps; c++) {
119052a3aeb4SToby Isaac           val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
1191b3a4bf2aSToby Isaac         }
119252a3aeb4SToby Isaac       }
11939566063dSJacob Faibussowitsch       PetscCall(MatSetValue(basisAtPoints,b,f,val,INSERT_VALUES));
1194b3a4bf2aSToby Isaac     }
1195b3a4bf2aSToby Isaac     offset += qPoints;
1196b3a4bf2aSToby Isaac   }
11979566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(basisAtPoints,MAT_FINAL_ASSEMBLY));
11989566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(basisAtPoints,MAT_FINAL_ASSEMBLY));
1199b3a4bf2aSToby Isaac   PetscFunctionReturn(0);
1200b3a4bf2aSToby Isaac }
1201b3a4bf2aSToby Isaac 
1202f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
12030c37af3bSToby Isaac {
12040c37af3bSToby Isaac   PetscDS        ds;
12050c37af3bSToby Isaac   PetscInt       spdim;
12060c37af3bSToby Isaac   PetscInt       numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
12070c37af3bSToby Isaac   const PetscInt *anchors;
1208f7c74593SToby Isaac   PetscSection   aSec;
12090c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
12100c37af3bSToby Isaac   IS             aIS;
12110c37af3bSToby Isaac 
12120c37af3bSToby Isaac   PetscFunctionBegin;
12139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm,&pStart,&pEnd));
12149566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm,&ds));
12159566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
12169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm,0,&cStart,&cEnd));
12179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS));
12189566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS,&anchors));
12199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec,&conStart,&conEnd));
12209566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&spdim));
12219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(spdim,&v0,spdim,&v0parent,spdim,&vtmp,spdim*spdim,&J,spdim*spdim,&Jparent,spdim*spdim,&invJparent));
12220c37af3bSToby Isaac 
12230c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
12240dd1b1feSToby Isaac     PetscObject       disc;
12250dd1b1feSToby Isaac     PetscClassId      id;
1226b3a4bf2aSToby Isaac     PetscSpace        bspace;
1227b3a4bf2aSToby Isaac     PetscDualSpace    dspace;
12289c3cf19fSMatthew G. Knepley     PetscInt          i, j, k, nPoints, Nc, offset;
122952a3aeb4SToby Isaac     PetscInt          fSize, maxDof;
1230b3a4bf2aSToby Isaac     PetscReal         *weights, *pointsRef, *pointsReal, *work;
12311683a169SBarry Smith     PetscScalar       *scwork;
12321683a169SBarry Smith     const PetscScalar *X;
12332c44ad04SToby Isaac     PetscInt          *sizes, *workIndRow, *workIndCol;
12340c37af3bSToby Isaac     Mat               Amat, Bmat, Xmat;
12352c44ad04SToby Isaac     const PetscInt    *numDof  = NULL;
1236085f0adfSToby Isaac     const PetscInt    ***perms = NULL;
1237085f0adfSToby Isaac     const PetscScalar ***flips = NULL;
12380c37af3bSToby Isaac 
12399566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(ds,f,&disc));
12409566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(disc,&id));
12410dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1242b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE) disc;
1243b3a4bf2aSToby Isaac 
12449566063dSJacob Faibussowitsch       PetscCall(PetscFEGetBasisSpace(fe,&bspace));
12459566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(fe,&dspace));
12469566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace,&fSize));
12479566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe,&Nc));
12480dd1b1feSToby Isaac     }
12490dd1b1feSToby Isaac     else if (id == PETSCFV_CLASSID) {
1250b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV) disc;
1251b3a4bf2aSToby Isaac 
12529566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv,&Nc));
12539566063dSJacob Faibussowitsch       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)fv),&bspace));
12549566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetType(bspace,PETSCSPACEPOLYNOMIAL));
12559566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetDegree(bspace,0,PETSC_DETERMINE));
12569566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumComponents(bspace,Nc));
12579566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumVariables(bspace,spdim));
12589566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(bspace));
12599566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv,&dspace));
12609566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace,&fSize));
12610dd1b1feSToby Isaac     }
126298921bdaSJacob Faibussowitsch     else SETERRQ(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
12639566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetNumDof(dspace,&numDof));
12642c44ad04SToby Isaac     for (i = 0, maxDof = 0; i <= spdim; i++) {maxDof = PetscMax(maxDof,numDof[i]);}
12659566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSymmetries(dspace,&perms,&flips));
12660dd1b1feSToby Isaac 
12679566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF,&Amat));
12689566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Amat,fSize,fSize,fSize,fSize));
12699566063dSJacob Faibussowitsch     PetscCall(MatSetType(Amat,MATSEQDENSE));
12709566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Amat));
12719566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Bmat));
12729566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Xmat));
12730c37af3bSToby Isaac     nPoints = 0;
12740c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
127552a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
12760c37af3bSToby Isaac       PetscQuadrature quad;
12770c37af3bSToby Isaac 
12789566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace,i,&quad));
12799566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad,NULL,&thisNc,&qPoints,NULL,NULL));
1280*08401ef6SPierre Jolivet       PetscCheck(thisNc == Nc,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %D does not much basis dim %D",thisNc,Nc);
12810c37af3bSToby Isaac       nPoints += qPoints;
12820c37af3bSToby Isaac     }
12839566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(fSize,&sizes,nPoints*Nc,&weights,spdim*nPoints,&pointsRef,spdim*nPoints,&pointsReal,nPoints*fSize*Nc,&work,maxDof,&workIndRow,maxDof,&workIndCol));
12849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof * maxDof,&scwork));
12850c37af3bSToby Isaac     offset = 0;
12860c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12870c37af3bSToby Isaac       PetscInt        qPoints;
12880c37af3bSToby Isaac       const PetscReal    *p, *w;
12890c37af3bSToby Isaac       PetscQuadrature quad;
12900c37af3bSToby Isaac 
12919566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace,i,&quad));
12929566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad,NULL,NULL,&qPoints,&p,&w));
12939566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(weights+Nc*offset,w,Nc*qPoints));
12949566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pointsRef+spdim*offset,p,spdim*qPoints));
1295b3a4bf2aSToby Isaac       sizes[i] = qPoints;
12960c37af3bSToby Isaac       offset  += qPoints;
12970c37af3bSToby Isaac     }
12989566063dSJacob Faibussowitsch     PetscCall(EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsRef,weights,work,Amat));
12999566063dSJacob Faibussowitsch     PetscCall(MatLUFactor(Amat,NULL,NULL,NULL));
13000c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
13010c37af3bSToby Isaac       PetscInt        parent;
13020c37af3bSToby Isaac       PetscInt        closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
13030c37af3bSToby Isaac       PetscInt        *childOffsets, *parentOffsets;
13040c37af3bSToby Isaac 
13059566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,c,&parent,NULL));
13060c37af3bSToby Isaac       if (parent == c) continue;
13079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure));
13080c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13090c37af3bSToby Isaac         PetscInt p = closure[2*i];
13100c37af3bSToby Isaac         PetscInt conDof;
13110c37af3bSToby Isaac 
13120c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1313085f0adfSToby Isaac         if (numFields) {
13149566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec,p,f,&conDof));
13150c37af3bSToby Isaac         }
13160c37af3bSToby Isaac         else {
13179566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec,p,&conDof));
13180c37af3bSToby Isaac         }
13190c37af3bSToby Isaac         if (conDof) break;
13200c37af3bSToby Isaac       }
13210c37af3bSToby Isaac       if (i == closureSize) {
13229566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure));
13230c37af3bSToby Isaac         continue;
13240c37af3bSToby Isaac       }
13250c37af3bSToby Isaac 
13269566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ));
13279566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent));
13280c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1329c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
1330c330f8ffSToby Isaac 
1331c330f8ffSToby Isaac         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i*spdim],vtmp);
1332c330f8ffSToby Isaac         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i*spdim]);
13330c37af3bSToby Isaac       }
13349566063dSJacob Faibussowitsch       PetscCall(EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsReal,weights,work,Bmat));
13359566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(Amat,Bmat,Xmat));
13369566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Xmat,&X));
13379566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP));
13389566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(closureSize+1,&childOffsets,closureSizeP+1,&parentOffsets));
13390c37af3bSToby Isaac       childOffsets[0] = 0;
13400c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13410c37af3bSToby Isaac         PetscInt p = closure[2*i];
13420c37af3bSToby Isaac         PetscInt dof;
13430c37af3bSToby Isaac 
1344085f0adfSToby Isaac         if (numFields) {
13459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,p,f,&dof));
13460c37af3bSToby Isaac         }
13470c37af3bSToby Isaac         else {
13489566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section,p,&dof));
13490c37af3bSToby Isaac         }
135052a3aeb4SToby Isaac         childOffsets[i+1]=childOffsets[i]+dof;
13510c37af3bSToby Isaac       }
13520c37af3bSToby Isaac       parentOffsets[0] = 0;
13530c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
13540c37af3bSToby Isaac         PetscInt p = closureP[2*i];
13550c37af3bSToby Isaac         PetscInt dof;
13560c37af3bSToby Isaac 
1357085f0adfSToby Isaac         if (numFields) {
13589566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,p,f,&dof));
13590c37af3bSToby Isaac         }
13600c37af3bSToby Isaac         else {
13619566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section,p,&dof));
13620c37af3bSToby Isaac         }
136352a3aeb4SToby Isaac         parentOffsets[i+1]=parentOffsets[i]+dof;
13640c37af3bSToby Isaac       }
13650c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13662c44ad04SToby Isaac         PetscInt conDof, conOff, aDof, aOff, nWork;
13670c37af3bSToby Isaac         PetscInt p = closure[2*i];
13680c37af3bSToby Isaac         PetscInt o = closure[2*i+1];
1369085f0adfSToby Isaac         const PetscInt    *perm;
1370085f0adfSToby Isaac         const PetscScalar *flip;
13710c37af3bSToby Isaac 
13720c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1373085f0adfSToby Isaac         if (numFields) {
13749566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec,p,f,&conDof));
13759566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&conOff));
13760c37af3bSToby Isaac         }
13770c37af3bSToby Isaac         else {
13789566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec,p,&conDof));
13799566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(cSec,p,&conOff));
13800c37af3bSToby Isaac         }
13810c37af3bSToby Isaac         if (!conDof) continue;
1382085f0adfSToby Isaac         perm  = (perms && perms[i]) ? perms[i][o] : NULL;
1383085f0adfSToby Isaac         flip  = (flips && flips[i]) ? flips[i][o] : NULL;
13849566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec,p,&aDof));
13859566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec,p,&aOff));
13862c44ad04SToby Isaac         nWork = childOffsets[i+1]-childOffsets[i];
13870c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
13880c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
13890c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
13900c37af3bSToby Isaac 
1391085f0adfSToby Isaac           if (numFields) {
13929566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section,a,f,&aSecDof));
13939566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section,a,f,&aSecOff));
13940c37af3bSToby Isaac           }
13950c37af3bSToby Isaac           else {
13969566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section,a,&aSecDof));
13979566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section,a,&aSecOff));
13980c37af3bSToby Isaac           }
13990c37af3bSToby Isaac           if (!aSecDof) continue;
14000c37af3bSToby Isaac 
14010c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
14020c37af3bSToby Isaac             PetscInt q = closureP[2*j];
14030c37af3bSToby Isaac             PetscInt oq = closureP[2*j+1];
14042c44ad04SToby Isaac 
14052c44ad04SToby Isaac             if (q == a) {
140652a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1407085f0adfSToby Isaac               const PetscInt    *permP;
1408085f0adfSToby Isaac               const PetscScalar *flipP;
1409085f0adfSToby Isaac 
1410085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1411085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
14122c44ad04SToby Isaac               nWorkP = parentOffsets[j+1]-parentOffsets[j];
14132c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
14141683a169SBarry Smith                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
14152c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
14162c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
14172c44ad04SToby Isaac                 for (s = 0; s < nWorkP; s++) {
14182c44ad04SToby Isaac                   scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
14192c44ad04SToby Isaac                 }
14202c44ad04SToby Isaac               }
142152a3aeb4SToby Isaac               for (r = 0; r < nWork; r++)  {workIndRow[perm  ? perm[r]  : r] = conOff  + r;}
142252a3aeb4SToby Isaac               for (s = 0; s < nWorkP; s++) {workIndCol[permP ? permP[s] : s] = aSecOff + s;}
14232c44ad04SToby Isaac               if (flip) {
14242c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14252c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14262c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flip[r];
14272c44ad04SToby Isaac                   }
14282c44ad04SToby Isaac                 }
14292c44ad04SToby Isaac               }
14302c44ad04SToby Isaac               if (flipP) {
14312c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14322c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14332c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flipP[s];
14342c44ad04SToby Isaac                   }
14352c44ad04SToby Isaac                 }
14362c44ad04SToby Isaac               }
14379566063dSJacob Faibussowitsch               PetscCall(MatSetValues(cMat,nWork,workIndRow,nWorkP,workIndCol,scwork,INSERT_VALUES));
14382c44ad04SToby Isaac               break;
14390c37af3bSToby Isaac             }
14400c37af3bSToby Isaac           }
14410c37af3bSToby Isaac         }
14420c37af3bSToby Isaac       }
14439566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Xmat,&X));
14449566063dSJacob Faibussowitsch       PetscCall(PetscFree2(childOffsets,parentOffsets));
14459566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure));
14469566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP));
14470c37af3bSToby Isaac     }
14489566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Amat));
14499566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Bmat));
14509566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Xmat));
14519566063dSJacob Faibussowitsch     PetscCall(PetscFree(scwork));
14529566063dSJacob Faibussowitsch     PetscCall(PetscFree7(sizes,weights,pointsRef,pointsReal,work,workIndRow,workIndCol));
1453b3a4bf2aSToby Isaac     if (id == PETSCFV_CLASSID) {
14549566063dSJacob Faibussowitsch       PetscCall(PetscSpaceDestroy(&bspace));
1455b3a4bf2aSToby Isaac     }
14560c37af3bSToby Isaac   }
14579566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY));
14589566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY));
14599566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0,v0parent,vtmp,J,Jparent,invJparent));
14609566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS,&anchors));
14610c37af3bSToby Isaac 
14620c37af3bSToby Isaac   PetscFunctionReturn(0);
14630c37af3bSToby Isaac }
146495a0b26dSToby Isaac 
146521968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
146695a0b26dSToby Isaac {
1467f7c74593SToby Isaac   Mat               refCmat;
146821968bf8SToby Isaac   PetscDS           ds;
1469085f0adfSToby Isaac   PetscInt          numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
147021968bf8SToby Isaac   PetscScalar       ***refPointFieldMats;
147121968bf8SToby Isaac   PetscSection      refConSec, refAnSec, refSection;
147221968bf8SToby Isaac   IS                refAnIS;
147321968bf8SToby Isaac   const PetscInt    *refAnchors;
1474085f0adfSToby Isaac   const PetscInt    **perms;
1475085f0adfSToby Isaac   const PetscScalar **flips;
147695a0b26dSToby Isaac 
147795a0b26dSToby Isaac   PetscFunctionBegin;
14789566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree,&ds));
14799566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
1480085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
14819566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&refConSec,&refCmat,NULL));
14829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree,&refAnSec,&refAnIS));
14839566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(refAnIS,&refAnchors));
14849566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree,&refSection));
14859566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
14869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats));
14879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd-pRefStart,&refPointFieldN));
14889566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec,&maxDof));
14899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec,&maxAnDof));
14909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof,&rows));
14919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof*maxAnDof,&cols));
149295a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
149395a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
149495a0b26dSToby Isaac 
14959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree,p,&parent,NULL));
14969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec,p,&pDof));
149795a0b26dSToby Isaac     if (!pDof || parent == p) continue;
149895a0b26dSToby Isaac 
14999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxFields,&refPointFieldMats[p-pRefStart]));
15009566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(maxFields,&refPointFieldN[p-pRefStart]));
15019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure));
1502085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1503085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
150495a0b26dSToby Isaac 
1505085f0adfSToby Isaac       if (f < numFields) {
15069566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
15079566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec,p,f,&cOff));
15089566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips));
1509085f0adfSToby Isaac       } else {
15109566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec,p,&cDof));
15119566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec,p,&cOff));
15129566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetPointSyms(refSection,closureSize,closure,&perms,&flips));
151395a0b26dSToby Isaac       }
151495a0b26dSToby Isaac 
151595a0b26dSToby Isaac       for (r = 0; r < cDof; r++) {
151695a0b26dSToby Isaac         rows[r] = cOff + r;
151795a0b26dSToby Isaac       }
151895a0b26dSToby Isaac       numCols = 0;
151995a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
152095a0b26dSToby Isaac         PetscInt          q = closure[2*i];
152195a0b26dSToby Isaac         PetscInt          aDof, aOff, j;
1522085f0adfSToby Isaac         const PetscInt    *perm = perms ? perms[i] : NULL;
152395a0b26dSToby Isaac 
1524085f0adfSToby Isaac         if (numFields) {
15259566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection,q,f,&aDof));
15269566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection,q,f,&aOff));
152795a0b26dSToby Isaac         }
152895a0b26dSToby Isaac         else {
15299566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection,q,&aDof));
15309566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection,q,&aOff));
153195a0b26dSToby Isaac         }
153295a0b26dSToby Isaac 
153395a0b26dSToby Isaac         for (j = 0; j < aDof; j++) {
1534085f0adfSToby Isaac           cols[numCols++] = aOff + (perm ? perm[j] : j);
153595a0b26dSToby Isaac         }
153695a0b26dSToby Isaac       }
153795a0b26dSToby Isaac       refPointFieldN[p-pRefStart][f] = numCols;
15389566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]));
15399566063dSJacob Faibussowitsch       PetscCall(MatGetValues(refCmat,cDof,rows,numCols,cols,refPointFieldMats[p-pRefStart][f]));
1540085f0adfSToby Isaac       if (flips) {
1541085f0adfSToby Isaac         PetscInt colOff = 0;
1542085f0adfSToby Isaac 
1543085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1544085f0adfSToby Isaac           PetscInt          q = closure[2*i];
1545085f0adfSToby Isaac           PetscInt          aDof, aOff, j;
1546085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1547085f0adfSToby Isaac 
1548085f0adfSToby Isaac           if (numFields) {
15499566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(refSection,q,f,&aDof));
15509566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(refSection,q,f,&aOff));
1551085f0adfSToby Isaac           }
1552085f0adfSToby Isaac           else {
15539566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(refSection,q,&aDof));
15549566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(refSection,q,&aOff));
1555085f0adfSToby Isaac           }
1556085f0adfSToby Isaac           if (flip) {
1557085f0adfSToby Isaac             PetscInt k;
1558085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1559085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1560085f0adfSToby Isaac                 refPointFieldMats[p-pRefStart][f][k * numCols + colOff + j] *= flip[j];
1561085f0adfSToby Isaac               }
1562085f0adfSToby Isaac             }
1563085f0adfSToby Isaac           }
1564085f0adfSToby Isaac           colOff += aDof;
1565085f0adfSToby Isaac         }
1566085f0adfSToby Isaac       }
1567085f0adfSToby Isaac       if (numFields) {
15689566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestoreFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips));
1569085f0adfSToby Isaac       } else {
15709566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestorePointSyms(refSection,closureSize,closure,&perms,&flips));
1571085f0adfSToby Isaac       }
157295a0b26dSToby Isaac     }
15739566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure));
157495a0b26dSToby Isaac   }
157521968bf8SToby Isaac   *childrenMats = refPointFieldMats;
157621968bf8SToby Isaac   *childrenN = refPointFieldN;
15779566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(refAnIS,&refAnchors));
15789566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
15799566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
158021968bf8SToby Isaac   PetscFunctionReturn(0);
158121968bf8SToby Isaac }
158221968bf8SToby Isaac 
158321968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
158421968bf8SToby Isaac {
158521968bf8SToby Isaac   PetscDS        ds;
158621968bf8SToby Isaac   PetscInt       **refPointFieldN;
158721968bf8SToby Isaac   PetscScalar    ***refPointFieldMats;
1588085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
158921968bf8SToby Isaac   PetscSection   refConSec;
159021968bf8SToby Isaac 
159121968bf8SToby Isaac   PetscFunctionBegin;
159221968bf8SToby Isaac   refPointFieldN = *childrenN;
159321968bf8SToby Isaac   *childrenN = NULL;
159421968bf8SToby Isaac   refPointFieldMats = *childrenMats;
159521968bf8SToby Isaac   *childrenMats = NULL;
15969566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree,&ds));
15979566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
1598367003a6SStefano Zampini   maxFields = PetscMax(1,numFields);
15999566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
16009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
160121968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
160221968bf8SToby Isaac     PetscInt parent, pDof;
160321968bf8SToby Isaac 
16049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree,p,&parent,NULL));
16059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec,p,&pDof));
160621968bf8SToby Isaac     if (!pDof || parent == p) continue;
160721968bf8SToby Isaac 
1608085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
160921968bf8SToby Isaac       PetscInt cDof;
161021968bf8SToby Isaac 
1611085f0adfSToby Isaac       if (numFields) {
16129566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
161321968bf8SToby Isaac       }
161421968bf8SToby Isaac       else {
16159566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec,p,&cDof));
161621968bf8SToby Isaac       }
161721968bf8SToby Isaac 
16189566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
161921968bf8SToby Isaac     }
16209566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
16219566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldN[p - pRefStart]));
162221968bf8SToby Isaac   }
16239566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
16249566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldN));
162521968bf8SToby Isaac   PetscFunctionReturn(0);
162621968bf8SToby Isaac }
162721968bf8SToby Isaac 
162821968bf8SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
162921968bf8SToby Isaac {
163021968bf8SToby Isaac   DM             refTree;
163121968bf8SToby Isaac   PetscDS        ds;
163221968bf8SToby Isaac   Mat            refCmat;
1633085f0adfSToby Isaac   PetscInt       numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
163421968bf8SToby Isaac   PetscScalar ***refPointFieldMats, *pointWork;
163521968bf8SToby Isaac   PetscSection   refConSec, refAnSec, anSec;
163621968bf8SToby Isaac   IS             refAnIS, anIS;
163721968bf8SToby Isaac   const PetscInt *anchors;
163821968bf8SToby Isaac 
163921968bf8SToby Isaac   PetscFunctionBegin;
164021968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
16419566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm,&ds));
16429566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
1643085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
16449566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm,&refTree));
16459566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm,refTree));
16469566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&refConSec,&refCmat,NULL));
16479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree,&refAnSec,&refAnIS));
16489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&anSec,&anIS));
16499566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(anIS,&anchors));
16509566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
16519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(conSec,&conStart,&conEnd));
16529566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec,&maxDof));
16539566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec,&maxAnDof));
16549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof*maxDof*maxAnDof,&pointWork));
165521968bf8SToby Isaac 
165621968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
16579566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
165895a0b26dSToby Isaac 
165995a0b26dSToby Isaac   /* step 2: compute the preorder */
16609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm,&pStart,&pEnd));
16619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(pEnd-pStart,&perm,pEnd-pStart,&iperm));
166295a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
166395a0b26dSToby Isaac     perm[p - pStart] = p;
166495a0b26dSToby Isaac     iperm[p - pStart] = p-pStart;
166595a0b26dSToby Isaac   }
166695a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
166795a0b26dSToby Isaac     PetscInt point = perm[p];
166895a0b26dSToby Isaac     PetscInt parent;
166995a0b26dSToby Isaac 
16709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm,point,&parent,NULL));
167195a0b26dSToby Isaac     if (parent == point) {
167295a0b26dSToby Isaac       p++;
167395a0b26dSToby Isaac     }
167495a0b26dSToby Isaac     else {
167595a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
167695a0b26dSToby Isaac 
16779566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
167895a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
167995a0b26dSToby Isaac         PetscInt q = closure[2*i];
168095a0b26dSToby Isaac         if (iperm[q-pStart] > iperm[point-pStart]) {
168195a0b26dSToby Isaac           /* swap */
168295a0b26dSToby Isaac           perm[p]               = q;
168395a0b26dSToby Isaac           perm[iperm[q-pStart]] = point;
168495a0b26dSToby Isaac           iperm[point-pStart]   = iperm[q-pStart];
168595a0b26dSToby Isaac           iperm[q-pStart]       = p;
168695a0b26dSToby Isaac           break;
168795a0b26dSToby Isaac         }
168895a0b26dSToby Isaac       }
168995a0b26dSToby Isaac       size = closureSize;
16909566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
169195a0b26dSToby Isaac       if (i == size) {
169295a0b26dSToby Isaac         p++;
169395a0b26dSToby Isaac       }
169495a0b26dSToby Isaac     }
169595a0b26dSToby Isaac   }
169695a0b26dSToby Isaac 
169795a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
169895a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
169995a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
170095a0b26dSToby Isaac    * values outside of the Mat first.
170195a0b26dSToby Isaac    */
170295a0b26dSToby Isaac   {
170395a0b26dSToby Isaac     PetscInt nRows, row, nnz;
170495a0b26dSToby Isaac     PetscBool done;
170595a0b26dSToby Isaac     const PetscInt *ia, *ja;
170695a0b26dSToby Isaac     PetscScalar *vals;
170795a0b26dSToby Isaac 
17089566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done));
170928b400f6SJacob Faibussowitsch     PetscCheck(done,PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not get RowIJ of constraint matrix");
171095a0b26dSToby Isaac     nnz  = ia[nRows];
171195a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
171295a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
17139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz,&vals));
171495a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
171595a0b26dSToby Isaac       PetscInt        parent, childid, closureSize, *closure = NULL;
171695a0b26dSToby Isaac       PetscInt        point = perm[p], pointDof;
171795a0b26dSToby Isaac 
17189566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,point,&parent,&childid));
171995a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
17209566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(conSec,point,&pointDof));
172195a0b26dSToby Isaac       if (!pointDof) continue;
17229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
1723085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1724085f0adfSToby Isaac         PetscInt cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
172595a0b26dSToby Isaac         PetscScalar *pointMat;
1726085f0adfSToby Isaac         const PetscInt    **perms;
1727085f0adfSToby Isaac         const PetscScalar **flips;
172895a0b26dSToby Isaac 
1729085f0adfSToby Isaac         if (numFields) {
17309566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(conSec,point,f,&cDof));
17319566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(conSec,point,f,&cOff));
173295a0b26dSToby Isaac         }
173395a0b26dSToby Isaac         else {
17349566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(conSec,point,&cDof));
17359566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(conSec,point,&cOff));
173695a0b26dSToby Isaac         }
173795a0b26dSToby Isaac         if (!cDof) continue;
17389566063dSJacob Faibussowitsch         if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section,f,closureSize,closure,&perms,&flips));
17399566063dSJacob Faibussowitsch         else           PetscCall(PetscSectionGetPointSyms(section,closureSize,closure,&perms,&flips));
174095a0b26dSToby Isaac 
174195a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
174276bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
174395a0b26dSToby Isaac           for (r = 0; r < cDof; r++) {
174495a0b26dSToby Isaac             if (cDof > 1 && r) {
1745*08401ef6SPierre Jolivet               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: %D vs. %D", (ia[cOff+r+1]-ia[cOff+r]), (ia[cOff+r]-ia[cOff+r-1]));
174695a0b26dSToby Isaac             }
174795a0b26dSToby Isaac           }
174876bd3646SJed Brown         }
174995a0b26dSToby Isaac         /* zero rows */
175095a0b26dSToby Isaac         for (i = ia[cOff] ; i< ia[cOff+cDof];i++) {
175195a0b26dSToby Isaac           vals[i] = 0.;
175295a0b26dSToby Isaac         }
175395a0b26dSToby Isaac         matOffset = ia[cOff];
175495a0b26dSToby Isaac         numFillCols = ia[cOff+1] - matOffset;
175595a0b26dSToby Isaac         pointMat = refPointFieldMats[childid-pRefStart][f];
175695a0b26dSToby Isaac         numCols = refPointFieldN[childid-pRefStart][f];
175795a0b26dSToby Isaac         offset = 0;
175895a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
175995a0b26dSToby Isaac           PetscInt q = closure[2*i];
176095a0b26dSToby Isaac           PetscInt aDof, aOff, j, k, qConDof, qConOff;
1761085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1762085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
176395a0b26dSToby Isaac 
176495a0b26dSToby Isaac           qConDof = qConOff = 0;
1765085f0adfSToby Isaac           if (numFields) {
17669566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section,q,f,&aDof));
17679566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section,q,f,&aOff));
176895a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
17699566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(conSec,q,f,&qConDof));
17709566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldOffset(conSec,q,f,&qConOff));
177195a0b26dSToby Isaac             }
177295a0b26dSToby Isaac           }
177395a0b26dSToby Isaac           else {
17749566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section,q,&aDof));
17759566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section,q,&aOff));
177695a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
17779566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(conSec,q,&qConDof));
17789566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(conSec,q,&qConOff));
177995a0b26dSToby Isaac             }
178095a0b26dSToby Isaac           }
178195a0b26dSToby Isaac           if (!aDof) continue;
178295a0b26dSToby Isaac           if (qConDof) {
178395a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
178495a0b26dSToby Isaac              * be filled, thanks to preordering */
178595a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
178695a0b26dSToby Isaac             PetscInt aMatOffset = ia[qConOff];
178795a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
178895a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
178995a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
179095a0b26dSToby Isaac                 PetscScalar inVal = 0;
179195a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1792085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
179395a0b26dSToby Isaac 
1794085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
179595a0b26dSToby Isaac                 }
179695a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
179795a0b26dSToby Isaac               }
179895a0b26dSToby Isaac             }
179995a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
180095a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
180195a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
180295a0b26dSToby Isaac               for (;k < numFillCols; k++) {
180395a0b26dSToby Isaac                 if (ja[matOffset + k] == col) {
180495a0b26dSToby Isaac                   break;
180595a0b26dSToby Isaac                 }
180695a0b26dSToby Isaac               }
1807*08401ef6SPierre Jolivet               PetscCheck(k != numFillCols,PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, col);
180895a0b26dSToby Isaac               for (r = 0; r < cDof; r++) {
180995a0b26dSToby Isaac                 vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
181095a0b26dSToby Isaac               }
181195a0b26dSToby Isaac             }
181295a0b26dSToby Isaac           }
181395a0b26dSToby Isaac           else {
181495a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
181595a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
181695a0b26dSToby Isaac               if (ja[matOffset + k] == aOff) {
181795a0b26dSToby Isaac                 break;
181895a0b26dSToby Isaac               }
181995a0b26dSToby Isaac             }
1820*08401ef6SPierre Jolivet             PetscCheck(k != numFillCols,PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, aOff);
182195a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1822085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1823085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1824085f0adfSToby Isaac 
1825085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
182695a0b26dSToby Isaac               }
182795a0b26dSToby Isaac             }
182895a0b26dSToby Isaac           }
182995a0b26dSToby Isaac           offset += aDof;
183095a0b26dSToby Isaac         }
1831085f0adfSToby Isaac         if (numFields) {
18329566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestoreFieldPointSyms(section,f,closureSize,closure,&perms,&flips));
1833085f0adfSToby Isaac         } else {
18349566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestorePointSyms(section,closureSize,closure,&perms,&flips));
1835085f0adfSToby Isaac         }
183695a0b26dSToby Isaac       }
18379566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
183895a0b26dSToby Isaac     }
183995a0b26dSToby Isaac     for (row = 0; row < nRows; row++) {
18409566063dSJacob Faibussowitsch       PetscCall(MatSetValues(cMat,1,&row,ia[row+1]-ia[row],&ja[ia[row]],&vals[ia[row]],INSERT_VALUES));
184195a0b26dSToby Isaac     }
18429566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done));
184328b400f6SJacob Faibussowitsch     PetscCheck(done,PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not restore RowIJ of constraint matrix");
18449566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY));
18459566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY));
18469566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
184795a0b26dSToby Isaac   }
184895a0b26dSToby Isaac 
184995a0b26dSToby Isaac   /* clean up */
18509566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(anIS,&anchors));
18519566063dSJacob Faibussowitsch   PetscCall(PetscFree2(perm,iperm));
18529566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointWork));
18539566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
185495a0b26dSToby Isaac   PetscFunctionReturn(0);
185595a0b26dSToby Isaac }
185695a0b26dSToby Isaac 
18576f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
18586f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
18596f5f1567SToby Isaac PetscErrorCode DMPlexTreeRefineCell (DM dm, PetscInt cell, DM *ncdm)
18606f5f1567SToby Isaac {
18616f5f1567SToby Isaac   DM K;
1862420f55faSMatthew G. Knepley   PetscMPIInt rank;
18636f5f1567SToby Isaac   PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
18646f5f1567SToby Isaac   PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations;
18656f5f1567SToby Isaac   PetscInt *Kembedding;
18666f5f1567SToby Isaac   PetscInt *cellClosure=NULL, nc;
18676f5f1567SToby Isaac   PetscScalar *newVertexCoords;
18686f5f1567SToby Isaac   PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
18696f5f1567SToby Isaac   PetscSection parentSection;
18706f5f1567SToby Isaac 
18716f5f1567SToby Isaac   PetscFunctionBegin;
18729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
18739566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dim));
18749566063dSJacob Faibussowitsch   PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
18759566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ncdm,dim));
18766f5f1567SToby Isaac 
18779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
18789566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm),&parentSection));
18799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm,&K));
1880dd400576SPatrick Sanan   if (rank == 0) {
18816f5f1567SToby Isaac     /* compute the new charts */
18829566063dSJacob Faibussowitsch     PetscCall(PetscMalloc5(dim+1,&pNewCount,dim+1,&pNewStart,dim+1,&pNewEnd,dim+1,&pOldStart,dim+1,&pOldEnd));
18836f5f1567SToby Isaac     offset = 0;
18846f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18856f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
18866f5f1567SToby Isaac 
18876f5f1567SToby Isaac       pNewStart[d] = offset;
18889566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm,d,&pOldStart[d],&pOldEnd[d]));
18899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K,d,&kStart,&kEnd));
18906f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
18916f5f1567SToby Isaac       /* adding the new points */
18926f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
18936f5f1567SToby Isaac       if (!d) {
18946f5f1567SToby Isaac         /* removing the cell */
18956f5f1567SToby Isaac         pNewCount[d]--;
18966f5f1567SToby Isaac       }
18976f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18986f5f1567SToby Isaac         PetscInt parent;
18999566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K,k,&parent,NULL));
19006f5f1567SToby Isaac         if (parent == k) {
19016f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
19026f5f1567SToby Isaac           pNewCount[d]--;
19036f5f1567SToby Isaac         }
19046f5f1567SToby Isaac       }
19056f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
19066f5f1567SToby Isaac       offset = pNewEnd[d];
19076f5f1567SToby Isaac 
19086f5f1567SToby Isaac     }
19092c71b3e2SJacob Faibussowitsch     PetscCheckFalse(cell < pOldStart[0] || cell >= pOldEnd[0],PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"%d not in cell range [%d, %d)", cell, pOldStart[0], pOldEnd[0]);
19106f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
19119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure));
19126f5f1567SToby Isaac 
19139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pNewEnd[dim],&newConeSizes));
19146f5f1567SToby Isaac     {
1915b5a892a1SMatthew G. Knepley       DMPolytopeType pct, qct;
19166f5f1567SToby Isaac       PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
19176f5f1567SToby Isaac 
19189566063dSJacob Faibussowitsch       PetscCall(DMPlexGetChart(K,&kStart,&kEnd));
19199566063dSJacob Faibussowitsch       PetscCall(PetscMalloc4(kEnd-kStart,&Kembedding,kEnd-kStart,&perm,kEnd-kStart,&iperm,kEnd-kStart,&preOrient));
19206f5f1567SToby Isaac 
19216f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19226f5f1567SToby Isaac         perm[k - kStart] = k;
19236f5f1567SToby Isaac         iperm [k - kStart] = k - kStart;
19246f5f1567SToby Isaac         preOrient[k - kStart] = 0;
19256f5f1567SToby Isaac       }
19266f5f1567SToby Isaac 
19279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK));
19286f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
19296f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2*j+1];
19306f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2*j+1];
19316f5f1567SToby Isaac         PetscInt p, q;
19326f5f1567SToby Isaac 
19336f5f1567SToby Isaac         p = closureK[2*j];
19346f5f1567SToby Isaac         q = cellClosure[2*j];
19359566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(K, p, &pct));
19369566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, q, &qct));
19376f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
19386f5f1567SToby Isaac           if (q >= pOldStart[d] && q < pOldEnd[d]) {
19396f5f1567SToby Isaac             Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
19406f5f1567SToby Isaac           }
19416f5f1567SToby Isaac         }
1942b5a892a1SMatthew G. Knepley         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1943b5a892a1SMatthew G. Knepley         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
19446f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
19456f5f1567SToby Isaac           PetscInt numChildren, i;
19466f5f1567SToby Isaac           const PetscInt *children;
19476f5f1567SToby Isaac 
19489566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(K,p,&numChildren,&children));
19496f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
19506f5f1567SToby Isaac             PetscInt kPerm, oPerm;
19516f5f1567SToby Isaac 
19526f5f1567SToby Isaac             k    = children[i];
19539566063dSJacob Faibussowitsch             PetscCall(DMPlexReferenceTreeGetChildSymmetry(K,p,parentOrientA,0,k,parentOrientB,&oPerm,&kPerm));
19546f5f1567SToby Isaac             /* perm = what refTree position I'm in */
19556f5f1567SToby Isaac             perm[kPerm-kStart]      = k;
19566f5f1567SToby Isaac             /* iperm = who is at this position */
19576f5f1567SToby Isaac             iperm[k-kStart]         = kPerm-kStart;
19586f5f1567SToby Isaac             preOrient[kPerm-kStart] = oPerm;
19596f5f1567SToby Isaac           }
19606f5f1567SToby Isaac         }
19616f5f1567SToby Isaac       }
19629566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK));
19636f5f1567SToby Isaac     }
19649566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection,0,pNewEnd[dim]));
19656f5f1567SToby Isaac     offset = 0;
19666f5f1567SToby Isaac     numNewCones = 0;
19676f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19686f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
19696f5f1567SToby Isaac       PetscInt p;
19706f5f1567SToby Isaac       PetscInt size;
19716f5f1567SToby Isaac 
19726f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19736f5f1567SToby Isaac         /* skip cell 0 */
19746f5f1567SToby Isaac         if (p == cell) continue;
19756f5f1567SToby Isaac         /* old cones to new cones */
19769566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm,p,&size));
19776f5f1567SToby Isaac         newConeSizes[offset++] = size;
19786f5f1567SToby Isaac         numNewCones += size;
19796f5f1567SToby Isaac       }
19806f5f1567SToby Isaac 
19819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K,d,&kStart,&kEnd));
19826f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19836f5f1567SToby Isaac         PetscInt kParent;
19846f5f1567SToby Isaac 
19859566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K,k,&kParent,NULL));
19866f5f1567SToby Isaac         if (kParent != k) {
19876f5f1567SToby Isaac           Kembedding[k] = offset;
19889566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K,k,&size));
19896f5f1567SToby Isaac           newConeSizes[offset++] = size;
19906f5f1567SToby Isaac           numNewCones += size;
19916f5f1567SToby Isaac           if (kParent != 0) {
19929566063dSJacob Faibussowitsch             PetscCall(PetscSectionSetDof(parentSection,Kembedding[k],1));
19936f5f1567SToby Isaac           }
19946f5f1567SToby Isaac         }
19956f5f1567SToby Isaac       }
19966f5f1567SToby Isaac     }
19976f5f1567SToby Isaac 
19989566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
19999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(parentSection,&numPointsWithParents));
20009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numNewCones,&newCones,numNewCones,&newOrientations));
20019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPointsWithParents,&parents,numPointsWithParents,&childIDs));
20026f5f1567SToby Isaac 
20036f5f1567SToby Isaac     /* fill new cones */
20046f5f1567SToby Isaac     offset = 0;
20056f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20066f5f1567SToby Isaac       PetscInt kStart, kEnd, k, l;
20076f5f1567SToby Isaac       PetscInt p;
20086f5f1567SToby Isaac       PetscInt size;
20096f5f1567SToby Isaac       const PetscInt *cone, *orientation;
20106f5f1567SToby Isaac 
20116f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
20126f5f1567SToby Isaac         /* skip cell 0 */
20136f5f1567SToby Isaac         if (p == cell) continue;
20146f5f1567SToby Isaac         /* old cones to new cones */
20159566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm,p,&size));
20169566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm,p,&cone));
20179566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeOrientation(dm,p,&orientation));
20186f5f1567SToby Isaac         for (l = 0; l < size; l++) {
20196f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
20206f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
20216f5f1567SToby Isaac         }
20226f5f1567SToby Isaac       }
20236f5f1567SToby Isaac 
20249566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K,d,&kStart,&kEnd));
20256f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20266f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
20276f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
20286f5f1567SToby Isaac 
20299566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K,k,&kParent,NULL));
20306f5f1567SToby Isaac         if (kParent != k) {
20316f5f1567SToby Isaac           /* embed new cones */
20329566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K,k,&size));
20339566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(K,kPerm,&cone));
20349566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeOrientation(K,kPerm,&orientation));
20356f5f1567SToby Isaac           for (l = 0; l < size; l++) {
20366f5f1567SToby Isaac             PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size -(preO + 1) - l) % size);
20376f5f1567SToby Isaac             PetscInt newO, lSize, oTrue;
2038b5a892a1SMatthew G. Knepley             DMPolytopeType ct = DM_NUM_POLYTOPES;
20396f5f1567SToby Isaac 
20406f5f1567SToby Isaac             q                         = iperm[cone[m]];
20416f5f1567SToby Isaac             newCones[offset]          = Kembedding[q];
20429566063dSJacob Faibussowitsch             PetscCall(DMPlexGetConeSize(K,q,&lSize));
2043b5a892a1SMatthew G. Knepley             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
2044b5a892a1SMatthew G. Knepley             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
2045b5a892a1SMatthew G. Knepley             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
20466f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
20476f5f1567SToby Isaac             newO                      = DihedralCompose(lSize,oTrue,preOrient[q]);
2048b5a892a1SMatthew G. Knepley             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
20496f5f1567SToby Isaac           }
20506f5f1567SToby Isaac           if (kParent != 0) {
20516f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
20529566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(parentSection,Kembedding[k],&pOffset));
20536f5f1567SToby Isaac             parents[pOffset]  = newPoint;
20546f5f1567SToby Isaac             childIDs[pOffset] = k;
20556f5f1567SToby Isaac           }
20566f5f1567SToby Isaac         }
20576f5f1567SToby Isaac       }
20586f5f1567SToby Isaac     }
20596f5f1567SToby Isaac 
20609566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(dim*(pNewEnd[dim]-pNewStart[dim]),&newVertexCoords));
20616f5f1567SToby Isaac 
20626f5f1567SToby Isaac     /* fill coordinates */
20636f5f1567SToby Isaac     offset = 0;
20646f5f1567SToby Isaac     {
2065d90620a3SMatthew G. Knepley       PetscInt kStart, kEnd, l;
20666f5f1567SToby Isaac       PetscSection vSection;
20676f5f1567SToby Isaac       PetscInt v;
20686f5f1567SToby Isaac       Vec coords;
20696f5f1567SToby Isaac       PetscScalar *coordvals;
20706f5f1567SToby Isaac       PetscInt dof, off;
2071c111c6b7SMatthew G. Knepley       PetscReal v0[3], J[9], detJ;
20726f5f1567SToby Isaac 
207376bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
2074d90620a3SMatthew G. Knepley         PetscInt k;
20759566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(K,0,&kStart,&kEnd));
20766f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
20779566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
2078*08401ef6SPierre Jolivet           PetscCheck(detJ > 0.,PETSC_COMM_SELF,PETSC_ERR_PLIB,"reference tree cell %d has bad determinant",k);
20796f5f1567SToby Isaac         }
2080d90620a3SMatthew G. Knepley       }
20819566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
20829566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm,&vSection));
20839566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm,&coords));
20849566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords,&coordvals));
20856f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
20866f5f1567SToby Isaac 
20879566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(vSection,v,&dof));
20889566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(vSection,v,&off));
20896f5f1567SToby Isaac         for (l = 0; l < dof; l++) {
20906f5f1567SToby Isaac           newVertexCoords[offset++] = coordvals[off + l];
20916f5f1567SToby Isaac         }
20926f5f1567SToby Isaac       }
20939566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords,&coordvals));
20946f5f1567SToby Isaac 
20959566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(K,&vSection));
20969566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(K,&coords));
20979566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords,&coordvals));
20989566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(K,0,&kStart,&kEnd));
20996f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
21009bc368c7SMatthew G. Knepley         PetscReal coord[3], newCoord[3];
21016f5f1567SToby Isaac         PetscInt  vPerm = perm[v];
21026f5f1567SToby Isaac         PetscInt  kParent;
2103c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
21046f5f1567SToby Isaac 
21059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K,v,&kParent,NULL));
21066f5f1567SToby Isaac         if (kParent != v) {
21076f5f1567SToby Isaac           /* this is a new vertex */
21089566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(vSection,vPerm,&off));
21099bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off+l]);
2110367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
21119bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset+l] = newCoord[l];
21126f5f1567SToby Isaac           offset += dim;
21136f5f1567SToby Isaac         }
21146f5f1567SToby Isaac       }
21159566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords,&coordvals));
21166f5f1567SToby Isaac     }
21176f5f1567SToby Isaac 
21186f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
21196f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
21206f5f1567SToby Isaac       PetscInt tmp;
21216f5f1567SToby Isaac 
21226f5f1567SToby Isaac       tmp = pNewCount[d];
21236f5f1567SToby Isaac       pNewCount[d] = pNewCount[dim - d];
21246f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
21256f5f1567SToby Isaac     }
21266f5f1567SToby Isaac 
21279566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm,dim,pNewCount,newConeSizes,newCones,newOrientations,newVertexCoords));
21289566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm,K));
21299566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm,parentSection,parents,childIDs));
21306f5f1567SToby Isaac 
21316f5f1567SToby Isaac     /* clean up */
21329566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure));
21339566063dSJacob Faibussowitsch     PetscCall(PetscFree5(pNewCount,pNewStart,pNewEnd,pOldStart,pOldEnd));
21349566063dSJacob Faibussowitsch     PetscCall(PetscFree(newConeSizes));
21359566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCones,newOrientations));
21369566063dSJacob Faibussowitsch     PetscCall(PetscFree(newVertexCoords));
21379566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parents,childIDs));
21389566063dSJacob Faibussowitsch     PetscCall(PetscFree4(Kembedding,perm,iperm,preOrient));
21396f5f1567SToby Isaac   }
21406f5f1567SToby Isaac   else {
21416f5f1567SToby Isaac     PetscInt    p, counts[4];
21426f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
21436f5f1567SToby Isaac     Vec         coordVec;
21446f5f1567SToby Isaac     PetscScalar *coords;
21456f5f1567SToby Isaac 
21466f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
21476f5f1567SToby Isaac       PetscInt dStart, dEnd;
21486f5f1567SToby Isaac 
21499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm,d,&dStart,&dEnd));
21506f5f1567SToby Isaac       counts[d] = dEnd - dStart;
21516f5f1567SToby Isaac     }
21529566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEnd-pStart,&coneSizes));
21536f5f1567SToby Isaac     for (p = pStart; p < pEnd; p++) {
21549566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm,p,&coneSizes[p-pStart]));
21556f5f1567SToby Isaac     }
21569566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCones(dm, &cones));
21579566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientations(dm, &orientations));
21589566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm,&coordVec));
21599566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordVec,&coords));
21606f5f1567SToby Isaac 
21619566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection,pStart,pEnd));
21629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
21639566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm,dim,counts,coneSizes,cones,orientations,NULL));
21649566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm,K));
21659566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm,parentSection,NULL,NULL));
21669566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordVec,&coords));
21676f5f1567SToby Isaac   }
21689566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
21696f5f1567SToby Isaac 
21706f5f1567SToby Isaac   PetscFunctionReturn(0);
21716f5f1567SToby Isaac }
21726ecaa68aSToby Isaac 
21736ecaa68aSToby Isaac PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
21746ecaa68aSToby Isaac {
21756ecaa68aSToby Isaac   PetscSF           coarseToFineEmbedded;
21766ecaa68aSToby Isaac   PetscSection      globalCoarse, globalFine;
21776ecaa68aSToby Isaac   PetscSection      localCoarse, localFine;
21786ecaa68aSToby Isaac   PetscSection      aSec, cSec;
21796ecaa68aSToby Isaac   PetscSection      rootIndicesSec, rootMatricesSec;
218046bdb399SToby Isaac   PetscSection      leafIndicesSec, leafMatricesSec;
218146bdb399SToby Isaac   PetscInt          *rootIndices, *leafIndices;
218246bdb399SToby Isaac   PetscScalar       *rootMatrices, *leafMatrices;
21836ecaa68aSToby Isaac   IS                aIS;
21846ecaa68aSToby Isaac   const PetscInt    *anchors;
21856ecaa68aSToby Isaac   Mat               cMat;
21864acb8e1eSToby Isaac   PetscInt          numFields, maxFields;
21876ecaa68aSToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p;
21886ecaa68aSToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
21891c58ffc4SToby Isaac   PetscInt          *maxChildIds;
2190e44e4e7fSToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
21914acb8e1eSToby Isaac   const PetscInt    ***perms;
21924acb8e1eSToby Isaac   const PetscScalar ***flips;
21936ecaa68aSToby Isaac 
21946ecaa68aSToby Isaac   PetscFunctionBegin;
21959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
21969566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine,&pStartF,&pEndF));
21979566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine,&globalFine));
21986ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
219989698031SToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
220089698031SToby Isaac     const PetscInt *leaves;
22016ecaa68aSToby Isaac 
22029566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL));
220389698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
220489698031SToby Isaac       p = leaves ? leaves[l] : l;
22059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
22069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
22076ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
22086ecaa68aSToby Isaac         numPointsWithDofs++;
22096ecaa68aSToby Isaac       }
22106ecaa68aSToby Isaac     }
22119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
22127cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
221389698031SToby Isaac       p = leaves ? leaves[l] : l;
22149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
22159566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
22166ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
221789698031SToby Isaac         pointsWithDofs[offset++] = l;
22186ecaa68aSToby Isaac       }
22196ecaa68aSToby Isaac     }
22209566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
22219566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
22226ecaa68aSToby Isaac   }
22236ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
22249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC-pStartC,&maxChildIds));
22256ecaa68aSToby Isaac   for (p = pStartC; p < pEndC; p++) {
22268d2f55e7SToby Isaac     maxChildIds[p - pStartC] = -2;
22276ecaa68aSToby Isaac   }
22289566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX));
22299566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX));
223046bdb399SToby Isaac 
22319566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse,&localCoarse));
22329566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse,&globalCoarse));
223346bdb399SToby Isaac 
22349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse,&aSec,&aIS));
22359566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS,&anchors));
22369566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd));
223746bdb399SToby Isaac 
22389566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse,&cSec,&cMat,NULL));
22399566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec,&cStart,&cEnd));
224046bdb399SToby Isaac 
224146bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
22429566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec));
22439566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootMatricesSec));
22449566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootIndicesSec,pStartC,pEndC));
22459566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootMatricesSec,pStartC,pEndC));
22469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse,&numFields));
2247713c1c5dSToby Isaac   maxFields = PetscMax(1,numFields);
22489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc7(maxFields+1,&offsets,maxFields+1,&offsetsCopy,maxFields+1,&newOffsets,maxFields+1,&newOffsetsCopy,maxFields+1,&rowOffsets,maxFields+1,&numD,maxFields+1,&numO));
22499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxFields+1,(PetscInt****)&perms,maxFields+1,(PetscScalar****)&flips));
22509566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *) perms, (maxFields+1) * sizeof(const PetscInt **)));
22519566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *) flips, (maxFields+1) * sizeof(const PetscScalar **)));
225246bdb399SToby Isaac 
225346bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
22548d2f55e7SToby Isaac     PetscInt dof, matSize   = 0;
22556ecaa68aSToby Isaac     PetscInt aDof           = 0;
22566ecaa68aSToby Isaac     PetscInt cDof           = 0;
22576ecaa68aSToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
22586ecaa68aSToby Isaac     PetscInt numRowIndices  = 0;
22596ecaa68aSToby Isaac     PetscInt numColIndices  = 0;
2260f13f9184SToby Isaac     PetscInt f;
22616ecaa68aSToby Isaac 
22629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
22631cfc5b76SToby Isaac     if (dof < 0) {
22641cfc5b76SToby Isaac       dof = -(dof + 1);
22651cfc5b76SToby Isaac     }
22666ecaa68aSToby Isaac     if (p >= aStart && p < aEnd) {
22679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(aSec,p,&aDof));
22686ecaa68aSToby Isaac     }
22696ecaa68aSToby Isaac     if (p >= cStart && p < cEnd) {
22709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec,p,&cDof));
22716ecaa68aSToby Isaac     }
2272f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2273f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
22746ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2275f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
22766ecaa68aSToby Isaac 
22779566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
227846bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
22796ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
22806ecaa68aSToby Isaac 
22819566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse,c,&clDof));
22826ecaa68aSToby Isaac         numRowIndices += clDof;
22836ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
22849566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse,c,f,&clDof));
22856ecaa68aSToby Isaac           offsets[f + 1] += clDof;
22866ecaa68aSToby Isaac         }
22876ecaa68aSToby Isaac       }
22886ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
22896ecaa68aSToby Isaac         offsets[f + 1]   += offsets[f];
22906ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
22916ecaa68aSToby Isaac       }
229246bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
22939566063dSJacob Faibussowitsch       PetscCall(DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,NULL,NULL,NULL,&numColIndices,NULL,NULL,newOffsets,PETSC_FALSE));
22949566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
22956ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
22966ecaa68aSToby Isaac         numColIndices = numRowIndices;
22976ecaa68aSToby Isaac         matSize = 0;
22986ecaa68aSToby Isaac       }
229946bdb399SToby Isaac       else if (numFields) { /* we send one submat for each field: sum their sizes */
23006ecaa68aSToby Isaac         matSize = 0;
23016ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23026ecaa68aSToby Isaac           PetscInt numRow, numCol;
23036ecaa68aSToby Isaac 
23046ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2305f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
23066ecaa68aSToby Isaac           matSize += numRow * numCol;
23076ecaa68aSToby Isaac         }
23086ecaa68aSToby Isaac       }
23096ecaa68aSToby Isaac       else {
23106ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
23116ecaa68aSToby Isaac       }
2312f13f9184SToby Isaac     } else if (maxChildId == -1) {
23138d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2314f13f9184SToby Isaac         PetscInt aOff, a;
23156ecaa68aSToby Isaac 
23169566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec,p,&aOff));
23176ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23186ecaa68aSToby Isaac           PetscInt fDof;
23196ecaa68aSToby Isaac 
23209566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
232121968bf8SToby Isaac           offsets[f+1] = fDof;
23226ecaa68aSToby Isaac         }
23236ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
23246ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
23256ecaa68aSToby Isaac 
23269566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(localCoarse,anchor,&aLocalDof));
23276ecaa68aSToby Isaac           numColIndices += aLocalDof;
23286ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23296ecaa68aSToby Isaac             PetscInt fDof;
23306ecaa68aSToby Isaac 
23319566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof));
233221968bf8SToby Isaac             newOffsets[f+1] += fDof;
23336ecaa68aSToby Isaac           }
23346ecaa68aSToby Isaac         }
23356ecaa68aSToby Isaac         if (numFields) {
23366ecaa68aSToby Isaac           matSize = 0;
23376ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
233821968bf8SToby Isaac             matSize += offsets[f+1] * newOffsets[f+1];
23396ecaa68aSToby Isaac           }
23406ecaa68aSToby Isaac         }
23416ecaa68aSToby Isaac         else {
23426ecaa68aSToby Isaac           matSize = numColIndices * dof;
23436ecaa68aSToby Isaac         }
23446ecaa68aSToby Isaac       }
23456ecaa68aSToby Isaac       else { /* no children, and no constraints on dofs: just get the global indices */
23466ecaa68aSToby Isaac         numColIndices = dof;
23476ecaa68aSToby Isaac         matSize       = 0;
23486ecaa68aSToby Isaac       }
23498d2f55e7SToby Isaac     }
235046bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
23519566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootIndicesSec,p,numColIndices ? numColIndices+2*numFields : 0));
23529566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootMatricesSec,p,matSize));
23536ecaa68aSToby Isaac   }
23549566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootIndicesSec));
23559566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootMatricesSec));
23566ecaa68aSToby Isaac   {
23576ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
23586ecaa68aSToby Isaac 
23599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices));
23609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootMatricesSec,&numRootMatrices));
23619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numRootIndices,&rootIndices,numRootMatrices,&rootMatrices));
23626ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
23636ecaa68aSToby Isaac       PetscInt    numRowIndices, numColIndices, matSize, dof;
2364f13f9184SToby Isaac       PetscInt    pIndOff, pMatOff, f;
23656ecaa68aSToby Isaac       PetscInt    *pInd;
23666ecaa68aSToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
23676ecaa68aSToby Isaac       PetscScalar *pMat = NULL;
23686ecaa68aSToby Isaac 
23699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec,p,&numColIndices));
23706ecaa68aSToby Isaac       if (!numColIndices) {
23716ecaa68aSToby Isaac         continue;
23726ecaa68aSToby Isaac       }
2373f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2374f13f9184SToby Isaac         offsets[f]        = 0;
2375f13f9184SToby Isaac         newOffsets[f]     = 0;
2376f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2377f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2378f13f9184SToby Isaac       }
23796ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
23809566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec,p,&pIndOff));
23816ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
23829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootMatricesSec,p,&matSize));
23836ecaa68aSToby Isaac       if (matSize) {
23849566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootMatricesSec,p,&pMatOff));
23856ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
23866ecaa68aSToby Isaac       }
23879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
23881cfc5b76SToby Isaac       if (dof < 0) {
23891cfc5b76SToby Isaac         dof = -(dof + 1);
23901cfc5b76SToby Isaac       }
23916ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
23926ecaa68aSToby Isaac         PetscInt i, j;
23936ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
23946ecaa68aSToby Isaac 
23956ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
23966ecaa68aSToby Isaac           PetscInt numIndices, *indices;
23979566063dSJacob Faibussowitsch           PetscCall(DMPlexGetClosureIndices(coarse,localCoarse,globalCoarse,p,PETSC_TRUE,&numIndices,&indices,offsets,NULL));
2398*08401ef6SPierre Jolivet           PetscCheck(numIndices == numColIndices,PETSC_COMM_SELF,PETSC_ERR_PLIB,"mismatching constraint indices calculations");
23996ecaa68aSToby Isaac           for (i = 0; i < numColIndices; i++) {
24006ecaa68aSToby Isaac             pInd[i] = indices[i];
24016ecaa68aSToby Isaac           }
24026ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
240346bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i+1];
240446bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i+1];
24056ecaa68aSToby Isaac           }
24069566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreClosureIndices(coarse,localCoarse,globalCoarse,p,PETSC_TRUE,&numIndices,&indices,offsets,NULL));
24076ecaa68aSToby Isaac         }
24086ecaa68aSToby Isaac         else {
24096ecaa68aSToby Isaac           PetscInt closureSize, *closure = NULL, cl;
24106ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
24116ecaa68aSToby Isaac           PetscInt numPoints,*points;
24126ecaa68aSToby Isaac 
24139566063dSJacob Faibussowitsch           PetscCall(DMGetWorkArray(coarse,numRowIndices * numRowIndices,MPIU_SCALAR,&pMatIn));
24146ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
24156ecaa68aSToby Isaac             for (j = 0; j < numRowIndices; j++) {
24166ecaa68aSToby Isaac               pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
24176ecaa68aSToby Isaac             }
24186ecaa68aSToby Isaac           }
24199566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
24204acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24219566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]));
24229566063dSJacob Faibussowitsch             else           PetscCall(PetscSectionGetPointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]));
24234acb8e1eSToby Isaac           }
24246ecaa68aSToby Isaac           if (numFields) {
24256ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
24266ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
24276ecaa68aSToby Isaac 
24286ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
24296ecaa68aSToby Isaac                 PetscInt fDof;
24306ecaa68aSToby Isaac 
24319566063dSJacob Faibussowitsch                 PetscCall(PetscSectionGetFieldDof(localCoarse,c,f,&fDof));
24326ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
24336ecaa68aSToby Isaac               }
24346ecaa68aSToby Isaac             }
24356ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
24366ecaa68aSToby Isaac               offsets[f + 1]   += offsets[f];
24376ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
24386ecaa68aSToby Isaac             }
24396ecaa68aSToby Isaac           }
24404acb8e1eSToby Isaac           /* TODO : flips here ? */
24416ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
24429566063dSJacob Faibussowitsch           PetscCall(DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,perms,pMatIn,&numPoints,NULL,&points,&pMatModified,newOffsets,PETSC_FALSE));
24434acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24449566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]));
24459566063dSJacob Faibussowitsch             else           PetscCall(PetscSectionRestorePointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]));
24464acb8e1eSToby Isaac           }
24474acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24489566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]));
24499566063dSJacob Faibussowitsch             else           PetscCall(PetscSectionGetPointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]));
24504acb8e1eSToby Isaac           }
24516ecaa68aSToby Isaac           if (!numFields) {
24526ecaa68aSToby Isaac             for (i = 0; i < numRowIndices * numColIndices; i++) {
24536ecaa68aSToby Isaac               pMat[i] = pMatModified[i];
24546ecaa68aSToby Isaac             }
24556ecaa68aSToby Isaac           }
24566ecaa68aSToby Isaac           else {
2457f13f9184SToby Isaac             PetscInt i, j, count;
24586ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
24596ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f+1]; i++) {
24606ecaa68aSToby Isaac                 for (j = newOffsets[f]; j < newOffsets[f+1]; j++, count++) {
24616ecaa68aSToby Isaac                   pMat[count] = pMatModified[i * numColIndices + j];
24626ecaa68aSToby Isaac                 }
24636ecaa68aSToby Isaac               }
24646ecaa68aSToby Isaac             }
24656ecaa68aSToby Isaac           }
24669566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatModified));
24679566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
24689566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatIn));
24696ecaa68aSToby Isaac           if (numFields) {
247046bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
247146bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f+1];
247246bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f+1];
24736ecaa68aSToby Isaac             }
24744acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
24754acb8e1eSToby Isaac               PetscInt globalOff, c = points[2*cl];
24769566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
24779566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
24786ecaa68aSToby Isaac             }
24796ecaa68aSToby Isaac           } else {
24804acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
24814acb8e1eSToby Isaac               PetscInt c = points[2*cl], globalOff;
24824acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
24834acb8e1eSToby Isaac 
24849566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
24859566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
24866ecaa68aSToby Isaac             }
24876ecaa68aSToby Isaac           }
24884acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24899566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]));
24909566063dSJacob Faibussowitsch             else           PetscCall(PetscSectionRestorePointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]));
24914acb8e1eSToby Isaac           }
24929566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse,numPoints,MPIU_SCALAR,&points));
24936ecaa68aSToby Isaac         }
24946ecaa68aSToby Isaac       }
24956ecaa68aSToby Isaac       else if (matSize) {
24966ecaa68aSToby Isaac         PetscInt cOff;
24976ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
24986ecaa68aSToby Isaac 
24996ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
2500*08401ef6SPierre Jolivet         PetscCheck(numRowIndices == dof,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Miscounted dofs");
25019566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices));
25029566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse,numColIndices,MPIU_INT,&colIndices));
25039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec,p,&cOff));
25049566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec,p,&aDof));
25059566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec,p,&aOff));
25066ecaa68aSToby Isaac         if (numFields) {
25076ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25086ecaa68aSToby Isaac             PetscInt fDof;
2509f13f9184SToby Isaac 
25109566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSec,p,f,&fDof));
25116ecaa68aSToby Isaac             offsets[f + 1] = fDof;
25126ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
25136ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
25149566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof));
25156ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
25166ecaa68aSToby Isaac             }
25176ecaa68aSToby Isaac           }
25186ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25196ecaa68aSToby Isaac             offsets[f + 1]       += offsets[f];
25206ecaa68aSToby Isaac             offsetsCopy[f + 1]    = offsets[f + 1];
25216ecaa68aSToby Isaac             newOffsets[f + 1]    += newOffsets[f];
25226ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
25236ecaa68aSToby Isaac           }
25249566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec,PETSC_TRUE,p,cOff,offsetsCopy,PETSC_TRUE,NULL,-1, NULL,rowIndices));
25256ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25266ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25279566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse,anchor,&lOff));
25289566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_TRUE,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL,-1, NULL,colIndices));
25296ecaa68aSToby Isaac           }
25306ecaa68aSToby Isaac         }
25316ecaa68aSToby Isaac         else {
25329566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(cSec,PETSC_TRUE,p,cOff,offsetsCopy,PETSC_TRUE,NULL, NULL,rowIndices));
25336ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25346ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25359566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse,anchor,&lOff));
25369566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_TRUE,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL, NULL,colIndices));
25376ecaa68aSToby Isaac           }
25386ecaa68aSToby Isaac         }
25396ecaa68aSToby Isaac         if (numFields) {
2540f13f9184SToby Isaac           PetscInt count, a;
2541f13f9184SToby Isaac 
25426ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
25436ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
25446ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
25459566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat,iSize,&rowIndices[offsets[f]],jSize,&colIndices[newOffsets[f]],&pMat[count]));
25466ecaa68aSToby Isaac             count += iSize * jSize;
254746bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
254846bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f+1];
25496ecaa68aSToby Isaac           }
25506ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25516ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25526ecaa68aSToby Isaac             PetscInt gOff;
25539566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse,anchor,&gOff));
25549566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL,-1, NULL,pInd));
25556ecaa68aSToby Isaac           }
25566ecaa68aSToby Isaac         }
25576ecaa68aSToby Isaac         else {
25586ecaa68aSToby Isaac           PetscInt a;
25599566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat,numRowIndices,rowIndices,numColIndices,colIndices,pMat));
25606ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25616ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25626ecaa68aSToby Isaac             PetscInt gOff;
25639566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse,anchor,&gOff));
25649566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL, NULL,pInd));
25656ecaa68aSToby Isaac           }
25666ecaa68aSToby Isaac         }
25679566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse,numColIndices,MPIU_INT,&colIndices));
25689566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices));
25696ecaa68aSToby Isaac       }
25706ecaa68aSToby Isaac       else {
25716ecaa68aSToby Isaac         PetscInt gOff;
25726ecaa68aSToby Isaac 
25739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalCoarse,p,&gOff));
25746ecaa68aSToby Isaac         if (numFields) {
25756ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25766ecaa68aSToby Isaac             PetscInt fDof;
25779566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
25786ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
25796ecaa68aSToby Isaac           }
25806ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
258146bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
258246bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f+1];
25836ecaa68aSToby Isaac           }
25849566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1, NULL,pInd));
2585367003a6SStefano Zampini         } else {
25869566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL, NULL,pInd));
25876ecaa68aSToby Isaac         }
25886ecaa68aSToby Isaac       }
25896ecaa68aSToby Isaac     }
25909566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
25916ecaa68aSToby Isaac   }
259246bdb399SToby Isaac   {
259346bdb399SToby Isaac     PetscSF  indicesSF, matricesSF;
259446bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
259546bdb399SToby Isaac 
25969566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec));
25979566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafMatricesSec));
25989566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded,rootIndicesSec,&remoteOffsetsIndices,leafIndicesSec));
25999566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded,rootMatricesSec,&remoteOffsetsMatrices,leafMatricesSec));
26009566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded,rootIndicesSec,remoteOffsetsIndices,leafIndicesSec,&indicesSF));
26019566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded,rootMatricesSec,remoteOffsetsMatrices,leafMatricesSec,&matricesSF));
26029566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
26039566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsIndices));
26049566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsMatrices));
26059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec,&numLeafIndices));
26069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafMatricesSec,&numLeafMatrices));
26079566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numLeafIndices,&leafIndices,numLeafMatrices,&leafMatrices));
26089566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(indicesSF,MPIU_INT,rootIndices,leafIndices,MPI_REPLACE));
26099566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices,MPI_REPLACE));
26109566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(indicesSF,MPIU_INT,rootIndices,leafIndices,MPI_REPLACE));
26119566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices,MPI_REPLACE));
26129566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&matricesSF));
26139566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
26149566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rootIndices,rootMatrices));
26159566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootIndicesSec));
26169566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootMatricesSec));
261746bdb399SToby Isaac   }
261846bdb399SToby Isaac   /* count to preallocate */
26199566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine,&localFine));
262046bdb399SToby Isaac   {
262146bdb399SToby Isaac     PetscInt    nGlobal;
262246bdb399SToby Isaac     PetscInt    *dnnz, *onnz;
2623b9a5774bSToby Isaac     PetscLayout rowMap, colMap;
2624b9a5774bSToby Isaac     PetscInt    rowStart, rowEnd, colStart, colEnd;
26251c58ffc4SToby Isaac     PetscInt    maxDof;
26261c58ffc4SToby Isaac     PetscInt    *rowIndices;
26271c58ffc4SToby Isaac     DM           refTree;
26281c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
26291c58ffc4SToby Isaac     PetscScalar  ***refPointFieldMats;
26301c58ffc4SToby Isaac     PetscSection refConSec, refAnSec;
26310eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,maxConDof,maxColumns,leafStart,leafEnd;
26321c58ffc4SToby Isaac     PetscScalar  *pointWork;
263346bdb399SToby Isaac 
26349566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine,&nGlobal));
26359566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nGlobal,&dnnz,nGlobal,&onnz));
26369566063dSJacob Faibussowitsch     PetscCall(MatGetLayouts(mat,&rowMap,&colMap));
26379566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rowMap));
26389566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(colMap));
26399566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rowMap,&rowStart,&rowEnd));
26409566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(colMap,&colStart,&colEnd));
26419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine,&maxDof));
26429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafIndicesSec,&leafStart,&leafEnd));
26439566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
26440eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
264546bdb399SToby Isaac       PetscInt    gDof, gcDof, gOff;
264646bdb399SToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
264746bdb399SToby Isaac       PetscInt    matSize;
264821968bf8SToby Isaac       PetscInt    i;
264946bdb399SToby Isaac 
26509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&gDof));
26519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&gcDof));
265246bdb399SToby Isaac       if ((gDof - gcDof) <= 0) {
265346bdb399SToby Isaac         continue;
265446bdb399SToby Isaac       }
26559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine,p,&gOff));
2656*08401ef6SPierre Jolivet       PetscCheck(gOff >= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"I though having global dofs meant a non-negative offset");
26572c71b3e2SJacob Faibussowitsch       PetscCheckFalse((gOff < rowStart) || ((gOff + gDof - gcDof) > rowEnd),PETSC_COMM_SELF,PETSC_ERR_PLIB,"I thought the row map would constrain the global dofs");
26589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec,p,&numColIndices));
26599566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec,p,&pIndOff));
266046bdb399SToby Isaac       numColIndices -= 2 * numFields;
2661*08401ef6SPierre Jolivet       PetscCheck(numColIndices > 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"global fine dof with no dofs to interpolate from");
266246bdb399SToby Isaac       pInd = &leafIndices[pIndOff];
266321968bf8SToby Isaac       offsets[0]        = 0;
266421968bf8SToby Isaac       offsetsCopy[0]    = 0;
266521968bf8SToby Isaac       newOffsets[0]     = 0;
266621968bf8SToby Isaac       newOffsetsCopy[0] = 0;
266746bdb399SToby Isaac       if (numFields) {
266821968bf8SToby Isaac         PetscInt f;
266946bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
267046bdb399SToby Isaac           PetscInt rowDof;
267146bdb399SToby Isaac 
26729566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine,p,f,&rowDof));
267321968bf8SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
267421968bf8SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
267521968bf8SToby Isaac           newOffsets[f + 1]     = pInd[numColIndices + numFields + f];
267621968bf8SToby Isaac           numD[f] = 0;
267721968bf8SToby Isaac           numO[f] = 0;
267846bdb399SToby Isaac         }
26799566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,rowIndices));
268046bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
268121968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
268221968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
268346bdb399SToby Isaac 
268446bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
268546bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
268646bdb399SToby Isaac 
268746bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
268821968bf8SToby Isaac               numD[f]++;
268946bdb399SToby Isaac             }
269046bdb399SToby Isaac             else if (gInd >= 0) { /* negative means non-entry */
269121968bf8SToby Isaac               numO[f]++;
269246bdb399SToby Isaac             }
269346bdb399SToby Isaac           }
269446bdb399SToby Isaac         }
269546bdb399SToby Isaac       }
269646bdb399SToby Isaac       else {
26979566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,rowIndices));
269821968bf8SToby Isaac         numD[0] = 0;
269921968bf8SToby Isaac         numO[0] = 0;
270046bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
270146bdb399SToby Isaac           PetscInt gInd = pInd[i];
270246bdb399SToby Isaac 
270346bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
270421968bf8SToby Isaac             numD[0]++;
270546bdb399SToby Isaac           }
270646bdb399SToby Isaac           else if (gInd >= 0) { /* negative means non-entry */
270721968bf8SToby Isaac             numO[0]++;
270846bdb399SToby Isaac           }
270946bdb399SToby Isaac         }
271046bdb399SToby Isaac       }
27119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec,p,&matSize));
271246bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
271346bdb399SToby Isaac         PetscInt childId;
271446bdb399SToby Isaac 
271546bdb399SToby Isaac         childId = childIds[p-pStartF];
271621968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
271746bdb399SToby Isaac           if (numFields) {
2718b9a5774bSToby Isaac             PetscInt f;
2719b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
272021968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
272146bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
272221968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
272321968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
272446bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
27252c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2726b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
272746bdb399SToby Isaac                 }
272846bdb399SToby Isaac                 else if (gIndCoarse >= 0) { /* remote */
27292c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2730b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
273146bdb399SToby Isaac                 }
273246bdb399SToby Isaac                 else { /* constrained */
2733*08401ef6SPierre Jolivet                   PetscCheck(gIndFine < 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
273446bdb399SToby Isaac                 }
273546bdb399SToby Isaac               }
273646bdb399SToby Isaac             }
273746bdb399SToby Isaac           }
273846bdb399SToby Isaac           else {
2739b9a5774bSToby Isaac             PetscInt i;
2740b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
274146bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
274246bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
274346bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
27442c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2745b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
274646bdb399SToby Isaac               }
274746bdb399SToby Isaac               else if (gIndCoarse >= 0) { /* remote */
27482c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2749b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
275046bdb399SToby Isaac               }
275146bdb399SToby Isaac               else { /* constrained */
2752*08401ef6SPierre Jolivet                 PetscCheck(gIndFine < 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
275346bdb399SToby Isaac               }
275446bdb399SToby Isaac             }
275546bdb399SToby Isaac           }
275646bdb399SToby Isaac         }
275746bdb399SToby Isaac         else { /* interpolate from all */
275846bdb399SToby Isaac           if (numFields) {
2759b9a5774bSToby Isaac             PetscInt f;
2760b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
276121968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
276246bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
276321968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
276446bdb399SToby Isaac                 if (gIndFine >= 0) {
27652c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2766b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2767b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
276846bdb399SToby Isaac                 }
276946bdb399SToby Isaac               }
277046bdb399SToby Isaac             }
277146bdb399SToby Isaac           }
277246bdb399SToby Isaac           else {
2773b9a5774bSToby Isaac             PetscInt i;
2774b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
277546bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
277646bdb399SToby Isaac               if (gIndFine >= 0) {
27772c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2778b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2779b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
278046bdb399SToby Isaac               }
278146bdb399SToby Isaac             }
278246bdb399SToby Isaac           }
278346bdb399SToby Isaac         }
278446bdb399SToby Isaac       }
278546bdb399SToby Isaac       else { /* interpolate from all */
278646bdb399SToby Isaac         if (numFields) {
2787b9a5774bSToby Isaac           PetscInt f;
2788b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
278921968bf8SToby Isaac             PetscInt numRows = offsets[f+1] - offsets[f], row;
279046bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
279121968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
279246bdb399SToby Isaac               if (gIndFine >= 0) {
27932c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2794b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2795b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
279646bdb399SToby Isaac               }
279746bdb399SToby Isaac             }
279846bdb399SToby Isaac           }
279946bdb399SToby Isaac         }
280046bdb399SToby Isaac         else { /* every dof get a full row */
2801b9a5774bSToby Isaac           PetscInt i;
2802b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
280346bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
280446bdb399SToby Isaac             if (gIndFine >= 0) {
28052c71b3e2SJacob Faibussowitsch               PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2806b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2807b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
280846bdb399SToby Isaac             }
280946bdb399SToby Isaac           }
281046bdb399SToby Isaac         }
281146bdb399SToby Isaac       }
281246bdb399SToby Isaac     }
28139566063dSJacob Faibussowitsch     PetscCall(MatXAIJSetPreallocation(mat,1,dnnz,onnz,NULL,NULL));
28149566063dSJacob Faibussowitsch     PetscCall(PetscFree2(dnnz,onnz));
281521968bf8SToby Isaac 
28169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine,&refTree));
28179566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
28189566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
28199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree,&refAnSec,NULL));
28209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
28219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(refConSec,&maxConDof));
28229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(leafIndicesSec,&maxColumns));
28239566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxConDof*maxColumns,&pointWork));
28240eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2825e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2826e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2827e44e4e7fSToby Isaac       PetscInt matSize;
2828e44e4e7fSToby Isaac       PetscInt childId;
2829e44e4e7fSToby Isaac 
28309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&gDof));
28319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&gcDof));
2832e44e4e7fSToby Isaac       if ((gDof - gcDof) <= 0) {
2833e44e4e7fSToby Isaac         continue;
2834e44e4e7fSToby Isaac       }
2835e44e4e7fSToby Isaac       childId = childIds[p-pStartF];
28369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine,p,&gOff));
28379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec,p,&numColIndices));
28389566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec,p,&pIndOff));
2839e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2840e44e4e7fSToby Isaac       pInd = &leafIndices[pIndOff];
2841e44e4e7fSToby Isaac       offsets[0]        = 0;
2842e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2843e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2844e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2845e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2846e44e4e7fSToby Isaac       if (numFields) {
2847e44e4e7fSToby Isaac         PetscInt f;
2848e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2849e44e4e7fSToby Isaac           PetscInt rowDof;
2850e44e4e7fSToby Isaac 
28519566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine,p,f,&rowDof));
2852e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2853e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2854e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2855e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2856e44e4e7fSToby Isaac         }
28579566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,rowIndices));
2858e44e4e7fSToby Isaac       }
28591c58ffc4SToby Isaac       else {
28609566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,rowIndices));
28611c58ffc4SToby Isaac       }
28629566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec,p,&matSize));
2863e44e4e7fSToby Isaac       if (!matSize) { /* incoming matrix is identity */
2864e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2865e44e4e7fSToby Isaac           if (numFields) {
2866e44e4e7fSToby Isaac             PetscInt f;
2867e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2868e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
2869e44e4e7fSToby Isaac               for (row = 0; row < numRows; row++) {
28709566063dSJacob Faibussowitsch                 PetscCall(MatSetValue(mat,rowIndices[offsets[f]+row],pInd[newOffsets[f]+row],1.,INSERT_VALUES));
287121968bf8SToby Isaac               }
287221968bf8SToby Isaac             }
2873e44e4e7fSToby Isaac           }
2874e44e4e7fSToby Isaac           else {
2875e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
2876e44e4e7fSToby Isaac             for (row = 0; row < numRows; row++) {
28779566063dSJacob Faibussowitsch               PetscCall(MatSetValue(mat,rowIndices[row],pInd[row],1.,INSERT_VALUES));
2878e44e4e7fSToby Isaac             }
2879e44e4e7fSToby Isaac           }
2880e44e4e7fSToby Isaac         }
2881e44e4e7fSToby Isaac         else { /* interpolate from all */
2882e44e4e7fSToby Isaac           if (numFields) {
2883e44e4e7fSToby Isaac             PetscInt f;
2884e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2885e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f];
2886e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
28879566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],refPointFieldMats[childId - pRefStart][f],INSERT_VALUES));
2888e44e4e7fSToby Isaac             }
2889e44e4e7fSToby Isaac           }
2890e44e4e7fSToby Isaac           else {
28919566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,refPointFieldMats[childId - pRefStart][0],INSERT_VALUES));
2892e44e4e7fSToby Isaac           }
2893e44e4e7fSToby Isaac         }
2894e44e4e7fSToby Isaac       }
2895e44e4e7fSToby Isaac       else { /* interpolate from all */
2896e44e4e7fSToby Isaac         PetscInt    pMatOff;
2897e44e4e7fSToby Isaac         PetscScalar *pMat;
2898e44e4e7fSToby Isaac 
28999566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafMatricesSec,p,&pMatOff));
2900e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2901e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2902e44e4e7fSToby Isaac           if (numFields) {
2903e44e4e7fSToby Isaac             PetscInt f, count;
2904e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2905e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2906e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2907e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2908e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2909e44e4e7fSToby Isaac 
29109566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],inMat,INSERT_VALUES));
2911e44e4e7fSToby Isaac               count += numCols * numInRows;
2912e44e4e7fSToby Isaac             }
2913e44e4e7fSToby Isaac           }
2914e44e4e7fSToby Isaac           else {
29159566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,pMat,INSERT_VALUES));
2916e44e4e7fSToby Isaac           }
2917e44e4e7fSToby Isaac         }
2918e44e4e7fSToby Isaac         else { /* multiply the incoming matrix by the child interpolation */
2919e44e4e7fSToby Isaac           if (numFields) {
2920e44e4e7fSToby Isaac             PetscInt f, count;
2921e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2922e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2923e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2924e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2925e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2926e44e4e7fSToby Isaac               PetscInt i, j, k;
2927*08401ef6SPierre Jolivet               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2928e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2929e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2930e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2931e44e4e7fSToby Isaac                   for (k = 0; k < numInRows; k++) {
2932e44e4e7fSToby Isaac                     val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2933e44e4e7fSToby Isaac                   }
2934e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2935e44e4e7fSToby Isaac                 }
2936e44e4e7fSToby Isaac               }
29379566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],pointWork,INSERT_VALUES));
2938e44e4e7fSToby Isaac               count += numCols * numInRows;
2939e44e4e7fSToby Isaac             }
2940e44e4e7fSToby Isaac           }
2941267d4f3fSToby Isaac           else { /* every dof gets a full row */
2942e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2943e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2944e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2945e44e4e7fSToby Isaac             PetscInt i, j, k;
2946*08401ef6SPierre Jolivet             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2947e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2948e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2949e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2950e44e4e7fSToby Isaac                 for (k = 0; k < numInRows; k++) {
2951e44e4e7fSToby Isaac                   val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2952e44e4e7fSToby Isaac                 }
2953e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2954e44e4e7fSToby Isaac               }
2955e44e4e7fSToby Isaac             }
29569566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat,numRows,rowIndices,numCols,pInd,pointWork,INSERT_VALUES));
2957e44e4e7fSToby Isaac           }
2958e44e4e7fSToby Isaac         }
2959e44e4e7fSToby Isaac       }
2960e44e4e7fSToby Isaac     }
29619566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
29629566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
29639566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointWork));
2964e44e4e7fSToby Isaac   }
29659566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
29669566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
29679566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
29689566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafMatricesSec));
29699566063dSJacob Faibussowitsch   PetscCall(PetscFree2(leafIndices,leafMatrices));
29709566063dSJacob Faibussowitsch   PetscCall(PetscFree2(*(PetscInt****)&perms,*(PetscScalar****)&flips));
29719566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO));
29729566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS,&anchors));
29736ecaa68aSToby Isaac   PetscFunctionReturn(0);
29746ecaa68aSToby Isaac }
2975154bca37SToby Isaac 
29768d2f55e7SToby Isaac /*
29778d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
29788d2f55e7SToby Isaac  *
29798d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
29808d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
29818d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
29828d2f55e7SToby Isaac  *       a_{i,j} = 0;
29838d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
29848d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
29858d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
29868d2f55e7SToby Isaac  */
29878d2f55e7SToby Isaac PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
29888d2f55e7SToby Isaac {
29898d2f55e7SToby Isaac   PetscDS        ds;
29908d2f55e7SToby Isaac   PetscSection   section, cSection;
29918d2f55e7SToby Isaac   DMLabel        canonical, depth;
29928d2f55e7SToby Isaac   Mat            cMat, mat;
29938d2f55e7SToby Isaac   PetscInt       *nnz;
29948d2f55e7SToby Isaac   PetscInt       f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
29958d2f55e7SToby Isaac   PetscInt       m, n;
29968d2f55e7SToby Isaac   PetscScalar    *pointScalar;
29978d2f55e7SToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
29988d2f55e7SToby Isaac 
29998d2f55e7SToby Isaac   PetscFunctionBegin;
30009566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree,&section));
30019566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(refTree, &dim));
30029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(dim,&v0,dim,&v0parent,dim,&vtmp,dim*dim,&J,dim*dim,&Jparent,dim*dim,&invJ));
30039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(dim,&pointScalar,dim,&pointRef));
30049566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree,&ds));
30059566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
30069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section,&numSecFields));
30079566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree,"canonical",&canonical));
30089566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree,"depth",&depth));
30099566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&cSection,&cMat,NULL));
30109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
30119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
30129566063dSJacob Faibussowitsch   PetscCall(MatGetSize(cMat,&n,&m)); /* the injector has transpose sizes from the constraint matrix */
30138d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
30149566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(m,&nnz));
30158d2f55e7SToby 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 */
30168d2f55e7SToby Isaac     const PetscInt *children;
30178d2f55e7SToby Isaac     PetscInt numChildren;
30188d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30198d2f55e7SToby Isaac 
30208d2f55e7SToby Isaac     if (canonical) {
30218d2f55e7SToby Isaac       PetscInt pCanonical;
30229566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical,p,&pCanonical));
30238d2f55e7SToby Isaac       if (p != pCanonical) continue;
30248d2f55e7SToby Isaac     }
30259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree,p,&numChildren,&children));
30268d2f55e7SToby Isaac     if (!numChildren) continue;
30278d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30288d2f55e7SToby Isaac       PetscInt child = children[i];
30298d2f55e7SToby Isaac       PetscInt dof;
30308d2f55e7SToby Isaac 
30319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,child,&dof));
30328d2f55e7SToby Isaac       numChildDof += dof;
30338d2f55e7SToby Isaac     }
30349566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section,p,&numSelfDof));
30358d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30368d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
30378d2f55e7SToby Isaac       PetscInt selfOff;
30388d2f55e7SToby Isaac 
30398d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
30408d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
30418d2f55e7SToby Isaac           PetscInt child = children[i];
30428d2f55e7SToby Isaac           PetscInt dof;
30438d2f55e7SToby Isaac 
30449566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,child,f,&dof));
30458d2f55e7SToby Isaac           numChildDof += dof;
30468d2f55e7SToby Isaac         }
30479566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section,p,f,&numSelfDof));
30489566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section,p,f,&selfOff));
30498d2f55e7SToby Isaac       }
30508d2f55e7SToby Isaac       else {
30519566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section,p,&selfOff));
30528d2f55e7SToby Isaac       }
30538d2f55e7SToby Isaac       for (i = 0; i < numSelfDof; i++) {
30548d2f55e7SToby Isaac         nnz[selfOff + i] = numChildDof;
30558d2f55e7SToby Isaac       }
30568d2f55e7SToby Isaac     }
30578d2f55e7SToby Isaac   }
30589566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(PETSC_COMM_SELF,m,n,m,n,-1,nnz,-1,NULL,&mat));
30599566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
30608d2f55e7SToby Isaac   /* Setp 2: compute entries */
30618d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
30628d2f55e7SToby Isaac     const PetscInt *children;
30638d2f55e7SToby Isaac     PetscInt numChildren;
30648d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30658d2f55e7SToby Isaac 
30668d2f55e7SToby Isaac     /* same conditions about when entries occur */
30678d2f55e7SToby Isaac     if (canonical) {
30688d2f55e7SToby Isaac       PetscInt pCanonical;
30699566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical,p,&pCanonical));
30708d2f55e7SToby Isaac       if (p != pCanonical) continue;
30718d2f55e7SToby Isaac     }
30729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree,p,&numChildren,&children));
30738d2f55e7SToby Isaac     if (!numChildren) continue;
30748d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30758d2f55e7SToby Isaac       PetscInt child = children[i];
30768d2f55e7SToby Isaac       PetscInt dof;
30778d2f55e7SToby Isaac 
30789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,child,&dof));
30798d2f55e7SToby Isaac       numChildDof += dof;
30808d2f55e7SToby Isaac     }
30819566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section,p,&numSelfDof));
30828d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30838d2f55e7SToby Isaac 
30848d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
308559fc6756SToby Isaac       PetscInt       pI = -1, cI = -1;
308652a3aeb4SToby Isaac       PetscInt       selfOff, Nc, parentCell;
30878d2f55e7SToby Isaac       PetscInt       cellShapeOff;
30888d2f55e7SToby Isaac       PetscObject    disc;
30898d2f55e7SToby Isaac       PetscDualSpace dsp;
30908d2f55e7SToby Isaac       PetscClassId   classId;
30918d2f55e7SToby Isaac       PetscScalar    *pointMat;
30923b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
30938d2f55e7SToby Isaac       PetscInt       pO = PETSC_MIN_INT;
30948d2f55e7SToby Isaac       const PetscInt *depthNumDof;
30958d2f55e7SToby Isaac 
30968d2f55e7SToby Isaac       if (numSecFields) {
30978d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
30988d2f55e7SToby Isaac           PetscInt child = children[i];
30998d2f55e7SToby Isaac           PetscInt dof;
31008d2f55e7SToby Isaac 
31019566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,child,f,&dof));
31028d2f55e7SToby Isaac           numChildDof += dof;
31038d2f55e7SToby Isaac         }
31049566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section,p,f,&numSelfDof));
31059566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section,p,f,&selfOff));
31068d2f55e7SToby Isaac       }
31078d2f55e7SToby Isaac       else {
31089566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section,p,&selfOff));
31098d2f55e7SToby Isaac       }
31108d2f55e7SToby Isaac 
31113b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
31128d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
31138d2f55e7SToby Isaac         parentCell = p;
31148d2f55e7SToby Isaac       }
31158d2f55e7SToby Isaac       else {
31168d2f55e7SToby Isaac         PetscInt *star = NULL;
31178d2f55e7SToby Isaac         PetscInt numStar;
31188d2f55e7SToby Isaac 
31198d2f55e7SToby Isaac         parentCell = -1;
31209566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star));
31218d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
31228d2f55e7SToby Isaac           PetscInt c = star[2 * i];
31238d2f55e7SToby Isaac 
31248d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
31258d2f55e7SToby Isaac             parentCell = c;
31268d2f55e7SToby Isaac             break;
31278d2f55e7SToby Isaac           }
31288d2f55e7SToby Isaac         }
31299566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star));
31308d2f55e7SToby Isaac       }
3131a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
31329566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds,f,&disc));
31339566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc,&classId));
3134c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
31359566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp));
3136c5356c36SToby Isaac       }
3137c5356c36SToby Isaac       else if (classId == PETSCFV_CLASSID) {
31389566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace((PetscFV)disc,&dsp));
3139c5356c36SToby Isaac       }
3140c5356c36SToby Isaac       else {
31419b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported discretization object");
3142c5356c36SToby Isaac       }
31439566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumDof(dsp,&depthNumDof));
31449566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumComponents(dsp,&Nc));
31458d2f55e7SToby Isaac       {
31468d2f55e7SToby Isaac         PetscInt *closure = NULL;
31478d2f55e7SToby Isaac         PetscInt numClosure;
31488d2f55e7SToby Isaac 
31499566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure));
315059fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
31518d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
31528d2f55e7SToby Isaac 
31538d2f55e7SToby Isaac           pO = closure[2 * i + 1];
315459fc6756SToby Isaac           if (point == p) {
315559fc6756SToby Isaac             pI = i;
315659fc6756SToby Isaac             break;
315759fc6756SToby Isaac           }
31589566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(depth,point,&pointDepth));
31598d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
31608d2f55e7SToby Isaac         }
31619566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure));
31628d2f55e7SToby Isaac       }
31638d2f55e7SToby Isaac 
31649566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat));
31659566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows));
316652a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
316752a3aeb4SToby Isaac       for (i = 0; i < numSelfDof; i++) {
316852a3aeb4SToby Isaac         matRows[i] = selfOff + i;
31693b1c2a6aSToby Isaac       }
317052a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
31713b1c2a6aSToby Isaac       {
31723b1c2a6aSToby Isaac         PetscInt colOff = 0;
31733b1c2a6aSToby Isaac 
31743b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
31753b1c2a6aSToby Isaac           PetscInt child = children[i];
31763b1c2a6aSToby Isaac           PetscInt dof, off, j;
31773b1c2a6aSToby Isaac 
31783b1c2a6aSToby Isaac           if (numSecFields) {
31799566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSection,child,f,&dof));
31809566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(cSection,child,f,&off));
31813b1c2a6aSToby Isaac           }
31823b1c2a6aSToby Isaac           else {
31839566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(cSection,child,&dof));
31849566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(cSection,child,&off));
31853b1c2a6aSToby Isaac           }
31863b1c2a6aSToby Isaac 
318752a3aeb4SToby Isaac           for (j = 0; j < dof; j++) {
318852a3aeb4SToby Isaac             matCols[colOff++] = off + j;
31893b1c2a6aSToby Isaac           }
31903b1c2a6aSToby Isaac         }
31913b1c2a6aSToby Isaac       }
31928d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
31938d2f55e7SToby Isaac         PetscFE        fe = (PetscFE) disc;
31948d2f55e7SToby Isaac         PetscInt       fSize;
319559fc6756SToby Isaac         const PetscInt ***perms;
319659fc6756SToby Isaac         const PetscScalar ***flips;
319759fc6756SToby Isaac         const PetscInt *pperms;
319859fc6756SToby Isaac 
31999566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe,&dsp));
32009566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetDimension(dsp,&fSize));
32019566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
320259fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
320352a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
32048d2f55e7SToby Isaac           PetscQuadrature q;
320552a3aeb4SToby Isaac           PetscInt        dim, thisNc, numPoints, j, k;
32068d2f55e7SToby Isaac           const PetscReal *points;
32078d2f55e7SToby Isaac           const PetscReal *weights;
32088d2f55e7SToby Isaac           PetscInt        *closure = NULL;
32098d2f55e7SToby Isaac           PetscInt        numClosure;
321059fc6756SToby Isaac           PetscInt        iCell = pperms ? pperms[i] : i;
321159fc6756SToby Isaac           PetscInt        parentCellShapeDof = cellShapeOff + iCell;
3212ef0bb6c7SMatthew G. Knepley           PetscTabulation Tparent;
32138d2f55e7SToby Isaac 
32149566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(dsp,parentCellShapeDof,&q));
32159566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(q,&dim,&thisNc,&numPoints,&points,&weights));
3216*08401ef6SPierre Jolivet           PetscCheck(thisNc == Nc,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %D does not much basis dim %D",thisNc,Nc);
32179566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe,1,numPoints,points,0,&Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
32183b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
32198d2f55e7SToby Isaac             PetscInt          childCell = -1;
322052a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3221c330f8ffSToby Isaac             const PetscReal   xi0[3] = {-1.,-1.,-1.};
32228d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
32238d2f55e7SToby Isaac             const PetscScalar *point;
3224ef0bb6c7SMatthew G. Knepley             PetscTabulation Tchild;
32258d2f55e7SToby Isaac             PetscInt          childCellShapeOff, pointMatOff;
32268d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
32278d2f55e7SToby Isaac             PetscInt          d;
32288d2f55e7SToby Isaac 
32298d2f55e7SToby Isaac             for (d = 0; d < dim; d++) {
32308d2f55e7SToby Isaac               pointScalar[d] = points[dim * j + d];
32318d2f55e7SToby Isaac             }
32328d2f55e7SToby Isaac             point = pointScalar;
32338d2f55e7SToby Isaac #else
32348d2f55e7SToby Isaac             point = pointReal;
32358d2f55e7SToby Isaac #endif
32368d2f55e7SToby Isaac 
3237ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
32383b1c2a6aSToby Isaac 
32393b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
32408d2f55e7SToby Isaac               PetscInt child = children[k];
32418d2f55e7SToby Isaac               PetscInt *star = NULL;
32428d2f55e7SToby Isaac               PetscInt numStar, s;
32438d2f55e7SToby Isaac 
32449566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star));
32458d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
32468d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
32478d2f55e7SToby Isaac 
32488d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
32499566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(refTree,dim,point,c,&childCell));
32508d2f55e7SToby Isaac                 if (childCell >= 0) break;
32518d2f55e7SToby Isaac               }
32529566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star));
32538d2f55e7SToby Isaac               if (childCell >= 0) break;
32548d2f55e7SToby Isaac             }
3255*08401ef6SPierre Jolivet             PetscCheck(childCell >= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not locate quadrature point");
32569566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
32579566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3258c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3259c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
32608d2f55e7SToby Isaac 
32619566063dSJacob Faibussowitsch             PetscCall(PetscFECreateTabulation(fe,1,1,pointRef,0,&Tchild));
32629566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure));
32633b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3264c5356c36SToby Isaac               PetscInt child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
32658d2f55e7SToby Isaac               PetscInt l;
326659fc6756SToby Isaac               const PetscInt *cperms;
32678d2f55e7SToby Isaac 
32689566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(depth,child,&childDepth));
32698d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
327059fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
32718d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
32728d2f55e7SToby Isaac                 PetscInt pointDepth;
32738d2f55e7SToby Isaac 
32748d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
327559fc6756SToby Isaac                 if (point == child) {
327659fc6756SToby Isaac                   cI = l;
327759fc6756SToby Isaac                   break;
327859fc6756SToby Isaac                 }
32799566063dSJacob Faibussowitsch                 PetscCall(DMLabelGetValue(depth,point,&pointDepth));
32808d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
32818d2f55e7SToby Isaac               }
32828d2f55e7SToby Isaac               if (l == numClosure) {
32838d2f55e7SToby Isaac                 pointMatOff += childDof;
32848d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
32858d2f55e7SToby Isaac               }
328659fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
32878d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
328859fc6756SToby Isaac                 PetscInt    lCell = cperms ? cperms[l] : l;
328959fc6756SToby Isaac                 PetscInt    childCellDof = childCellShapeOff + lCell;
329052a3aeb4SToby Isaac                 PetscReal   *childValAtPoint;
329152a3aeb4SToby Isaac                 PetscReal   val = 0.;
32928d2f55e7SToby Isaac 
3293ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
329452a3aeb4SToby Isaac                 for (m = 0; m < Nc; m++) {
329552a3aeb4SToby Isaac                   val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
329652a3aeb4SToby Isaac                 }
329752a3aeb4SToby Isaac 
329852a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
32998d2f55e7SToby Isaac               }
33008d2f55e7SToby Isaac               pointMatOff += childDof;
33018d2f55e7SToby Isaac             }
33029566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure));
33039566063dSJacob Faibussowitsch             PetscCall(PetscTabulationDestroy(&Tchild));
33048d2f55e7SToby Isaac           }
33059566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&Tparent));
33068d2f55e7SToby Isaac         }
33078d2f55e7SToby Isaac       }
3308c5356c36SToby Isaac       else { /* just the volume-weighted averages of the children */
33093b1c2a6aSToby Isaac         PetscReal parentVol;
3310bfaa5bdcSToby Isaac         PetscInt  childCell;
33113b1c2a6aSToby Isaac 
33129566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3313bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
331452a3aeb4SToby Isaac           PetscInt  child = children[i], j;
33153b1c2a6aSToby Isaac           PetscReal childVol;
33163b1c2a6aSToby Isaac 
33173b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
33189566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
331952a3aeb4SToby Isaac           for (j = 0; j < Nc; j++) {
3320bfaa5bdcSToby Isaac             pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
332152a3aeb4SToby Isaac           }
3322bfaa5bdcSToby Isaac           childCell++;
33233b1c2a6aSToby Isaac         }
33248d2f55e7SToby Isaac       }
33253b1c2a6aSToby Isaac       /* Insert pointMat into mat */
33269566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat,numSelfDof,matRows,numChildDof,matCols,pointMat,INSERT_VALUES));
33279566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows));
33289566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat));
33298d2f55e7SToby Isaac     }
33308d2f55e7SToby Isaac   }
33319566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0,v0parent,vtmp,J,Jparent,invJ));
33329566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointScalar,pointRef));
33339566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
33349566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
33358d2f55e7SToby Isaac   *inj = mat;
33368d2f55e7SToby Isaac   PetscFunctionReturn(0);
33378d2f55e7SToby Isaac }
33388d2f55e7SToby Isaac 
3339f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3340f30e825dSToby Isaac {
3341f30e825dSToby Isaac   PetscDS        ds;
3342f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3343f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3344f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3345f30e825dSToby Isaac 
3346f30e825dSToby Isaac   PetscFunctionBegin;
33479566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree,&ds));
33489566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
33499566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
33509566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree,&refSection));
33519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
33529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats));
33539566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec,&maxDof));
33549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof,&rows));
33559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof*maxDof,&cols));
3356f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3357f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3358f30e825dSToby Isaac 
33599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree,p,&parent,NULL));
33609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec,p,&pDof));
33619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection,parent,&parentDof));
3362f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3363f30e825dSToby Isaac 
33649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]));
3365f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
336652a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3367f30e825dSToby Isaac 
3368f30e825dSToby Isaac       if (numFields > 1) {
33699566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
33709566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec,p,f,&cOff));
3371f30e825dSToby Isaac       }
3372f30e825dSToby Isaac       else {
33739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec,p,&cDof));
33749566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec,p,&cOff));
3375f30e825dSToby Isaac       }
3376f30e825dSToby Isaac 
3377f30e825dSToby Isaac       for (r = 0; r < cDof; r++) {
3378f30e825dSToby Isaac         rows[r] = cOff + r;
3379f30e825dSToby Isaac       }
3380f30e825dSToby Isaac       numCols = 0;
3381f30e825dSToby Isaac       {
3382f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3383f30e825dSToby Isaac 
3384f30e825dSToby Isaac         if (numFields > 1) {
33859566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection,parent,f,&aDof));
33869566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection,parent,f,&aOff));
3387f30e825dSToby Isaac         }
3388f30e825dSToby Isaac         else {
33899566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection,parent,&aDof));
33909566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection,parent,&aOff));
3391f30e825dSToby Isaac         }
3392f30e825dSToby Isaac 
3393f30e825dSToby Isaac         for (j = 0; j < aDof; j++) {
3394f30e825dSToby Isaac           cols[numCols++] = aOff + j;
3395f30e825dSToby Isaac         }
3396f30e825dSToby Isaac       }
33979566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]));
3398f30e825dSToby Isaac       /* transpose of constraint matrix */
33999566063dSJacob Faibussowitsch       PetscCall(MatGetValues(inj,numCols,cols,cDof,rows,refPointFieldMats[p-pRefStart][f]));
3400f30e825dSToby Isaac     }
3401f30e825dSToby Isaac   }
3402f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
34039566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
34049566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
3405f30e825dSToby Isaac   PetscFunctionReturn(0);
3406f30e825dSToby Isaac }
3407f30e825dSToby Isaac 
3408f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3409f30e825dSToby Isaac {
3410f30e825dSToby Isaac   PetscDS        ds;
3411f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3412f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3413c6154584SToby Isaac   PetscSection   refConSec, refSection;
3414f30e825dSToby Isaac 
3415f30e825dSToby Isaac   PetscFunctionBegin;
3416f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3417f30e825dSToby Isaac   *childrenMats = NULL;
34189566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree,&ds));
34199566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree,&refSection));
34209566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
34219566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
34229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
3423f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3424f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3425f30e825dSToby Isaac 
34269566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree,p,&parent,NULL));
34279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec,p,&pDof));
34289566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection,parent,&parentDof));
3429f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3430f30e825dSToby Isaac 
3431f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3432f30e825dSToby Isaac       PetscInt cDof;
3433f30e825dSToby Isaac 
3434f30e825dSToby Isaac       if (numFields > 1) {
34359566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
3436f30e825dSToby Isaac       }
3437f30e825dSToby Isaac       else {
34389566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec,p,&cDof));
3439f30e825dSToby Isaac       }
3440f30e825dSToby Isaac 
34419566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3442f30e825dSToby Isaac     }
34439566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3444f30e825dSToby Isaac   }
34459566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
3446f30e825dSToby Isaac   PetscFunctionReturn(0);
3447f30e825dSToby Isaac }
3448f30e825dSToby Isaac 
3449ebf164c7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree,Mat *injRef)
3450154bca37SToby Isaac {
3451ebf164c7SToby Isaac   Mat            cMatRef;
34526148253fSToby Isaac   PetscObject    injRefObj;
34538d2f55e7SToby Isaac 
3454154bca37SToby Isaac   PetscFunctionBegin;
34559566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,NULL,&cMatRef,NULL));
34569566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",&injRefObj));
3457ebf164c7SToby Isaac   *injRef = (Mat) injRefObj;
3458ebf164c7SToby Isaac   if (!*injRef) {
34599566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorReferenceTree(refTree,injRef));
34609566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",(PetscObject)*injRef));
3461ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
34629566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3463ebf164c7SToby Isaac   }
3464ebf164c7SToby Isaac   PetscFunctionReturn(0);
34656148253fSToby Isaac }
3466f30e825dSToby Isaac 
3467c921d74cSToby Isaac 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)
3468ebf164c7SToby Isaac {
3469c921d74cSToby Isaac   PetscInt       pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3470ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3471ebf164c7SToby Isaac   PetscSection   localCoarse, localFine, leafIndicesSec;
3472c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3473c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3474c921d74cSToby Isaac   const PetscInt *rootDegrees;
3475c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3476ebf164c7SToby Isaac   PetscSF        coarseToFineEmbedded;
3477ebf164c7SToby Isaac 
3478ebf164c7SToby Isaac   PetscFunctionBegin;
34799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
34809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine,&pStartF,&pEndF));
34819566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine,&localFine));
34829566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine,&globalFine));
34839566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec));
34849566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafIndicesSec,pStartF, pEndF));
34859566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localFine,&maxDof));
34868d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
34877e96bdafSToby Isaac     PetscInt l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
34887e96bdafSToby Isaac     const PetscInt *leaves;
34898d2f55e7SToby Isaac 
34909566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL));
34917e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
34927e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
34939566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
34949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
34958d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
34968d2f55e7SToby Isaac         numPointsWithDofs++;
3497f30e825dSToby Isaac 
34989566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localFine,p,&dof));
34999566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafIndicesSec,p,dof + 1));
35008d2f55e7SToby Isaac       }
35018d2f55e7SToby Isaac     }
35029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
35039566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafIndicesSec));
35049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec,&numIndices));
35059566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1),&leafInds));
35069566063dSJacob Faibussowitsch     if (gatheredValues)  PetscCall(PetscMalloc1(numIndices,&leafVals));
35077e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
35087e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35099566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
35109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
35118d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3512f30e825dSToby Isaac         PetscInt    off, gOff;
3513f30e825dSToby Isaac         PetscInt    *pInd;
3514c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3515f30e825dSToby Isaac 
35167e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3517f30e825dSToby Isaac 
35189566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec,p,&off));
3519f30e825dSToby Isaac 
3520c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3521c921d74cSToby Isaac         if (gatheredValues) {
3522c921d74cSToby Isaac           PetscInt i;
3523c921d74cSToby Isaac 
3524c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3525c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3526c921d74cSToby Isaac         }
35279566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalFine,p,&gOff));
3528f30e825dSToby Isaac 
3529f30e825dSToby Isaac         offsets[0] = 0;
3530f30e825dSToby Isaac         if (numFields) {
3531f30e825dSToby Isaac           PetscInt f;
3532f30e825dSToby Isaac 
3533f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3534f30e825dSToby Isaac             PetscInt fDof;
35359566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localFine,p,f,&fDof));
3536f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3537f30e825dSToby Isaac           }
35389566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1, NULL,pInd));
3539367003a6SStefano Zampini         } else {
35409566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL, NULL,pInd));
3541f30e825dSToby Isaac         }
35429566063dSJacob Faibussowitsch         if (gatheredValues) PetscCall(VecGetValues(fineVec,dof,pInd,pVal));
35438d2f55e7SToby Isaac       }
35448d2f55e7SToby Isaac     }
35459566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
35469566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
35478d2f55e7SToby Isaac   }
3548f30e825dSToby Isaac 
35499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
35509566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse,&localCoarse));
35519566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse,&globalCoarse));
3552f30e825dSToby Isaac 
35536148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
35546148253fSToby Isaac     MPI_Datatype threeInt;
35556148253fSToby Isaac     PetscMPIInt  rank;
35566148253fSToby Isaac     PetscInt     (*parentNodeAndIdCoarse)[3];
35576148253fSToby Isaac     PetscInt     (*parentNodeAndIdFine)[3];
35586148253fSToby Isaac     PetscInt     p, nleaves, nleavesToParents;
35596148253fSToby Isaac     PetscSF      pointSF, sfToParents;
35606148253fSToby Isaac     const PetscInt *ilocal;
35616148253fSToby Isaac     const PetscSFNode *iremote;
35626148253fSToby Isaac     PetscSFNode  *iremoteToParents;
35636148253fSToby Isaac     PetscInt     *ilocalToParents;
35646148253fSToby Isaac 
35659566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse),&rank));
35669566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(3,MPIU_INT,&threeInt));
35679566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&threeInt));
35689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEndC-pStartC,&parentNodeAndIdCoarse,pEndF-pStartF,&parentNodeAndIdFine));
35699566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(coarse,&pointSF));
35709566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointSF,NULL,&nleaves,&ilocal,&iremote));
35716148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
35726148253fSToby Isaac       PetscInt parent, childId;
35739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(coarse,p,&parent,&childId));
35746148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
35756148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
35766148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
35776148253fSToby Isaac       if (nleaves > 0) {
35786148253fSToby Isaac         PetscInt leaf = -1;
35796148253fSToby Isaac 
35806148253fSToby Isaac         if (ilocal) {
35819566063dSJacob Faibussowitsch           PetscCall(PetscFindInt(parent,nleaves,ilocal,&leaf));
35826148253fSToby Isaac         }
35836148253fSToby Isaac         else {
35846148253fSToby Isaac           leaf = p - pStartC;
35856148253fSToby Isaac         }
35866148253fSToby Isaac         if (leaf >= 0) {
35876148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
35886148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
35896148253fSToby Isaac         }
35906148253fSToby Isaac       }
35916148253fSToby Isaac     }
35926148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
35936148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
35946148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
35956148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
35966148253fSToby Isaac     }
35979566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine,MPI_REPLACE));
35989566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine,MPI_REPLACE));
35996148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3600f30e825dSToby Isaac       PetscInt dof;
3601f30e825dSToby Isaac 
36029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec,p,&dof));
3603f30e825dSToby Isaac       if (dof) {
3604f30e825dSToby Isaac         PetscInt off;
3605f30e825dSToby Isaac 
36069566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec,p,&off));
3607c921d74cSToby Isaac         if (gatheredIndices) {
3608c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3609c921d74cSToby Isaac         } else if (gatheredValues) {
3610c921d74cSToby Isaac           leafVals[off] = (PetscScalar) PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3611c921d74cSToby Isaac         }
3612f30e825dSToby Isaac       }
36136148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36146148253fSToby Isaac         nleavesToParents++;
36156148253fSToby Isaac       }
36166148253fSToby Isaac     }
36179566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents,&ilocalToParents));
36189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents,&iremoteToParents));
36196148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
36206148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36216148253fSToby Isaac         ilocalToParents[nleavesToParents] = p - pStartF;
36226148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p-pStartF][0];
36236148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p-pStartF][1];
36246148253fSToby Isaac         nleavesToParents++;
36256148253fSToby Isaac       }
36266148253fSToby Isaac     }
36279566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse),&sfToParents));
36289566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(sfToParents,pEndC-pStartC,nleavesToParents,ilocalToParents,PETSC_OWN_POINTER,iremoteToParents,PETSC_OWN_POINTER));
36299566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
36306148253fSToby Isaac 
36316148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
36326148253fSToby Isaac 
36339566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parentNodeAndIdCoarse,parentNodeAndIdFine));
36349566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&threeInt));
36356148253fSToby Isaac   }
3636f30e825dSToby Isaac 
36376148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
36386148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
36396148253fSToby Isaac     PetscSF  sfDofsOnly;
36406148253fSToby Isaac 
36416148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
36429566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
36439566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
36446148253fSToby Isaac       if ((dof - cdof) > 0) {
36456148253fSToby Isaac         numPointsWithDofs++;
36466148253fSToby Isaac       }
36476148253fSToby Isaac     }
36489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
36496148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
36509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
36519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
36526148253fSToby Isaac       if ((dof - cdof) > 0) {
3653e03d9830SToby Isaac         pointsWithDofs[offset++] = p - pStartC;
36546148253fSToby Isaac       }
36556148253fSToby Isaac     }
36569566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
36579566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
36589566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
36596148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
36606148253fSToby Isaac   }
3661f30e825dSToby Isaac 
36626148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
36639566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded,&rootDegrees));
36649566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded,&rootDegrees));
36659566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&multiRootSec));
36669566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(multiRootSec,pStartC,pEndC));
36678d2f55e7SToby Isaac   for (p = pStartC; p < pEndC; p++) {
36689566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(multiRootSec,p,rootDegrees[p-pStartC]));
36698d2f55e7SToby Isaac   }
36709566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(multiRootSec));
36719566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(multiRootSec,&numMulti));
36729566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec));
3673f30e825dSToby Isaac   { /* distribute the leaf section */
3674f30e825dSToby Isaac     PetscSF multi, multiInv, indicesSF;
3675f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
36768d2f55e7SToby Isaac 
36779566063dSJacob Faibussowitsch     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded,&multi));
36789566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF(multi,&multiInv));
36799566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(multiInv,leafIndicesSec,&remoteOffsets,rootIndicesSec));
36809566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(multiInv,leafIndicesSec,remoteOffsets,rootIndicesSec,&indicesSF));
36819566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
36829566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&multiInv));
36839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices));
3684c921d74cSToby Isaac     if (gatheredIndices) {
36859566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices,&rootInds));
36869566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF,MPIU_INT,leafInds,rootInds,MPI_REPLACE));
36879566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF,MPIU_INT,leafInds,rootInds,MPI_REPLACE));
3688c921d74cSToby Isaac     }
3689c921d74cSToby Isaac     if (gatheredValues) {
36909566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices,&rootVals));
36919566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF,MPIU_SCALAR,leafVals,rootVals,MPI_REPLACE));
36929566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF,MPIU_SCALAR,leafVals,rootVals,MPI_REPLACE));
3693c921d74cSToby Isaac     }
36949566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
36958d2f55e7SToby Isaac   }
36969566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
36979566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafInds));
36989566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafVals));
36999566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3700c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3701c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3702c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3703c921d74cSToby Isaac   if (gatheredValues)  *gatheredValues  = rootVals;
3704ebf164c7SToby Isaac   PetscFunctionReturn(0);
3705ebf164c7SToby Isaac }
3706ebf164c7SToby Isaac 
3707ebf164c7SToby Isaac PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3708ebf164c7SToby Isaac {
3709ebf164c7SToby Isaac   DM             refTree;
3710c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3711ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3712ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3713ebf164c7SToby Isaac   PetscSection   cSecRef;
3714277f51e8SBarry Smith   PetscInt       *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3715ebf164c7SToby Isaac   Mat            injRef;
3716c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3717ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3718ebf164c7SToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
3719ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3720ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3721ebf164c7SToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3722ebf164c7SToby Isaac 
3723ebf164c7SToby Isaac   PetscFunctionBegin;
3724ebf164c7SToby Isaac 
3725ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
37269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse,&refTree));
37279566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&cSecRef,NULL,NULL));
37289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd));
37299566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree,&injRef));
3730ebf164c7SToby Isaac 
37319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine,&pStartF,&pEndF));
37329566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine,&localFine));
37339566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine,&globalFine));
37349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine,&numFields));
37359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
37369566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse,&localCoarse));
37379566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse,&globalCoarse));
37389566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse,&maxDof));
3739ebf164c7SToby Isaac   {
3740ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
37419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets));
3742ebf164c7SToby Isaac   }
3743ebf164c7SToby Isaac 
37449566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse,fine,coarseToFine,childIds,NULL,numFields,offsets,&multiRootSec,&rootIndicesSec,&rootIndices,NULL));
37458d2f55e7SToby Isaac 
37469566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof,&parentIndices));
3747f30e825dSToby Isaac 
3748f30e825dSToby Isaac   /* count indices */
37499566063dSJacob Faibussowitsch   PetscCall(MatGetLayouts(mat,&rowMap,&colMap));
37509566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
37519566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
37529566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap,&rowStart,&rowEnd));
37539566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap,&colStart,&colEnd));
37549566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(rowEnd-rowStart,&nnzD,rowEnd-rowStart,&nnzO));
3755f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3756f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
37578d2f55e7SToby Isaac 
37589566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
37599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
3760f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
37619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse,p,&gOff));
37628d2f55e7SToby Isaac 
37638d2f55e7SToby Isaac     rowOffsets[0] = 0;
3764f30e825dSToby Isaac     offsetsCopy[0] = 0;
37658d2f55e7SToby Isaac     if (numFields) {
37668d2f55e7SToby Isaac       PetscInt f;
37678d2f55e7SToby Isaac 
3768f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3769f30e825dSToby Isaac         PetscInt fDof;
37709566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
3771f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
37728d2f55e7SToby Isaac       }
37739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,parentIndices));
3774367003a6SStefano Zampini     } else {
37759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,parentIndices));
3776f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
37778d2f55e7SToby Isaac     }
3778f30e825dSToby Isaac 
37799566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec,p,&numLeaves));
37809566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec,p,&leafStart));
3781f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3782f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3783f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3784f30e825dSToby Isaac       const PetscInt *childIndices;
3785f30e825dSToby Isaac 
37869566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec,l,&numIndices));
37879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec,l,&offset));
3788f30e825dSToby Isaac       childId = rootIndices[offset++];
3789f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3790f30e825dSToby Isaac       numIndices--;
3791f30e825dSToby Isaac 
3792f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3793f30e825dSToby Isaac         PetscInt i;
3794f30e825dSToby Isaac 
3795f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3796f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3797f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3798f30e825dSToby Isaac           if (rowIndex < 0) continue;
3799*08401ef6SPierre Jolivet           PetscCheck(colIndex >= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unconstrained fine and constrained coarse");
3800a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3801f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
3802f30e825dSToby Isaac           }
3803f30e825dSToby Isaac           else {
3804f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3805f30e825dSToby Isaac           }
3806f30e825dSToby Isaac         }
3807f30e825dSToby Isaac       }
3808f30e825dSToby Isaac       else {
3809f30e825dSToby Isaac         PetscInt parentId, f, lim;
3810f30e825dSToby Isaac 
38119566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree,childId,&parentId,NULL));
3812f30e825dSToby Isaac 
3813f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3814f30e825dSToby Isaac         offsets[0] = 0;
38158d2f55e7SToby Isaac         if (numFields) {
38168d2f55e7SToby Isaac           PetscInt f;
3817f30e825dSToby Isaac 
38188d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3819f30e825dSToby Isaac             PetscInt fDof;
38209566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef,childId,f,&fDof));
3821f30e825dSToby Isaac 
3822f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
38238d2f55e7SToby Isaac           }
38248d2f55e7SToby Isaac         }
38258d2f55e7SToby Isaac         else {
3826f30e825dSToby Isaac           PetscInt cDof;
3827f30e825dSToby Isaac 
38289566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef,childId,&cDof));
3829f30e825dSToby Isaac           offsets[1] = cDof;
3830f30e825dSToby Isaac         }
3831f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3832f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3833f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3834f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3835f30e825dSToby Isaac 
3836f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3837f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3838f30e825dSToby Isaac 
3839f30e825dSToby Isaac             if (colIndex < 0) continue;
3840f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3841f30e825dSToby Isaac               numD++;
3842f30e825dSToby Isaac             }
3843f30e825dSToby Isaac             else {
3844f30e825dSToby Isaac               numO++;
3845f30e825dSToby Isaac             }
3846f30e825dSToby Isaac           }
3847f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3848f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3849f30e825dSToby Isaac 
3850f30e825dSToby Isaac             if (rowIndex < 0) continue;
3851f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3852f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
38538d2f55e7SToby Isaac           }
38548d2f55e7SToby Isaac         }
38558d2f55e7SToby Isaac       }
3856f30e825dSToby Isaac     }
3857f30e825dSToby Isaac   }
3858f30e825dSToby Isaac   /* preallocate */
38599566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mat,1,nnzD,nnzO,NULL,NULL));
38609566063dSJacob Faibussowitsch   PetscCall(PetscFree2(nnzD,nnzO));
3861f30e825dSToby Isaac   /* insert values */
38629566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats));
3863f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3864f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3865f30e825dSToby Isaac 
38669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
38679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
3868f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
38699566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse,p,&gOff));
3870f30e825dSToby Isaac 
3871f30e825dSToby Isaac     rowOffsets[0] = 0;
3872f30e825dSToby Isaac     offsetsCopy[0] = 0;
38738d2f55e7SToby Isaac     if (numFields) {
38748d2f55e7SToby Isaac       PetscInt f;
3875f30e825dSToby Isaac 
38768d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3877f30e825dSToby Isaac         PetscInt fDof;
38789566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
3879f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3880f30e825dSToby Isaac       }
38819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,parentIndices));
3882367003a6SStefano Zampini     } else {
38839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,parentIndices));
3884f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3885f30e825dSToby Isaac     }
3886f30e825dSToby Isaac 
38879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec,p,&numLeaves));
38889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec,p,&leafStart));
3889f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3890f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3891f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3892f30e825dSToby Isaac       const PetscInt *childIndices;
3893f30e825dSToby Isaac 
38949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec,l,&numIndices));
38959566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec,l,&offset));
3896f30e825dSToby Isaac       childId = rootIndices[offset++];
3897f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3898f30e825dSToby Isaac       numIndices--;
3899f30e825dSToby Isaac 
3900f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3901f30e825dSToby Isaac         PetscInt i;
3902f30e825dSToby Isaac 
3903f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
39049566063dSJacob Faibussowitsch           PetscCall(MatSetValue(mat,parentIndices[i],childIndices[i],1.,INSERT_VALUES));
39058d2f55e7SToby Isaac         }
39068d2f55e7SToby Isaac       }
39078d2f55e7SToby Isaac       else {
3908f30e825dSToby Isaac         PetscInt parentId, f, lim;
39098d2f55e7SToby Isaac 
39109566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree,childId,&parentId,NULL));
3911f30e825dSToby Isaac 
3912f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3913f30e825dSToby Isaac         offsets[0] = 0;
39148d2f55e7SToby Isaac         if (numFields) {
3915f30e825dSToby Isaac           PetscInt f;
39168d2f55e7SToby Isaac 
3917f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3918f30e825dSToby Isaac             PetscInt fDof;
39199566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef,childId,f,&fDof));
3920f30e825dSToby Isaac 
3921f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
39228d2f55e7SToby Isaac           }
39238d2f55e7SToby Isaac         }
39248d2f55e7SToby Isaac         else {
3925f30e825dSToby Isaac           PetscInt cDof;
3926f30e825dSToby Isaac 
39279566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef,childId,&cDof));
3928f30e825dSToby Isaac           offsets[1] = cDof;
39298d2f55e7SToby Isaac         }
3930f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3931f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3932f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3933f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3934f30e825dSToby Isaac 
39359566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat,rowOffsets[f+1]-rowOffsets[f],rowIndices,offsets[f+1]-offsets[f],colIndices,childMat,INSERT_VALUES));
39368d2f55e7SToby Isaac         }
39378d2f55e7SToby Isaac       }
39388d2f55e7SToby Isaac     }
39398d2f55e7SToby Isaac   }
39409566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
39419566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
39429566063dSJacob Faibussowitsch   PetscCall(PetscFree(parentIndices));
39439566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats));
39449566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootIndices));
39459566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets,offsetsCopy,rowOffsets));
3946f30e825dSToby Isaac 
39479566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
39489566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
3949154bca37SToby Isaac   PetscFunctionReturn(0);
3950154bca37SToby Isaac }
395138fc2455SToby Isaac 
39520eb7e1eaSToby Isaac static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3953ebf164c7SToby Isaac {
395462095d54SToby Isaac   PetscSF           coarseToFineEmbedded;
395562095d54SToby Isaac   PetscSection      globalCoarse, globalFine;
395662095d54SToby Isaac   PetscSection      localCoarse, localFine;
395762095d54SToby Isaac   PetscSection      aSec, cSec;
395862095d54SToby Isaac   PetscSection      rootValuesSec;
395962095d54SToby Isaac   PetscSection      leafValuesSec;
396062095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
396162095d54SToby Isaac   IS                aIS;
396262095d54SToby Isaac   const PetscInt    *anchors;
396362095d54SToby Isaac   Mat               cMat;
396462095d54SToby Isaac   PetscInt          numFields;
3965412e9a14SMatthew G. Knepley   PetscInt          pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
396662095d54SToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
396762095d54SToby Isaac   PetscInt          *maxChildIds;
396862095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
39690eb7e1eaSToby Isaac   PetscFV           fv = NULL;
39700eb7e1eaSToby Isaac   PetscInt          dim, numFVcomps = -1, fvField = -1;
39710eb7e1eaSToby Isaac   DM                cellDM = NULL, gradDM = NULL;
39720eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
39730eb7e1eaSToby Isaac   const PetscScalar *gradArray = NULL;
397462095d54SToby Isaac 
3975ebf164c7SToby Isaac   PetscFunctionBegin;
39769566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE));
39779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
39789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(coarse,0,&cellStart,&cellEnd));
39799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine,&pStartF,&pEndF));
39809566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine,&globalFine));
39819566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(coarse,&dim));
398262095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3983e4a60869SToby Isaac     PetscInt       nleaves, l;
3984e4a60869SToby Isaac     const PetscInt *leaves;
398562095d54SToby Isaac     PetscInt       dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
398662095d54SToby Isaac 
39879566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL));
3988e4a60869SToby Isaac 
3989e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3990e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3991e4a60869SToby Isaac 
39929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
39939566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
399462095d54SToby Isaac       if ((dof - cdof) > 0) {
399562095d54SToby Isaac         numPointsWithDofs++;
399662095d54SToby Isaac       }
399762095d54SToby Isaac     }
39989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
39994833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
4000e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
4001e4a60869SToby Isaac 
40029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
40039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
400462095d54SToby Isaac       if ((dof - cdof) > 0) {
4005e4a60869SToby Isaac         pointsWithDofs[offset++] = l;
400662095d54SToby Isaac       }
400762095d54SToby Isaac     }
40089566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
40099566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
401062095d54SToby Isaac   }
401162095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
40129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC-pStartC,&maxChildIds));
401362095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) {
401462095d54SToby Isaac     maxChildIds[p - pStartC] = -2;
401562095d54SToby Isaac   }
40169566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX));
40179566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX));
401862095d54SToby Isaac 
40199566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse,&localCoarse));
40209566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse,&globalCoarse));
402162095d54SToby Isaac 
40229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse,&aSec,&aIS));
40239566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS,&anchors));
40249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd));
402562095d54SToby Isaac 
40269566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse,&cSec,&cMat,NULL));
40279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec,&cStart,&cEnd));
402862095d54SToby Isaac 
402962095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
40309566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootValuesSec));
40319566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootValuesSec,pStartC,pEndC));
40329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse,&numFields));
403362095d54SToby Isaac   {
403462095d54SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
40359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO));
403662095d54SToby Isaac   }
40370eb7e1eaSToby Isaac   if (grad) {
40380eb7e1eaSToby Isaac     PetscInt i;
40390eb7e1eaSToby Isaac 
40409566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeom,&cellDM));
40419566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeom,&cellGeomArray));
40429566063dSJacob Faibussowitsch     PetscCall(VecGetDM(grad,&gradDM));
40439566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(grad,&gradArray));
40440eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1,numFields); i++) {
40450eb7e1eaSToby Isaac       PetscObject  obj;
40460eb7e1eaSToby Isaac       PetscClassId id;
40470eb7e1eaSToby Isaac 
40489566063dSJacob Faibussowitsch       PetscCall(DMGetField(coarse, i, NULL, &obj));
40499566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj,&id));
40500eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
40510eb7e1eaSToby Isaac         fv      = (PetscFV) obj;
40529566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv,&numFVcomps));
40530eb7e1eaSToby Isaac         fvField = i;
40540eb7e1eaSToby Isaac         break;
40550eb7e1eaSToby Isaac       }
40560eb7e1eaSToby Isaac     }
40570eb7e1eaSToby Isaac   }
405862095d54SToby Isaac 
405962095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
406062095d54SToby Isaac     PetscInt dof;
406162095d54SToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
406262095d54SToby Isaac     PetscInt numValues      = 0;
406362095d54SToby Isaac 
40649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
406562095d54SToby Isaac     if (dof < 0) {
406662095d54SToby Isaac       dof = -(dof + 1);
406762095d54SToby Isaac     }
406862095d54SToby Isaac     offsets[0]    = 0;
406962095d54SToby Isaac     newOffsets[0] = 0;
407062095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
407162095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
407262095d54SToby Isaac 
40739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
407462095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
407562095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
407662095d54SToby Isaac 
40779566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse,c,&clDof));
407862095d54SToby Isaac         numValues += clDof;
407962095d54SToby Isaac       }
40809566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
408162095d54SToby Isaac     }
408262095d54SToby Isaac     else if (maxChildId == -1) {
40839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localCoarse,p,&numValues));
408462095d54SToby Isaac     }
408562095d54SToby Isaac     /* we will pack the column indices with the field offsets */
408678b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
40870eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
40880eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
40890eb7e1eaSToby Isaac     }
40909566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootValuesSec,p,numValues));
409162095d54SToby Isaac   }
40929566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootValuesSec));
409362095d54SToby Isaac   {
409462095d54SToby Isaac     PetscInt          numRootValues;
409562095d54SToby Isaac     const PetscScalar *coarseArray;
409662095d54SToby Isaac 
40979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootValuesSec,&numRootValues));
40989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRootValues,&rootValues));
40999566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecCoarseLocal,&coarseArray));
410062095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
410162095d54SToby Isaac       PetscInt    numValues;
410262095d54SToby Isaac       PetscInt    pValOff;
410362095d54SToby Isaac       PetscScalar *pVal;
410462095d54SToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
410562095d54SToby Isaac 
41069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootValuesSec,p,&numValues));
410762095d54SToby Isaac       if (!numValues) {
410862095d54SToby Isaac         continue;
410962095d54SToby Isaac       }
41109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootValuesSec,p,&pValOff));
411162095d54SToby Isaac       pVal = &(rootValues[pValOff]);
411262095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
41130eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
41149566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(coarse,NULL,vecCoarseLocal,p,&closureSize,&pVal));
41150eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
4116193eb951SToby Isaac           PetscFVCellGeom *cg;
41176dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
41180eb7e1eaSToby Isaac           PetscInt        i;
41190eb7e1eaSToby Isaac 
41200eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
41210eb7e1eaSToby Isaac 
41229566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(cellDM,p,cellGeomArray,(void *) &cg));
41230eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
41240eb7e1eaSToby Isaac           pVal += dim;
41259566063dSJacob Faibussowitsch           PetscCall(DMPlexPointGlobalRead(gradDM,p,gradArray,(void *) &gradVals));
41260eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
41270eb7e1eaSToby Isaac         }
412862095d54SToby Isaac       }
412978b7adb5SToby Isaac       else if (maxChildId == -1) {
413078b7adb5SToby Isaac         PetscInt lDof, lOff, i;
413178b7adb5SToby Isaac 
41329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse,p,&lDof));
41339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(localCoarse,p,&lOff));
413478b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
413578b7adb5SToby Isaac       }
413678b7adb5SToby Isaac     }
41379566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecCoarseLocal,&coarseArray));
41389566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
413962095d54SToby Isaac   }
414062095d54SToby Isaac   {
414162095d54SToby Isaac     PetscSF  valuesSF;
414262095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
414362095d54SToby Isaac 
41449566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafValuesSec));
41459566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded,rootValuesSec,&remoteOffsetsValues,leafValuesSec));
41469566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded,rootValuesSec,remoteOffsetsValues,leafValuesSec,&valuesSF));
41479566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
41489566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsValues));
41499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafValuesSec,&numLeafValues));
41509566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafValues,&leafValues));
41519566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(valuesSF,MPIU_SCALAR,rootValues,leafValues,MPI_REPLACE));
41529566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(valuesSF,MPIU_SCALAR,rootValues,leafValues,MPI_REPLACE));
41539566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&valuesSF));
41549566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootValues));
41559566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootValuesSec));
415662095d54SToby Isaac   }
41579566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine,&localFine));
415862095d54SToby Isaac   {
415962095d54SToby Isaac     PetscInt    maxDof;
416062095d54SToby Isaac     PetscInt    *rowIndices;
416162095d54SToby Isaac     DM           refTree;
416262095d54SToby Isaac     PetscInt     **refPointFieldN;
416362095d54SToby Isaac     PetscScalar  ***refPointFieldMats;
416462095d54SToby Isaac     PetscSection refConSec, refAnSec;
41650eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,leafStart,leafEnd;
416662095d54SToby Isaac     PetscScalar  *pointWork;
416762095d54SToby Isaac 
41689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine,&maxDof));
41699566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
41709566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork));
41719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine,&refTree));
41729566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(fine,refTree));
41739566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
41749566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
41759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree,&refAnSec,NULL));
41769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
41779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafValuesSec,&leafStart,&leafEnd));
41789566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSimplexOrBoxCells(fine,0,&cellStart,&cellEnd));
41790eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
418062095d54SToby Isaac       PetscInt          gDof, gcDof, gOff, lDof;
418162095d54SToby Isaac       PetscInt          numValues, pValOff;
418262095d54SToby Isaac       PetscInt          childId;
418362095d54SToby Isaac       const PetscScalar *pVal;
41840eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
418562095d54SToby Isaac 
41869566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&gDof));
41879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localFine,p,&lDof));
41889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&gcDof));
418962095d54SToby Isaac       if ((gDof - gcDof) <= 0) {
419062095d54SToby Isaac         continue;
419162095d54SToby Isaac       }
41929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine,p,&gOff));
41939566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafValuesSec,p,&numValues));
419462095d54SToby Isaac       if (!numValues) continue;
41959566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafValuesSec,p,&pValOff));
419662095d54SToby Isaac       pVal = &leafValues[pValOff];
419762095d54SToby Isaac       offsets[0]        = 0;
419862095d54SToby Isaac       offsetsCopy[0]    = 0;
419962095d54SToby Isaac       newOffsets[0]     = 0;
420062095d54SToby Isaac       newOffsetsCopy[0] = 0;
42014833aeb0SToby Isaac       childId           = cids[p - pStartF];
420262095d54SToby Isaac       if (numFields) {
420362095d54SToby Isaac         PetscInt f;
420462095d54SToby Isaac         for (f = 0; f < numFields; f++) {
420562095d54SToby Isaac           PetscInt rowDof;
420662095d54SToby Isaac 
42079566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine,p,f,&rowDof));
420862095d54SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
420962095d54SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
421062095d54SToby Isaac           /* TODO: closure indices */
42119f4e70e1SToby Isaac           newOffsets[f + 1]     = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
421262095d54SToby Isaac         }
42139566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,NULL,rowIndices));
421462095d54SToby Isaac       }
421562095d54SToby Isaac       else {
42164833aeb0SToby Isaac         offsets[0]    = 0;
42174833aeb0SToby Isaac         offsets[1]    = lDof;
42184833aeb0SToby Isaac         newOffsets[0] = 0;
42194833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
42209566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,NULL,rowIndices));
422162095d54SToby Isaac       }
422262095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
42239566063dSJacob Faibussowitsch         PetscCall(VecSetValues(vecFine,numValues,rowIndices,pVal,INSERT_VALUES));
422462095d54SToby Isaac       } else {
422562095d54SToby Isaac         PetscInt f;
422662095d54SToby Isaac 
422778b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
422878b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
422978b7adb5SToby Isaac           fvGradData = &pVal[numValues];
423078b7adb5SToby Isaac         }
423162095d54SToby Isaac         for (f = 0; f < PetscMax(1,numFields); f++) {
423262095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
423362095d54SToby Isaac           PetscInt numRows = offsets[f+1] - offsets[f];
423462095d54SToby Isaac           PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
423562095d54SToby Isaac           const PetscScalar *cVal = &pVal[newOffsets[f]];
423662095d54SToby Isaac           PetscScalar *rVal = &pointWork[offsets[f]];
423762095d54SToby Isaac           PetscInt i, j;
423862095d54SToby Isaac 
4239708c7f19SToby Isaac #if 0
42409566063dSJacob Faibussowitsch           PetscCall(PetscInfo(coarse,"childId %D, numRows %D, numCols %D, refPointFieldN %D maxDof %D\n",childId,numRows,numCols,refPointFieldN[childId - pRefStart][f], maxDof));
4241708c7f19SToby Isaac #endif
424262095d54SToby Isaac           for (i = 0; i < numRows; i++) {
424362095d54SToby Isaac             PetscScalar val = 0.;
424462095d54SToby Isaac             for (j = 0; j < numCols; j++) {
424562095d54SToby Isaac               val += childMat[i * numCols + j] * cVal[j];
424662095d54SToby Isaac             }
424762095d54SToby Isaac             rVal[i] = val;
424862095d54SToby Isaac           }
42490eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
42500eb7e1eaSToby Isaac             PetscReal   centroid[3];
42510eb7e1eaSToby Isaac             PetscScalar diff[3];
42520eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
42530eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
42540eb7e1eaSToby Isaac 
42559566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFVM(fine,p,NULL,centroid,NULL));
42560eb7e1eaSToby Isaac             for (i = 0; i < dim; i++) {
42570eb7e1eaSToby Isaac               diff[i] = centroid[i] - parentCentroid[i];
42580eb7e1eaSToby Isaac             }
42590eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
42600eb7e1eaSToby Isaac               PetscScalar val = 0.;
42610eb7e1eaSToby Isaac 
426289698031SToby Isaac               for (j = 0; j < dim; j++) {
42630eb7e1eaSToby Isaac                 val += gradient[dim * i + j] * diff[j];
42640eb7e1eaSToby Isaac               }
42650eb7e1eaSToby Isaac               rVal[i] += val;
42660eb7e1eaSToby Isaac             }
42670eb7e1eaSToby Isaac           }
42689566063dSJacob Faibussowitsch           PetscCall(VecSetValues(vecFine,numRows,&rowIndices[offsets[f]],rVal,INSERT_VALUES));
426962095d54SToby Isaac         }
427062095d54SToby Isaac       }
427162095d54SToby Isaac     }
42729566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
42739566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork));
42749566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
427562095d54SToby Isaac   }
42769566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafValues));
42779566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafValuesSec));
42789566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO));
42799566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS,&anchors));
4280ebf164c7SToby Isaac   PetscFunctionReturn(0);
4281ebf164c7SToby Isaac }
4282ebf164c7SToby Isaac 
4283ebf164c7SToby Isaac static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4284ebf164c7SToby Isaac {
4285c921d74cSToby Isaac   DM             refTree;
4286c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4287c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4288c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4289c921d74cSToby Isaac   PetscSection   cSecRef;
4290c921d74cSToby Isaac   PetscInt       *parentIndices, pRefStart, pRefEnd;
4291d3bc4906SToby Isaac   PetscScalar    *rootValues, *parentValues;
4292c921d74cSToby Isaac   Mat            injRef;
4293c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4294c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4295c921d74cSToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
4296c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4297c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4298c921d74cSToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4299c921d74cSToby Isaac 
4300ebf164c7SToby Isaac   PetscFunctionBegin;
4301c921d74cSToby Isaac 
4302c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
43039566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE));
43049566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecCoarse,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE));
43059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse,&refTree));
43069566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(coarse,refTree));
43079566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&cSecRef,NULL,NULL));
43089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd));
43099566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree,&injRef));
4310c921d74cSToby Isaac 
43119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine,&pStartF,&pEndF));
43129566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine,&localFine));
43139566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine,&globalFine));
43149566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine,&numFields));
43159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
43169566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse,&localCoarse));
43179566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse,&globalCoarse));
43189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse,&maxDof));
4319c921d74cSToby Isaac   {
4320c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
43219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets));
4322c921d74cSToby Isaac   }
4323c921d74cSToby Isaac 
43249566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse,fine,coarseToFine,cids,vecFine,numFields,offsets,&multiRootSec,&rootIndicesSec,NULL,&rootValues));
4325c921d74cSToby Isaac 
43269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxDof,&parentIndices,maxDof,&parentValues));
4327c921d74cSToby Isaac 
4328c921d74cSToby Isaac   /* count indices */
43299566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecFine,&colMap));
43309566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecCoarse,&rowMap));
43319566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
43329566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
43339566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap,&rowStart,&rowEnd));
43349566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap,&colStart,&colEnd));
4335c921d74cSToby Isaac   /* insert values */
43369566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats));
4337c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4338c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
433978b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4340c921d74cSToby Isaac 
43419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
43429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
4343c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
43449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localCoarse,p,&dof));
43459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse,p,&gOff));
4346c921d74cSToby Isaac 
4347c921d74cSToby Isaac     rowOffsets[0] = 0;
4348c921d74cSToby Isaac     offsetsCopy[0] = 0;
4349c921d74cSToby Isaac     if (numFields) {
4350c921d74cSToby Isaac       PetscInt f;
4351c921d74cSToby Isaac 
4352c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4353c921d74cSToby Isaac         PetscInt fDof;
43549566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
4355c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4356c921d74cSToby Isaac       }
43579566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,NULL,parentIndices));
4358367003a6SStefano Zampini     } else {
43599566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,NULL,parentIndices));
4360c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4361c921d74cSToby Isaac     }
4362c921d74cSToby Isaac 
43639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec,p,&numLeaves));
43649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec,p,&leafStart));
4365c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
43662f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4367c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4368c921d74cSToby Isaac       PetscInt numIndices, childId, offset;
4369c921d74cSToby Isaac       const PetscScalar *childValues;
4370c921d74cSToby Isaac 
43719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec,l,&numIndices));
43729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec,l,&offset));
4373c921d74cSToby Isaac       childId = (PetscInt) PetscRealPart(rootValues[offset++]);
4374c921d74cSToby Isaac       childValues = &rootValues[offset];
4375c921d74cSToby Isaac       numIndices--;
4376c921d74cSToby Isaac 
4377c921d74cSToby Isaac       if (childId == -2) { /* skip */
4378c921d74cSToby Isaac         continue;
4379c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
43802f65e181SToby Isaac         PetscInt m;
43812f65e181SToby Isaac 
438278b7adb5SToby Isaac         contribute = PETSC_TRUE;
43832f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4384beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4385d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4386d3bc4906SToby Isaac 
438778b7adb5SToby Isaac         contribute = PETSC_TRUE;
43889566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree,childId,&parentId,NULL));
4389d3bc4906SToby Isaac 
4390d3bc4906SToby Isaac         lim = PetscMax(1,numFields);
4391d3bc4906SToby Isaac         offsets[0] = 0;
4392d3bc4906SToby Isaac         if (numFields) {
4393d3bc4906SToby Isaac           PetscInt f;
4394d3bc4906SToby Isaac 
4395d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4396d3bc4906SToby Isaac             PetscInt fDof;
43979566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef,childId,f,&fDof));
4398d3bc4906SToby Isaac 
4399d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4400d3bc4906SToby Isaac           }
4401d3bc4906SToby Isaac         }
4402d3bc4906SToby Isaac         else {
4403d3bc4906SToby Isaac           PetscInt cDof;
4404d3bc4906SToby Isaac 
44059566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef,childId,&cDof));
4406d3bc4906SToby Isaac           offsets[1] = cDof;
4407d3bc4906SToby Isaac         }
4408d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4409d3bc4906SToby Isaac           PetscScalar       *childMat   = &childrenMats[childId - pRefStart][f][0];
4410d3bc4906SToby Isaac           PetscInt          n           = offsets[f+1]-offsets[f];
4411e328ff09SToby Isaac           PetscInt          m           = rowOffsets[f+1]-rowOffsets[f];
4412d3bc4906SToby Isaac           PetscInt          i, j;
4413d3bc4906SToby Isaac           const PetscScalar *colValues  = &childValues[offsets[f]];
4414d3bc4906SToby Isaac 
4415e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4416d3bc4906SToby Isaac             PetscScalar val = 0.;
4417d3bc4906SToby Isaac             for (j = 0; j < n; j++) {
4418d3bc4906SToby Isaac               val += childMat[n * i + j] * colValues[j];
4419d3bc4906SToby Isaac             }
4420e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4421d3bc4906SToby Isaac           }
4422d3bc4906SToby Isaac         }
4423c921d74cSToby Isaac       }
4424c921d74cSToby Isaac     }
44259566063dSJacob Faibussowitsch     if (contribute) PetscCall(VecSetValues(vecCoarse,dof,parentIndices,parentValues,INSERT_VALUES));
4426c921d74cSToby Isaac   }
44279566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
44289566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
44299566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parentIndices,parentValues));
44309566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats));
44319566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootValues));
44329566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets,offsetsCopy,rowOffsets));
4433ebf164c7SToby Isaac   PetscFunctionReturn(0);
4434ebf164c7SToby Isaac }
4435ebf164c7SToby Isaac 
4436ff1f73f7SToby Isaac /*@
4437ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4438ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4439ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4440ff1f73f7SToby Isaac 
4441ff1f73f7SToby Isaac   collective
4442ff1f73f7SToby Isaac 
4443ff1f73f7SToby Isaac   Input Parameters:
4444ff1f73f7SToby Isaac + dmIn        - The DMPlex mesh for the input vector
4445ff1f73f7SToby Isaac . vecIn       - The input vector
4446ff1f73f7SToby Isaac . sfRefine    - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4447ff1f73f7SToby Isaac                 the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4448ff1f73f7SToby Isaac . sfCoarsen   - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4449ff1f73f7SToby Isaac                 the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4450ff1f73f7SToby Isaac . cidsRefine  - The childIds of the points in dmOut.  These childIds relate back to the reference tree: childid[j] = k implies
4451ff1f73f7SToby Isaac                 that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4452ff1f73f7SToby Isaac                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in dmOut is exactly
4453ff1f73f7SToby Isaac                 equivalent to its root in dmIn, so no interpolation is necessary.  childid[j] = -2 indicates that this
4454ff1f73f7SToby Isaac                 point j in dmOut is not a leaf of sfRefine.
4455ff1f73f7SToby Isaac . cidsCoarsen - The childIds of the points in dmIn.  These childIds relate back to the reference tree: childid[j] = k implies
4456ff1f73f7SToby Isaac                 that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4457ff1f73f7SToby Isaac                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4458ff1f73f7SToby Isaac . useBCs      - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4459ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4460ff1f73f7SToby Isaac 
4461ff1f73f7SToby Isaac   Output Parameters:
44628966356dSPierre Jolivet . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transferred
4463ff1f73f7SToby Isaac                 projection of vecIn from dmIn to dmOut.  Note that any field discretized with a PetscFV finite volume
4464ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4465ff1f73f7SToby Isaac                 coarse points to fine points.
4466ff1f73f7SToby Isaac 
4467ff1f73f7SToby Isaac   Level: developer
4468ff1f73f7SToby Isaac 
4469fd292e60Sprj- .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree(), PetscFVGetComputeGradients()
4470ff1f73f7SToby Isaac @*/
4471ff1f73f7SToby Isaac PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
447238fc2455SToby Isaac {
447338fc2455SToby Isaac   PetscFunctionBegin;
44749566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut,0.0));
4475ff1f73f7SToby Isaac   if (sfRefine) {
4476fbfa57b9SToby Isaac     Vec vecInLocal;
44770eb7e1eaSToby Isaac     DM  dmGrad = NULL;
44780eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4479fbfa57b9SToby Isaac 
44809566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmIn,&vecInLocal));
44819566063dSJacob Faibussowitsch     PetscCall(VecSet(vecInLocal,0.0));
44820eb7e1eaSToby Isaac     {
44830eb7e1eaSToby Isaac       PetscInt  numFields, i;
44840eb7e1eaSToby Isaac 
44859566063dSJacob Faibussowitsch       PetscCall(DMGetNumFields(dmIn, &numFields));
44860eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
44870eb7e1eaSToby Isaac         PetscObject  obj;
44880eb7e1eaSToby Isaac         PetscClassId classid;
44890eb7e1eaSToby Isaac 
44909566063dSJacob Faibussowitsch         PetscCall(DMGetField(dmIn, i, NULL, &obj));
44919566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &classid));
44920eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
44939566063dSJacob Faibussowitsch           PetscCall(DMPlexGetDataFVM(dmIn,(PetscFV)obj,&cellGeom,&faceGeom,&dmGrad));
44940eb7e1eaSToby Isaac           break;
44950eb7e1eaSToby Isaac         }
44960eb7e1eaSToby Isaac       }
44970eb7e1eaSToby Isaac     }
44980eb7e1eaSToby Isaac     if (useBCs) {
44999566063dSJacob Faibussowitsch       PetscCall(DMPlexInsertBoundaryValues(dmIn,PETSC_TRUE,vecInLocal,time,faceGeom,cellGeom,NULL));
45000eb7e1eaSToby Isaac     }
45019566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmIn,vecIn,INSERT_VALUES,vecInLocal));
45029566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmIn,vecIn,INSERT_VALUES,vecInLocal));
45030eb7e1eaSToby Isaac     if (dmGrad) {
45049566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad,&grad));
45059566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradientsFVM(dmIn,vecInLocal,grad));
45060eb7e1eaSToby Isaac     }
45079566063dSJacob Faibussowitsch     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn,vecInLocal,dmOut,vecOut,sfRefine,cidsRefine,grad,cellGeom));
45089566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn,&vecInLocal));
45090eb7e1eaSToby Isaac     if (dmGrad) {
45109566063dSJacob Faibussowitsch       PetscCall(DMRestoreGlobalVector(dmGrad,&grad));
45110eb7e1eaSToby Isaac     }
4512ebf164c7SToby Isaac   }
4513ff1f73f7SToby Isaac   if (sfCoarsen) {
45149566063dSJacob Faibussowitsch     PetscCall(DMPlexTransferVecTree_Inject(dmIn,vecIn,dmOut,vecOut,sfCoarsen,cidsCoarsen));
4515ebf164c7SToby Isaac   }
45169566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(vecOut));
45179566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(vecOut));
451838fc2455SToby Isaac   PetscFunctionReturn(0);
451938fc2455SToby Isaac }
4520