xref: /petsc/src/dm/impls/plex/plextree.c (revision 0eb7e1eae252ea4368f51905e6ed2ea3dd84b0fd)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2d6a7ad0dSToby Isaac #include <../src/sys/utils/hash.h>
3af0996ceSBarry Smith #include <petsc/private/isimpl.h>
4af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
5d6a7ad0dSToby Isaac #include <petscsf.h>
60c37af3bSToby Isaac #include <petscds.h>
7d6a7ad0dSToby Isaac 
8d6a7ad0dSToby Isaac /** hierarchy routines */
9d6a7ad0dSToby Isaac 
10d6a7ad0dSToby Isaac #undef __FUNCT__
11d6a7ad0dSToby Isaac #define __FUNCT__ "DMPlexSetReferenceTree"
12d6a7ad0dSToby Isaac /*@
13d6a7ad0dSToby Isaac   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
14d6a7ad0dSToby Isaac 
15d6a7ad0dSToby Isaac   Not collective
16d6a7ad0dSToby Isaac 
17d6a7ad0dSToby Isaac   Input Parameters:
18d6a7ad0dSToby Isaac + dm - The DMPlex object
19d6a7ad0dSToby Isaac - ref - The reference tree DMPlex object
20d6a7ad0dSToby Isaac 
210b7167a0SToby Isaac   Level: intermediate
22d6a7ad0dSToby Isaac 
23da43764aSToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexCreateDefaultReferenceTree()
24d6a7ad0dSToby Isaac @*/
25d6a7ad0dSToby Isaac PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
26d6a7ad0dSToby Isaac {
27d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
28d6a7ad0dSToby Isaac   PetscErrorCode  ierr;
29d6a7ad0dSToby Isaac 
30d6a7ad0dSToby Isaac   PetscFunctionBegin;
31d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3247a1df27SMatthew G. Knepley   if (ref) {PetscValidHeaderSpecific(ref, DM_CLASSID, 2);}
33d6a7ad0dSToby Isaac   ierr = PetscObjectReference((PetscObject)ref);CHKERRQ(ierr);
34d6a7ad0dSToby Isaac   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
35d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
36d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
37d6a7ad0dSToby Isaac }
38d6a7ad0dSToby Isaac 
39d6a7ad0dSToby Isaac #undef __FUNCT__
40d6a7ad0dSToby Isaac #define __FUNCT__ "DMPlexGetReferenceTree"
41d6a7ad0dSToby Isaac /*@
42d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
43d6a7ad0dSToby Isaac 
44d6a7ad0dSToby Isaac   Not collective
45d6a7ad0dSToby Isaac 
46d6a7ad0dSToby Isaac   Input Parameters:
47d6a7ad0dSToby Isaac . dm - The DMPlex object
48d6a7ad0dSToby Isaac 
49d6a7ad0dSToby Isaac   Output Parameters
50d6a7ad0dSToby Isaac . ref - The reference tree DMPlex object
51d6a7ad0dSToby Isaac 
520b7167a0SToby Isaac   Level: intermediate
53d6a7ad0dSToby Isaac 
54da43764aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexCreateDefaultReferenceTree()
55d6a7ad0dSToby Isaac @*/
56d6a7ad0dSToby Isaac PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
57d6a7ad0dSToby Isaac {
58d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
59d6a7ad0dSToby Isaac 
60d6a7ad0dSToby Isaac   PetscFunctionBegin;
61d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
62d6a7ad0dSToby Isaac   PetscValidPointer(ref,2);
63d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
64d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
65d6a7ad0dSToby Isaac }
66d6a7ad0dSToby Isaac 
67dcbd3bf7SToby Isaac #undef __FUNCT__
68dcbd3bf7SToby Isaac #define __FUNCT__ "DMPlexReferenceTreeGetChildSymmetry_Default"
69dcbd3bf7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
70dcbd3bf7SToby Isaac {
71dcbd3bf7SToby Isaac   PetscInt       coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
72dcbd3bf7SToby Isaac   PetscErrorCode ierr;
73dcbd3bf7SToby Isaac 
74dcbd3bf7SToby Isaac   PetscFunctionBegin;
75dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
76dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
77dcbd3bf7SToby Isaac     if (childB) *childB = childA;
78dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
79dcbd3bf7SToby Isaac   }
80dcbd3bf7SToby Isaac   for (dim = 0; dim < 3; dim++) {
81dcbd3bf7SToby Isaac     ierr = DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd);CHKERRQ(ierr);
82dcbd3bf7SToby Isaac     if (parent >= dStart && parent <= dEnd) {
83dcbd3bf7SToby Isaac       break;
84dcbd3bf7SToby Isaac     }
85dcbd3bf7SToby Isaac   }
86dcbd3bf7SToby Isaac   if (dim > 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim);
87dcbd3bf7SToby Isaac   if (!dim) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
88dcbd3bf7SToby Isaac   if (childA < dStart || childA >= dEnd) {
89dcbd3bf7SToby Isaac     /* this is a lower-dimensional child: bootstrap */
90dcbd3bf7SToby Isaac     PetscInt size, i, sA = -1, sB, sOrientB, sConeSize;
91dcbd3bf7SToby Isaac     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
92dcbd3bf7SToby Isaac 
93dcbd3bf7SToby Isaac     ierr = DMPlexGetSupportSize(dm,childA,&size);CHKERRQ(ierr);
94dcbd3bf7SToby Isaac     ierr = DMPlexGetSupport(dm,childA,&supp);CHKERRQ(ierr);
95dcbd3bf7SToby Isaac 
96dcbd3bf7SToby Isaac     /* find a point sA in supp(childA) that has the same parent */
97dcbd3bf7SToby Isaac     for (i = 0; i < size; i++) {
98dcbd3bf7SToby Isaac       PetscInt sParent;
99dcbd3bf7SToby Isaac 
100dcbd3bf7SToby Isaac       sA   = supp[i];
101dcbd3bf7SToby Isaac       if (sA == parent) continue;
102dcbd3bf7SToby Isaac       ierr = DMPlexGetTreeParent(dm,sA,&sParent,NULL);CHKERRQ(ierr);
103dcbd3bf7SToby Isaac       if (sParent == parent) {
104dcbd3bf7SToby Isaac         break;
105dcbd3bf7SToby Isaac       }
106dcbd3bf7SToby Isaac     }
107dcbd3bf7SToby Isaac     if (i == size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
108dcbd3bf7SToby Isaac     /* find out which point sB is in an equivalent position to sA under
109dcbd3bf7SToby Isaac      * parentOrientB */
110dcbd3bf7SToby Isaac     ierr = DMPlexReferenceTreeGetChildSymmetry_Default(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB);CHKERRQ(ierr);
111dcbd3bf7SToby Isaac     ierr = DMPlexGetConeSize(dm,sA,&sConeSize);CHKERRQ(ierr);
112dcbd3bf7SToby Isaac     ierr = DMPlexGetCone(dm,sA,&coneA);CHKERRQ(ierr);
113dcbd3bf7SToby Isaac     ierr = DMPlexGetCone(dm,sB,&coneB);CHKERRQ(ierr);
114dcbd3bf7SToby Isaac     ierr = DMPlexGetConeOrientation(dm,sA,&oA);CHKERRQ(ierr);
115dcbd3bf7SToby Isaac     ierr = DMPlexGetConeOrientation(dm,sB,&oB);CHKERRQ(ierr);
116dcbd3bf7SToby Isaac     /* step through the cone of sA in natural order */
117dcbd3bf7SToby Isaac     for (i = 0; i < sConeSize; i++) {
118dcbd3bf7SToby Isaac       if (coneA[i] == childA) {
119dcbd3bf7SToby Isaac         /* if childA is at position i in coneA,
120dcbd3bf7SToby Isaac          * then we want the point that is at sOrientB*i in coneB */
121dcbd3bf7SToby Isaac         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
122dcbd3bf7SToby Isaac         if (childB) *childB = coneB[j];
123dcbd3bf7SToby Isaac         if (childOrientB) {
124dcbd3bf7SToby Isaac           PetscInt oBtrue;
125dcbd3bf7SToby Isaac 
126dcbd3bf7SToby Isaac           ierr          = DMPlexGetConeSize(dm,childA,&coneSize);CHKERRQ(ierr);
127dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
128dcbd3bf7SToby Isaac           if (coneSize != 0 && coneSize != 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
129dcbd3bf7SToby Isaac           /* we may have to flip an edge */
130dcbd3bf7SToby Isaac           oBtrue        = coneSize ? ((sOrientB >= 0) ? oB[j] : -(oB[j] + 2)) : 0;
131dcbd3bf7SToby Isaac           ABswap        = DihedralSwap(coneSize,oA[i],oBtrue);CHKERRQ(ierr);
132dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
133dcbd3bf7SToby Isaac         }
134dcbd3bf7SToby Isaac         break;
135dcbd3bf7SToby Isaac       }
136dcbd3bf7SToby Isaac     }
137dcbd3bf7SToby Isaac     if (i == sConeSize) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
138dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
139dcbd3bf7SToby Isaac   }
140dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
141dcbd3bf7SToby Isaac   ierr   = DMPlexGetConeSize(dm,parent,&coneSize);CHKERRQ(ierr);
142dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
143dcbd3bf7SToby Isaac   if (dim == 2) {
144dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
145dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
146dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
147dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
148dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
149dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
150947b95d8SBarry Smith   } else {
151dcbd3bf7SToby Isaac     ABswapVert = ABswap;
152dcbd3bf7SToby Isaac   }
153dcbd3bf7SToby Isaac   if (childB) {
154dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
155dcbd3bf7SToby Isaac     PetscInt p, posA = -1, numChildren, i;
156dcbd3bf7SToby Isaac     const PetscInt *children;
157dcbd3bf7SToby Isaac 
158dcbd3bf7SToby Isaac     /* count which position the child is in */
159dcbd3bf7SToby Isaac     ierr = DMPlexGetTreeChildren(dm,parent,&numChildren,&children);CHKERRQ(ierr);
160dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
161dcbd3bf7SToby Isaac       p = children[i];
162dcbd3bf7SToby Isaac       if (p == childA) {
163dcbd3bf7SToby Isaac         posA = i;
164dcbd3bf7SToby Isaac         break;
165dcbd3bf7SToby Isaac       }
166dcbd3bf7SToby Isaac     }
167dcbd3bf7SToby Isaac     if (posA >= coneSize) {
168dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
169dcbd3bf7SToby Isaac        * is invariant */
170dcbd3bf7SToby Isaac       if (dim != 2 || posA != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Expected a middle triangle, got something else");
171dcbd3bf7SToby Isaac       *childB = childA;
172dcbd3bf7SToby Isaac     }
173dcbd3bf7SToby Isaac     else {
174dcbd3bf7SToby Isaac       /* figure out position B by applying ABswapVert */
175dcbd3bf7SToby Isaac       PetscInt posB;
176dcbd3bf7SToby Isaac 
177dcbd3bf7SToby Isaac       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
178dcbd3bf7SToby Isaac       if (childB) *childB = children[posB];
179dcbd3bf7SToby Isaac     }
180dcbd3bf7SToby Isaac   }
181dcbd3bf7SToby Isaac   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
182dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
183dcbd3bf7SToby Isaac }
184dcbd3bf7SToby Isaac 
185dcbd3bf7SToby Isaac #undef __FUNCT__
186dcbd3bf7SToby Isaac #define __FUNCT__ "DMPlexReferenceTreeGetChildSymmetry"
187dcbd3bf7SToby Isaac /*@
188dcbd3bf7SToby Isaac   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
189dcbd3bf7SToby Isaac 
190dcbd3bf7SToby Isaac   Input Parameters:
191dcbd3bf7SToby Isaac + dm - the reference tree DMPlex object
192dcbd3bf7SToby Isaac . parent - the parent point
193dcbd3bf7SToby Isaac . parentOrientA - the reference orientation for describing the parent
194dcbd3bf7SToby Isaac . childOrientA - the reference orientation for describing the child
195dcbd3bf7SToby Isaac . childA - the reference childID for describing the child
196dcbd3bf7SToby Isaac - parentOrientB - the new orientation for describing the parent
197dcbd3bf7SToby Isaac 
198dcbd3bf7SToby Isaac   Output Parameters:
199dcbd3bf7SToby Isaac + childOrientB - if not NULL, set to the new oreintation for describing the child
200dcbd3bf7SToby Isaac . childB - if not NULL, the new childID for describing the child
201dcbd3bf7SToby Isaac 
202dcbd3bf7SToby Isaac   Level: developer
203dcbd3bf7SToby Isaac 
204dcbd3bf7SToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexSetReferenceTree(), DMPlexSetTree()
205dcbd3bf7SToby Isaac @*/
206dcbd3bf7SToby Isaac PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
207dcbd3bf7SToby Isaac {
208dcbd3bf7SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
209dcbd3bf7SToby Isaac   PetscErrorCode ierr;
210dcbd3bf7SToby Isaac 
211dcbd3bf7SToby Isaac   PetscFunctionBegin;
212dcbd3bf7SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
213dcbd3bf7SToby Isaac   if (!mesh->getchildsymmetry) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlexReferenceTreeGetChildSymmetry not implemented");
214dcbd3bf7SToby Isaac   ierr = mesh->getchildsymmetry(dm,parent,parentOrientA,childOrientA,childA,parentOrientB,childOrientB,childB);CHKERRQ(ierr);
215dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
216dcbd3bf7SToby Isaac }
217dcbd3bf7SToby Isaac 
218776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM,PetscSection,PetscInt*,PetscInt*,PetscBool,PetscBool);
219f9f063d4SToby Isaac 
220da43764aSToby Isaac #undef __FUNCT__
2210e2cc29aSToby Isaac #define __FUNCT__ "DMPlexCreateReferenceTree_Union"
2220e2cc29aSToby Isaac PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
223da43764aSToby Isaac {
2240e2cc29aSToby Isaac   MPI_Comm       comm;
2250e2cc29aSToby Isaac   PetscInt       dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
226da43764aSToby Isaac   PetscInt      *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
227da43764aSToby Isaac   DMLabel        identity, identityRef;
22810f7e118SToby Isaac   PetscSection   unionSection, unionConeSection, parentSection;
229da43764aSToby Isaac   PetscScalar   *unionCoords;
230da43764aSToby Isaac   IS             perm;
231da43764aSToby Isaac   PetscErrorCode ierr;
232da43764aSToby Isaac 
233da43764aSToby Isaac   PetscFunctionBegin;
2340e2cc29aSToby Isaac   comm = PetscObjectComm((PetscObject)K);
2350e2cc29aSToby Isaac   ierr = DMGetDimension(K, &dim);CHKERRQ(ierr);
236da43764aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
2370e2cc29aSToby Isaac   ierr = DMGetLabel(K, labelName, &identity);CHKERRQ(ierr);
2380e2cc29aSToby Isaac   ierr = DMGetLabel(Kref, labelName, &identityRef);CHKERRQ(ierr);
239da43764aSToby Isaac   ierr = DMPlexGetChart(Kref, &pRefStart, &pRefEnd);CHKERRQ(ierr);
240da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionSection);CHKERRQ(ierr);
241da43764aSToby Isaac   ierr = PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart));CHKERRQ(ierr);
242da43764aSToby Isaac   /* count points that will go in the union */
243da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
244da43764aSToby Isaac     ierr = PetscSectionSetDof(unionSection, p - pStart, 1);CHKERRQ(ierr);
245da43764aSToby Isaac   }
246da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
247da43764aSToby Isaac     PetscInt q, qSize;
248da43764aSToby Isaac     ierr = DMLabelGetValue(identityRef, p, &q);CHKERRQ(ierr);
249da43764aSToby Isaac     ierr = DMLabelGetStratumSize(identityRef, q, &qSize);CHKERRQ(ierr);
250da43764aSToby Isaac     if (qSize > 1) {
251da43764aSToby Isaac       ierr = PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1);CHKERRQ(ierr);
252da43764aSToby Isaac     }
253da43764aSToby Isaac   }
254854ce69bSBarry Smith   ierr = PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart,&permvals);CHKERRQ(ierr);
255da43764aSToby Isaac   offset = 0;
256da43764aSToby Isaac   /* stratify points in the union by topological dimension */
257da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
258da43764aSToby Isaac     PetscInt cStart, cEnd, c;
259da43764aSToby Isaac 
260da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K, d, &cStart, &cEnd);CHKERRQ(ierr);
261da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
262da43764aSToby Isaac       permvals[offset++] = c;
263da43764aSToby Isaac     }
264da43764aSToby Isaac 
265da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd);CHKERRQ(ierr);
266da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
267da43764aSToby Isaac       permvals[offset++] = c + (pEnd - pStart);
268da43764aSToby Isaac     }
269da43764aSToby Isaac   }
270da43764aSToby Isaac   ierr = ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm);CHKERRQ(ierr);
271da43764aSToby Isaac   ierr = PetscSectionSetPermutation(unionSection,perm);CHKERRQ(ierr);
272da43764aSToby Isaac   ierr = PetscSectionSetUp(unionSection);CHKERRQ(ierr);
273da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionSection,&numUnionPoints);CHKERRQ(ierr);
274da43764aSToby Isaac   ierr = PetscMalloc2(numUnionPoints,&coneSizes,dim+1,&numDimPoints);CHKERRQ(ierr);
275da43764aSToby Isaac   /* count dimension points */
276da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
277da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
278da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K,d,&cStart,NULL);CHKERRQ(ierr);
279da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff);CHKERRQ(ierr);
280da43764aSToby Isaac     if (d < dim) {
281da43764aSToby Isaac       ierr = DMPlexGetHeightStratum(K,d+1,&cStart,NULL);CHKERRQ(ierr);
282da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff2);CHKERRQ(ierr);
283da43764aSToby Isaac     }
284da43764aSToby Isaac     else {
285da43764aSToby Isaac       cOff2 = numUnionPoints;
286da43764aSToby Isaac     }
287da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
288da43764aSToby Isaac   }
289da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionConeSection);CHKERRQ(ierr);
290da43764aSToby Isaac   ierr = PetscSectionSetChart(unionConeSection, 0, numUnionPoints);CHKERRQ(ierr);
291da43764aSToby Isaac   /* count the cones in the union */
292da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
293da43764aSToby Isaac     PetscInt dof, uOff;
294da43764aSToby Isaac 
295da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
296da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
297da43764aSToby Isaac     ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
298da43764aSToby Isaac     coneSizes[uOff] = dof;
299da43764aSToby Isaac   }
300da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
301da43764aSToby Isaac     PetscInt dof, uDof, uOff;
302da43764aSToby Isaac 
303da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
304da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
305da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
306da43764aSToby Isaac     if (uDof) {
307da43764aSToby Isaac       ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
308da43764aSToby Isaac       coneSizes[uOff] = dof;
309da43764aSToby Isaac     }
310da43764aSToby Isaac   }
311da43764aSToby Isaac   ierr = PetscSectionSetUp(unionConeSection);CHKERRQ(ierr);
312da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionConeSection,&numCones);CHKERRQ(ierr);
313da43764aSToby Isaac   ierr = PetscMalloc2(numCones,&unionCones,numCones,&unionOrientations);CHKERRQ(ierr);
314da43764aSToby Isaac   /* write the cones in the union */
315da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
316da43764aSToby Isaac     PetscInt dof, uOff, c, cOff;
317da43764aSToby Isaac     const PetscInt *cone, *orientation;
318da43764aSToby Isaac 
319da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
320da43764aSToby Isaac     ierr = DMPlexGetCone(K, p, &cone);CHKERRQ(ierr);
321da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(K, p, &orientation);CHKERRQ(ierr);
322da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
323da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
324da43764aSToby Isaac     for (c = 0; c < dof; c++) {
325da43764aSToby Isaac       PetscInt e, eOff;
326da43764aSToby Isaac       e                           = cone[c];
327da43764aSToby Isaac       ierr                        = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
328da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
329da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
330da43764aSToby Isaac     }
331da43764aSToby Isaac   }
332da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
333da43764aSToby Isaac     PetscInt dof, uDof, uOff, c, cOff;
334da43764aSToby Isaac     const PetscInt *cone, *orientation;
335da43764aSToby Isaac 
336da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
337da43764aSToby Isaac     ierr = DMPlexGetCone(Kref, p, &cone);CHKERRQ(ierr);
338da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(Kref, p, &orientation);CHKERRQ(ierr);
339da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
340da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
341da43764aSToby Isaac     if (uDof) {
342da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
343da43764aSToby Isaac       for (c = 0; c < dof; c++) {
344da43764aSToby Isaac         PetscInt e, eOff, eDof;
345da43764aSToby Isaac 
346da43764aSToby Isaac         e    = cone[c];
347da43764aSToby Isaac         ierr = PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart),&eDof);CHKERRQ(ierr);
348da43764aSToby Isaac         if (eDof) {
349da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff);CHKERRQ(ierr);
350da43764aSToby Isaac         }
351da43764aSToby Isaac         else {
352da43764aSToby Isaac           ierr = DMLabelGetValue(identityRef, e, &e);CHKERRQ(ierr);
353da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
354da43764aSToby Isaac         }
355da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
356da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
357da43764aSToby Isaac       }
358da43764aSToby Isaac     }
359da43764aSToby Isaac   }
360da43764aSToby Isaac   /* get the coordinates */
361da43764aSToby Isaac   {
362da43764aSToby Isaac     PetscInt vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
363da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
364da43764aSToby Isaac     Vec      KcoordsVec, KrefCoordsVec;
365da43764aSToby Isaac     PetscScalar *Kcoords;
366da43764aSToby Isaac 
367da43764aSToby Isaac     DMGetCoordinateSection(K, &KcoordsSec);CHKERRQ(ierr);
368da43764aSToby Isaac     DMGetCoordinatesLocal(K, &KcoordsVec);CHKERRQ(ierr);
369da43764aSToby Isaac     DMGetCoordinateSection(Kref, &KrefCoordsSec);CHKERRQ(ierr);
370da43764aSToby Isaac     DMGetCoordinatesLocal(Kref, &KrefCoordsVec);CHKERRQ(ierr);
371da43764aSToby Isaac 
372da43764aSToby Isaac     numVerts = numDimPoints[0];
373da43764aSToby Isaac     ierr     = PetscMalloc1(numVerts * dim,&unionCoords);CHKERRQ(ierr);
374da43764aSToby Isaac     ierr     = DMPlexGetDepthStratum(K,0,&vStart,&vEnd);CHKERRQ(ierr);
375da43764aSToby Isaac 
376da43764aSToby Isaac     offset = 0;
377da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
378da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pStart,&vOff);CHKERRQ(ierr);
379da43764aSToby Isaac       ierr = VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords);CHKERRQ(ierr);
380da43764aSToby Isaac       for (d = 0; d < dim; d++) {
381da43764aSToby Isaac         unionCoords[offset * dim + d] = Kcoords[d];
382da43764aSToby Isaac       }
383da43764aSToby Isaac       offset++;
384da43764aSToby Isaac     }
385da43764aSToby Isaac     ierr = DMPlexGetDepthStratum(Kref,0,&vRefStart,&vRefEnd);CHKERRQ(ierr);
386da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
387da43764aSToby Isaac       ierr = PetscSectionGetDof(unionSection,v - pRefStart + (pEnd - pStart),&vDof);CHKERRQ(ierr);
388da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pRefStart + (pEnd - pStart),&vOff);CHKERRQ(ierr);
389da43764aSToby Isaac       ierr = VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords);CHKERRQ(ierr);
390da43764aSToby Isaac       if (vDof) {
391da43764aSToby Isaac         for (d = 0; d < dim; d++) {
392da43764aSToby Isaac           unionCoords[offset * dim + d] = Kcoords[d];
393da43764aSToby Isaac         }
394da43764aSToby Isaac         offset++;
395da43764aSToby Isaac       }
396da43764aSToby Isaac     }
397da43764aSToby Isaac   }
398da43764aSToby Isaac   ierr = DMCreate(comm,ref);CHKERRQ(ierr);
399da43764aSToby Isaac   ierr = DMSetType(*ref,DMPLEX);CHKERRQ(ierr);
40028f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ref,dim);CHKERRQ(ierr);
401da43764aSToby Isaac   ierr = DMPlexCreateFromDAG(*ref,dim,numDimPoints,coneSizes,unionCones,unionOrientations,unionCoords);CHKERRQ(ierr);
40210f7e118SToby Isaac   /* set the tree */
40310f7e118SToby Isaac   ierr = PetscSectionCreate(comm,&parentSection);CHKERRQ(ierr);
40410f7e118SToby Isaac   ierr = PetscSectionSetChart(parentSection,0,numUnionPoints);CHKERRQ(ierr);
40510f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
40610f7e118SToby Isaac     PetscInt uDof, uOff;
40710f7e118SToby Isaac 
40810f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
40910f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
41010f7e118SToby Isaac     if (uDof) {
41110f7e118SToby Isaac       PetscSectionSetDof(parentSection,uOff,1);CHKERRQ(ierr);
41210f7e118SToby Isaac     }
41310f7e118SToby Isaac   }
41410f7e118SToby Isaac   ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
41510f7e118SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&parentSize);CHKERRQ(ierr);
41610f7e118SToby Isaac   ierr = PetscMalloc2(parentSize,&parents,parentSize,&childIDs);CHKERRQ(ierr);
41710f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
41810f7e118SToby Isaac     PetscInt uDof, uOff;
41910f7e118SToby Isaac 
42010f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
42110f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
42210f7e118SToby Isaac     if (uDof) {
42310f7e118SToby Isaac       PetscInt pOff, parent, parentU;
42410f7e118SToby Isaac       PetscSectionGetOffset(parentSection,uOff,&pOff);CHKERRQ(ierr);
42510f7e118SToby Isaac       DMLabelGetValue(identityRef,p,&parent);CHKERRQ(ierr);
42610f7e118SToby Isaac       ierr = PetscSectionGetOffset(unionSection, parent - pStart,&parentU);CHKERRQ(ierr);
42710f7e118SToby Isaac       parents[pOff] = parentU;
42810f7e118SToby Isaac       childIDs[pOff] = uOff;
42910f7e118SToby Isaac     }
43010f7e118SToby Isaac   }
431776742edSToby Isaac   ierr = DMPlexSetTree_Internal(*ref,parentSection,parents,childIDs,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
43210f7e118SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
43310f7e118SToby Isaac   ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
43410f7e118SToby Isaac 
435da43764aSToby Isaac   /* clean up */
436da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionSection);CHKERRQ(ierr);
437da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionConeSection);CHKERRQ(ierr);
438da43764aSToby Isaac   ierr = ISDestroy(&perm);CHKERRQ(ierr);
439da43764aSToby Isaac   ierr = PetscFree(unionCoords);CHKERRQ(ierr);
440da43764aSToby Isaac   ierr = PetscFree2(unionCones,unionOrientations);CHKERRQ(ierr);
441da43764aSToby Isaac   ierr = PetscFree2(coneSizes,numDimPoints);CHKERRQ(ierr);
4420e2cc29aSToby Isaac   PetscFunctionReturn(0);
4430e2cc29aSToby Isaac }
4440e2cc29aSToby Isaac 
4450e2cc29aSToby Isaac #undef __FUNCT__
4460e2cc29aSToby Isaac #define __FUNCT__ "DMPlexCreateDefaultReferenceTree"
4470e2cc29aSToby Isaac /*@
4480e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4490e2cc29aSToby Isaac 
4500e2cc29aSToby Isaac   Collective on comm
4510e2cc29aSToby Isaac 
4520e2cc29aSToby Isaac   Input Parameters:
4530e2cc29aSToby Isaac + comm    - the MPI communicator
4540e2cc29aSToby Isaac . dim     - the spatial dimension
4550e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4560e2cc29aSToby Isaac 
4570e2cc29aSToby Isaac   Output Parameters:
4580e2cc29aSToby Isaac . ref     - the reference tree DMPlex object
4590e2cc29aSToby Isaac 
4600e2cc29aSToby Isaac   Level: intermediate
4610e2cc29aSToby Isaac 
4620e2cc29aSToby Isaac .keywords: reference cell
4630e2cc29aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree()
4640e2cc29aSToby Isaac @*/
4650e2cc29aSToby Isaac PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
4660e2cc29aSToby Isaac {
4670e2cc29aSToby Isaac   DM_Plex       *mesh;
4680e2cc29aSToby Isaac   DM             K, Kref;
4690e2cc29aSToby Isaac   PetscInt       p, pStart, pEnd;
4700e2cc29aSToby Isaac   DMLabel        identity;
4710e2cc29aSToby Isaac   PetscErrorCode ierr;
4720e2cc29aSToby Isaac 
4730e2cc29aSToby Isaac   PetscFunctionBegin;
4740e2cc29aSToby Isaac #if 1
4750e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4760e2cc29aSToby Isaac #endif
4770e2cc29aSToby Isaac   /* create a reference element */
4780e2cc29aSToby Isaac   ierr = DMPlexCreateReferenceCell(comm, dim, simplex, &K);CHKERRQ(ierr);
4790e2cc29aSToby Isaac   ierr = DMCreateLabel(K, "identity");CHKERRQ(ierr);
4800e2cc29aSToby Isaac   ierr = DMGetLabel(K, "identity", &identity);CHKERRQ(ierr);
4810e2cc29aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
4820e2cc29aSToby Isaac   for (p = pStart; p < pEnd; p++) {
4830e2cc29aSToby Isaac     ierr = DMLabelSetValue(identity, p, p);CHKERRQ(ierr);
4840e2cc29aSToby Isaac   }
4850e2cc29aSToby Isaac   /* refine it */
4860e2cc29aSToby Isaac   ierr = DMRefine(K,comm,&Kref);CHKERRQ(ierr);
4870e2cc29aSToby Isaac 
4880e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4890e2cc29aSToby Isaac    * points that appear in both */
4900e2cc29aSToby Isaac   ierr = DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref);CHKERRQ(ierr);
4910e2cc29aSToby Isaac   mesh = (DM_Plex *) (*ref)->data;
4920e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
493da43764aSToby Isaac   ierr = DMDestroy(&K);CHKERRQ(ierr);
494da43764aSToby Isaac   ierr = DMDestroy(&Kref);CHKERRQ(ierr);
495da43764aSToby Isaac   PetscFunctionReturn(0);
496da43764aSToby Isaac }
497da43764aSToby Isaac 
498d961a43aSToby Isaac #undef __FUNCT__
499878b19aaSToby Isaac #define __FUNCT__ "DMPlexTreeSymmetrize"
500878b19aaSToby Isaac static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
501878b19aaSToby Isaac {
502878b19aaSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
503878b19aaSToby Isaac   PetscSection   childSec, pSec;
504878b19aaSToby Isaac   PetscInt       p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
505878b19aaSToby Isaac   PetscInt       *offsets, *children, pStart, pEnd;
506878b19aaSToby Isaac   PetscErrorCode ierr;
507878b19aaSToby Isaac 
508878b19aaSToby Isaac   PetscFunctionBegin;
509878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
510878b19aaSToby Isaac   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
511878b19aaSToby Isaac   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
512878b19aaSToby Isaac   pSec = mesh->parentSection;
513878b19aaSToby Isaac   if (!pSec) PetscFunctionReturn(0);
514878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(pSec,&pSize);CHKERRQ(ierr);
515878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
516878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
517878b19aaSToby Isaac 
518878b19aaSToby Isaac     parMax = PetscMax(parMax,par+1);
519878b19aaSToby Isaac     parMin = PetscMin(parMin,par);
520878b19aaSToby Isaac   }
521878b19aaSToby Isaac   if (parMin > parMax) {
522878b19aaSToby Isaac     parMin = -1;
523878b19aaSToby Isaac     parMax = -1;
524878b19aaSToby Isaac   }
525878b19aaSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)pSec),&childSec);CHKERRQ(ierr);
526878b19aaSToby Isaac   ierr = PetscSectionSetChart(childSec,parMin,parMax);CHKERRQ(ierr);
527878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
528878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
529878b19aaSToby Isaac 
530878b19aaSToby Isaac     ierr = PetscSectionAddDof(childSec,par,1);CHKERRQ(ierr);
531878b19aaSToby Isaac   }
532878b19aaSToby Isaac   ierr = PetscSectionSetUp(childSec);CHKERRQ(ierr);
533878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(childSec,&cSize);CHKERRQ(ierr);
534878b19aaSToby Isaac   ierr = PetscMalloc1(cSize,&children);CHKERRQ(ierr);
535878b19aaSToby Isaac   ierr = PetscCalloc1(parMax-parMin,&offsets);CHKERRQ(ierr);
536878b19aaSToby Isaac   ierr = PetscSectionGetChart(pSec,&pStart,&pEnd);CHKERRQ(ierr);
537878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
538878b19aaSToby Isaac     PetscInt dof, off, i;
539878b19aaSToby Isaac 
540878b19aaSToby Isaac     ierr = PetscSectionGetDof(pSec,p,&dof);CHKERRQ(ierr);
541878b19aaSToby Isaac     ierr = PetscSectionGetOffset(pSec,p,&off);CHKERRQ(ierr);
542878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
543878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
544878b19aaSToby Isaac 
545878b19aaSToby Isaac       ierr = PetscSectionGetOffset(childSec,par,&cOff);CHKERRQ(ierr);
546878b19aaSToby Isaac       children[cOff + offsets[par-parMin]++] = p;
547878b19aaSToby Isaac     }
548878b19aaSToby Isaac   }
549878b19aaSToby Isaac   mesh->childSection = childSec;
550878b19aaSToby Isaac   mesh->children = children;
551878b19aaSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
552878b19aaSToby Isaac   PetscFunctionReturn(0);
553878b19aaSToby Isaac }
554878b19aaSToby Isaac 
555878b19aaSToby Isaac #undef __FUNCT__
5566dd5a8c8SToby Isaac #define __FUNCT__ "AnchorsFlatten"
5576dd5a8c8SToby Isaac static PetscErrorCode AnchorsFlatten (PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
5586dd5a8c8SToby Isaac {
5596dd5a8c8SToby Isaac   PetscInt       pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5606dd5a8c8SToby Isaac   const PetscInt *vals;
5616dd5a8c8SToby Isaac   PetscSection   secNew;
5626dd5a8c8SToby Isaac   PetscBool      anyNew, globalAnyNew;
5636dd5a8c8SToby Isaac   PetscBool      compress;
5646dd5a8c8SToby Isaac   PetscErrorCode ierr;
5656dd5a8c8SToby Isaac 
5666dd5a8c8SToby Isaac   PetscFunctionBegin;
5676dd5a8c8SToby Isaac   ierr = PetscSectionGetChart(section,&pStart,&pEnd);CHKERRQ(ierr);
5686dd5a8c8SToby Isaac   ierr = ISGetLocalSize(is,&size);CHKERRQ(ierr);
5696dd5a8c8SToby Isaac   ierr = ISGetIndices(is,&vals);CHKERRQ(ierr);
5706dd5a8c8SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secNew);CHKERRQ(ierr);
5716dd5a8c8SToby Isaac   ierr = PetscSectionSetChart(secNew,pStart,pEnd);CHKERRQ(ierr);
5726dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5736dd5a8c8SToby Isaac     PetscInt dof;
5746dd5a8c8SToby Isaac 
5756dd5a8c8SToby Isaac     p = vals[i];
5766dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5776dd5a8c8SToby Isaac     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5786dd5a8c8SToby Isaac     if (dof) break;
5796dd5a8c8SToby Isaac   }
5806dd5a8c8SToby Isaac   if (i == size) {
5816dd5a8c8SToby Isaac     ierr     = PetscSectionSetUp(secNew);CHKERRQ(ierr);
5826dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5836dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5846dd5a8c8SToby Isaac     sizeNew  = 0;
5856dd5a8c8SToby Isaac   }
5866dd5a8c8SToby Isaac   else {
5876dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5886dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5896dd5a8c8SToby Isaac       PetscInt dof, off;
5906dd5a8c8SToby Isaac 
5916dd5a8c8SToby Isaac       ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5926dd5a8c8SToby Isaac       ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
5936dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5946dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5956dd5a8c8SToby Isaac 
5966dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5976dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
5986dd5a8c8SToby Isaac         }
5996dd5a8c8SToby Isaac         if (qDof) {
6006dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, qDof);CHKERRQ(ierr);
6016dd5a8c8SToby Isaac         }
6026dd5a8c8SToby Isaac         else {
6036dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, 1);CHKERRQ(ierr);
6046dd5a8c8SToby Isaac         }
6056dd5a8c8SToby Isaac       }
6066dd5a8c8SToby Isaac     }
6076dd5a8c8SToby Isaac     ierr = PetscSectionSetUp(secNew);CHKERRQ(ierr);
6086dd5a8c8SToby Isaac     ierr = PetscSectionGetStorageSize(secNew,&sizeNew);CHKERRQ(ierr);
6096dd5a8c8SToby Isaac     ierr = PetscMalloc1(sizeNew,&valsNew);CHKERRQ(ierr);
6106dd5a8c8SToby Isaac     compress = PETSC_FALSE;
6116dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
6126dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
6136dd5a8c8SToby Isaac 
6146dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
6156dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
6166dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(secNew, p, &dofNew);CHKERRQ(ierr);
6176dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(secNew, p, &offNew);CHKERRQ(ierr);
6186dd5a8c8SToby Isaac       count = 0;
6196dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
6206dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
6216dd5a8c8SToby Isaac 
6226dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
6236dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
6246dd5a8c8SToby Isaac           ierr = PetscSectionGetOffset(section, q, &qOff);CHKERRQ(ierr);
6256dd5a8c8SToby Isaac         }
6266dd5a8c8SToby Isaac         if (qDof) {
6276dd5a8c8SToby Isaac           PetscInt oldCount = count;
6286dd5a8c8SToby Isaac 
6296dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
6306dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
6316dd5a8c8SToby Isaac 
6326dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
6336dd5a8c8SToby Isaac               if (valsNew[offNew + k] == r) {
6346dd5a8c8SToby Isaac                 break;
6356dd5a8c8SToby Isaac               }
6366dd5a8c8SToby Isaac             }
6376dd5a8c8SToby Isaac             if (k == oldCount) {
6386dd5a8c8SToby Isaac               valsNew[offNew + count++] = r;
6396dd5a8c8SToby Isaac             }
6406dd5a8c8SToby Isaac           }
6416dd5a8c8SToby Isaac         }
6426dd5a8c8SToby Isaac         else {
6436dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
6446dd5a8c8SToby Isaac 
6456dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
6466dd5a8c8SToby Isaac             if (valsNew[offNew + k] == q) {
6476dd5a8c8SToby Isaac               break;
6486dd5a8c8SToby Isaac             }
6496dd5a8c8SToby Isaac           }
6506dd5a8c8SToby Isaac           if (k == oldCount) {
6516dd5a8c8SToby Isaac             valsNew[offNew + count++] = q;
6526dd5a8c8SToby Isaac           }
6536dd5a8c8SToby Isaac         }
6546dd5a8c8SToby Isaac       }
6556dd5a8c8SToby Isaac       if (count < dofNew) {
6566dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secNew, p, count);CHKERRQ(ierr);
6576dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6586dd5a8c8SToby Isaac       }
6596dd5a8c8SToby Isaac     }
6606dd5a8c8SToby Isaac   }
6616dd5a8c8SToby Isaac   ierr = ISRestoreIndices(is,&vals);CHKERRQ(ierr);
662b2566f29SBarry Smith   ierr = MPIU_Allreduce(&anyNew,&globalAnyNew,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
6636dd5a8c8SToby Isaac   if (!globalAnyNew) {
6646dd5a8c8SToby Isaac     ierr = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6656dd5a8c8SToby Isaac     *sectionNew = NULL;
6666dd5a8c8SToby Isaac     *isNew = NULL;
6676dd5a8c8SToby Isaac   }
6686dd5a8c8SToby Isaac   else {
6696dd5a8c8SToby Isaac     PetscBool globalCompress;
6706dd5a8c8SToby Isaac 
671b2566f29SBarry Smith     ierr = MPIU_Allreduce(&compress,&globalCompress,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
6726dd5a8c8SToby Isaac     if (compress) {
6736dd5a8c8SToby Isaac       PetscSection secComp;
6746dd5a8c8SToby Isaac       PetscInt *valsComp = NULL;
6756dd5a8c8SToby Isaac 
6766dd5a8c8SToby Isaac       ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secComp);CHKERRQ(ierr);
6776dd5a8c8SToby Isaac       ierr = PetscSectionSetChart(secComp,pStart,pEnd);CHKERRQ(ierr);
6786dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6796dd5a8c8SToby Isaac         PetscInt dof;
6806dd5a8c8SToby Isaac 
6816dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6826dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secComp, p, dof);CHKERRQ(ierr);
6836dd5a8c8SToby Isaac       }
6846dd5a8c8SToby Isaac       ierr = PetscSectionSetUp(secComp);CHKERRQ(ierr);
6856dd5a8c8SToby Isaac       ierr = PetscSectionGetStorageSize(secComp,&sizeNew);CHKERRQ(ierr);
6866dd5a8c8SToby Isaac       ierr = PetscMalloc1(sizeNew,&valsComp);CHKERRQ(ierr);
6876dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6886dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6896dd5a8c8SToby Isaac 
6906dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6916dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secNew, p, &off);CHKERRQ(ierr);
6926dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secComp, p, &offNew);CHKERRQ(ierr);
6936dd5a8c8SToby Isaac         for (j = 0; j < dof; j++) {
6946dd5a8c8SToby Isaac           valsComp[offNew + j] = valsNew[off + j];
6956dd5a8c8SToby Isaac         }
6966dd5a8c8SToby Isaac       }
6976dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6986dd5a8c8SToby Isaac       secNew  = secComp;
6996dd5a8c8SToby Isaac       ierr    = PetscFree(valsNew);CHKERRQ(ierr);
7006dd5a8c8SToby Isaac       valsNew = valsComp;
7016dd5a8c8SToby Isaac     }
7026dd5a8c8SToby Isaac     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is),sizeNew,valsNew,PETSC_OWN_POINTER,isNew);CHKERRQ(ierr);
7036dd5a8c8SToby Isaac   }
7046dd5a8c8SToby Isaac   PetscFunctionReturn(0);
7056dd5a8c8SToby Isaac }
7066dd5a8c8SToby Isaac 
7076dd5a8c8SToby Isaac #undef __FUNCT__
708f7c74593SToby Isaac #define __FUNCT__ "DMPlexCreateAnchors_Tree"
709f7c74593SToby Isaac static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
71066af876cSToby Isaac {
71166af876cSToby Isaac   PetscInt       p, pStart, pEnd, *anchors, size;
71266af876cSToby Isaac   PetscInt       aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
71366af876cSToby Isaac   PetscSection   aSec;
714f9f063d4SToby Isaac   DMLabel        canonLabel;
71566af876cSToby Isaac   IS             aIS;
71666af876cSToby Isaac   PetscErrorCode ierr;
71766af876cSToby Isaac 
71866af876cSToby Isaac   PetscFunctionBegin;
71966af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
72066af876cSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
721c58f1c22SToby Isaac   ierr = DMGetLabel(dm,"canonical",&canonLabel);CHKERRQ(ierr);
72266af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
72366af876cSToby Isaac     PetscInt parent;
72466af876cSToby Isaac 
725f9f063d4SToby Isaac     if (canonLabel) {
726f9f063d4SToby Isaac       PetscInt canon;
727f9f063d4SToby Isaac 
728f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
729f9f063d4SToby Isaac       if (p != canon) continue;
730f9f063d4SToby Isaac     }
73166af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
73266af876cSToby Isaac     if (parent != p) {
73366af876cSToby Isaac       aMin = PetscMin(aMin,p);
73466af876cSToby Isaac       aMax = PetscMax(aMax,p+1);
73566af876cSToby Isaac     }
73666af876cSToby Isaac   }
73766af876cSToby Isaac   if (aMin > aMax) {
73866af876cSToby Isaac     aMin = -1;
73966af876cSToby Isaac     aMax = -1;
74066af876cSToby Isaac   }
741e228b242SToby Isaac   ierr = PetscSectionCreate(PETSC_COMM_SELF,&aSec);CHKERRQ(ierr);
74266af876cSToby Isaac   ierr = PetscSectionSetChart(aSec,aMin,aMax);CHKERRQ(ierr);
74366af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
74466af876cSToby Isaac     PetscInt parent, ancestor = p;
74566af876cSToby Isaac 
746f9f063d4SToby Isaac     if (canonLabel) {
747f9f063d4SToby Isaac       PetscInt canon;
748f9f063d4SToby Isaac 
749f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
750f9f063d4SToby Isaac       if (p != canon) continue;
751f9f063d4SToby Isaac     }
75266af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
75366af876cSToby Isaac     while (parent != ancestor) {
75466af876cSToby Isaac       ancestor = parent;
75566af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
75666af876cSToby Isaac     }
75766af876cSToby Isaac     if (ancestor != p) {
75866af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
75966af876cSToby Isaac 
76066af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
76166af876cSToby Isaac       ierr = PetscSectionSetDof(aSec,p,closureSize);CHKERRQ(ierr);
76266af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
76366af876cSToby Isaac     }
76466af876cSToby Isaac   }
76566af876cSToby Isaac   ierr = PetscSectionSetUp(aSec);CHKERRQ(ierr);
76666af876cSToby Isaac   ierr = PetscSectionGetStorageSize(aSec,&size);CHKERRQ(ierr);
76766af876cSToby Isaac   ierr = PetscMalloc1(size,&anchors);CHKERRQ(ierr);
76866af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
76966af876cSToby Isaac     PetscInt parent, ancestor = p;
77066af876cSToby Isaac 
771f9f063d4SToby Isaac     if (canonLabel) {
772f9f063d4SToby Isaac       PetscInt canon;
773f9f063d4SToby Isaac 
774f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
775f9f063d4SToby Isaac       if (p != canon) continue;
776f9f063d4SToby Isaac     }
77766af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
77866af876cSToby Isaac     while (parent != ancestor) {
77966af876cSToby Isaac       ancestor = parent;
78066af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
78166af876cSToby Isaac     }
78266af876cSToby Isaac     if (ancestor != p) {
78366af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
78466af876cSToby Isaac 
78566af876cSToby Isaac       ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
78666af876cSToby Isaac 
78766af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
78866af876cSToby Isaac       for (j = 0; j < closureSize; j++) {
78966af876cSToby Isaac         anchors[aOff + j] = closure[2*j];
79066af876cSToby Isaac       }
79166af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
79266af876cSToby Isaac     }
79366af876cSToby Isaac   }
794e228b242SToby Isaac   ierr = ISCreateGeneral(PETSC_COMM_SELF,size,anchors,PETSC_OWN_POINTER,&aIS);CHKERRQ(ierr);
7956dd5a8c8SToby Isaac   {
7966dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7976dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7986dd5a8c8SToby Isaac 
7996dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aSec);CHKERRQ(ierr);
8006dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aIS);CHKERRQ(ierr);
8016dd5a8c8SToby Isaac     while (aSecNew) {
8026dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
8036dd5a8c8SToby Isaac       ierr    = ISDestroy(&aIS);CHKERRQ(ierr);
8046dd5a8c8SToby Isaac       aSec    = aSecNew;
8056dd5a8c8SToby Isaac       aIS     = aISNew;
8066dd5a8c8SToby Isaac       aSecNew = NULL;
8076dd5a8c8SToby Isaac       aISNew  = NULL;
8086dd5a8c8SToby Isaac       ierr    = AnchorsFlatten(aSec,aIS,&aSecNew,&aISNew);CHKERRQ(ierr);
8096dd5a8c8SToby Isaac     }
8106dd5a8c8SToby Isaac   }
811a17985deSToby Isaac   ierr = DMPlexSetAnchors(dm,aSec,aIS);CHKERRQ(ierr);
81266af876cSToby Isaac   ierr = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
81366af876cSToby Isaac   ierr = ISDestroy(&aIS);CHKERRQ(ierr);
81466af876cSToby Isaac   PetscFunctionReturn(0);
81566af876cSToby Isaac }
81666af876cSToby Isaac 
81766af876cSToby Isaac #undef __FUNCT__
8186461c1adSToby Isaac #define __FUNCT__ "DMPlexGetTrueSupportSize"
8196461c1adSToby Isaac static PetscErrorCode DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt *dof,PetscInt *numTrueSupp)
8206461c1adSToby Isaac {
8216461c1adSToby Isaac   PetscErrorCode ierr;
8226461c1adSToby Isaac 
8236461c1adSToby Isaac   PetscFunctionBegin;
8246461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
8256461c1adSToby Isaac     PetscInt i, alldof;
8266461c1adSToby Isaac     const PetscInt *supp;
8276461c1adSToby Isaac     PetscInt count = 0;
8286461c1adSToby Isaac 
8296461c1adSToby Isaac     ierr = DMPlexGetSupportSize(dm,p,&alldof);CHKERRQ(ierr);
8306461c1adSToby Isaac     ierr = DMPlexGetSupport(dm,p,&supp);CHKERRQ(ierr);
8316461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
8326461c1adSToby Isaac       PetscInt q = supp[i], numCones, j;
8336461c1adSToby Isaac       const PetscInt *cone;
8346461c1adSToby Isaac 
8356461c1adSToby Isaac       ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
8366461c1adSToby Isaac       ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
8376461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
8386461c1adSToby Isaac         if (cone[j] == p) break;
8396461c1adSToby Isaac       }
8406461c1adSToby Isaac       if (j < numCones) count++;
8416461c1adSToby Isaac     }
8426461c1adSToby Isaac     numTrueSupp[p] = count;
8436461c1adSToby Isaac   }
8446461c1adSToby Isaac   *dof = numTrueSupp[p];
8456461c1adSToby Isaac   PetscFunctionReturn(0);
8466461c1adSToby Isaac }
8476461c1adSToby Isaac 
8486461c1adSToby Isaac #undef __FUNCT__
849776742edSToby Isaac #define __FUNCT__ "DMPlexTreeExchangeSupports"
850776742edSToby Isaac static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
851776742edSToby Isaac {
852776742edSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
853776742edSToby Isaac   PetscSection newSupportSection;
854776742edSToby Isaac   PetscInt newSize, *newSupports, pStart, pEnd, p, d, depth;
8556461c1adSToby Isaac   PetscInt *numTrueSupp;
856776742edSToby Isaac   PetscInt *offsets;
857776742edSToby Isaac   PetscErrorCode ierr;
858776742edSToby Isaac 
859776742edSToby Isaac   PetscFunctionBegin;
860776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
861776742edSToby Isaac   /* symmetrize the hierarchy */
862776742edSToby Isaac   ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr);
863e228b242SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)),&newSupportSection);CHKERRQ(ierr);
864776742edSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
865776742edSToby Isaac   ierr = PetscSectionSetChart(newSupportSection,pStart,pEnd);CHKERRQ(ierr);
866776742edSToby Isaac   ierr = PetscCalloc1(pEnd,&offsets);CHKERRQ(ierr);
8676461c1adSToby Isaac   ierr = PetscMalloc1(pEnd,&numTrueSupp);CHKERRQ(ierr);
8686461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8696461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
870776742edSToby Isaac    * parent(q) */
871776742edSToby Isaac   for (d = 0; d <= depth; d++) {
872776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
873776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
874776742edSToby Isaac       PetscInt dof, q, qdof, parent;
875776742edSToby Isaac 
8766461c1adSToby Isaac       ierr = DMPlexGetTrueSupportSize(dm,p,&dof,numTrueSupp);CHKERRQ(ierr);
877776742edSToby Isaac       ierr = PetscSectionAddDof(newSupportSection, p, dof);CHKERRQ(ierr);
878776742edSToby Isaac       q    = p;
879776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
880776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
881776742edSToby Isaac         q = parent;
882776742edSToby Isaac 
8836461c1adSToby Isaac         ierr = DMPlexGetTrueSupportSize(dm,q,&qdof,numTrueSupp);CHKERRQ(ierr);
884776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,p,qdof);CHKERRQ(ierr);
885776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,q,dof);CHKERRQ(ierr);
886776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
887776742edSToby Isaac       }
888776742edSToby Isaac     }
889776742edSToby Isaac   }
890776742edSToby Isaac   ierr = PetscSectionSetUp(newSupportSection);CHKERRQ(ierr);
891776742edSToby Isaac   ierr = PetscSectionGetStorageSize(newSupportSection,&newSize);CHKERRQ(ierr);
892776742edSToby Isaac   ierr = PetscMalloc1(newSize,&newSupports);CHKERRQ(ierr);
893776742edSToby Isaac   for (d = 0; d <= depth; d++) {
894776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
895776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
896776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
897776742edSToby Isaac 
898776742edSToby Isaac       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
899776742edSToby Isaac       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
900776742edSToby Isaac       ierr = PetscSectionGetDof(newSupportSection, p, &newDof);CHKERRQ(ierr);
901776742edSToby Isaac       ierr = PetscSectionGetOffset(newSupportSection, p, &newOff);CHKERRQ(ierr);
902776742edSToby Isaac       for (i = 0; i < dof; i++) {
9036461c1adSToby Isaac         PetscInt numCones, j;
9046461c1adSToby Isaac         const PetscInt *cone;
9056461c1adSToby Isaac         PetscInt q = mesh->supports[off + i];
9066461c1adSToby Isaac 
9076461c1adSToby Isaac         ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
9086461c1adSToby Isaac         ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
9096461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
9106461c1adSToby Isaac           if (cone[j] == p) break;
9116461c1adSToby Isaac         }
9126461c1adSToby Isaac         if (j < numCones) newSupports[newOff+offsets[p]++] = q;
913776742edSToby Isaac       }
914776742edSToby Isaac       mesh->maxSupportSize = PetscMax(mesh->maxSupportSize,newDof);
915776742edSToby Isaac 
916776742edSToby Isaac       q    = p;
917776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
918776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
919776742edSToby Isaac         q = parent;
920776742edSToby Isaac         ierr = PetscSectionGetDof(mesh->supportSection, q, &qdof);CHKERRQ(ierr);
921776742edSToby Isaac         ierr = PetscSectionGetOffset(mesh->supportSection, q, &qoff);CHKERRQ(ierr);
922776742edSToby Isaac         ierr = PetscSectionGetOffset(newSupportSection, q, &newqOff);CHKERRQ(ierr);
923776742edSToby Isaac         for (i = 0; i < qdof; i++) {
9246461c1adSToby Isaac           PetscInt numCones, j;
9256461c1adSToby Isaac           const PetscInt *cone;
9266461c1adSToby Isaac           PetscInt r = mesh->supports[qoff + i];
9276461c1adSToby Isaac 
9286461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9296461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9306461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9316461c1adSToby Isaac             if (cone[j] == q) break;
9326461c1adSToby Isaac           }
9336461c1adSToby Isaac           if (j < numCones) newSupports[newOff+offsets[p]++] = r;
934776742edSToby Isaac         }
935776742edSToby Isaac         for (i = 0; i < dof; i++) {
9366461c1adSToby Isaac           PetscInt numCones, j;
9376461c1adSToby Isaac           const PetscInt *cone;
9386461c1adSToby Isaac           PetscInt r = mesh->supports[off + i];
9396461c1adSToby Isaac 
9406461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9416461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9426461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9436461c1adSToby Isaac             if (cone[j] == p) break;
9446461c1adSToby Isaac           }
9456461c1adSToby Isaac           if (j < numCones) newSupports[newqOff+offsets[q]++] = r;
946776742edSToby Isaac         }
947776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
948776742edSToby Isaac       }
949776742edSToby Isaac     }
950776742edSToby Isaac   }
951776742edSToby Isaac   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
952776742edSToby Isaac   mesh->supportSection = newSupportSection;
953776742edSToby Isaac   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
954776742edSToby Isaac   mesh->supports = newSupports;
955776742edSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
9566461c1adSToby Isaac   ierr = PetscFree(numTrueSupp);CHKERRQ(ierr);
957776742edSToby Isaac 
958776742edSToby Isaac   PetscFunctionReturn(0);
959776742edSToby Isaac }
960776742edSToby Isaac 
961f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM,PetscSection,PetscSection,Mat);
962f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM,PetscSection,PetscSection,Mat);
963f7c74593SToby Isaac 
964776742edSToby Isaac #undef __FUNCT__
965f9f063d4SToby Isaac #define __FUNCT__ "DMPlexSetTree_Internal"
966776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
967f9f063d4SToby Isaac {
968f9f063d4SToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
969f9f063d4SToby Isaac   DM             refTree;
970f9f063d4SToby Isaac   PetscInt       size;
971f9f063d4SToby Isaac   PetscErrorCode ierr;
972f9f063d4SToby Isaac 
973f9f063d4SToby Isaac   PetscFunctionBegin;
974f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
975f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
976f9f063d4SToby Isaac   ierr = PetscObjectReference((PetscObject)parentSection);CHKERRQ(ierr);
977f9f063d4SToby Isaac   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
978f9f063d4SToby Isaac   mesh->parentSection = parentSection;
979f9f063d4SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&size);CHKERRQ(ierr);
980f9f063d4SToby Isaac   if (parents != mesh->parents) {
981f9f063d4SToby Isaac     ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
982f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->parents);CHKERRQ(ierr);
983f9f063d4SToby Isaac     ierr = PetscMemcpy(mesh->parents, parents, size * sizeof(*parents));CHKERRQ(ierr);
984f9f063d4SToby Isaac   }
985f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
986f9f063d4SToby Isaac     ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
987f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->childIDs);CHKERRQ(ierr);
988f9f063d4SToby Isaac     ierr = PetscMemcpy(mesh->childIDs, childIDs, size * sizeof(*childIDs));CHKERRQ(ierr);
989f9f063d4SToby Isaac   }
990f9f063d4SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
991f9f063d4SToby Isaac   if (refTree) {
992f9f063d4SToby Isaac     DMLabel canonLabel;
993f9f063d4SToby Isaac 
994c58f1c22SToby Isaac     ierr = DMGetLabel(refTree,"canonical",&canonLabel);CHKERRQ(ierr);
995f9f063d4SToby Isaac     if (canonLabel) {
996f9f063d4SToby Isaac       PetscInt i;
997f9f063d4SToby Isaac 
998f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
999f9f063d4SToby Isaac         PetscInt canon;
1000f9f063d4SToby Isaac         ierr = DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon);CHKERRQ(ierr);
1001f9f063d4SToby Isaac         if (canon >= 0) {
1002f9f063d4SToby Isaac           mesh->childIDs[i] = canon;
1003f9f063d4SToby Isaac         }
1004f9f063d4SToby Isaac       }
1005f9f063d4SToby Isaac     }
1006f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
1007f7c74593SToby Isaac   }
1008f7c74593SToby Isaac   else {
1009f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
1010f9f063d4SToby Isaac   }
1011f9f063d4SToby Isaac   ierr = DMPlexTreeSymmetrize(dm);CHKERRQ(ierr);
1012f9f063d4SToby Isaac   if (computeCanonical) {
1013f9f063d4SToby Isaac     PetscInt d, dim;
1014f9f063d4SToby Isaac 
1015f9f063d4SToby Isaac     /* add the canonical label */
101628f4b327SMatthew G. Knepley     ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
1017c58f1c22SToby Isaac     ierr = DMCreateLabel(dm,"canonical");CHKERRQ(ierr);
1018f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
1019f9f063d4SToby Isaac       PetscInt p, dStart, dEnd, canon = -1, cNumChildren;
1020f9f063d4SToby Isaac       const PetscInt *cChildren;
1021f9f063d4SToby Isaac 
1022f9f063d4SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
1023f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1024f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&cNumChildren,&cChildren);CHKERRQ(ierr);
1025f9f063d4SToby Isaac         if (cNumChildren) {
1026f9f063d4SToby Isaac           canon = p;
1027f9f063d4SToby Isaac           break;
1028f9f063d4SToby Isaac         }
1029f9f063d4SToby Isaac       }
1030f9f063d4SToby Isaac       if (canon == -1) continue;
1031f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1032f9f063d4SToby Isaac         PetscInt numChildren, i;
1033f9f063d4SToby Isaac         const PetscInt *children;
1034f9f063d4SToby Isaac 
1035f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&numChildren,&children);CHKERRQ(ierr);
1036f9f063d4SToby Isaac         if (numChildren) {
1037f9f063d4SToby Isaac           if (numChildren != cNumChildren) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"All parent points in a stratum should have the same number of children: %d != %d", numChildren, cNumChildren);
1038c58f1c22SToby Isaac           ierr = DMSetLabelValue(dm,"canonical",p,canon);CHKERRQ(ierr);
1039f9f063d4SToby Isaac           for (i = 0; i < numChildren; i++) {
1040c58f1c22SToby Isaac             ierr = DMSetLabelValue(dm,"canonical",children[i],cChildren[i]);CHKERRQ(ierr);
1041f9f063d4SToby Isaac           }
1042f9f063d4SToby Isaac         }
1043f9f063d4SToby Isaac       }
1044f9f063d4SToby Isaac     }
1045f9f063d4SToby Isaac   }
1046776742edSToby Isaac   if (exchangeSupports) {
1047776742edSToby Isaac     ierr = DMPlexTreeExchangeSupports(dm);CHKERRQ(ierr);
1048776742edSToby Isaac   }
1049f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
1050f7c74593SToby Isaac   /* reset anchors */
1051f7c74593SToby Isaac   ierr = DMPlexSetAnchors(dm,NULL,NULL);CHKERRQ(ierr);
1052f9f063d4SToby Isaac   PetscFunctionReturn(0);
1053f9f063d4SToby Isaac }
1054f9f063d4SToby Isaac 
1055f9f063d4SToby Isaac #undef __FUNCT__
10560b7167a0SToby Isaac #define __FUNCT__ "DMPlexSetTree"
10570b7167a0SToby Isaac /*@
10580b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
10590b7167a0SToby Isaac   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
10600b7167a0SToby Isaac   tree root.
10610b7167a0SToby Isaac 
10620b7167a0SToby Isaac   Collective on dm
10630b7167a0SToby Isaac 
10640b7167a0SToby Isaac   Input Parameters:
10650b7167a0SToby Isaac + dm - the DMPlex object
10660b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
10670b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
10680b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
10690b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
10700b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
10710b7167a0SToby Isaac 
10720b7167a0SToby Isaac   Level: intermediate
10730b7167a0SToby Isaac 
1074a17985deSToby Isaac .seealso: DMPlexGetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
10750b7167a0SToby Isaac @*/
1076b2f41788SToby Isaac PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
10770b7167a0SToby Isaac {
10780b7167a0SToby Isaac   PetscErrorCode ierr;
10790b7167a0SToby Isaac 
10800b7167a0SToby Isaac   PetscFunctionBegin;
1081776742edSToby Isaac   ierr = DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
10820b7167a0SToby Isaac   PetscFunctionReturn(0);
10830b7167a0SToby Isaac }
10840b7167a0SToby Isaac 
10850b7167a0SToby Isaac #undef __FUNCT__
1086b2f41788SToby Isaac #define __FUNCT__ "DMPlexGetTree"
1087b2f41788SToby Isaac /*@
1088b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1089b2f41788SToby Isaac   Collective on dm
1090b2f41788SToby Isaac 
1091b2f41788SToby Isaac   Input Parameters:
1092b2f41788SToby Isaac . dm - the DMPlex object
1093b2f41788SToby Isaac 
1094b2f41788SToby Isaac   Output Parameters:
1095b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1096b2f41788SToby Isaac                   offset indexes the parent and childID list
1097b2f41788SToby Isaac . parents - a list of the point parents
1098b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1099b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1100b2f41788SToby Isaac . childSection - the inverse of the parent section
1101b2f41788SToby Isaac - children - a list of the point children
1102b2f41788SToby Isaac 
1103b2f41788SToby Isaac   Level: intermediate
1104b2f41788SToby Isaac 
1105a17985deSToby Isaac .seealso: DMPlexSetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
1106b2f41788SToby Isaac @*/
1107b2f41788SToby Isaac PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1108b2f41788SToby Isaac {
1109b2f41788SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
1110b2f41788SToby Isaac 
1111b2f41788SToby Isaac   PetscFunctionBegin;
1112b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1113b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1114b2f41788SToby Isaac   if (parents)       *parents       = mesh->parents;
1115b2f41788SToby Isaac   if (childIDs)      *childIDs      = mesh->childIDs;
1116b2f41788SToby Isaac   if (childSection)  *childSection  = mesh->childSection;
1117b2f41788SToby Isaac   if (children)      *children      = mesh->children;
1118b2f41788SToby Isaac   PetscFunctionReturn(0);
1119b2f41788SToby Isaac }
1120b2f41788SToby Isaac 
1121b2f41788SToby Isaac #undef __FUNCT__
1122d961a43aSToby Isaac #define __FUNCT__ "DMPlexGetTreeParent"
1123d961a43aSToby Isaac /*@
1124d961a43aSToby Isaac   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the Sieve DAG)
1125d961a43aSToby Isaac 
1126d961a43aSToby Isaac   Input Parameters:
1127d961a43aSToby Isaac + dm - the DMPlex object
1128d961a43aSToby Isaac - point - the query point
1129d961a43aSToby Isaac 
1130d961a43aSToby Isaac   Output Parameters:
1131d961a43aSToby Isaac + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1132d961a43aSToby Isaac - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point
1133d961a43aSToby Isaac             does not have a parent
1134d961a43aSToby Isaac 
1135d961a43aSToby Isaac   Level: intermediate
1136d961a43aSToby Isaac 
1137d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeChildren()
1138d961a43aSToby Isaac @*/
1139d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1140d961a43aSToby Isaac {
1141d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1142d961a43aSToby Isaac   PetscSection   pSec;
1143d961a43aSToby Isaac   PetscErrorCode ierr;
1144d961a43aSToby Isaac 
1145d961a43aSToby Isaac   PetscFunctionBegin;
1146d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1147d961a43aSToby Isaac   pSec = mesh->parentSection;
1148d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1149d961a43aSToby Isaac     PetscInt dof;
1150d961a43aSToby Isaac 
1151d961a43aSToby Isaac     ierr = PetscSectionGetDof (pSec, point, &dof);CHKERRQ(ierr);
1152d961a43aSToby Isaac     if (dof) {
1153d961a43aSToby Isaac       PetscInt off;
1154d961a43aSToby Isaac 
1155d961a43aSToby Isaac       ierr = PetscSectionGetOffset (pSec, point, &off);CHKERRQ(ierr);
1156d961a43aSToby Isaac       if (parent)  *parent = mesh->parents[off];
1157d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
1158d961a43aSToby Isaac       PetscFunctionReturn(0);
1159d961a43aSToby Isaac     }
1160d961a43aSToby Isaac   }
1161d961a43aSToby Isaac   if (parent) {
1162d961a43aSToby Isaac     *parent = point;
1163d961a43aSToby Isaac   }
1164d961a43aSToby Isaac   if (childID) {
1165d961a43aSToby Isaac     *childID = 0;
1166d961a43aSToby Isaac   }
1167d961a43aSToby Isaac   PetscFunctionReturn(0);
1168d961a43aSToby Isaac }
1169d961a43aSToby Isaac 
1170d961a43aSToby Isaac #undef __FUNCT__
1171d961a43aSToby Isaac #define __FUNCT__ "DMPlexGetTreeChildren"
1172d961a43aSToby Isaac /*@C
1173d961a43aSToby Isaac   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the Sieve DAG)
1174d961a43aSToby Isaac 
1175d961a43aSToby Isaac   Input Parameters:
1176d961a43aSToby Isaac + dm - the DMPlex object
1177d961a43aSToby Isaac - point - the query point
1178d961a43aSToby Isaac 
1179d961a43aSToby Isaac   Output Parameters:
1180d961a43aSToby Isaac + numChildren - if not NULL, set to the number of children
1181d961a43aSToby Isaac - children - if not NULL, set to a list children, or set to NULL if the point has no children
1182d961a43aSToby Isaac 
1183d961a43aSToby Isaac   Level: intermediate
1184d961a43aSToby Isaac 
1185d961a43aSToby Isaac   Fortran Notes:
1186d961a43aSToby Isaac   Since it returns an array, this routine is only available in Fortran 90, and you must
1187d961a43aSToby Isaac   include petsc.h90 in your code.
1188d961a43aSToby Isaac 
1189d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeParent()
1190d961a43aSToby Isaac @*/
1191d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1192d961a43aSToby Isaac {
1193d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1194d961a43aSToby Isaac   PetscSection   childSec;
1195d961a43aSToby Isaac   PetscInt       dof = 0;
1196d961a43aSToby Isaac   PetscErrorCode ierr;
1197d961a43aSToby Isaac 
1198d961a43aSToby Isaac   PetscFunctionBegin;
1199d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1200d961a43aSToby Isaac   childSec = mesh->childSection;
1201d961a43aSToby Isaac   if (childSec && point >= childSec->pStart && point < childSec->pEnd) {
1202d961a43aSToby Isaac     ierr = PetscSectionGetDof (childSec, point, &dof);CHKERRQ(ierr);
1203d961a43aSToby Isaac   }
1204d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1205d961a43aSToby Isaac   if (children) {
1206d961a43aSToby Isaac     if (dof) {
1207d961a43aSToby Isaac       PetscInt off;
1208d961a43aSToby Isaac 
1209d961a43aSToby Isaac       ierr = PetscSectionGetOffset (childSec, point, &off);CHKERRQ(ierr);
1210d961a43aSToby Isaac       *children = &mesh->children[off];
1211d961a43aSToby Isaac     }
1212d961a43aSToby Isaac     else {
1213d961a43aSToby Isaac       *children = NULL;
1214d961a43aSToby Isaac     }
1215d961a43aSToby Isaac   }
1216d961a43aSToby Isaac   PetscFunctionReturn(0);
1217d961a43aSToby Isaac }
12180c37af3bSToby Isaac 
12190c37af3bSToby Isaac #undef __FUNCT__
1220f7c74593SToby Isaac #define __FUNCT__ "DMPlexComputeAnchorMatrix_Tree_Direct"
1221f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
12220c37af3bSToby Isaac {
12230c37af3bSToby Isaac   PetscDS        ds;
12240c37af3bSToby Isaac   PetscInt       spdim;
12250c37af3bSToby Isaac   PetscInt       numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
12260c37af3bSToby Isaac   const PetscInt *anchors;
1227f7c74593SToby Isaac   PetscSection   aSec;
12280c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
12290c37af3bSToby Isaac   IS             aIS;
12300c37af3bSToby Isaac   PetscErrorCode ierr;
12310c37af3bSToby Isaac 
12320c37af3bSToby Isaac   PetscFunctionBegin;
12330c37af3bSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
12340c37af3bSToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
12350c37af3bSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
12360c37af3bSToby Isaac   ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
1237a17985deSToby Isaac   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
12380c37af3bSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
12390c37af3bSToby Isaac   ierr = PetscSectionGetChart(cSec,&conStart,&conEnd);CHKERRQ(ierr);
124028f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&spdim);CHKERRQ(ierr);
12410c37af3bSToby Isaac   ierr = PetscMalloc6(spdim,&v0,spdim,&v0parent,spdim,&vtmp,spdim*spdim,&J,spdim*spdim,&Jparent,spdim*spdim,&invJparent);CHKERRQ(ierr);
12420c37af3bSToby Isaac 
12430c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
12440dd1b1feSToby Isaac     PetscObject disc;
12450dd1b1feSToby Isaac     PetscFE fe = NULL;
12460dd1b1feSToby Isaac     PetscFV fv = NULL;
12470dd1b1feSToby Isaac     PetscClassId id;
12480c37af3bSToby Isaac     PetscDualSpace space;
12490c37af3bSToby Isaac     PetscInt i, j, k, nPoints, offset;
12500c37af3bSToby Isaac     PetscInt fSize, fComp;
1251c111c6b7SMatthew G. Knepley     PetscReal *B = NULL;
12520c37af3bSToby Isaac     PetscReal *weights, *pointsRef, *pointsReal;
12530c37af3bSToby Isaac     Mat Amat, Bmat, Xmat;
12540c37af3bSToby Isaac 
12550dd1b1feSToby Isaac     ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
12560dd1b1feSToby Isaac     ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
12570dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
12580dd1b1feSToby Isaac       fe = (PetscFE) disc;
12590c37af3bSToby Isaac       ierr = PetscFEGetDualSpace(fe,&space);CHKERRQ(ierr);
12600c37af3bSToby Isaac       ierr = PetscDualSpaceGetDimension(space,&fSize);CHKERRQ(ierr);
12610c37af3bSToby Isaac       ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr);
12620dd1b1feSToby Isaac     }
12630dd1b1feSToby Isaac     else if (id == PETSCFV_CLASSID) {
12640dd1b1feSToby Isaac       fv = (PetscFV) disc;
12650dd1b1feSToby Isaac       ierr = PetscFVGetDualSpace(fv,&space);CHKERRQ(ierr);
12660dd1b1feSToby Isaac       ierr = PetscDualSpaceGetDimension(space,&fSize);CHKERRQ(ierr);
12670dd1b1feSToby Isaac       ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr);
12680dd1b1feSToby Isaac     }
12690dd1b1feSToby Isaac     else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
12700dd1b1feSToby Isaac 
12710c37af3bSToby Isaac     ierr = MatCreate(PETSC_COMM_SELF,&Amat);CHKERRQ(ierr);
12720c37af3bSToby Isaac     ierr = MatSetSizes(Amat,fSize,fSize,fSize,fSize);CHKERRQ(ierr);
12730c37af3bSToby Isaac     ierr = MatSetType(Amat,MATSEQDENSE);CHKERRQ(ierr);
12740c37af3bSToby Isaac     ierr = MatSetUp(Amat);CHKERRQ(ierr);
12750c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Bmat);CHKERRQ(ierr);
12760c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Xmat);CHKERRQ(ierr);
12770c37af3bSToby Isaac     nPoints = 0;
12780c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12790c37af3bSToby Isaac       PetscInt        qPoints;
12800c37af3bSToby Isaac       PetscQuadrature quad;
12810c37af3bSToby Isaac 
12820c37af3bSToby Isaac       ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr);
12830c37af3bSToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,&qPoints,NULL,NULL);CHKERRQ(ierr);
12840c37af3bSToby Isaac       nPoints += qPoints;
12850c37af3bSToby Isaac     }
12860c37af3bSToby Isaac     ierr = PetscMalloc3(nPoints,&weights,spdim*nPoints,&pointsRef,spdim*nPoints,&pointsReal);CHKERRQ(ierr);
12870c37af3bSToby Isaac     offset = 0;
12880c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12890c37af3bSToby Isaac       PetscInt        qPoints;
12900c37af3bSToby Isaac       const PetscReal    *p, *w;
12910c37af3bSToby Isaac       PetscQuadrature quad;
12920c37af3bSToby Isaac 
12930c37af3bSToby Isaac       ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr);
12940c37af3bSToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,&qPoints,&p,&w);CHKERRQ(ierr);
12950c37af3bSToby Isaac       ierr = PetscMemcpy(weights+offset,w,qPoints*sizeof(*w));CHKERRQ(ierr);
12960c37af3bSToby Isaac       ierr = PetscMemcpy(pointsRef+spdim*offset,p,spdim*qPoints*sizeof(*p));CHKERRQ(ierr);
12970c37af3bSToby Isaac       offset += qPoints;
12980c37af3bSToby Isaac     }
12990dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
13000c37af3bSToby Isaac       ierr = PetscFEGetTabulation(fe,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr);
13010dd1b1feSToby Isaac     }
13020dd1b1feSToby Isaac     else {
13030dd1b1feSToby Isaac       ierr = PetscFVGetTabulation(fv,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr);
13040dd1b1feSToby Isaac     }
13050c37af3bSToby Isaac     offset = 0;
13060c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
13070c37af3bSToby Isaac       PetscInt        qPoints;
13080c37af3bSToby Isaac       PetscQuadrature quad;
13090c37af3bSToby Isaac 
13100c37af3bSToby Isaac       ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr);
13110c37af3bSToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,&qPoints,NULL,NULL);CHKERRQ(ierr);
13120c37af3bSToby Isaac       for (j = 0; j < fSize; j++) {
13130c37af3bSToby Isaac         PetscScalar val = 0.;
13140c37af3bSToby Isaac 
13150c37af3bSToby Isaac         for (k = 0; k < qPoints; k++) {
13160c37af3bSToby Isaac           val += B[((offset + k) * fSize + j) * fComp] * weights[k];
13170c37af3bSToby Isaac         }
13180c37af3bSToby Isaac         ierr = MatSetValue(Amat,i,j,val,INSERT_VALUES);CHKERRQ(ierr);
13190c37af3bSToby Isaac       }
13200c37af3bSToby Isaac       offset += qPoints;
13210c37af3bSToby Isaac     }
13220dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
13230c37af3bSToby Isaac       ierr = PetscFERestoreTabulation(fe,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr);
13240dd1b1feSToby Isaac     }
13250dd1b1feSToby Isaac     else {
13260dd1b1feSToby Isaac       ierr = PetscFVRestoreTabulation(fv,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr);
13270dd1b1feSToby Isaac     }
13280c37af3bSToby Isaac     ierr = MatAssemblyBegin(Amat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
13290c37af3bSToby Isaac     ierr = MatAssemblyEnd(Amat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
13300c37af3bSToby Isaac     ierr = MatLUFactor(Amat,NULL,NULL,NULL);CHKERRQ(ierr);
13310c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
13320c37af3bSToby Isaac       PetscInt parent;
13330c37af3bSToby Isaac       PetscInt closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
13340c37af3bSToby Isaac       PetscInt *childOffsets, *parentOffsets;
13350c37af3bSToby Isaac 
13360c37af3bSToby Isaac       ierr = DMPlexGetTreeParent(dm,c,&parent,NULL);CHKERRQ(ierr);
13370c37af3bSToby Isaac       if (parent == c) continue;
13380c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13390c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13400c37af3bSToby Isaac         PetscInt p = closure[2*i];
13410c37af3bSToby Isaac         PetscInt conDof;
13420c37af3bSToby Isaac 
13430c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
13440c37af3bSToby Isaac         if (numFields > 1) {
13450c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
13460c37af3bSToby Isaac         }
13470c37af3bSToby Isaac         else {
13480c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
13490c37af3bSToby Isaac         }
13500c37af3bSToby Isaac         if (conDof) break;
13510c37af3bSToby Isaac       }
13520c37af3bSToby Isaac       if (i == closureSize) {
13530c37af3bSToby Isaac         ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13540c37af3bSToby Isaac         continue;
13550c37af3bSToby Isaac       }
13560c37af3bSToby Isaac 
135773a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
135873a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent);CHKERRQ(ierr);
13590c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
13600c37af3bSToby Isaac         CoordinatesRefToReal(spdim, spdim, v0, J, &pointsRef[i*spdim],vtmp);CHKERRQ(ierr);
13610c37af3bSToby Isaac         CoordinatesRealToRef(spdim, spdim, v0parent, invJparent, vtmp, &pointsReal[i*spdim]);CHKERRQ(ierr);
13620c37af3bSToby Isaac       }
13630dd1b1feSToby Isaac       if (id == PETSCFE_CLASSID) {
13640c37af3bSToby Isaac         ierr = PetscFEGetTabulation(fe,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr);
13650dd1b1feSToby Isaac       }
13660dd1b1feSToby Isaac       else {
13670dd1b1feSToby Isaac         ierr = PetscFVGetTabulation(fv,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr);
13680dd1b1feSToby Isaac       }
13690c37af3bSToby Isaac       offset = 0;
13700c37af3bSToby Isaac       for (i = 0; i < fSize; i++) {
13710c37af3bSToby Isaac         PetscInt        qPoints;
13720c37af3bSToby Isaac         PetscQuadrature quad;
13730c37af3bSToby Isaac 
13740c37af3bSToby Isaac         ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr);
13750c37af3bSToby Isaac         ierr = PetscQuadratureGetData(quad,NULL,&qPoints,NULL,NULL);CHKERRQ(ierr);
13760c37af3bSToby Isaac         for (j = 0; j < fSize; j++) {
13770c37af3bSToby Isaac           PetscScalar val = 0.;
13780c37af3bSToby Isaac 
13790c37af3bSToby Isaac           for (k = 0; k < qPoints; k++) {
13800c37af3bSToby Isaac             val += B[((offset + k) * fSize + j) * fComp] * weights[k];
13810c37af3bSToby Isaac           }
13820c37af3bSToby Isaac           MatSetValue(Bmat,i,j,val,INSERT_VALUES);CHKERRQ(ierr);
13830c37af3bSToby Isaac         }
13840c37af3bSToby Isaac         offset += qPoints;
13850c37af3bSToby Isaac       }
13860dd1b1feSToby Isaac       if (id == PETSCFE_CLASSID) {
13870c37af3bSToby Isaac         ierr = PetscFERestoreTabulation(fe,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr);
13880dd1b1feSToby Isaac       }
13890dd1b1feSToby Isaac       else {
13900dd1b1feSToby Isaac         ierr = PetscFVRestoreTabulation(fv,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr);
13910dd1b1feSToby Isaac       }
13920c37af3bSToby Isaac       ierr = MatAssemblyBegin(Bmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
13930c37af3bSToby Isaac       ierr = MatAssemblyEnd(Bmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
13940c37af3bSToby Isaac       ierr = MatMatSolve(Amat,Bmat,Xmat);CHKERRQ(ierr);
13950c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
13960c37af3bSToby Isaac       ierr = PetscMalloc2(closureSize+1,&childOffsets,closureSizeP+1,&parentOffsets);CHKERRQ(ierr);
13970c37af3bSToby Isaac       childOffsets[0] = 0;
13980c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13990c37af3bSToby Isaac         PetscInt p = closure[2*i];
14000c37af3bSToby Isaac         PetscInt dof;
14010c37af3bSToby Isaac 
14020c37af3bSToby Isaac         if (numFields > 1) {
14030c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
14040c37af3bSToby Isaac         }
14050c37af3bSToby Isaac         else {
14060c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
14070c37af3bSToby Isaac         }
14080c37af3bSToby Isaac         childOffsets[i+1]=childOffsets[i]+dof / fComp;
14090c37af3bSToby Isaac       }
14100c37af3bSToby Isaac       parentOffsets[0] = 0;
14110c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
14120c37af3bSToby Isaac         PetscInt p = closureP[2*i];
14130c37af3bSToby Isaac         PetscInt dof;
14140c37af3bSToby Isaac 
14150c37af3bSToby Isaac         if (numFields > 1) {
14160c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
14170c37af3bSToby Isaac         }
14180c37af3bSToby Isaac         else {
14190c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
14200c37af3bSToby Isaac         }
14210c37af3bSToby Isaac         parentOffsets[i+1]=parentOffsets[i]+dof / fComp;
14220c37af3bSToby Isaac       }
14230c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
14240c37af3bSToby Isaac         PetscInt conDof, conOff, aDof, aOff;
14250c37af3bSToby Isaac         PetscInt p = closure[2*i];
14260c37af3bSToby Isaac         PetscInt o = closure[2*i+1];
14270c37af3bSToby Isaac 
14280c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
14290c37af3bSToby Isaac         if (numFields > 1) {
14300c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
14310c37af3bSToby Isaac           ierr = PetscSectionGetFieldOffset(cSec,p,f,&conOff);CHKERRQ(ierr);
14320c37af3bSToby Isaac         }
14330c37af3bSToby Isaac         else {
14340c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
14350c37af3bSToby Isaac           ierr = PetscSectionGetOffset(cSec,p,&conOff);CHKERRQ(ierr);
14360c37af3bSToby Isaac         }
14370c37af3bSToby Isaac         if (!conDof) continue;
14380c37af3bSToby Isaac         ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
14390c37af3bSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
14400c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
14410c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
14420c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
14430c37af3bSToby Isaac 
14440c37af3bSToby Isaac           if (numFields > 1) {
14450c37af3bSToby Isaac             ierr = PetscSectionGetFieldDof(section,a,f,&aSecDof);CHKERRQ(ierr);
14460c37af3bSToby Isaac             ierr = PetscSectionGetFieldOffset(section,a,f,&aSecOff);CHKERRQ(ierr);
14470c37af3bSToby Isaac           }
14480c37af3bSToby Isaac           else {
14490c37af3bSToby Isaac             ierr = PetscSectionGetDof(section,a,&aSecDof);CHKERRQ(ierr);
14500c37af3bSToby Isaac             ierr = PetscSectionGetOffset(section,a,&aSecOff);CHKERRQ(ierr);
14510c37af3bSToby Isaac           }
14520c37af3bSToby Isaac           if (!aSecDof) continue;
14530c37af3bSToby Isaac 
14540c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
14550c37af3bSToby Isaac             PetscInt q = closureP[2*j];
14560c37af3bSToby Isaac             PetscInt oq = closureP[2*j+1];
14570c37af3bSToby Isaac 
14580c37af3bSToby Isaac             if (q == a) {
14590c37af3bSToby Isaac               PetscInt r, s, t;
14600c37af3bSToby Isaac 
14610c37af3bSToby Isaac               for (r = childOffsets[i]; r < childOffsets[i+1]; r++) {
14620c37af3bSToby Isaac                 for (s = parentOffsets[j]; s < parentOffsets[j+1]; s++) {
14630c37af3bSToby Isaac                   PetscScalar val;
14640c37af3bSToby Isaac                   PetscInt insertCol, insertRow;
14650c37af3bSToby Isaac 
14660c37af3bSToby Isaac                   ierr = MatGetValue(Xmat,r,s,&val);CHKERRQ(ierr);
14670c37af3bSToby Isaac                   if (o >= 0) {
14680c37af3bSToby Isaac                     insertRow = conOff + fComp * (r - childOffsets[i]);
14690c37af3bSToby Isaac                   }
14700c37af3bSToby Isaac                   else {
14710c37af3bSToby Isaac                     insertRow = conOff + fComp * (childOffsets[i + 1] - 1 - r);
14720c37af3bSToby Isaac                   }
14730c37af3bSToby Isaac                   if (oq >= 0) {
14740c37af3bSToby Isaac                     insertCol = aSecOff + fComp * (s - parentOffsets[j]);
14750c37af3bSToby Isaac                   }
14760c37af3bSToby Isaac                   else {
14770c37af3bSToby Isaac                     insertCol = aSecOff + fComp * (parentOffsets[j + 1] - 1 - s);
14780c37af3bSToby Isaac                   }
14790c37af3bSToby Isaac                   for (t = 0; t < fComp; t++) {
14800c37af3bSToby Isaac                     ierr = MatSetValue(cMat,insertRow + t,insertCol + t,val,INSERT_VALUES);CHKERRQ(ierr);
14810c37af3bSToby Isaac                   }
14820c37af3bSToby Isaac                 }
14830c37af3bSToby Isaac               }
14840c37af3bSToby Isaac             }
14850c37af3bSToby Isaac           }
14860c37af3bSToby Isaac         }
14870c37af3bSToby Isaac       }
14880c37af3bSToby Isaac       ierr = PetscFree2(childOffsets,parentOffsets);CHKERRQ(ierr);
14890c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
14900c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
14910c37af3bSToby Isaac     }
14920c37af3bSToby Isaac     ierr = MatDestroy(&Amat);CHKERRQ(ierr);
14930c37af3bSToby Isaac     ierr = MatDestroy(&Bmat);CHKERRQ(ierr);
14940c37af3bSToby Isaac     ierr = MatDestroy(&Xmat);CHKERRQ(ierr);
14950c37af3bSToby Isaac     ierr = PetscFree3(weights,pointsRef,pointsReal);CHKERRQ(ierr);
14960c37af3bSToby Isaac   }
14970c37af3bSToby Isaac   ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14980c37af3bSToby Isaac   ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14990c37af3bSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJparent);CHKERRQ(ierr);
15000c37af3bSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
15010c37af3bSToby Isaac 
15020c37af3bSToby Isaac   PetscFunctionReturn(0);
15030c37af3bSToby Isaac }
150495a0b26dSToby Isaac 
150595a0b26dSToby Isaac #undef __FUNCT__
150621968bf8SToby Isaac #define __FUNCT__ "DMPlexReferenceTreeGetChildrenMatrices"
150721968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
150895a0b26dSToby Isaac {
1509f7c74593SToby Isaac   Mat            refCmat;
151021968bf8SToby Isaac   PetscDS        ds;
151121968bf8SToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
151221968bf8SToby Isaac   PetscScalar    ***refPointFieldMats;
151321968bf8SToby Isaac   PetscSection   refConSec, refAnSec, refSection;
151421968bf8SToby Isaac   IS             refAnIS;
151521968bf8SToby Isaac   const PetscInt *refAnchors;
151695a0b26dSToby Isaac   PetscErrorCode ierr;
151795a0b26dSToby Isaac 
151895a0b26dSToby Isaac   PetscFunctionBegin;
151921968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
152095a0b26dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1521f7c74593SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
1522a17985deSToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
152395a0b26dSToby Isaac   ierr = ISGetIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
152495a0b26dSToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
152595a0b26dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
152695a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
152795a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldN);CHKERRQ(ierr);
152895a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
152995a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
153095a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
153195a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof*maxAnDof,&cols);CHKERRQ(ierr);
153295a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
153395a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
153495a0b26dSToby Isaac 
153595a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
153695a0b26dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
153795a0b26dSToby Isaac     if (!pDof || parent == p) continue;
153895a0b26dSToby Isaac 
153995a0b26dSToby Isaac     ierr = PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
154095a0b26dSToby Isaac     ierr = PetscCalloc1(numFields,&refPointFieldN[p-pRefStart]);CHKERRQ(ierr);
154195a0b26dSToby Isaac     ierr = DMPlexGetTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
154295a0b26dSToby Isaac     for (f = 0; f < numFields; f++) {
154395a0b26dSToby Isaac       PetscInt cDof, cOff, numCols, r, i, fComp;
15440dd1b1feSToby Isaac       PetscObject disc;
15450dd1b1feSToby Isaac       PetscClassId id;
15460dd1b1feSToby Isaac       PetscFE fe = NULL;
15470dd1b1feSToby Isaac       PetscFV fv = NULL;
154895a0b26dSToby Isaac 
15490dd1b1feSToby Isaac       ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
15500dd1b1feSToby Isaac       ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
15510dd1b1feSToby Isaac       if (id == PETSCFE_CLASSID) {
15520dd1b1feSToby Isaac         fe = (PetscFE) disc;
155395a0b26dSToby Isaac         ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr);
15540dd1b1feSToby Isaac       }
15550dd1b1feSToby Isaac       else if (id == PETSCFV_CLASSID) {
15560dd1b1feSToby Isaac         fv = (PetscFV) disc;
15570dd1b1feSToby Isaac         ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr);
15580dd1b1feSToby Isaac       }
15590dd1b1feSToby Isaac       else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
156095a0b26dSToby Isaac 
156195a0b26dSToby Isaac       if (numFields > 1) {
156295a0b26dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
156395a0b26dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
156495a0b26dSToby Isaac       }
156595a0b26dSToby Isaac       else {
156695a0b26dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
156795a0b26dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
156895a0b26dSToby Isaac       }
156995a0b26dSToby Isaac 
157095a0b26dSToby Isaac       if (!cDof) continue;
157195a0b26dSToby Isaac       for (r = 0; r < cDof; r++) {
157295a0b26dSToby Isaac         rows[r] = cOff + r;
157395a0b26dSToby Isaac       }
157495a0b26dSToby Isaac       numCols = 0;
157595a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
157695a0b26dSToby Isaac         PetscInt q = closure[2*i];
157795a0b26dSToby Isaac         PetscInt o = closure[2*i+1];
157895a0b26dSToby Isaac         PetscInt aDof, aOff, j;
157995a0b26dSToby Isaac 
158095a0b26dSToby Isaac         if (numFields > 1) {
158195a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
158295a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
158395a0b26dSToby Isaac         }
158495a0b26dSToby Isaac         else {
158595a0b26dSToby Isaac           ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
158695a0b26dSToby Isaac           ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
158795a0b26dSToby Isaac         }
158895a0b26dSToby Isaac 
158995a0b26dSToby Isaac         for (j = 0; j < aDof; j++) {
159095a0b26dSToby Isaac           PetscInt node = (o >= 0) ? (j / fComp) : ((aDof - 1 - j) / fComp);
159195a0b26dSToby Isaac           PetscInt comp = (j % fComp);
159295a0b26dSToby Isaac 
159395a0b26dSToby Isaac           cols[numCols++] = aOff + node * fComp + comp;
159495a0b26dSToby Isaac         }
159595a0b26dSToby Isaac       }
159695a0b26dSToby Isaac       refPointFieldN[p-pRefStart][f] = numCols;
159795a0b26dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
159895a0b26dSToby Isaac       ierr = MatGetValues(refCmat,cDof,rows,numCols,cols,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
159995a0b26dSToby Isaac     }
160095a0b26dSToby Isaac     ierr = DMPlexRestoreTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
160195a0b26dSToby Isaac   }
160221968bf8SToby Isaac   *childrenMats = refPointFieldMats;
160321968bf8SToby Isaac   *childrenN = refPointFieldN;
160421968bf8SToby Isaac   ierr = ISRestoreIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
160521968bf8SToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
160621968bf8SToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
160721968bf8SToby Isaac   PetscFunctionReturn(0);
160821968bf8SToby Isaac }
160921968bf8SToby Isaac 
161021968bf8SToby Isaac #undef __FUNCT__
161121968bf8SToby Isaac #define __FUNCT__ "DMPlexReferenceTreeRestoreChildrenMatrices"
161221968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
161321968bf8SToby Isaac {
161421968bf8SToby Isaac   PetscDS        ds;
161521968bf8SToby Isaac   PetscInt       **refPointFieldN;
161621968bf8SToby Isaac   PetscScalar    ***refPointFieldMats;
161721968bf8SToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
161821968bf8SToby Isaac   PetscSection   refConSec;
161921968bf8SToby Isaac   PetscErrorCode ierr;
162021968bf8SToby Isaac 
162121968bf8SToby Isaac   PetscFunctionBegin;
162221968bf8SToby Isaac   refPointFieldN = *childrenN;
162321968bf8SToby Isaac   *childrenN = NULL;
162421968bf8SToby Isaac   refPointFieldMats = *childrenMats;
162521968bf8SToby Isaac   *childrenMats = NULL;
162621968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
162721968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
162821968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
1629e44e4e7fSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
163021968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
163121968bf8SToby Isaac     PetscInt parent, pDof;
163221968bf8SToby Isaac 
163321968bf8SToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
163421968bf8SToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
163521968bf8SToby Isaac     if (!pDof || parent == p) continue;
163621968bf8SToby Isaac 
163721968bf8SToby Isaac     for (f = 0; f < numFields; f++) {
163821968bf8SToby Isaac       PetscInt cDof;
163921968bf8SToby Isaac 
164021968bf8SToby Isaac       if (numFields > 1) {
164121968bf8SToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
164221968bf8SToby Isaac       }
164321968bf8SToby Isaac       else {
164421968bf8SToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
164521968bf8SToby Isaac       }
164621968bf8SToby Isaac 
164721968bf8SToby Isaac       if (!cDof) continue;
164821968bf8SToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
164921968bf8SToby Isaac     }
165021968bf8SToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
165121968bf8SToby Isaac     ierr = PetscFree(refPointFieldN[p - pRefStart]);CHKERRQ(ierr);
165221968bf8SToby Isaac   }
165321968bf8SToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
165421968bf8SToby Isaac   ierr = PetscFree(refPointFieldN);CHKERRQ(ierr);
165521968bf8SToby Isaac   PetscFunctionReturn(0);
165621968bf8SToby Isaac }
165721968bf8SToby Isaac 
165821968bf8SToby Isaac #undef __FUNCT__
165921968bf8SToby Isaac #define __FUNCT__ "DMPlexComputeAnchorMatrix_Tree_FromReference"
166021968bf8SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
166121968bf8SToby Isaac {
166221968bf8SToby Isaac   DM             refTree;
166321968bf8SToby Isaac   PetscDS        ds;
166421968bf8SToby Isaac   Mat            refCmat;
166521968bf8SToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
166621968bf8SToby Isaac   PetscScalar ***refPointFieldMats, *pointWork;
166721968bf8SToby Isaac   PetscSection   refConSec, refAnSec, anSec;
166821968bf8SToby Isaac   IS             refAnIS, anIS;
166921968bf8SToby Isaac   const PetscInt *anchors;
167021968bf8SToby Isaac   PetscErrorCode ierr;
167121968bf8SToby Isaac 
167221968bf8SToby Isaac   PetscFunctionBegin;
167321968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
167421968bf8SToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
167521968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
167621968bf8SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
167721968bf8SToby Isaac   ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
167821968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
167921968bf8SToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
168021968bf8SToby Isaac   ierr = DMPlexGetAnchors(dm,&anSec,&anIS);CHKERRQ(ierr);
168121968bf8SToby Isaac   ierr = ISGetIndices(anIS,&anchors);CHKERRQ(ierr);
168221968bf8SToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
168321968bf8SToby Isaac   ierr = PetscSectionGetChart(conSec,&conStart,&conEnd);CHKERRQ(ierr);
168421968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
168521968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
168621968bf8SToby Isaac   ierr = PetscMalloc1(maxDof*maxDof*maxAnDof,&pointWork);CHKERRQ(ierr);
168721968bf8SToby Isaac 
168821968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
168921968bf8SToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
169095a0b26dSToby Isaac 
169195a0b26dSToby Isaac   /* step 2: compute the preorder */
169295a0b26dSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
169395a0b26dSToby Isaac   ierr = PetscMalloc2(pEnd-pStart,&perm,pEnd-pStart,&iperm);CHKERRQ(ierr);
169495a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
169595a0b26dSToby Isaac     perm[p - pStart] = p;
169695a0b26dSToby Isaac     iperm[p - pStart] = p-pStart;
169795a0b26dSToby Isaac   }
169895a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
169995a0b26dSToby Isaac     PetscInt point = perm[p];
170095a0b26dSToby Isaac     PetscInt parent;
170195a0b26dSToby Isaac 
170295a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
170395a0b26dSToby Isaac     if (parent == point) {
170495a0b26dSToby Isaac       p++;
170595a0b26dSToby Isaac     }
170695a0b26dSToby Isaac     else {
170795a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
170895a0b26dSToby Isaac 
170995a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
171095a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
171195a0b26dSToby Isaac         PetscInt q = closure[2*i];
171295a0b26dSToby Isaac         if (iperm[q-pStart] > iperm[point-pStart]) {
171395a0b26dSToby Isaac           /* swap */
171495a0b26dSToby Isaac           perm[p]               = q;
171595a0b26dSToby Isaac           perm[iperm[q-pStart]] = point;
171695a0b26dSToby Isaac           iperm[point-pStart]   = iperm[q-pStart];
171795a0b26dSToby Isaac           iperm[q-pStart]       = p;
171895a0b26dSToby Isaac           break;
171995a0b26dSToby Isaac         }
172095a0b26dSToby Isaac       }
172195a0b26dSToby Isaac       size = closureSize;
172295a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
172395a0b26dSToby Isaac       if (i == size) {
172495a0b26dSToby Isaac         p++;
172595a0b26dSToby Isaac       }
172695a0b26dSToby Isaac     }
172795a0b26dSToby Isaac   }
172895a0b26dSToby Isaac 
172995a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
173095a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
173195a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
173295a0b26dSToby Isaac    * values outside of the Mat first.
173395a0b26dSToby Isaac    */
173495a0b26dSToby Isaac   {
173595a0b26dSToby Isaac     PetscInt nRows, row, nnz;
173695a0b26dSToby Isaac     PetscBool done;
173795a0b26dSToby Isaac     const PetscInt *ia, *ja;
173895a0b26dSToby Isaac     PetscScalar *vals;
173995a0b26dSToby Isaac 
174095a0b26dSToby Isaac     ierr = MatGetRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
174195a0b26dSToby Isaac     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not get RowIJ of constraint matrix");
174295a0b26dSToby Isaac     nnz  = ia[nRows];
174395a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
174495a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
174595a0b26dSToby Isaac     ierr = PetscMalloc1(nnz,&vals);CHKERRQ(ierr);
174695a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
174795a0b26dSToby Isaac       PetscInt parent, childid, closureSize, *closure = NULL;
174895a0b26dSToby Isaac       PetscInt point = perm[p], pointDof;
174995a0b26dSToby Isaac 
175095a0b26dSToby Isaac       ierr = DMPlexGetTreeParent(dm,point,&parent,&childid);CHKERRQ(ierr);
175195a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
175295a0b26dSToby Isaac       ierr = PetscSectionGetDof(conSec,point,&pointDof);CHKERRQ(ierr);
175395a0b26dSToby Isaac       if (!pointDof) continue;
175495a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
175595a0b26dSToby Isaac       for (f = 0; f < numFields; f++) {
17569fc93327SToby Isaac         PetscInt cDof, cOff, numCols, numFillCols, i, r, fComp = -1, matOffset, offset;
175795a0b26dSToby Isaac         PetscScalar *pointMat;
17580dd1b1feSToby Isaac         PetscObject disc;
17590dd1b1feSToby Isaac         PetscClassId id;
17600dd1b1feSToby Isaac         PetscFE fe = NULL;
17610dd1b1feSToby Isaac         PetscFV fv = NULL;
176295a0b26dSToby Isaac 
17630dd1b1feSToby Isaac         ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
17640dd1b1feSToby Isaac         ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
17650dd1b1feSToby Isaac         if (id == PETSCFE_CLASSID) {
17660dd1b1feSToby Isaac           fe = (PetscFE) disc;
176795a0b26dSToby Isaac           ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr);
17680dd1b1feSToby Isaac         }
17690dd1b1feSToby Isaac         else if (id == PETSCFV_CLASSID) {
17700dd1b1feSToby Isaac           fv = (PetscFV) disc;
17710dd1b1feSToby Isaac           ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr);
17720dd1b1feSToby Isaac         }
17739fc93327SToby Isaac         else {
17749fc93327SToby Isaac           SETERRQ(PetscObjectComm((PetscObject)disc),PETSC_ERR_SUP,"Unsupported discretization");
17759fc93327SToby Isaac         }
177695a0b26dSToby Isaac 
177795a0b26dSToby Isaac         if (numFields > 1) {
177895a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(conSec,point,f,&cDof);CHKERRQ(ierr);
177995a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(conSec,point,f,&cOff);CHKERRQ(ierr);
178095a0b26dSToby Isaac         }
178195a0b26dSToby Isaac         else {
178295a0b26dSToby Isaac           ierr = PetscSectionGetDof(conSec,point,&cDof);CHKERRQ(ierr);
178395a0b26dSToby Isaac           ierr = PetscSectionGetOffset(conSec,point,&cOff);CHKERRQ(ierr);
178495a0b26dSToby Isaac         }
178595a0b26dSToby Isaac         if (!cDof) continue;
178695a0b26dSToby Isaac 
178795a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
178895a0b26dSToby Isaac #if defined(PETSC_USE_DEBUG)
178995a0b26dSToby Isaac         for (r = 0; r < cDof; r++) {
179095a0b26dSToby Isaac           if (cDof > 1 && r) {
179121968bf8SToby Isaac             if ((ia[cOff+r+1]-ia[cOff+r]) != (ia[cOff+r]-ia[cOff+r-1])) SETERRQ2(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]));
179295a0b26dSToby Isaac           }
179395a0b26dSToby Isaac         }
179495a0b26dSToby Isaac #endif
179595a0b26dSToby Isaac         /* zero rows */
179695a0b26dSToby Isaac         for (i = ia[cOff] ; i< ia[cOff+cDof];i++) {
179795a0b26dSToby Isaac           vals[i] = 0.;
179895a0b26dSToby Isaac         }
179995a0b26dSToby Isaac         matOffset = ia[cOff];
180095a0b26dSToby Isaac         numFillCols = ia[cOff+1] - matOffset;
180195a0b26dSToby Isaac         pointMat = refPointFieldMats[childid-pRefStart][f];
180295a0b26dSToby Isaac         numCols = refPointFieldN[childid-pRefStart][f];
180395a0b26dSToby Isaac         offset = 0;
180495a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
180595a0b26dSToby Isaac           PetscInt q = closure[2*i];
180695a0b26dSToby Isaac           PetscInt o = closure[2*i+1];
180795a0b26dSToby Isaac           PetscInt aDof, aOff, j, k, qConDof, qConOff;
180895a0b26dSToby Isaac 
180995a0b26dSToby Isaac           qConDof = qConOff = 0;
181095a0b26dSToby Isaac           if (numFields > 1) {
181195a0b26dSToby Isaac             ierr = PetscSectionGetFieldDof(section,q,f,&aDof);CHKERRQ(ierr);
181295a0b26dSToby Isaac             ierr = PetscSectionGetFieldOffset(section,q,f,&aOff);CHKERRQ(ierr);
181395a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
181495a0b26dSToby Isaac               ierr = PetscSectionGetFieldDof(conSec,q,f,&qConDof);CHKERRQ(ierr);
181595a0b26dSToby Isaac               ierr = PetscSectionGetFieldOffset(conSec,q,f,&qConOff);CHKERRQ(ierr);
181695a0b26dSToby Isaac             }
181795a0b26dSToby Isaac           }
181895a0b26dSToby Isaac           else {
181995a0b26dSToby Isaac             ierr = PetscSectionGetDof(section,q,&aDof);CHKERRQ(ierr);
182095a0b26dSToby Isaac             ierr = PetscSectionGetOffset(section,q,&aOff);CHKERRQ(ierr);
182195a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
182295a0b26dSToby Isaac               ierr = PetscSectionGetDof(conSec,q,&qConDof);CHKERRQ(ierr);
182395a0b26dSToby Isaac               ierr = PetscSectionGetOffset(conSec,q,&qConOff);CHKERRQ(ierr);
182495a0b26dSToby Isaac             }
182595a0b26dSToby Isaac           }
182695a0b26dSToby Isaac           if (!aDof) continue;
182795a0b26dSToby Isaac           if (qConDof) {
182895a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
182995a0b26dSToby Isaac              * be filled, thanks to preordering */
183095a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
183195a0b26dSToby Isaac             PetscInt aMatOffset = ia[qConOff];
183295a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
183395a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
183495a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
183595a0b26dSToby Isaac                 PetscScalar inVal = 0;
183695a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
183795a0b26dSToby Isaac                   PetscInt node = (o >= 0) ? (k / fComp) : ((aDof - 1 - k) / fComp);
183895a0b26dSToby Isaac                   PetscInt comp = (k % fComp);
183995a0b26dSToby Isaac                   PetscInt col  = node * fComp + comp;
184095a0b26dSToby Isaac 
184195a0b26dSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j];
184295a0b26dSToby Isaac                 }
184395a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
184495a0b26dSToby Isaac               }
184595a0b26dSToby Isaac             }
184695a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
184795a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
184895a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
184995a0b26dSToby Isaac               for (;k < numFillCols; k++) {
185095a0b26dSToby Isaac                 if (ja[matOffset + k] == col) {
185195a0b26dSToby Isaac                   break;
185295a0b26dSToby Isaac                 }
185395a0b26dSToby Isaac               }
185495a0b26dSToby Isaac               if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, col);
185595a0b26dSToby Isaac               for (r = 0; r < cDof; r++) {
185695a0b26dSToby Isaac                 vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
185795a0b26dSToby Isaac               }
185895a0b26dSToby Isaac             }
185995a0b26dSToby Isaac           }
186095a0b26dSToby Isaac           else {
186195a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
186295a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
186395a0b26dSToby Isaac               if (ja[matOffset + k] == aOff) {
186495a0b26dSToby Isaac                 break;
186595a0b26dSToby Isaac               }
186695a0b26dSToby Isaac             }
186795a0b26dSToby Isaac             if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, aOff);
186895a0b26dSToby Isaac             for (j = 0; j < aDof; j++) {
186995a0b26dSToby Isaac               PetscInt node = (o >= 0) ? (j / fComp) : ((aDof - 1 - j) / fComp);
187095a0b26dSToby Isaac               PetscInt comp = (j % fComp);
187195a0b26dSToby Isaac               PetscInt col  = node * fComp + comp;
187295a0b26dSToby Isaac               for (r = 0; r < cDof; r++) {
187395a0b26dSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + col];
187495a0b26dSToby Isaac               }
187595a0b26dSToby Isaac             }
187695a0b26dSToby Isaac           }
187795a0b26dSToby Isaac           offset += aDof;
187895a0b26dSToby Isaac         }
187995a0b26dSToby Isaac       }
188095a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
188195a0b26dSToby Isaac     }
188295a0b26dSToby Isaac     for (row = 0; row < nRows; row++) {
188395a0b26dSToby Isaac       ierr = MatSetValues(cMat,1,&row,ia[row+1]-ia[row],&ja[ia[row]],&vals[ia[row]],INSERT_VALUES);CHKERRQ(ierr);
188495a0b26dSToby Isaac     }
188595a0b26dSToby Isaac     ierr = MatRestoreRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
188695a0b26dSToby Isaac     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not restore RowIJ of constraint matrix");
188795a0b26dSToby Isaac     ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
188895a0b26dSToby Isaac     ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
188995a0b26dSToby Isaac     ierr = PetscFree(vals);CHKERRQ(ierr);
189095a0b26dSToby Isaac   }
189195a0b26dSToby Isaac 
189295a0b26dSToby Isaac   /* clean up */
189395a0b26dSToby Isaac   ierr = ISRestoreIndices(anIS,&anchors);CHKERRQ(ierr);
189495a0b26dSToby Isaac   ierr = PetscFree2(perm,iperm);CHKERRQ(ierr);
189595a0b26dSToby Isaac   ierr = PetscFree(pointWork);CHKERRQ(ierr);
189621968bf8SToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
189795a0b26dSToby Isaac   PetscFunctionReturn(0);
189895a0b26dSToby Isaac }
189995a0b26dSToby Isaac 
19006f5f1567SToby Isaac #undef __FUNCT__
19016f5f1567SToby Isaac #define __FUNCT__ "DMPlexTreeRefineCell"
19026f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
19036f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
19046f5f1567SToby Isaac PetscErrorCode DMPlexTreeRefineCell (DM dm, PetscInt cell, DM *ncdm)
19056f5f1567SToby Isaac {
19066f5f1567SToby Isaac   DM K;
1907420f55faSMatthew G. Knepley   PetscMPIInt rank;
19086f5f1567SToby Isaac   PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
19096f5f1567SToby Isaac   PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations;
19106f5f1567SToby Isaac   PetscInt *Kembedding;
19116f5f1567SToby Isaac   PetscInt *cellClosure=NULL, nc;
19126f5f1567SToby Isaac   PetscScalar *newVertexCoords;
19136f5f1567SToby Isaac   PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
19146f5f1567SToby Isaac   PetscSection parentSection;
19156f5f1567SToby Isaac   PetscErrorCode ierr;
19166f5f1567SToby Isaac 
19176f5f1567SToby Isaac   PetscFunctionBegin;
19186f5f1567SToby Isaac   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRQ(ierr);
191928f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
19206f5f1567SToby Isaac   ierr = DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm);CHKERRQ(ierr);
192128f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ncdm,dim);CHKERRQ(ierr);
19226f5f1567SToby Isaac 
19236f5f1567SToby Isaac   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
19246f5f1567SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&parentSection);CHKERRQ(ierr);
19256f5f1567SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&K);CHKERRQ(ierr);
19266f5f1567SToby Isaac   if (!rank) {
19276f5f1567SToby Isaac     /* compute the new charts */
19286f5f1567SToby Isaac     ierr = PetscMalloc5(dim+1,&pNewCount,dim+1,&pNewStart,dim+1,&pNewEnd,dim+1,&pOldStart,dim+1,&pOldEnd);CHKERRQ(ierr);
19296f5f1567SToby Isaac     offset = 0;
19306f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19316f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
19326f5f1567SToby Isaac 
19336f5f1567SToby Isaac       pNewStart[d] = offset;
19346f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(dm,d,&pOldStart[d],&pOldEnd[d]);CHKERRQ(ierr);
19356f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
19366f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
19376f5f1567SToby Isaac       /* adding the new points */
19386f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
19396f5f1567SToby Isaac       if (!d) {
19406f5f1567SToby Isaac         /* removing the cell */
19416f5f1567SToby Isaac         pNewCount[d]--;
19426f5f1567SToby Isaac       }
19436f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19446f5f1567SToby Isaac         PetscInt parent;
19456f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&parent,NULL);CHKERRQ(ierr);
19466f5f1567SToby Isaac         if (parent == k) {
19476f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
19486f5f1567SToby Isaac           pNewCount[d]--;
19496f5f1567SToby Isaac         }
19506f5f1567SToby Isaac       }
19516f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
19526f5f1567SToby Isaac       offset = pNewEnd[d];
19536f5f1567SToby Isaac 
19546f5f1567SToby Isaac     }
19556f5f1567SToby Isaac     if (cell < pOldStart[0] || cell >= pOldEnd[0]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"%d not in cell range [%d, %d)", cell, pOldStart[0], pOldEnd[0]);
19566f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
19576f5f1567SToby Isaac     ierr = DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
19586f5f1567SToby Isaac 
19596f5f1567SToby Isaac     ierr = PetscMalloc1(pNewEnd[dim],&newConeSizes);CHKERRQ(ierr);
19606f5f1567SToby Isaac     {
19616f5f1567SToby Isaac       PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
19626f5f1567SToby Isaac 
19636f5f1567SToby Isaac       ierr = DMPlexGetChart(K,&kStart,&kEnd);CHKERRQ(ierr);
19646f5f1567SToby Isaac       ierr = PetscMalloc4(kEnd-kStart,&Kembedding,kEnd-kStart,&perm,kEnd-kStart,&iperm,kEnd-kStart,&preOrient);CHKERRQ(ierr);
19656f5f1567SToby Isaac 
19666f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19676f5f1567SToby Isaac         perm[k - kStart] = k;
19686f5f1567SToby Isaac         iperm [k - kStart] = k - kStart;
19696f5f1567SToby Isaac         preOrient[k - kStart] = 0;
19706f5f1567SToby Isaac       }
19716f5f1567SToby Isaac 
19726f5f1567SToby Isaac       ierr = DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
19736f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
19746f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2*j+1];
19756f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2*j+1];
19766f5f1567SToby Isaac         PetscInt p, q;
19776f5f1567SToby Isaac 
19786f5f1567SToby Isaac         p = closureK[2*j];
19796f5f1567SToby Isaac         q = cellClosure[2*j];
19806f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
19816f5f1567SToby Isaac           if (q >= pOldStart[d] && q < pOldEnd[d]) {
19826f5f1567SToby Isaac             Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
19836f5f1567SToby Isaac           }
19846f5f1567SToby Isaac         }
19856f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
19866f5f1567SToby Isaac           PetscInt numChildren, i;
19876f5f1567SToby Isaac           const PetscInt *children;
19886f5f1567SToby Isaac 
19896f5f1567SToby Isaac           ierr = DMPlexGetTreeChildren(K,p,&numChildren,&children);CHKERRQ(ierr);
19906f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
19916f5f1567SToby Isaac             PetscInt kPerm, oPerm;
19926f5f1567SToby Isaac 
19936f5f1567SToby Isaac             k    = children[i];
19946f5f1567SToby Isaac             ierr = DMPlexReferenceTreeGetChildSymmetry(K,p,parentOrientA,0,k,parentOrientB,&oPerm,&kPerm);CHKERRQ(ierr);
19956f5f1567SToby Isaac             /* perm = what refTree position I'm in */
19966f5f1567SToby Isaac             perm[kPerm-kStart]      = k;
19976f5f1567SToby Isaac             /* iperm = who is at this position */
19986f5f1567SToby Isaac             iperm[k-kStart]         = kPerm-kStart;
19996f5f1567SToby Isaac             preOrient[kPerm-kStart] = oPerm;
20006f5f1567SToby Isaac           }
20016f5f1567SToby Isaac         }
20026f5f1567SToby Isaac       }
20036f5f1567SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
20046f5f1567SToby Isaac     }
20056f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,0,pNewEnd[dim]);CHKERRQ(ierr);
20066f5f1567SToby Isaac     offset = 0;
20076f5f1567SToby Isaac     numNewCones = 0;
20086f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20096f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
20106f5f1567SToby Isaac       PetscInt p;
20116f5f1567SToby Isaac       PetscInt size;
20126f5f1567SToby Isaac 
20136f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
20146f5f1567SToby Isaac         /* skip cell 0 */
20156f5f1567SToby Isaac         if (p == cell) continue;
20166f5f1567SToby Isaac         /* old cones to new cones */
20176f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
20186f5f1567SToby Isaac         newConeSizes[offset++] = size;
20196f5f1567SToby Isaac         numNewCones += size;
20206f5f1567SToby Isaac       }
20216f5f1567SToby Isaac 
20226f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
20236f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20246f5f1567SToby Isaac         PetscInt kParent;
20256f5f1567SToby Isaac 
20266f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
20276f5f1567SToby Isaac         if (kParent != k) {
20286f5f1567SToby Isaac           Kembedding[k] = offset;
20296f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
20306f5f1567SToby Isaac           newConeSizes[offset++] = size;
20316f5f1567SToby Isaac           numNewCones += size;
20326f5f1567SToby Isaac           if (kParent != 0) {
20336f5f1567SToby Isaac             ierr = PetscSectionSetDof(parentSection,Kembedding[k],1);CHKERRQ(ierr);
20346f5f1567SToby Isaac           }
20356f5f1567SToby Isaac         }
20366f5f1567SToby Isaac       }
20376f5f1567SToby Isaac     }
20386f5f1567SToby Isaac 
20396f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
20406f5f1567SToby Isaac     ierr = PetscSectionGetStorageSize(parentSection,&numPointsWithParents);CHKERRQ(ierr);
20416f5f1567SToby Isaac     ierr = PetscMalloc2(numNewCones,&newCones,numNewCones,&newOrientations);CHKERRQ(ierr);
20426f5f1567SToby Isaac     ierr = PetscMalloc2(numPointsWithParents,&parents,numPointsWithParents,&childIDs);CHKERRQ(ierr);
20436f5f1567SToby Isaac 
20446f5f1567SToby Isaac     /* fill new cones */
20456f5f1567SToby Isaac     offset = 0;
20466f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20476f5f1567SToby Isaac       PetscInt kStart, kEnd, k, l;
20486f5f1567SToby Isaac       PetscInt p;
20496f5f1567SToby Isaac       PetscInt size;
20506f5f1567SToby Isaac       const PetscInt *cone, *orientation;
20516f5f1567SToby Isaac 
20526f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
20536f5f1567SToby Isaac         /* skip cell 0 */
20546f5f1567SToby Isaac         if (p == cell) continue;
20556f5f1567SToby Isaac         /* old cones to new cones */
20566f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
20576f5f1567SToby Isaac         ierr = DMPlexGetCone(dm,p,&cone);CHKERRQ(ierr);
20586f5f1567SToby Isaac         ierr = DMPlexGetConeOrientation(dm,p,&orientation);CHKERRQ(ierr);
20596f5f1567SToby Isaac         for (l = 0; l < size; l++) {
20606f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
20616f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
20626f5f1567SToby Isaac         }
20636f5f1567SToby Isaac       }
20646f5f1567SToby Isaac 
20656f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
20666f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20676f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
20686f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
20696f5f1567SToby Isaac 
20706f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
20716f5f1567SToby Isaac         if (kParent != k) {
20726f5f1567SToby Isaac           /* embed new cones */
20736f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
20746f5f1567SToby Isaac           ierr = DMPlexGetCone(K,kPerm,&cone);CHKERRQ(ierr);
20756f5f1567SToby Isaac           ierr = DMPlexGetConeOrientation(K,kPerm,&orientation);CHKERRQ(ierr);
20766f5f1567SToby Isaac           for (l = 0; l < size; l++) {
20776f5f1567SToby Isaac             PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size -(preO + 1) - l) % size);
20786f5f1567SToby Isaac             PetscInt newO, lSize, oTrue;
20796f5f1567SToby Isaac 
20806f5f1567SToby Isaac             q                         = iperm[cone[m]];
20816f5f1567SToby Isaac             newCones[offset]          = Kembedding[q];
20826f5f1567SToby Isaac             ierr                      = DMPlexGetConeSize(K,q,&lSize);CHKERRQ(ierr);
20836f5f1567SToby Isaac             oTrue                     = orientation[m];
20846f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
20856f5f1567SToby Isaac             newO                      = DihedralCompose(lSize,oTrue,preOrient[q]);
20866f5f1567SToby Isaac             newOrientations[offset++] = newO;
20876f5f1567SToby Isaac           }
20886f5f1567SToby Isaac           if (kParent != 0) {
20896f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
20906f5f1567SToby Isaac             ierr              = PetscSectionGetOffset(parentSection,Kembedding[k],&pOffset);CHKERRQ(ierr);
20916f5f1567SToby Isaac             parents[pOffset]  = newPoint;
20926f5f1567SToby Isaac             childIDs[pOffset] = k;
20936f5f1567SToby Isaac           }
20946f5f1567SToby Isaac         }
20956f5f1567SToby Isaac       }
20966f5f1567SToby Isaac     }
20976f5f1567SToby Isaac 
20986f5f1567SToby Isaac     ierr = PetscMalloc1(dim*(pNewEnd[dim]-pNewStart[dim]),&newVertexCoords);CHKERRQ(ierr);
20996f5f1567SToby Isaac 
21006f5f1567SToby Isaac     /* fill coordinates */
21016f5f1567SToby Isaac     offset = 0;
21026f5f1567SToby Isaac     {
2103d90620a3SMatthew G. Knepley       PetscInt kStart, kEnd, l;
21046f5f1567SToby Isaac       PetscSection vSection;
21056f5f1567SToby Isaac       PetscInt v;
21066f5f1567SToby Isaac       Vec coords;
21076f5f1567SToby Isaac       PetscScalar *coordvals;
21086f5f1567SToby Isaac       PetscInt dof, off;
2109c111c6b7SMatthew G. Knepley       PetscReal v0[3], J[9], detJ;
21106f5f1567SToby Isaac 
21116f5f1567SToby Isaac #if defined(PETSC_USE_DEBUG)
2112d90620a3SMatthew G. Knepley       {
2113d90620a3SMatthew G. Knepley         PetscInt k;
21146f5f1567SToby Isaac         ierr = DMPlexGetHeightStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
21156f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
211673a7f2aaSMatthew G. Knepley           ierr = DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
21176f5f1567SToby Isaac           if (detJ <= 0.) SETERRQ1 (PETSC_COMM_SELF,PETSC_ERR_PLIB,"reference tree cell %d has bad determinant",k);
21186f5f1567SToby Isaac         }
2119d90620a3SMatthew G. Knepley       }
21206f5f1567SToby Isaac #endif
212173a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
21226f5f1567SToby Isaac       ierr = DMGetCoordinateSection(dm,&vSection);CHKERRQ(ierr);
21236f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr);
21246f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
21256f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
21266f5f1567SToby Isaac 
21276f5f1567SToby Isaac         ierr = PetscSectionGetDof(vSection,v,&dof);CHKERRQ(ierr);
21286f5f1567SToby Isaac         ierr = PetscSectionGetOffset(vSection,v,&off);CHKERRQ(ierr);
21296f5f1567SToby Isaac         for (l = 0; l < dof; l++) {
21306f5f1567SToby Isaac           newVertexCoords[offset++] = coordvals[off + l];
21316f5f1567SToby Isaac         }
21326f5f1567SToby Isaac       }
21336f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21346f5f1567SToby Isaac 
21356f5f1567SToby Isaac       ierr = DMGetCoordinateSection(K,&vSection);CHKERRQ(ierr);
21366f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(K,&coords);CHKERRQ(ierr);
21376f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
21386f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
21396f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
21409bc368c7SMatthew G. Knepley         PetscReal coord[3], newCoord[3];
21416f5f1567SToby Isaac         PetscInt  vPerm = perm[v];
21426f5f1567SToby Isaac         PetscInt  kParent;
21436f5f1567SToby Isaac 
21446f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,v,&kParent,NULL);CHKERRQ(ierr);
21456f5f1567SToby Isaac         if (kParent != v) {
21466f5f1567SToby Isaac           /* this is a new vertex */
21476f5f1567SToby Isaac           ierr = PetscSectionGetOffset(vSection,vPerm,&off);CHKERRQ(ierr);
21489bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off+l]);
21499bc368c7SMatthew G. Knepley           CoordinatesRefToReal(dim, dim, v0, J, coord, newCoord);CHKERRQ(ierr);
21509bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset+l] = newCoord[l];
21516f5f1567SToby Isaac           offset += dim;
21526f5f1567SToby Isaac         }
21536f5f1567SToby Isaac       }
21546f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21556f5f1567SToby Isaac     }
21566f5f1567SToby Isaac 
21576f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
21586f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
21596f5f1567SToby Isaac       PetscInt tmp;
21606f5f1567SToby Isaac 
21616f5f1567SToby Isaac       tmp = pNewCount[d];
21626f5f1567SToby Isaac       pNewCount[d] = pNewCount[dim - d];
21636f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
21646f5f1567SToby Isaac     }
21656f5f1567SToby Isaac 
21666f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,pNewCount,newConeSizes,newCones,newOrientations,newVertexCoords);CHKERRQ(ierr);
21676f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
21686f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,parents,childIDs);CHKERRQ(ierr);
21696f5f1567SToby Isaac 
21706f5f1567SToby Isaac     /* clean up */
21716f5f1567SToby Isaac     ierr = DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
21726f5f1567SToby Isaac     ierr = PetscFree5(pNewCount,pNewStart,pNewEnd,pOldStart,pOldEnd);CHKERRQ(ierr);
21736f5f1567SToby Isaac     ierr = PetscFree(newConeSizes);CHKERRQ(ierr);
21746f5f1567SToby Isaac     ierr = PetscFree2(newCones,newOrientations);CHKERRQ(ierr);
21756f5f1567SToby Isaac     ierr = PetscFree(newVertexCoords);CHKERRQ(ierr);
21766f5f1567SToby Isaac     ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
21776f5f1567SToby Isaac     ierr = PetscFree4(Kembedding,perm,iperm,preOrient);CHKERRQ(ierr);
21786f5f1567SToby Isaac   }
21796f5f1567SToby Isaac   else {
21806f5f1567SToby Isaac     PetscInt    p, counts[4];
21816f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
21826f5f1567SToby Isaac     Vec         coordVec;
21836f5f1567SToby Isaac     PetscScalar *coords;
21846f5f1567SToby Isaac 
21856f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
21866f5f1567SToby Isaac       PetscInt dStart, dEnd;
21876f5f1567SToby Isaac 
21886f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
21896f5f1567SToby Isaac       counts[d] = dEnd - dStart;
21906f5f1567SToby Isaac     }
21916f5f1567SToby Isaac     ierr = PetscMalloc1(pEnd-pStart,&coneSizes);CHKERRQ(ierr);
21926f5f1567SToby Isaac     for (p = pStart; p < pEnd; p++) {
21936f5f1567SToby Isaac       ierr = DMPlexGetConeSize(dm,p,&coneSizes[p-pStart]);CHKERRQ(ierr);
21946f5f1567SToby Isaac     }
21956f5f1567SToby Isaac     ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
21966f5f1567SToby Isaac     ierr = DMPlexGetConeOrientations(dm, &orientations);CHKERRQ(ierr);
21976f5f1567SToby Isaac     ierr = DMGetCoordinatesLocal(dm,&coordVec);CHKERRQ(ierr);
21986f5f1567SToby Isaac     ierr = VecGetArray(coordVec,&coords);CHKERRQ(ierr);
21996f5f1567SToby Isaac 
22006f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,pStart,pEnd);CHKERRQ(ierr);
22016f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
22026f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,counts,coneSizes,cones,orientations,NULL);CHKERRQ(ierr);
22036f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
22046f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,NULL,NULL);CHKERRQ(ierr);
22056f5f1567SToby Isaac     ierr = VecRestoreArray(coordVec,&coords);CHKERRQ(ierr);
22066f5f1567SToby Isaac   }
22076f5f1567SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
22086f5f1567SToby Isaac 
22096f5f1567SToby Isaac   PetscFunctionReturn(0);
22106f5f1567SToby Isaac }
22116ecaa68aSToby Isaac 
22126ecaa68aSToby Isaac #undef __FUNCT__
22136ecaa68aSToby Isaac #define __FUNCT__ "DMPlexComputeInterpolatorTree"
22146ecaa68aSToby Isaac PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
22156ecaa68aSToby Isaac {
22166ecaa68aSToby Isaac   PetscSF        coarseToFineEmbedded;
22176ecaa68aSToby Isaac   PetscSection   globalCoarse, globalFine;
22186ecaa68aSToby Isaac   PetscSection   localCoarse, localFine;
22196ecaa68aSToby Isaac   PetscSection   aSec, cSec;
22206ecaa68aSToby Isaac   PetscSection   rootIndicesSec, rootMatricesSec;
222146bdb399SToby Isaac   PetscSection   leafIndicesSec, leafMatricesSec;
222246bdb399SToby Isaac   PetscInt       *rootIndices, *leafIndices;
222346bdb399SToby Isaac   PetscScalar    *rootMatrices, *leafMatrices;
22246ecaa68aSToby Isaac   IS             aIS;
22256ecaa68aSToby Isaac   const PetscInt *anchors;
22266ecaa68aSToby Isaac   Mat            cMat;
22276ecaa68aSToby Isaac   PetscInt       numFields;
22286ecaa68aSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
22296ecaa68aSToby Isaac   PetscInt       aStart, aEnd, cStart, cEnd;
22301c58ffc4SToby Isaac   PetscInt       *maxChildIds;
2231e44e4e7fSToby Isaac   PetscInt       *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
22326ecaa68aSToby Isaac   PetscErrorCode ierr;
22336ecaa68aSToby Isaac 
22346ecaa68aSToby Isaac   PetscFunctionBegin;
22356ecaa68aSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
22366ecaa68aSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
22376ecaa68aSToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
22386ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
22396ecaa68aSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
22406ecaa68aSToby Isaac 
22416ecaa68aSToby Isaac     for (p = pStartF, numPointsWithDofs = 0; p < pEndF; p++) {
22426ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22436ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22446ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
22456ecaa68aSToby Isaac         numPointsWithDofs++;
22466ecaa68aSToby Isaac       }
22476ecaa68aSToby Isaac     }
22486ecaa68aSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
22496ecaa68aSToby Isaac     for (p = pStartF, offset = 0; p < pEndF; p++) {
22506ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22516ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22526ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
22536ecaa68aSToby Isaac         pointsWithDofs[offset++] = p - pStartF;
22546ecaa68aSToby Isaac       }
22556ecaa68aSToby Isaac     }
22566ecaa68aSToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
2257ec92bd66SToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
22586ecaa68aSToby Isaac   }
22596ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
22606ecaa68aSToby Isaac   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
22616ecaa68aSToby Isaac   for (p = pStartC; p < pEndC; p++) {
22628d2f55e7SToby Isaac     maxChildIds[p - pStartC] = -2;
22636ecaa68aSToby Isaac   }
22646ecaa68aSToby Isaac   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
22656ecaa68aSToby Isaac   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
226646bdb399SToby Isaac 
22676ecaa68aSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
22686ecaa68aSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
226946bdb399SToby Isaac 
22706ecaa68aSToby Isaac   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
22716ecaa68aSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
22726ecaa68aSToby Isaac   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
227346bdb399SToby Isaac 
22746ecaa68aSToby Isaac   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
22756ecaa68aSToby Isaac   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
227646bdb399SToby Isaac 
227746bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
22786ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
22796ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootMatricesSec);CHKERRQ(ierr);
22806ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootIndicesSec,pStartC,pEndC);CHKERRQ(ierr);
22816ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootMatricesSec,pStartC,pEndC);CHKERRQ(ierr);
22826ecaa68aSToby Isaac   ierr = PetscSectionGetNumFields(globalCoarse,&numFields);CHKERRQ(ierr);
228321968bf8SToby Isaac   {
2284267d4f3fSToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
2285e44e4e7fSToby Isaac     ierr = PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO);CHKERRQ(ierr);
228621968bf8SToby Isaac   }
228746bdb399SToby Isaac 
228846bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
22898d2f55e7SToby Isaac     PetscInt dof, matSize   = 0;
22906ecaa68aSToby Isaac     PetscInt aDof           = 0;
22916ecaa68aSToby Isaac     PetscInt cDof           = 0;
22926ecaa68aSToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
22936ecaa68aSToby Isaac     PetscInt numRowIndices  = 0;
22946ecaa68aSToby Isaac     PetscInt numColIndices  = 0;
22956ecaa68aSToby Isaac 
22966ecaa68aSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
22971cfc5b76SToby Isaac     if (dof < 0) {
22981cfc5b76SToby Isaac       dof = -(dof + 1);
22991cfc5b76SToby Isaac     }
23006ecaa68aSToby Isaac     if (p >= aStart && p < aEnd) {
23016ecaa68aSToby Isaac       ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
23026ecaa68aSToby Isaac     }
23036ecaa68aSToby Isaac     if (p >= cStart && p < cEnd) {
23046ecaa68aSToby Isaac       ierr = PetscSectionGetDof(cSec,p,&cDof);CHKERRQ(ierr);
23056ecaa68aSToby Isaac     }
230621968bf8SToby Isaac     offsets[0]    = 0;
230721968bf8SToby Isaac     newOffsets[0] = 0;
23086ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
23096ecaa68aSToby Isaac       PetscInt *closure = NULL, closureSize, cl, f;
23106ecaa68aSToby Isaac 
23116ecaa68aSToby Isaac       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
231246bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
23136ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
23146ecaa68aSToby Isaac 
23156ecaa68aSToby Isaac         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
23166ecaa68aSToby Isaac         numRowIndices += clDof;
23176ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23186ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,c,f,&clDof);CHKERRQ(ierr);
23196ecaa68aSToby Isaac           offsets[f + 1] += clDof;
23206ecaa68aSToby Isaac         }
23216ecaa68aSToby Isaac       }
23226ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
23236ecaa68aSToby Isaac         offsets[f + 1]   += offsets[f];
23246ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
23256ecaa68aSToby Isaac       }
232646bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
23276ecaa68aSToby Isaac       ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,NULL,NULL,&numColIndices,NULL,NULL,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
23286ecaa68aSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
23296ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
23306ecaa68aSToby Isaac         numColIndices = numRowIndices;
23316ecaa68aSToby Isaac         matSize = 0;
23326ecaa68aSToby Isaac       }
233346bdb399SToby Isaac       else if (numFields) { /* we send one submat for each field: sum their sizes */
23346ecaa68aSToby Isaac         matSize = 0;
23356ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23366ecaa68aSToby Isaac           PetscInt numRow, numCol;
23376ecaa68aSToby Isaac 
23386ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
23396ecaa68aSToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f + 1];
23406ecaa68aSToby Isaac           matSize += numRow * numCol;
23416ecaa68aSToby Isaac         }
23426ecaa68aSToby Isaac       }
23436ecaa68aSToby Isaac       else {
23446ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
23456ecaa68aSToby Isaac       }
23466ecaa68aSToby Isaac     }
23478d2f55e7SToby Isaac     else if (maxChildId == -1) {
23488d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
23496ecaa68aSToby Isaac         PetscInt aOff, a, f;
23506ecaa68aSToby Isaac 
23516ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
23526ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23536ecaa68aSToby Isaac           PetscInt fDof;
23546ecaa68aSToby Isaac 
23556ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
235621968bf8SToby Isaac           offsets[f+1] = fDof;
23576ecaa68aSToby Isaac         }
23586ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
23596ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
23606ecaa68aSToby Isaac 
23616ecaa68aSToby Isaac           ierr = PetscSectionGetDof(localCoarse,anchor,&aLocalDof);CHKERRQ(ierr);
23626ecaa68aSToby Isaac           numColIndices += aLocalDof;
23636ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23646ecaa68aSToby Isaac             PetscInt fDof;
23656ecaa68aSToby Isaac 
23666ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
236721968bf8SToby Isaac             newOffsets[f+1] += fDof;
23686ecaa68aSToby Isaac           }
23696ecaa68aSToby Isaac         }
23706ecaa68aSToby Isaac         if (numFields) {
23716ecaa68aSToby Isaac           matSize = 0;
23726ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
237321968bf8SToby Isaac             matSize += offsets[f+1] * newOffsets[f+1];
23746ecaa68aSToby Isaac           }
23756ecaa68aSToby Isaac         }
23766ecaa68aSToby Isaac         else {
23776ecaa68aSToby Isaac           matSize = numColIndices * dof;
23786ecaa68aSToby Isaac         }
23796ecaa68aSToby Isaac       }
23806ecaa68aSToby Isaac       else { /* no children, and no constraints on dofs: just get the global indices */
23816ecaa68aSToby Isaac         numColIndices = dof;
23826ecaa68aSToby Isaac         matSize       = 0;
23836ecaa68aSToby Isaac       }
23848d2f55e7SToby Isaac     }
238546bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
23866ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootIndicesSec,p,numColIndices ? numColIndices+2*numFields : 0);CHKERRQ(ierr);
23876ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootMatricesSec,p,matSize);CHKERRQ(ierr);
23886ecaa68aSToby Isaac   }
23896ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootIndicesSec);CHKERRQ(ierr);
23906ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootMatricesSec);CHKERRQ(ierr);
23916ecaa68aSToby Isaac   {
23926ecaa68aSToby Isaac     PetscInt    numRootIndices, numRootMatrices;
23936ecaa68aSToby Isaac 
23946ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
23956ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootMatricesSec,&numRootMatrices);CHKERRQ(ierr);
23966ecaa68aSToby Isaac     ierr = PetscMalloc2(numRootIndices,&rootIndices,numRootMatrices,&rootMatrices);CHKERRQ(ierr);
23976ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
23986ecaa68aSToby Isaac       PetscInt    numRowIndices, numColIndices, matSize, dof;
23996ecaa68aSToby Isaac       PetscInt    pIndOff, pMatOff;
24006ecaa68aSToby Isaac       PetscInt    *pInd;
24016ecaa68aSToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
24026ecaa68aSToby Isaac       PetscScalar *pMat = NULL;
24036ecaa68aSToby Isaac 
24046ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,p,&numColIndices);CHKERRQ(ierr);
24056ecaa68aSToby Isaac       if (!numColIndices) {
24066ecaa68aSToby Isaac         continue;
24076ecaa68aSToby Isaac       }
240821968bf8SToby Isaac       offsets[0]        = 0;
240921968bf8SToby Isaac       newOffsets[0]     = 0;
241021968bf8SToby Isaac       offsetsCopy[0]    = 0;
241121968bf8SToby Isaac       newOffsetsCopy[0] = 0;
24126ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
24136ecaa68aSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,p,&pIndOff);CHKERRQ(ierr);
24146ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
24156ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootMatricesSec,p,&matSize);CHKERRQ(ierr);
24166ecaa68aSToby Isaac       if (matSize) {
24176ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(rootMatricesSec,p,&pMatOff);CHKERRQ(ierr);
24186ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
24196ecaa68aSToby Isaac       }
24206ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
24211cfc5b76SToby Isaac       if (dof < 0) {
24221cfc5b76SToby Isaac         dof = -(dof + 1);
24231cfc5b76SToby Isaac       }
24246ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
24256ecaa68aSToby Isaac         PetscInt i, j;
24266ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
24276ecaa68aSToby Isaac 
24286ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
24296ecaa68aSToby Isaac           PetscInt numIndices, *indices;
24306ecaa68aSToby Isaac           ierr = DMPlexGetClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
24316ecaa68aSToby Isaac           if (numIndices != numColIndices) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"mismatching constraint indices calculations");
24326ecaa68aSToby Isaac           for (i = 0; i < numColIndices; i++) {
24336ecaa68aSToby Isaac             pInd[i] = indices[i];
24346ecaa68aSToby Isaac           }
24356ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
243646bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i+1];
243746bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i+1];
24386ecaa68aSToby Isaac           }
243946bdb399SToby Isaac           ierr = DMPlexRestoreClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
24406ecaa68aSToby Isaac         }
24416ecaa68aSToby Isaac         else {
24426ecaa68aSToby Isaac           PetscInt closureSize, *closure = NULL, cl;
24436ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
24446ecaa68aSToby Isaac           PetscInt numPoints,*points;
24456ecaa68aSToby Isaac 
24466ecaa68aSToby Isaac           ierr = DMGetWorkArray(coarse,numRowIndices * numRowIndices,PETSC_SCALAR,&pMatIn);CHKERRQ(ierr);
24476ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
24486ecaa68aSToby Isaac             for (j = 0; j < numRowIndices; j++) {
24496ecaa68aSToby Isaac               pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
24506ecaa68aSToby Isaac             }
24516ecaa68aSToby Isaac           }
24526ecaa68aSToby Isaac           ierr = DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
24536ecaa68aSToby Isaac           if (numFields) {
24546ecaa68aSToby Isaac             PetscInt f;
24556ecaa68aSToby Isaac 
24566ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
24576ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
24586ecaa68aSToby Isaac 
24596ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
24606ecaa68aSToby Isaac                 PetscInt fDof;
24616ecaa68aSToby Isaac 
24626ecaa68aSToby Isaac                 ierr = PetscSectionGetFieldDof(localCoarse,c,f,&fDof);CHKERRQ(ierr);
24636ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
24646ecaa68aSToby Isaac               }
24656ecaa68aSToby Isaac             }
24666ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
24676ecaa68aSToby Isaac               offsets[f + 1]   += offsets[f];
24686ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
24696ecaa68aSToby Isaac             }
24706ecaa68aSToby Isaac           }
24716ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
2472267d4f3fSToby Isaac           ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,pMatIn,&numPoints,NULL,&points,&pMatModified,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
24736ecaa68aSToby Isaac           if (!numFields) {
24746ecaa68aSToby Isaac             for (i = 0; i < numRowIndices * numColIndices; i++) {
24756ecaa68aSToby Isaac               pMat[i] = pMatModified[i];
24766ecaa68aSToby Isaac             }
24776ecaa68aSToby Isaac           }
24786ecaa68aSToby Isaac           else {
24796ecaa68aSToby Isaac             PetscInt f, i, j, count;
24806ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
24816ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f+1]; i++) {
24826ecaa68aSToby Isaac                 for (j = newOffsets[f]; j < newOffsets[f+1]; j++, count++) {
24836ecaa68aSToby Isaac                   pMat[count] = pMatModified[i * numColIndices + j];
24846ecaa68aSToby Isaac                 }
24856ecaa68aSToby Isaac               }
24866ecaa68aSToby Isaac             }
24876ecaa68aSToby Isaac           }
24886ecaa68aSToby Isaac           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,PETSC_SCALAR,&pMatModified);CHKERRQ(ierr);
24896ecaa68aSToby Isaac           ierr = DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
24906ecaa68aSToby Isaac           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,PETSC_SCALAR,&pMatIn);CHKERRQ(ierr);
24916ecaa68aSToby Isaac           if (numFields) {
249246bdb399SToby Isaac             PetscInt f;
249346bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
249446bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f+1];
249546bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f+1];
24966ecaa68aSToby Isaac             }
24976ecaa68aSToby Isaac             for (cl = 0; cl < numPoints*2; cl += 2) {
24986ecaa68aSToby Isaac               PetscInt o = points[cl+1], globalOff, c = points[cl];
24996ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
2500415ce65aSMatthew G. Knepley               DMPlexGetIndicesPointFields_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, o, pInd);
25016ecaa68aSToby Isaac             }
25026ecaa68aSToby Isaac           } else {
25036ecaa68aSToby Isaac             for (cl = 0; cl < numPoints*2; cl += 2) {
25046ecaa68aSToby Isaac               PetscInt o = points[cl+1], c = points[cl], globalOff;
25056ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
2506415ce65aSMatthew G. Knepley               DMPlexGetIndicesPoint_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, o, pInd);
25076ecaa68aSToby Isaac             }
25086ecaa68aSToby Isaac           }
250928552ed4SToby Isaac           ierr = DMRestoreWorkArray(coarse,numPoints,PETSC_SCALAR,&points);CHKERRQ(ierr);
25106ecaa68aSToby Isaac         }
25116ecaa68aSToby Isaac       }
25126ecaa68aSToby Isaac       else if (matSize) {
25136ecaa68aSToby Isaac         PetscInt cOff;
25146ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
25156ecaa68aSToby Isaac 
25166ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
2517628cbfb8SToby Isaac         if (numRowIndices != dof) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Miscounted dofs");
25186ecaa68aSToby Isaac         ierr = DMGetWorkArray(coarse,numRowIndices,PETSC_INT,&rowIndices);CHKERRQ(ierr);
25196ecaa68aSToby Isaac         ierr = DMGetWorkArray(coarse,numColIndices,PETSC_INT,&colIndices);CHKERRQ(ierr);
25206ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(cSec,p,&cOff);CHKERRQ(ierr);
25216ecaa68aSToby Isaac         ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
25226ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
25236ecaa68aSToby Isaac         if (numFields) {
25246ecaa68aSToby Isaac           PetscInt f;
25256ecaa68aSToby Isaac 
25266ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25276ecaa68aSToby Isaac             PetscInt fDof;
25286ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(cSec,p,f,&fDof);CHKERRQ(ierr);
25296ecaa68aSToby Isaac             offsets[f + 1] = fDof;
25306ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
25316ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
25326ecaa68aSToby Isaac               ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
25336ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
25346ecaa68aSToby Isaac             }
25356ecaa68aSToby Isaac           }
25366ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25376ecaa68aSToby Isaac             offsets[f + 1]       += offsets[f];
25386ecaa68aSToby Isaac             offsetsCopy[f + 1]    = offsets[f + 1];
25396ecaa68aSToby Isaac             newOffsets[f + 1]    += newOffsets[f];
25406ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
25416ecaa68aSToby Isaac           }
2542415ce65aSMatthew G. Knepley           DMPlexGetIndicesPointFields_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,0,rowIndices);CHKERRQ(ierr);
25436ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25446ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25456ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
2546415ce65aSMatthew G. Knepley             DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,0,colIndices);CHKERRQ(ierr);
25476ecaa68aSToby Isaac           }
25486ecaa68aSToby Isaac         }
25496ecaa68aSToby Isaac         else {
2550415ce65aSMatthew G. Knepley           DMPlexGetIndicesPoint_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,0,rowIndices);CHKERRQ(ierr);
25516ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25526ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25536ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
2554415ce65aSMatthew G. Knepley             DMPlexGetIndicesPoint_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,0,colIndices);CHKERRQ(ierr);
25556ecaa68aSToby Isaac           }
25566ecaa68aSToby Isaac         }
25576ecaa68aSToby Isaac         if (numFields) {
25586ecaa68aSToby Isaac           PetscInt count, f, a;
25596ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
25606ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
25616ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
25626ecaa68aSToby Isaac             ierr = MatGetValues(cMat,iSize,&rowIndices[offsets[f]],jSize,&colIndices[newOffsets[f]],&pMat[count]);CHKERRQ(ierr);
25636ecaa68aSToby Isaac             count += iSize * jSize;
256446bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
256546bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f+1];
25666ecaa68aSToby Isaac           }
25676ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25686ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25696ecaa68aSToby Isaac             PetscInt gOff;
25706ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
2571415ce65aSMatthew G. Knepley             DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr);
25726ecaa68aSToby Isaac           }
25736ecaa68aSToby Isaac         }
25746ecaa68aSToby Isaac         else {
25756ecaa68aSToby Isaac           PetscInt a;
25766ecaa68aSToby Isaac           ierr = MatGetValues(cMat,numRowIndices,rowIndices,numColIndices,colIndices,pMat);CHKERRQ(ierr);
25776ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25786ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25796ecaa68aSToby Isaac             PetscInt gOff;
25806ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
2581415ce65aSMatthew G. Knepley             DMPlexGetIndicesPoint_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr);
25826ecaa68aSToby Isaac           }
25836ecaa68aSToby Isaac         }
25846ecaa68aSToby Isaac         ierr = DMRestoreWorkArray(coarse,numColIndices,PETSC_INT,&colIndices);CHKERRQ(ierr);
25856ecaa68aSToby Isaac         ierr = DMRestoreWorkArray(coarse,numRowIndices,PETSC_INT,&rowIndices);CHKERRQ(ierr);
25866ecaa68aSToby Isaac       }
25876ecaa68aSToby Isaac       else {
25886ecaa68aSToby Isaac         PetscInt gOff;
25896ecaa68aSToby Isaac 
25906ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
25916ecaa68aSToby Isaac         if (numFields) {
25926ecaa68aSToby Isaac           PetscInt f;
25936ecaa68aSToby Isaac 
25946ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25956ecaa68aSToby Isaac             PetscInt fDof;
25966ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
25976ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
25986ecaa68aSToby Isaac           }
25996ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
260046bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
260146bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f+1];
26026ecaa68aSToby Isaac           }
2603415ce65aSMatthew G. Knepley           DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr);
26046ecaa68aSToby Isaac         }
26056ecaa68aSToby Isaac         else {
2606415ce65aSMatthew G. Knepley           DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr);
26076ecaa68aSToby Isaac         }
26086ecaa68aSToby Isaac       }
26096ecaa68aSToby Isaac     }
2610e44e4e7fSToby Isaac     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
26116ecaa68aSToby Isaac   }
261246bdb399SToby Isaac   {
261346bdb399SToby Isaac     PetscSF  indicesSF, matricesSF;
261446bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
261546bdb399SToby Isaac 
261646bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
261746bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafMatricesSec);CHKERRQ(ierr);
261846bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootIndicesSec,&remoteOffsetsIndices,leafIndicesSec);CHKERRQ(ierr);
261946bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootMatricesSec,&remoteOffsetsMatrices,leafMatricesSec);CHKERRQ(ierr);
262046bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootIndicesSec,remoteOffsetsIndices,leafIndicesSec,&indicesSF);CHKERRQ(ierr);
262146bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootMatricesSec,remoteOffsetsMatrices,leafMatricesSec,&matricesSF);CHKERRQ(ierr);
2622e44e4e7fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
262346bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsIndices);CHKERRQ(ierr);
262446bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsMatrices);CHKERRQ(ierr);
262546bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numLeafIndices);CHKERRQ(ierr);
262646bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafMatricesSec,&numLeafMatrices);CHKERRQ(ierr);
262746bdb399SToby Isaac     ierr = PetscMalloc2(numLeafIndices,&leafIndices,numLeafMatrices,&leafMatrices);CHKERRQ(ierr);
262846bdb399SToby Isaac     ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2629267d4f3fSToby Isaac     ierr = PetscSFBcastBegin(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
263046bdb399SToby Isaac     ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2631267d4f3fSToby Isaac     ierr = PetscSFBcastEnd(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
263246bdb399SToby Isaac     ierr = PetscSFDestroy(&matricesSF);CHKERRQ(ierr);
263346bdb399SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
263446bdb399SToby Isaac     ierr = PetscFree2(rootIndices,rootMatrices);CHKERRQ(ierr);
263546bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
263646bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootMatricesSec);CHKERRQ(ierr);
263746bdb399SToby Isaac   }
263846bdb399SToby Isaac   /* count to preallocate */
263946bdb399SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
264046bdb399SToby Isaac   {
264146bdb399SToby Isaac     PetscInt    nGlobal;
264246bdb399SToby Isaac     PetscInt    *dnnz, *onnz;
2643b9a5774bSToby Isaac     PetscLayout rowMap, colMap;
2644b9a5774bSToby Isaac     PetscInt    rowStart, rowEnd, colStart, colEnd;
26451c58ffc4SToby Isaac     PetscInt    maxDof;
26461c58ffc4SToby Isaac     PetscInt    *rowIndices;
26471c58ffc4SToby Isaac     DM           refTree;
26481c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
26491c58ffc4SToby Isaac     PetscScalar  ***refPointFieldMats;
26501c58ffc4SToby Isaac     PetscSection refConSec, refAnSec;
2651*0eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,maxConDof,maxColumns,leafStart,leafEnd;
26521c58ffc4SToby Isaac     PetscScalar  *pointWork;
265346bdb399SToby Isaac 
265446bdb399SToby Isaac     ierr = PetscSectionGetConstrainedStorageSize(globalFine,&nGlobal);CHKERRQ(ierr);
265546bdb399SToby Isaac     ierr = PetscCalloc2(nGlobal,&dnnz,nGlobal,&onnz);CHKERRQ(ierr);
2656b9a5774bSToby Isaac     ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
2657b9a5774bSToby Isaac     ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
26581c58ffc4SToby Isaac     ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
2659b9a5774bSToby Isaac     ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
266046bdb399SToby Isaac     ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
26611c58ffc4SToby Isaac     ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr);
2662*0eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafIndicesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
26631c58ffc4SToby Isaac     ierr = DMGetWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
2664*0eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
266546bdb399SToby Isaac       PetscInt    gDof, gcDof, gOff;
266646bdb399SToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
266746bdb399SToby Isaac       PetscInt    matSize;
266821968bf8SToby Isaac       PetscInt    i;
266946bdb399SToby Isaac 
267046bdb399SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
267146bdb399SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
267246bdb399SToby Isaac       if ((gDof - gcDof) <= 0) {
267346bdb399SToby Isaac         continue;
267446bdb399SToby Isaac       }
267546bdb399SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
267646bdb399SToby Isaac       if (gOff < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"I though having global dofs meant a non-negative offset");
2677b9a5774bSToby Isaac       if ((gOff < rowStart) || ((gOff + gDof - gcDof) > rowEnd)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"I thought the row map would constrain the global dofs");
267846bdb399SToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
267946bdb399SToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
268046bdb399SToby Isaac       numColIndices -= 2 * numFields;
26811c58ffc4SToby Isaac       if (numColIndices <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"global fine dof with no dofs to interpolate from");
268246bdb399SToby Isaac       pInd = &leafIndices[pIndOff];
268321968bf8SToby Isaac       offsets[0]        = 0;
268421968bf8SToby Isaac       offsetsCopy[0]    = 0;
268521968bf8SToby Isaac       newOffsets[0]     = 0;
268621968bf8SToby Isaac       newOffsetsCopy[0] = 0;
268746bdb399SToby Isaac       if (numFields) {
268821968bf8SToby Isaac         PetscInt f;
268946bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
269046bdb399SToby Isaac           PetscInt rowDof;
269146bdb399SToby Isaac 
269246bdb399SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
269321968bf8SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
269421968bf8SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
269521968bf8SToby Isaac           newOffsets[f + 1]     = pInd[numColIndices + numFields + f];
269621968bf8SToby Isaac           numD[f] = 0;
269721968bf8SToby Isaac           numO[f] = 0;
269846bdb399SToby Isaac         }
2699415ce65aSMatthew G. Knepley         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr);
270046bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
270121968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
270221968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
270346bdb399SToby Isaac 
270446bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
270546bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
270646bdb399SToby Isaac 
270746bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
270821968bf8SToby Isaac               numD[f]++;
270946bdb399SToby Isaac             }
271046bdb399SToby Isaac             else if (gInd >= 0) { /* negative means non-entry */
271121968bf8SToby Isaac               numO[f]++;
271246bdb399SToby Isaac             }
271346bdb399SToby Isaac           }
271446bdb399SToby Isaac         }
271546bdb399SToby Isaac       }
271646bdb399SToby Isaac       else {
2717415ce65aSMatthew G. Knepley         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr);
271821968bf8SToby Isaac         numD[0] = 0;
271921968bf8SToby Isaac         numO[0] = 0;
272046bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
272146bdb399SToby Isaac           PetscInt gInd = pInd[i];
272246bdb399SToby Isaac 
272346bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
272421968bf8SToby Isaac             numD[0]++;
272546bdb399SToby Isaac           }
272646bdb399SToby Isaac           else if (gInd >= 0) { /* negative means non-entry */
272721968bf8SToby Isaac             numO[0]++;
272846bdb399SToby Isaac           }
272946bdb399SToby Isaac         }
273046bdb399SToby Isaac       }
273146bdb399SToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
273246bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
273346bdb399SToby Isaac         PetscInt childId;
273446bdb399SToby Isaac 
273546bdb399SToby Isaac         childId = childIds[p-pStartF];
273621968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
273746bdb399SToby Isaac           if (numFields) {
2738b9a5774bSToby Isaac             PetscInt f;
2739b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
274021968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
274146bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
274221968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
274321968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
274446bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2745b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2746b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
274746bdb399SToby Isaac                 }
274846bdb399SToby Isaac                 else if (gIndCoarse >= 0) { /* remote */
2749b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2750b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
275146bdb399SToby Isaac                 }
275246bdb399SToby Isaac                 else { /* constrained */
275346bdb399SToby Isaac                   if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
275446bdb399SToby Isaac                 }
275546bdb399SToby Isaac               }
275646bdb399SToby Isaac             }
275746bdb399SToby Isaac           }
275846bdb399SToby Isaac           else {
2759b9a5774bSToby Isaac             PetscInt i;
2760b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
276146bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
276246bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
276346bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2764b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2765b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
276646bdb399SToby Isaac               }
276746bdb399SToby Isaac               else if (gIndCoarse >= 0) { /* remote */
2768b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2769b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
277046bdb399SToby Isaac               }
277146bdb399SToby Isaac               else { /* constrained */
277246bdb399SToby Isaac                 if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
277346bdb399SToby Isaac               }
277446bdb399SToby Isaac             }
277546bdb399SToby Isaac           }
277646bdb399SToby Isaac         }
277746bdb399SToby Isaac         else { /* interpolate from all */
277846bdb399SToby Isaac           if (numFields) {
2779b9a5774bSToby Isaac             PetscInt f;
2780b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
278121968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
278246bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
278321968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
278446bdb399SToby Isaac                 if (gIndFine >= 0) {
2785b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2786b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2787b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
278846bdb399SToby Isaac                 }
278946bdb399SToby Isaac               }
279046bdb399SToby Isaac             }
279146bdb399SToby Isaac           }
279246bdb399SToby Isaac           else {
2793b9a5774bSToby Isaac             PetscInt i;
2794b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
279546bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
279646bdb399SToby Isaac               if (gIndFine >= 0) {
2797b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2798b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2799b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
280046bdb399SToby Isaac               }
280146bdb399SToby Isaac             }
280246bdb399SToby Isaac           }
280346bdb399SToby Isaac         }
280446bdb399SToby Isaac       }
280546bdb399SToby Isaac       else { /* interpolate from all */
280646bdb399SToby Isaac         if (numFields) {
2807b9a5774bSToby Isaac           PetscInt f;
2808b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
280921968bf8SToby Isaac             PetscInt numRows = offsets[f+1] - offsets[f], row;
281046bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
281121968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
281246bdb399SToby Isaac               if (gIndFine >= 0) {
2813b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2814b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2815b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
281646bdb399SToby Isaac               }
281746bdb399SToby Isaac             }
281846bdb399SToby Isaac           }
281946bdb399SToby Isaac         }
282046bdb399SToby Isaac         else { /* every dof get a full row */
2821b9a5774bSToby Isaac           PetscInt i;
2822b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
282346bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
282446bdb399SToby Isaac             if (gIndFine >= 0) {
2825b9a5774bSToby Isaac               if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2826b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2827b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
282846bdb399SToby Isaac             }
282946bdb399SToby Isaac           }
283046bdb399SToby Isaac         }
283146bdb399SToby Isaac       }
283246bdb399SToby Isaac     }
283346bdb399SToby Isaac     ierr = MatXAIJSetPreallocation(mat,1,dnnz,onnz,NULL,NULL);CHKERRQ(ierr);
283446bdb399SToby Isaac     ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
283521968bf8SToby Isaac 
283621968bf8SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
283721968bf8SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
2838e44e4e7fSToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
2839e44e4e7fSToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
2840e44e4e7fSToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
28411c58ffc4SToby Isaac     ierr = PetscSectionGetMaxDof(refConSec,&maxConDof);CHKERRQ(ierr);
28427c0540e0SToby Isaac     ierr = PetscSectionGetMaxDof(leafIndicesSec,&maxColumns);CHKERRQ(ierr);
28437c0540e0SToby Isaac     ierr = PetscMalloc1(maxConDof*maxColumns,&pointWork);CHKERRQ(ierr);
2844*0eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2845e44e4e7fSToby Isaac       PetscInt    gDof, gcDof, gOff;
2846e44e4e7fSToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
2847e44e4e7fSToby Isaac       PetscInt    matSize;
2848e44e4e7fSToby Isaac       PetscInt    childId;
2849e44e4e7fSToby Isaac 
2850e44e4e7fSToby Isaac 
2851e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
2852e44e4e7fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
2853e44e4e7fSToby Isaac       if ((gDof - gcDof) <= 0) {
2854e44e4e7fSToby Isaac         continue;
2855e44e4e7fSToby Isaac       }
2856e44e4e7fSToby Isaac       childId = childIds[p-pStartF];
2857e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
2858e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
2859e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
2860e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2861e44e4e7fSToby Isaac       pInd = &leafIndices[pIndOff];
2862e44e4e7fSToby Isaac       offsets[0]        = 0;
2863e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2864e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2865e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2866e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2867e44e4e7fSToby Isaac       if (numFields) {
2868e44e4e7fSToby Isaac         PetscInt f;
2869e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2870e44e4e7fSToby Isaac           PetscInt rowDof;
2871e44e4e7fSToby Isaac 
2872e44e4e7fSToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
2873e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2874e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2875e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2876e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2877e44e4e7fSToby Isaac         }
2878415ce65aSMatthew G. Knepley         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr);
2879e44e4e7fSToby Isaac       }
28801c58ffc4SToby Isaac       else {
2881415ce65aSMatthew G. Knepley         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr);
28821c58ffc4SToby Isaac       }
2883e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
2884e44e4e7fSToby Isaac       if (!matSize) { /* incoming matrix is identity */
2885e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2886e44e4e7fSToby Isaac           if (numFields) {
2887e44e4e7fSToby Isaac             PetscInt f;
2888e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2889e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
2890e44e4e7fSToby Isaac               for (row = 0; row < numRows; row++) {
2891e44e4e7fSToby Isaac                 ierr = MatSetValue(mat,rowIndices[offsets[f]+row],pInd[newOffsets[f]+row],1.,INSERT_VALUES);CHKERRQ(ierr);
289221968bf8SToby Isaac               }
289321968bf8SToby Isaac             }
2894e44e4e7fSToby Isaac           }
2895e44e4e7fSToby Isaac           else {
2896e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
2897e44e4e7fSToby Isaac             for (row = 0; row < numRows; row++) {
2898e44e4e7fSToby Isaac               ierr = MatSetValue(mat,rowIndices[row],pInd[row],1.,INSERT_VALUES);CHKERRQ(ierr);
2899e44e4e7fSToby Isaac             }
2900e44e4e7fSToby Isaac           }
2901e44e4e7fSToby Isaac         }
2902e44e4e7fSToby Isaac         else { /* interpolate from all */
2903e44e4e7fSToby Isaac           if (numFields) {
2904e44e4e7fSToby Isaac             PetscInt f;
2905e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2906e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f];
2907e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
2908e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],refPointFieldMats[childId - pRefStart][f],INSERT_VALUES);CHKERRQ(ierr);
2909e44e4e7fSToby Isaac             }
2910e44e4e7fSToby Isaac           }
2911e44e4e7fSToby Isaac           else {
2912e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,refPointFieldMats[childId - pRefStart][0],INSERT_VALUES);CHKERRQ(ierr);
2913e44e4e7fSToby Isaac           }
2914e44e4e7fSToby Isaac         }
2915e44e4e7fSToby Isaac       }
2916e44e4e7fSToby Isaac       else { /* interpolate from all */
2917e44e4e7fSToby Isaac         PetscInt    pMatOff;
2918e44e4e7fSToby Isaac         PetscScalar *pMat;
2919e44e4e7fSToby Isaac 
2920e44e4e7fSToby Isaac         ierr = PetscSectionGetOffset(leafMatricesSec,p,&pMatOff);CHKERRQ(ierr);
2921e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2922e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2923e44e4e7fSToby Isaac           if (numFields) {
2924e44e4e7fSToby Isaac             PetscInt f, count;
2925e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2926e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2927e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2928e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2929e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2930e44e4e7fSToby Isaac 
2931e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],inMat,INSERT_VALUES);CHKERRQ(ierr);
2932e44e4e7fSToby Isaac               count += numCols * numInRows;
2933e44e4e7fSToby Isaac             }
2934e44e4e7fSToby Isaac           }
2935e44e4e7fSToby Isaac           else {
2936e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,pMat,INSERT_VALUES);CHKERRQ(ierr);
2937e44e4e7fSToby Isaac           }
2938e44e4e7fSToby Isaac         }
2939e44e4e7fSToby Isaac         else { /* multiply the incoming matrix by the child interpolation */
2940e44e4e7fSToby Isaac           if (numFields) {
2941e44e4e7fSToby Isaac             PetscInt f, count;
2942e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2943e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2944e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2945e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2946e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2947e44e4e7fSToby Isaac               PetscInt i, j, k;
2948e44e4e7fSToby Isaac               if (refPointFieldN[childId - pRefStart][f] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2949e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2950e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2951e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2952e44e4e7fSToby Isaac                   for (k = 0; k < numInRows; k++) {
2953e44e4e7fSToby Isaac                     val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2954e44e4e7fSToby Isaac                   }
2955e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2956e44e4e7fSToby Isaac                 }
2957e44e4e7fSToby Isaac               }
2958e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],pointWork,INSERT_VALUES);CHKERRQ(ierr);
2959e44e4e7fSToby Isaac               count += numCols * numInRows;
2960e44e4e7fSToby Isaac             }
2961e44e4e7fSToby Isaac           }
2962267d4f3fSToby Isaac           else { /* every dof gets a full row */
2963e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2964e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2965e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2966e44e4e7fSToby Isaac             PetscInt i, j, k;
2967e44e4e7fSToby Isaac             if (refPointFieldN[childId - pRefStart][0] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2968e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2969e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2970e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2971e44e4e7fSToby Isaac                 for (k = 0; k < numInRows; k++) {
2972e44e4e7fSToby Isaac                   val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2973e44e4e7fSToby Isaac                 }
2974e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2975e44e4e7fSToby Isaac               }
2976e44e4e7fSToby Isaac             }
2977e44e4e7fSToby Isaac             ierr = MatSetValues(mat,numRows,rowIndices,numCols,pInd,pointWork,INSERT_VALUES);CHKERRQ(ierr);
2978e44e4e7fSToby Isaac           }
2979e44e4e7fSToby Isaac         }
2980e44e4e7fSToby Isaac       }
2981e44e4e7fSToby Isaac     }
29821c58ffc4SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
29831c58ffc4SToby Isaac     ierr = DMRestoreWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
2984e44e4e7fSToby Isaac     ierr = PetscFree(pointWork);CHKERRQ(ierr);
2985e44e4e7fSToby Isaac   }
2986e44e4e7fSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2987e44e4e7fSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2988e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
2989e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafMatricesSec);CHKERRQ(ierr);
2990e44e4e7fSToby Isaac   ierr = PetscFree2(leafIndices,leafMatrices);CHKERRQ(ierr);
2991e44e4e7fSToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
29926ecaa68aSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
29936ecaa68aSToby Isaac   PetscFunctionReturn(0);
29946ecaa68aSToby Isaac }
2995154bca37SToby Isaac 
2996154bca37SToby Isaac #undef __FUNCT__
29978d2f55e7SToby Isaac #define __FUNCT__ "DMPlexComputeInjectorReferenceTree"
29988d2f55e7SToby Isaac /*
29998d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
30008d2f55e7SToby Isaac  *
30018d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
30028d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
30038d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
30048d2f55e7SToby Isaac  *       a_{i,j} = 0;
30058d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
30068d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
30078d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
30088d2f55e7SToby Isaac  */
30098d2f55e7SToby Isaac PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
30108d2f55e7SToby Isaac {
30118d2f55e7SToby Isaac   PetscDS        ds;
30128d2f55e7SToby Isaac   PetscSection   section, cSection;
30138d2f55e7SToby Isaac   DMLabel        canonical, depth;
30148d2f55e7SToby Isaac   Mat            cMat, mat;
30158d2f55e7SToby Isaac   PetscInt       *nnz;
30168d2f55e7SToby Isaac   PetscInt       f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
30178d2f55e7SToby Isaac   PetscInt       m, n;
30188d2f55e7SToby Isaac   PetscScalar    *pointScalar;
30198d2f55e7SToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
30208d2f55e7SToby Isaac   PetscErrorCode ierr;
30218d2f55e7SToby Isaac 
30228d2f55e7SToby Isaac   PetscFunctionBegin;
30238d2f55e7SToby Isaac   ierr = DMGetDefaultSection(refTree,&section);CHKERRQ(ierr);
30248d2f55e7SToby Isaac   ierr = DMGetDimension(refTree, &dim);CHKERRQ(ierr);
30258d2f55e7SToby Isaac   ierr = PetscMalloc6(dim,&v0,dim,&v0parent,dim,&vtmp,dim*dim,&J,dim*dim,&Jparent,dim*dim,&invJ);CHKERRQ(ierr);
30268d2f55e7SToby Isaac   ierr = PetscMalloc2(dim,&pointScalar,dim,&pointRef);CHKERRQ(ierr);
30278d2f55e7SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
30288d2f55e7SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
30298d2f55e7SToby Isaac   ierr = PetscSectionGetNumFields(section,&numSecFields);CHKERRQ(ierr);
30308d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"canonical",&canonical);CHKERRQ(ierr);
30318d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"depth",&depth);CHKERRQ(ierr);
30328d2f55e7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSection,&cMat);CHKERRQ(ierr);
30338d2f55e7SToby Isaac   ierr = DMPlexGetChart(refTree, &pStart, &pEnd);CHKERRQ(ierr);
30348d2f55e7SToby Isaac   ierr = DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd);CHKERRQ(ierr);
30358d2f55e7SToby Isaac   ierr = MatGetSize(cMat,&n,&m);CHKERRQ(ierr); /* the injector has transpose sizes from the constraint matrix */
30368d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
30378d2f55e7SToby Isaac   ierr = PetscCalloc1(m,&nnz);CHKERRQ(ierr);
30388d2f55e7SToby 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 */
30398d2f55e7SToby Isaac     const PetscInt *children;
30408d2f55e7SToby Isaac     PetscInt numChildren;
30418d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30428d2f55e7SToby Isaac 
30438d2f55e7SToby Isaac     if (canonical) {
30448d2f55e7SToby Isaac       PetscInt pCanonical;
30458d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
30468d2f55e7SToby Isaac       if (p != pCanonical) continue;
30478d2f55e7SToby Isaac     }
30488d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
30498d2f55e7SToby Isaac     if (!numChildren) continue;
30508d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30518d2f55e7SToby Isaac       PetscInt child = children[i];
30528d2f55e7SToby Isaac       PetscInt dof;
30538d2f55e7SToby Isaac 
30548d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
30558d2f55e7SToby Isaac       numChildDof += dof;
30568d2f55e7SToby Isaac     }
30578d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
30588d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30598d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
30608d2f55e7SToby Isaac       PetscInt selfOff;
30618d2f55e7SToby Isaac 
30628d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
30638d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
30648d2f55e7SToby Isaac           PetscInt child = children[i];
30658d2f55e7SToby Isaac           PetscInt dof;
30668d2f55e7SToby Isaac 
30678d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
30688d2f55e7SToby Isaac           numChildDof += dof;
30698d2f55e7SToby Isaac         }
30708d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
30718d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
30728d2f55e7SToby Isaac       }
30738d2f55e7SToby Isaac       else {
30748d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
30758d2f55e7SToby Isaac       }
30768d2f55e7SToby Isaac       for (i = 0; i < numSelfDof; i++) {
30778d2f55e7SToby Isaac         nnz[selfOff + i] = numChildDof;
30788d2f55e7SToby Isaac       }
30798d2f55e7SToby Isaac     }
30808d2f55e7SToby Isaac   }
30818d2f55e7SToby Isaac   ierr = MatCreateAIJ(PETSC_COMM_SELF,m,n,m,n,-1,nnz,-1,NULL,&mat);CHKERRQ(ierr);
30828d2f55e7SToby Isaac   ierr = PetscFree(nnz);CHKERRQ(ierr);
30838d2f55e7SToby Isaac   /* Setp 2: compute entries */
30848d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
30858d2f55e7SToby Isaac     const PetscInt *children;
30868d2f55e7SToby Isaac     PetscInt numChildren;
30878d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30888d2f55e7SToby Isaac 
30898d2f55e7SToby Isaac     /* same conditions about when entries occur */
30908d2f55e7SToby Isaac     if (canonical) {
30918d2f55e7SToby Isaac       PetscInt pCanonical;
30928d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
30938d2f55e7SToby Isaac       if (p != pCanonical) continue;
30948d2f55e7SToby Isaac     }
30958d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
30968d2f55e7SToby Isaac     if (!numChildren) continue;
30978d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30988d2f55e7SToby Isaac       PetscInt child = children[i];
30998d2f55e7SToby Isaac       PetscInt dof;
31008d2f55e7SToby Isaac 
31018d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
31028d2f55e7SToby Isaac       numChildDof += dof;
31038d2f55e7SToby Isaac     }
31048d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
31058d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
31068d2f55e7SToby Isaac 
31078d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
31088d2f55e7SToby Isaac       PetscInt       selfOff, fComp, numSelfShapes, numChildShapes, parentCell;
31098d2f55e7SToby Isaac       PetscInt       cellShapeOff;
31108d2f55e7SToby Isaac       PetscObject    disc;
31118d2f55e7SToby Isaac       PetscDualSpace dsp;
31128d2f55e7SToby Isaac       PetscClassId   classId;
31138d2f55e7SToby Isaac       PetscScalar    *pointMat;
31143b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
31158d2f55e7SToby Isaac       PetscInt       pO = PETSC_MIN_INT;
31168d2f55e7SToby Isaac       const PetscInt *depthNumDof;
31178d2f55e7SToby Isaac 
31188d2f55e7SToby Isaac       if (numSecFields) {
31198d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
31208d2f55e7SToby Isaac           PetscInt child = children[i];
31218d2f55e7SToby Isaac           PetscInt dof;
31228d2f55e7SToby Isaac 
31238d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
31248d2f55e7SToby Isaac           numChildDof += dof;
31258d2f55e7SToby Isaac         }
31268d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
31278d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
31288d2f55e7SToby Isaac         ierr = PetscSectionGetFieldComponents(section,f,&fComp);CHKERRQ(ierr);
31298d2f55e7SToby Isaac       }
31308d2f55e7SToby Isaac       else {
31318d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
31328d2f55e7SToby Isaac         fComp = 1;
31338d2f55e7SToby Isaac       }
31348d2f55e7SToby Isaac       numSelfShapes  = numSelfDof  / fComp;
31358d2f55e7SToby Isaac       numChildShapes = numChildDof / fComp;
31368d2f55e7SToby Isaac 
31373b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
31388d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
31398d2f55e7SToby Isaac         parentCell = p;
31408d2f55e7SToby Isaac       }
31418d2f55e7SToby Isaac       else {
31428d2f55e7SToby Isaac         PetscInt *star = NULL;
31438d2f55e7SToby Isaac         PetscInt numStar;
31448d2f55e7SToby Isaac 
31458d2f55e7SToby Isaac         parentCell = -1;
31468d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31478d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
31488d2f55e7SToby Isaac           PetscInt c = star[2 * i];
31498d2f55e7SToby Isaac 
31508d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
31518d2f55e7SToby Isaac             parentCell = c;
31528d2f55e7SToby Isaac             break;
31538d2f55e7SToby Isaac           }
31548d2f55e7SToby Isaac         }
31558d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31568d2f55e7SToby Isaac       }
31578d2f55e7SToby Isaac       /* determine the offset of p's shape functions withing parentCell's shape functions */
3158c5356c36SToby Isaac       ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
3159c5356c36SToby Isaac       ierr = PetscObjectGetClassId(disc,&classId);CHKERRQ(ierr);
3160c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
3161c5356c36SToby Isaac         ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
3162c5356c36SToby Isaac       }
3163c5356c36SToby Isaac       else if (classId == PETSCFV_CLASSID) {
3164c5356c36SToby Isaac         ierr = PetscFVGetDualSpace((PetscFV)disc,&dsp);CHKERRQ(ierr);
3165c5356c36SToby Isaac       }
3166c5356c36SToby Isaac       else {
3167c5356c36SToby Isaac         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported discretization object");CHKERRQ(ierr);
3168c5356c36SToby Isaac       }
31698d2f55e7SToby Isaac       ierr = PetscDualSpaceGetNumDof(dsp,&depthNumDof);CHKERRQ(ierr);
31708d2f55e7SToby Isaac       {
31718d2f55e7SToby Isaac         PetscInt *closure = NULL;
31728d2f55e7SToby Isaac         PetscInt numClosure;
31738d2f55e7SToby Isaac 
31748d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
31758d2f55e7SToby Isaac         for (i = 0, cellShapeOff = 0; i < numClosure; i++) {
31768d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
31778d2f55e7SToby Isaac 
31788d2f55e7SToby Isaac           pO = closure[2 * i + 1];
31798d2f55e7SToby Isaac           if (point == p) break;
31808d2f55e7SToby Isaac           ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
31818d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
31828d2f55e7SToby Isaac         }
31838d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
31848d2f55e7SToby Isaac       }
31858d2f55e7SToby Isaac 
31868d2f55e7SToby Isaac       ierr = DMGetWorkArray(refTree, numSelfShapes * numChildShapes, PETSC_SCALAR,&pointMat);CHKERRQ(ierr);
31873b1c2a6aSToby Isaac       ierr = DMGetWorkArray(refTree, numSelfShapes + numChildShapes, PETSC_INT,&matRows);CHKERRQ(ierr);
31883b1c2a6aSToby Isaac       matCols = matRows + numSelfShapes;
31893b1c2a6aSToby Isaac       for (i = 0; i < numSelfShapes; i++) {
31903b1c2a6aSToby Isaac         matRows[i] = selfOff + i * fComp;
31913b1c2a6aSToby Isaac       }
31923b1c2a6aSToby Isaac       {
31933b1c2a6aSToby Isaac         PetscInt colOff = 0;
31943b1c2a6aSToby Isaac 
31953b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
31963b1c2a6aSToby Isaac           PetscInt child = children[i];
31973b1c2a6aSToby Isaac           PetscInt dof, off, j;
31983b1c2a6aSToby Isaac 
31993b1c2a6aSToby Isaac           if (numSecFields) {
3200c5356c36SToby Isaac             ierr = PetscSectionGetFieldDof(cSection,child,f,&dof);CHKERRQ(ierr);
3201c5356c36SToby Isaac             ierr = PetscSectionGetFieldOffset(cSection,child,f,&off);CHKERRQ(ierr);
32023b1c2a6aSToby Isaac           }
32033b1c2a6aSToby Isaac           else {
3204c5356c36SToby Isaac             ierr = PetscSectionGetDof(cSection,child,&dof);CHKERRQ(ierr);
3205c5356c36SToby Isaac             ierr = PetscSectionGetOffset(cSection,child,&off);CHKERRQ(ierr);
32063b1c2a6aSToby Isaac           }
32073b1c2a6aSToby Isaac 
32083b1c2a6aSToby Isaac           for (j = 0; j < dof / fComp; j++) {
32093b1c2a6aSToby Isaac             matCols[colOff++] = off + j * fComp;
32103b1c2a6aSToby Isaac           }
32113b1c2a6aSToby Isaac         }
32123b1c2a6aSToby Isaac       }
32138d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
32148d2f55e7SToby Isaac         PetscFE        fe = (PetscFE) disc;
32158d2f55e7SToby Isaac         PetscInt       fSize;
32168d2f55e7SToby Isaac 
32178d2f55e7SToby Isaac         ierr = PetscFEGetDualSpace(fe,&dsp);CHKERRQ(ierr);
32183b1c2a6aSToby Isaac         ierr = PetscDualSpaceGetDimension(dsp,&fSize);CHKERRQ(ierr);
32198d2f55e7SToby Isaac         for (i = 0; i < numSelfShapes; i++) { /* for every shape function */
32208d2f55e7SToby Isaac           PetscQuadrature q;
32218d2f55e7SToby Isaac           PetscInt        dim, numPoints, j, k;
32228d2f55e7SToby Isaac           const PetscReal *points;
32238d2f55e7SToby Isaac           const PetscReal *weights;
32248d2f55e7SToby Isaac           PetscInt        *closure = NULL;
32258d2f55e7SToby Isaac           PetscInt        numClosure;
32263b1c2a6aSToby Isaac           PetscInt        parentCellShapeDof = cellShapeOff + (pO < 0 ? (numSelfShapes - 1 - i) : i);
32278d2f55e7SToby Isaac           PetscReal       *Bparent;
32288d2f55e7SToby Isaac 
32293b1c2a6aSToby Isaac           ierr = PetscDualSpaceGetFunctional(dsp,parentCellShapeDof,&q);CHKERRQ(ierr);
32303b1c2a6aSToby Isaac           ierr = PetscQuadratureGetData(q,&dim,&numPoints,&points,&weights);CHKERRQ(ierr);
32313b1c2a6aSToby Isaac           ierr = PetscFEGetTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
32328d2f55e7SToby Isaac           for (k = 0; k < numChildShapes; k++) {
32338d2f55e7SToby Isaac             pointMat[numChildShapes * i + k] = 0.;
32348d2f55e7SToby Isaac           }
32353b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
32368d2f55e7SToby Isaac             PetscInt          childCell = -1;
32373b1c2a6aSToby Isaac             PetscReal         parentValAtPoint;
32388d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
32398d2f55e7SToby Isaac             const PetscScalar *point;
32408d2f55e7SToby Isaac             PetscReal         *Bchild;
32418d2f55e7SToby Isaac             PetscInt          childCellShapeOff, pointMatOff;
32428d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
32438d2f55e7SToby Isaac             PetscInt          d;
32448d2f55e7SToby Isaac 
32458d2f55e7SToby Isaac             for (d = 0; d < dim; d++) {
32468d2f55e7SToby Isaac               pointScalar[d] = points[dim * j + d];
32478d2f55e7SToby Isaac             }
32488d2f55e7SToby Isaac             point = pointScalar;
32498d2f55e7SToby Isaac #else
32508d2f55e7SToby Isaac             point = pointReal;
32518d2f55e7SToby Isaac #endif
32528d2f55e7SToby Isaac 
32533b1c2a6aSToby Isaac             parentValAtPoint = Bparent[(fSize * j + parentCellShapeDof) * fComp];
32543b1c2a6aSToby Isaac 
32553b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
32568d2f55e7SToby Isaac               PetscInt child = children[k];
32578d2f55e7SToby Isaac               PetscInt *star = NULL;
32588d2f55e7SToby Isaac               PetscInt numStar, s;
32598d2f55e7SToby Isaac 
32608d2f55e7SToby Isaac               ierr = DMPlexGetTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
32618d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
32628d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
32638d2f55e7SToby Isaac 
32648d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
32658d2f55e7SToby Isaac                 ierr = DMPlexLocatePoint_Internal(refTree,dim,point,c,&childCell);CHKERRQ(ierr);
32668d2f55e7SToby Isaac                 if (childCell >= 0) break;
32678d2f55e7SToby Isaac               }
32688d2f55e7SToby Isaac               ierr = DMPlexRestoreTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
32698d2f55e7SToby Isaac               if (childCell >= 0) break;
32708d2f55e7SToby Isaac             }
32718d2f55e7SToby Isaac             if (childCell < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not locate quadrature point");CHKERRQ(ierr);
32728d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
32738d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent);CHKERRQ(ierr);
32748d2f55e7SToby Isaac             CoordinatesRefToReal(dim, dim, v0parent, Jparent, pointReal, vtmp);
32758d2f55e7SToby Isaac             CoordinatesRealToRef(dim, dim, v0, invJ, vtmp, pointRef);
32768d2f55e7SToby Isaac 
32778d2f55e7SToby Isaac             ierr = PetscFEGetTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr);
32788d2f55e7SToby Isaac             ierr = DMPlexGetTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
32793b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3280c5356c36SToby Isaac               PetscInt child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
32818d2f55e7SToby Isaac               PetscInt l;
32828d2f55e7SToby Isaac 
32838d2f55e7SToby Isaac               ierr = DMLabelGetValue(depth,child,&childDepth);CHKERRQ(ierr);
32848d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
32858d2f55e7SToby Isaac               for (l = 0, childCellShapeOff = 0; l < numClosure; l++) {
32868d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
32878d2f55e7SToby Isaac                 PetscInt pointDepth;
32888d2f55e7SToby Isaac 
32898d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
32908d2f55e7SToby Isaac                 if (point == child) break;
32918d2f55e7SToby Isaac                 ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
32928d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
32938d2f55e7SToby Isaac               }
32948d2f55e7SToby Isaac               if (l == numClosure) {
32958d2f55e7SToby Isaac                 pointMatOff += childDof;
32968d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
32978d2f55e7SToby Isaac               }
32988d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
32993b1c2a6aSToby Isaac                 PetscInt    childCellDof    = childCellShapeOff + (childO ? (childDof - 1 - l) : l);
33003b1c2a6aSToby Isaac                 PetscReal   childValAtPoint = Bchild[childCellDof * fComp];
33018d2f55e7SToby Isaac 
33023b1c2a6aSToby Isaac                 pointMat[i * numChildShapes + pointMatOff + l] += weights[j] * parentValAtPoint * childValAtPoint;
33038d2f55e7SToby Isaac               }
33048d2f55e7SToby Isaac               pointMatOff += childDof;
33058d2f55e7SToby Isaac             }
33068d2f55e7SToby Isaac             ierr = DMPlexRestoreTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
33078d2f55e7SToby Isaac             ierr = PetscFERestoreTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr);
33088d2f55e7SToby Isaac           }
33098d2f55e7SToby Isaac           ierr = PetscFERestoreTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr);
33108d2f55e7SToby Isaac         }
33118d2f55e7SToby Isaac       }
3312c5356c36SToby Isaac       else { /* just the volume-weighted averages of the children */
33133b1c2a6aSToby Isaac         PetscInt  childShapeOff;
33143b1c2a6aSToby Isaac         PetscReal parentVol;
33153b1c2a6aSToby Isaac 
33163b1c2a6aSToby Isaac         ierr = DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL);CHKERRQ(ierr);
33173b1c2a6aSToby Isaac         for (i = 0, childShapeOff = 0; i < numChildren; i++) {
33183b1c2a6aSToby Isaac           PetscInt  child = children[i];
33193b1c2a6aSToby Isaac           PetscReal childVol;
33203b1c2a6aSToby Isaac 
33213b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
33223b1c2a6aSToby Isaac           ierr = DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL);CHKERRQ(ierr);
33233b1c2a6aSToby Isaac           pointMat[childShapeOff] = childVol / parentVol;
33243b1c2a6aSToby Isaac           childShapeOff++;
33253b1c2a6aSToby Isaac         }
33268d2f55e7SToby Isaac       }
33273b1c2a6aSToby Isaac       /* Insert pointMat into mat */
33283b1c2a6aSToby Isaac       for (i = 0; i < fComp; i++) {
33293b1c2a6aSToby Isaac         PetscInt j;
33303b1c2a6aSToby Isaac         ierr = MatSetValues(mat,numSelfShapes,matRows,numChildShapes,matCols,pointMat,INSERT_VALUES);CHKERRQ(ierr);
33313b1c2a6aSToby Isaac 
33323b1c2a6aSToby Isaac         for (j = 0; j < numSelfShapes; j++) {
33333b1c2a6aSToby Isaac           matRows[j]++;
33343b1c2a6aSToby Isaac         }
33353b1c2a6aSToby Isaac         for (j = 0; j < numChildShapes; j++) {
33363b1c2a6aSToby Isaac           matCols[j]++;
33373b1c2a6aSToby Isaac         }
33383b1c2a6aSToby Isaac       }
33393b1c2a6aSToby Isaac       ierr = DMRestoreWorkArray(refTree, numSelfShapes + numChildShapes, PETSC_INT,&matRows);CHKERRQ(ierr);
33408d2f55e7SToby Isaac       ierr = DMRestoreWorkArray(refTree, numSelfShapes * numChildShapes, PETSC_SCALAR,&pointMat);CHKERRQ(ierr);
33418d2f55e7SToby Isaac     }
33428d2f55e7SToby Isaac   }
33433b1c2a6aSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJ);CHKERRQ(ierr);
33448d2f55e7SToby Isaac   ierr = PetscFree2(pointScalar,pointRef);CHKERRQ(ierr);
33453b1c2a6aSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33463b1c2a6aSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33478d2f55e7SToby Isaac   *inj = mat;
33488d2f55e7SToby Isaac   PetscFunctionReturn(0);
33498d2f55e7SToby Isaac }
33508d2f55e7SToby Isaac 
33518d2f55e7SToby Isaac #undef __FUNCT__
3352f30e825dSToby Isaac #define __FUNCT__ "DMPlexReferenceTreeGetChildrenMatrices_Injection"
3353f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3354f30e825dSToby Isaac {
3355f30e825dSToby Isaac   PetscDS        ds;
3356f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3357f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3358f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3359f30e825dSToby Isaac   PetscErrorCode ierr;
3360f30e825dSToby Isaac 
3361f30e825dSToby Isaac   PetscFunctionBegin;
3362f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
3363f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3364f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
3365f30e825dSToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
3366f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3367f30e825dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
3368f30e825dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
3369f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
3370f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof*maxDof,&cols);CHKERRQ(ierr);
3371f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3372f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3373f30e825dSToby Isaac 
3374f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3375f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3376c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3377f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3378f30e825dSToby Isaac 
3379f30e825dSToby Isaac     ierr = PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
3380f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3381f30e825dSToby Isaac       PetscInt cDof, cOff, numCols, r, fComp;
3382f30e825dSToby Isaac       PetscObject disc;
3383f30e825dSToby Isaac       PetscClassId id;
3384f30e825dSToby Isaac       PetscFE fe = NULL;
3385f30e825dSToby Isaac       PetscFV fv = NULL;
3386f30e825dSToby Isaac 
3387f30e825dSToby Isaac       ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
3388f30e825dSToby Isaac       ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
3389f30e825dSToby Isaac       if (id == PETSCFE_CLASSID) {
3390f30e825dSToby Isaac         fe = (PetscFE) disc;
3391f30e825dSToby Isaac         ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr);
3392f30e825dSToby Isaac       }
3393f30e825dSToby Isaac       else if (id == PETSCFV_CLASSID) {
3394f30e825dSToby Isaac         fv = (PetscFV) disc;
3395f30e825dSToby Isaac         ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr);
3396f30e825dSToby Isaac       }
3397f30e825dSToby Isaac       else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
3398f30e825dSToby Isaac 
3399f30e825dSToby Isaac       if (numFields > 1) {
3400f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3401f30e825dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
3402f30e825dSToby Isaac       }
3403f30e825dSToby Isaac       else {
3404f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3405f30e825dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
3406f30e825dSToby Isaac       }
3407f30e825dSToby Isaac 
3408f30e825dSToby Isaac       if (!cDof) continue;
3409f30e825dSToby Isaac       for (r = 0; r < cDof; r++) {
3410f30e825dSToby Isaac         rows[r] = cOff + r;
3411f30e825dSToby Isaac       }
3412f30e825dSToby Isaac       numCols = 0;
3413f30e825dSToby Isaac       {
3414f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3415f30e825dSToby Isaac 
3416f30e825dSToby Isaac         if (numFields > 1) {
3417f30e825dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,parent,f,&aDof);CHKERRQ(ierr);
3418f30e825dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,parent,f,&aOff);CHKERRQ(ierr);
3419f30e825dSToby Isaac         }
3420f30e825dSToby Isaac         else {
3421f30e825dSToby Isaac           ierr = PetscSectionGetDof(refSection,parent,&aDof);CHKERRQ(ierr);
3422f30e825dSToby Isaac           ierr = PetscSectionGetOffset(refSection,parent,&aOff);CHKERRQ(ierr);
3423f30e825dSToby Isaac         }
3424f30e825dSToby Isaac 
3425f30e825dSToby Isaac         for (j = 0; j < aDof; j++) {
3426f30e825dSToby Isaac           cols[numCols++] = aOff + j;
3427f30e825dSToby Isaac         }
3428f30e825dSToby Isaac       }
3429f30e825dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3430f30e825dSToby Isaac       /* transpose of constraint matrix */
3431f30e825dSToby Isaac       ierr = MatGetValues(inj,numCols,cols,cDof,rows,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3432f30e825dSToby Isaac     }
3433f30e825dSToby Isaac   }
3434f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
3435f30e825dSToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
3436f30e825dSToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
3437f30e825dSToby Isaac   PetscFunctionReturn(0);
3438f30e825dSToby Isaac }
3439f30e825dSToby Isaac 
3440f30e825dSToby Isaac #undef __FUNCT__
3441f30e825dSToby Isaac #define __FUNCT__ "DMPlexReferenceTreeRestoreChildrenMatrices_Injection"
3442f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3443f30e825dSToby Isaac {
3444f30e825dSToby Isaac   PetscDS        ds;
3445f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3446f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3447c6154584SToby Isaac   PetscSection   refConSec, refSection;
3448f30e825dSToby Isaac   PetscErrorCode ierr;
3449f30e825dSToby Isaac 
3450f30e825dSToby Isaac   PetscFunctionBegin;
3451f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3452f30e825dSToby Isaac   *childrenMats = NULL;
3453f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
3454c6154584SToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
3455f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3456f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
3457f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3458f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3459f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3460f30e825dSToby Isaac 
3461f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3462f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3463c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3464f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3465f30e825dSToby Isaac 
3466f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3467f30e825dSToby Isaac       PetscInt cDof;
3468f30e825dSToby Isaac 
3469f30e825dSToby Isaac       if (numFields > 1) {
3470f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3471f30e825dSToby Isaac       }
3472f30e825dSToby Isaac       else {
3473f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3474f30e825dSToby Isaac       }
3475f30e825dSToby Isaac 
3476f30e825dSToby Isaac       if (!cDof) continue;
3477f30e825dSToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
3478f30e825dSToby Isaac     }
3479f30e825dSToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
3480f30e825dSToby Isaac   }
3481f30e825dSToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
3482f30e825dSToby Isaac   PetscFunctionReturn(0);
3483f30e825dSToby Isaac }
3484f30e825dSToby Isaac 
3485f30e825dSToby Isaac #undef __FUNCT__
3486ebf164c7SToby Isaac #define __FUNCT__ "DMPlexReferenceTreeGetInjector"
3487ebf164c7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree,Mat *injRef)
3488154bca37SToby Isaac {
3489ebf164c7SToby Isaac   Mat            cMatRef;
34906148253fSToby Isaac   PetscObject    injRefObj;
34918d2f55e7SToby Isaac   PetscErrorCode ierr;
34928d2f55e7SToby Isaac 
3493154bca37SToby Isaac   PetscFunctionBegin;
3494ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,NULL,&cMatRef);CHKERRQ(ierr);
34956148253fSToby Isaac   ierr = PetscObjectQuery((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",&injRefObj);CHKERRQ(ierr);
3496ebf164c7SToby Isaac   *injRef = (Mat) injRefObj;
3497ebf164c7SToby Isaac   if (!*injRef) {
3498ebf164c7SToby Isaac     ierr = DMPlexComputeInjectorReferenceTree(refTree,injRef);CHKERRQ(ierr);
3499ebf164c7SToby Isaac     ierr = PetscObjectCompose((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",(PetscObject)*injRef);CHKERRQ(ierr);
3500ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
3501ebf164c7SToby Isaac     ierr = PetscObjectDereference((PetscObject)*injRef);CHKERRQ(ierr);
3502ebf164c7SToby Isaac   }
3503ebf164c7SToby Isaac   PetscFunctionReturn(0);
35046148253fSToby Isaac }
3505f30e825dSToby Isaac 
3506ebf164c7SToby Isaac #undef __FUNCT__
3507c921d74cSToby Isaac #define __FUNCT__ "DMPlexTransferInjectorTree"
3508c921d74cSToby 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)
3509ebf164c7SToby Isaac {
3510c921d74cSToby Isaac   PetscInt       pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3511ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3512ebf164c7SToby Isaac   PetscSection   localCoarse, localFine, leafIndicesSec;
3513c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3514c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3515c921d74cSToby Isaac   const PetscInt *rootDegrees;
3516c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3517ebf164c7SToby Isaac   PetscSF        coarseToFineEmbedded;
3518ebf164c7SToby Isaac   PetscErrorCode ierr;
3519ebf164c7SToby Isaac 
3520ebf164c7SToby Isaac   PetscFunctionBegin;
3521ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
35228d2f55e7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
3523f30e825dSToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
35248d2f55e7SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3525f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
3526f30e825dSToby Isaac   ierr = PetscSectionSetChart(leafIndicesSec,pStartF, pEndF);CHKERRQ(ierr);
3527c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localFine,&maxDof);CHKERRQ(ierr);
35288d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
35297e96bdafSToby Isaac     PetscInt l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
35307e96bdafSToby Isaac     const PetscInt *leaves;
35318d2f55e7SToby Isaac 
35327e96bdafSToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
35337e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
35347e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35358d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
35368d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
35378d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
35388d2f55e7SToby Isaac         numPointsWithDofs++;
3539f30e825dSToby Isaac 
3540f30e825dSToby Isaac         ierr = PetscSectionGetDof(localFine,p,&dof);CHKERRQ(ierr);
3541f30e825dSToby Isaac         ierr = PetscSectionSetDof(leafIndicesSec,p,dof + 1);CHKERRQ(ierr);
35428d2f55e7SToby Isaac       }
35438d2f55e7SToby Isaac     }
35448d2f55e7SToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
3545f30e825dSToby Isaac     ierr = PetscSectionSetUp(leafIndicesSec);CHKERRQ(ierr);
3546f30e825dSToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numIndices);CHKERRQ(ierr);
3547c921d74cSToby Isaac     ierr = PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1),&leafInds);CHKERRQ(ierr);
3548c921d74cSToby Isaac     if (gatheredValues)  {ierr = PetscMalloc1(numIndices,&leafVals);CHKERRQ(ierr);}
35497e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
35507e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35518d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
35528d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
35538d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3554f30e825dSToby Isaac         PetscInt    off, gOff;
3555f30e825dSToby Isaac         PetscInt    *pInd;
3556c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3557f30e825dSToby Isaac 
35587e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3559f30e825dSToby Isaac 
3560f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3561f30e825dSToby Isaac 
3562c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3563c921d74cSToby Isaac         if (gatheredValues) {
3564c921d74cSToby Isaac           PetscInt i;
3565c921d74cSToby Isaac 
3566c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3567c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3568c921d74cSToby Isaac         }
3569f30e825dSToby Isaac         ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
3570f30e825dSToby Isaac 
3571f30e825dSToby Isaac         offsets[0] = 0;
3572f30e825dSToby Isaac         if (numFields) {
3573f30e825dSToby Isaac           PetscInt f;
3574f30e825dSToby Isaac 
3575f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3576f30e825dSToby Isaac             PetscInt fDof;
3577f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(localFine,p,f,&fDof);CHKERRQ(ierr);
3578f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3579f30e825dSToby Isaac           }
3580415ce65aSMatthew G. Knepley           DMPlexGetIndicesPointFields_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr);
3581f30e825dSToby Isaac         }
3582f30e825dSToby Isaac         else {
3583415ce65aSMatthew G. Knepley           DMPlexGetIndicesPoint_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr);
3584f30e825dSToby Isaac         }
3585c921d74cSToby Isaac         if (gatheredValues) {ierr = VecGetValues(fineVec,dof,pInd,pVal);CHKERRQ(ierr);}
35868d2f55e7SToby Isaac       }
35878d2f55e7SToby Isaac     }
35888d2f55e7SToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
3589f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
35908d2f55e7SToby Isaac   }
3591f30e825dSToby Isaac 
3592f30e825dSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
3593f30e825dSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
3594f30e825dSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3595f30e825dSToby Isaac 
35966148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
35976148253fSToby Isaac     MPI_Datatype threeInt;
35986148253fSToby Isaac     PetscMPIInt  rank;
35996148253fSToby Isaac     PetscInt     (*parentNodeAndIdCoarse)[3];
36006148253fSToby Isaac     PetscInt     (*parentNodeAndIdFine)[3];
36016148253fSToby Isaac     PetscInt     p, nleaves, nleavesToParents;
36026148253fSToby Isaac     PetscSF      pointSF, sfToParents;
36036148253fSToby Isaac     const PetscInt *ilocal;
36046148253fSToby Isaac     const PetscSFNode *iremote;
36056148253fSToby Isaac     PetscSFNode  *iremoteToParents;
36066148253fSToby Isaac     PetscInt     *ilocalToParents;
36076148253fSToby Isaac 
36086148253fSToby Isaac     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)coarse),&rank);CHKERRQ(ierr);
36096148253fSToby Isaac     ierr = MPI_Type_contiguous(3,MPIU_INT,&threeInt);CHKERRQ(ierr);
36106148253fSToby Isaac     ierr = MPI_Type_commit(&threeInt);CHKERRQ(ierr);
36116148253fSToby Isaac     ierr = PetscMalloc2(pEndC-pStartC,&parentNodeAndIdCoarse,pEndF-pStartF,&parentNodeAndIdFine);CHKERRQ(ierr);
36126148253fSToby Isaac     ierr = DMGetPointSF(coarse,&pointSF);CHKERRQ(ierr);
36136148253fSToby Isaac     ierr = PetscSFGetGraph(pointSF,NULL,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
36146148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
36156148253fSToby Isaac       PetscInt parent, childId;
36166148253fSToby Isaac       ierr = DMPlexGetTreeParent(coarse,p,&parent,&childId);CHKERRQ(ierr);
36176148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
36186148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
36196148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
36206148253fSToby Isaac       if (nleaves > 0) {
36216148253fSToby Isaac         PetscInt leaf = -1;
36226148253fSToby Isaac 
36236148253fSToby Isaac         if (ilocal) {
36246148253fSToby Isaac           ierr  = PetscFindInt(parent,nleaves,ilocal,&leaf);CHKERRQ(ierr);
36256148253fSToby Isaac         }
36266148253fSToby Isaac         else {
36276148253fSToby Isaac           leaf = p - pStartC;
36286148253fSToby Isaac         }
36296148253fSToby Isaac         if (leaf >= 0) {
36306148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
36316148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
36326148253fSToby Isaac         }
36336148253fSToby Isaac       }
36346148253fSToby Isaac     }
36356148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
36366148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
36376148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
36386148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
36396148253fSToby Isaac     }
36406148253fSToby Isaac     ierr = PetscSFBcastBegin(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36416148253fSToby Isaac     ierr = PetscSFBcastEnd(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36426148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3643f30e825dSToby Isaac       PetscInt dof;
3644f30e825dSToby Isaac 
3645f30e825dSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&dof);CHKERRQ(ierr);
3646f30e825dSToby Isaac       if (dof) {
3647f30e825dSToby Isaac         PetscInt off;
3648f30e825dSToby Isaac 
3649f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3650c921d74cSToby Isaac         if (gatheredIndices) {
3651c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3652c921d74cSToby Isaac         } else if (gatheredValues) {
3653c921d74cSToby Isaac           leafVals[off] = (PetscScalar) PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3654c921d74cSToby Isaac         }
3655f30e825dSToby Isaac       }
36566148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36576148253fSToby Isaac         nleavesToParents++;
36586148253fSToby Isaac       }
36596148253fSToby Isaac     }
36606148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&ilocalToParents);CHKERRQ(ierr);
36616148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&iremoteToParents);CHKERRQ(ierr);
36626148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
36636148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36646148253fSToby Isaac         ilocalToParents[nleavesToParents] = p - pStartF;
36656148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p-pStartF][0];
36666148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p-pStartF][1];
36676148253fSToby Isaac         nleavesToParents++;
36686148253fSToby Isaac       }
36696148253fSToby Isaac     }
36706148253fSToby Isaac     ierr = PetscSFCreate(PetscObjectComm((PetscObject)coarse),&sfToParents);CHKERRQ(ierr);
36716148253fSToby Isaac     ierr = PetscSFSetGraph(sfToParents,pEndC-pStartC,nleavesToParents,ilocalToParents,PETSC_OWN_POINTER,iremoteToParents,PETSC_OWN_POINTER);CHKERRQ(ierr);
36726148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
36736148253fSToby Isaac 
36746148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
36756148253fSToby Isaac 
36766148253fSToby Isaac     ierr = PetscFree2(parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36776148253fSToby Isaac     ierr = MPI_Type_free(&threeInt);CHKERRQ(ierr);
36786148253fSToby Isaac   }
3679f30e825dSToby Isaac 
36806148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
36816148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
36826148253fSToby Isaac     PetscSF  sfDofsOnly;
36836148253fSToby Isaac 
36846148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
36856148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
36866148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
36876148253fSToby Isaac       if ((dof - cdof) > 0) {
36886148253fSToby Isaac         numPointsWithDofs++;
36896148253fSToby Isaac       }
36906148253fSToby Isaac     }
36916148253fSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
36926148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
36936148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
36946148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
36956148253fSToby Isaac       if ((dof - cdof) > 0) {
3696e03d9830SToby Isaac         pointsWithDofs[offset++] = p - pStartC;
36976148253fSToby Isaac       }
36986148253fSToby Isaac     }
36996148253fSToby Isaac     ierr = PetscSFCreateEmbeddedSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly);CHKERRQ(ierr);
37006148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3701f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
37026148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
37036148253fSToby Isaac   }
3704f30e825dSToby Isaac 
37056148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
3706f30e825dSToby Isaac   ierr = PetscSFComputeDegreeBegin(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3707f30e825dSToby Isaac   ierr = PetscSFComputeDegreeEnd(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3708f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&multiRootSec);CHKERRQ(ierr);
3709f30e825dSToby Isaac   ierr = PetscSectionSetChart(multiRootSec,pStartC,pEndC);CHKERRQ(ierr);
37108d2f55e7SToby Isaac   for (p = pStartC; p < pEndC; p++) {
3711f30e825dSToby Isaac     ierr = PetscSectionSetDof(multiRootSec,p,rootDegrees[p-pStartC]);CHKERRQ(ierr);
37128d2f55e7SToby Isaac   }
3713f30e825dSToby Isaac   ierr = PetscSectionSetUp(multiRootSec);CHKERRQ(ierr);
3714f30e825dSToby Isaac   ierr = PetscSectionGetStorageSize(multiRootSec,&numMulti);CHKERRQ(ierr);
37158d2f55e7SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
3716f30e825dSToby Isaac   { /* distribute the leaf section */
3717f30e825dSToby Isaac     PetscSF multi, multiInv, indicesSF;
3718f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
37198d2f55e7SToby Isaac 
3720f30e825dSToby Isaac     ierr = PetscSFGetMultiSF(coarseToFineEmbedded,&multi);CHKERRQ(ierr);
3721f30e825dSToby Isaac     ierr = PetscSFCreateInverseSF(multi,&multiInv);CHKERRQ(ierr);
3722f30e825dSToby Isaac     ierr = PetscSFDistributeSection(multiInv,leafIndicesSec,&remoteOffsets,rootIndicesSec);CHKERRQ(ierr);
3723f30e825dSToby Isaac     ierr = PetscSFCreateSectionSF(multiInv,leafIndicesSec,remoteOffsets,rootIndicesSec,&indicesSF);CHKERRQ(ierr);
3724f30e825dSToby Isaac     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
3725f30e825dSToby Isaac     ierr = PetscSFDestroy(&multiInv);CHKERRQ(ierr);
37268d2f55e7SToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
3727c921d74cSToby Isaac     if (gatheredIndices) {
3728c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootInds);CHKERRQ(ierr);
3729c921d74cSToby Isaac       ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr);
3730c921d74cSToby Isaac       ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr);
3731c921d74cSToby Isaac     }
3732c921d74cSToby Isaac     if (gatheredValues) {
3733c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootVals);CHKERRQ(ierr);
3734c921d74cSToby Isaac       ierr = PetscSFBcastBegin(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr);
3735c921d74cSToby Isaac       ierr = PetscSFBcastEnd(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr);
3736c921d74cSToby Isaac     }
37378d2f55e7SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
37388d2f55e7SToby Isaac   }
3739ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
3740c921d74cSToby Isaac   ierr = PetscFree(leafInds);CHKERRQ(ierr);
3741c921d74cSToby Isaac   ierr = PetscFree(leafVals);CHKERRQ(ierr);
3742f30e825dSToby Isaac   ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3743c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3744c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3745c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3746c921d74cSToby Isaac   if (gatheredValues)  *gatheredValues  = rootVals;
3747ebf164c7SToby Isaac   PetscFunctionReturn(0);
3748ebf164c7SToby Isaac }
3749ebf164c7SToby Isaac 
3750ebf164c7SToby Isaac #undef __FUNCT__
3751ebf164c7SToby Isaac #define __FUNCT__ "DMPlexComputeInjectorTree"
3752ebf164c7SToby Isaac PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3753ebf164c7SToby Isaac {
3754ebf164c7SToby Isaac   DM             refTree;
3755c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3756ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3757ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3758ebf164c7SToby Isaac   PetscSection   cSecRef;
3759c921d74cSToby Isaac   PetscInt       *rootIndices, *parentIndices, pRefStart, pRefEnd;
3760ebf164c7SToby Isaac   Mat            injRef;
3761c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3762ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3763ebf164c7SToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
3764ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3765ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3766ebf164c7SToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3767ebf164c7SToby Isaac   PetscErrorCode ierr;
3768ebf164c7SToby Isaac 
3769ebf164c7SToby Isaac   PetscFunctionBegin;
3770ebf164c7SToby Isaac 
3771ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
3772ebf164c7SToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
3773ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
3774ebf164c7SToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3775ebf164c7SToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
3776ebf164c7SToby Isaac 
3777ebf164c7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
3778ebf164c7SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
3779ebf164c7SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3780ebf164c7SToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
3781ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
3782ebf164c7SToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
3783ebf164c7SToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3784ebf164c7SToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
3785ebf164c7SToby Isaac   {
3786ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
3787ebf164c7SToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
3788ebf164c7SToby Isaac   }
3789ebf164c7SToby Isaac 
3790c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,childIds,NULL,numFields,offsets,&multiRootSec,&rootIndicesSec,&rootIndices,NULL);CHKERRQ(ierr);
37918d2f55e7SToby Isaac 
3792f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&parentIndices);CHKERRQ(ierr);
3793f30e825dSToby Isaac 
3794f30e825dSToby Isaac   /* count indices */
37958d2f55e7SToby Isaac   ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
3796c6154584SToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
3797c6154584SToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
37988d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
37998d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
3800f30e825dSToby Isaac   ierr = PetscCalloc2(rowEnd-rowStart,&nnzD,rowEnd-rowStart,&nnzO);CHKERRQ(ierr);
3801f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3802f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
38038d2f55e7SToby Isaac 
3804f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3805f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3806f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3807f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
38088d2f55e7SToby Isaac 
38098d2f55e7SToby Isaac     rowOffsets[0] = 0;
3810f30e825dSToby Isaac     offsetsCopy[0] = 0;
38118d2f55e7SToby Isaac     if (numFields) {
38128d2f55e7SToby Isaac       PetscInt f;
38138d2f55e7SToby Isaac 
3814f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3815f30e825dSToby Isaac         PetscInt fDof;
3816f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3817f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
38188d2f55e7SToby Isaac       }
3819415ce65aSMatthew G. Knepley       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr);
38208d2f55e7SToby Isaac     }
38218d2f55e7SToby Isaac     else {
3822415ce65aSMatthew G. Knepley       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr);
3823f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
38248d2f55e7SToby Isaac     }
3825f30e825dSToby Isaac 
3826f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3827f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3828f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3829f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3830f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3831f30e825dSToby Isaac       const PetscInt *childIndices;
3832f30e825dSToby Isaac 
3833f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3834f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3835f30e825dSToby Isaac       childId = rootIndices[offset++];
3836f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3837f30e825dSToby Isaac       numIndices--;
3838f30e825dSToby Isaac 
3839f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3840f30e825dSToby Isaac         PetscInt i;
3841f30e825dSToby Isaac 
3842f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3843f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3844f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3845f30e825dSToby Isaac           if (rowIndex < 0) continue;
3846f30e825dSToby Isaac           if (colIndex < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unconstrained fine and constrained coarse");
3847a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3848f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
3849f30e825dSToby Isaac           }
3850f30e825dSToby Isaac           else {
3851f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3852f30e825dSToby Isaac           }
3853f30e825dSToby Isaac         }
3854f30e825dSToby Isaac       }
3855f30e825dSToby Isaac       else {
3856f30e825dSToby Isaac         PetscInt parentId, f, lim;
3857f30e825dSToby Isaac 
3858f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3859f30e825dSToby Isaac 
3860f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3861f30e825dSToby Isaac         offsets[0] = 0;
38628d2f55e7SToby Isaac         if (numFields) {
38638d2f55e7SToby Isaac           PetscInt f;
3864f30e825dSToby Isaac 
38658d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3866f30e825dSToby Isaac             PetscInt fDof;
3867f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
3868f30e825dSToby Isaac 
3869f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
38708d2f55e7SToby Isaac           }
38718d2f55e7SToby Isaac         }
38728d2f55e7SToby Isaac         else {
3873f30e825dSToby Isaac           PetscInt cDof;
3874f30e825dSToby Isaac 
3875f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
3876f30e825dSToby Isaac           offsets[1] = cDof;
3877f30e825dSToby Isaac         }
3878f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3879f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3880f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3881f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3882f30e825dSToby Isaac 
3883f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3884f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3885f30e825dSToby Isaac 
3886f30e825dSToby Isaac             if (colIndex < 0) continue;
3887f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3888f30e825dSToby Isaac               numD++;
3889f30e825dSToby Isaac             }
3890f30e825dSToby Isaac             else {
3891f30e825dSToby Isaac               numO++;
3892f30e825dSToby Isaac             }
3893f30e825dSToby Isaac           }
3894f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3895f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3896f30e825dSToby Isaac 
3897f30e825dSToby Isaac             if (rowIndex < 0) continue;
3898f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3899f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
39008d2f55e7SToby Isaac           }
39018d2f55e7SToby Isaac         }
39028d2f55e7SToby Isaac       }
3903f30e825dSToby Isaac     }
3904f30e825dSToby Isaac   }
3905f30e825dSToby Isaac   /* preallocate */
3906f30e825dSToby Isaac   ierr = MatXAIJSetPreallocation(mat,1,nnzD,nnzO,NULL,NULL);CHKERRQ(ierr);
3907f30e825dSToby Isaac   ierr = PetscFree2(nnzD,nnzO);CHKERRQ(ierr);
3908f30e825dSToby Isaac   /* insert values */
3909f30e825dSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
3910f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3911f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3912f30e825dSToby Isaac 
3913f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3914f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3915f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3916f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
3917f30e825dSToby Isaac 
3918f30e825dSToby Isaac     rowOffsets[0] = 0;
3919f30e825dSToby Isaac     offsetsCopy[0] = 0;
39208d2f55e7SToby Isaac     if (numFields) {
39218d2f55e7SToby Isaac       PetscInt f;
3922f30e825dSToby Isaac 
39238d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3924f30e825dSToby Isaac         PetscInt fDof;
3925f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3926f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3927f30e825dSToby Isaac       }
3928415ce65aSMatthew G. Knepley       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr);
3929f30e825dSToby Isaac     }
3930f30e825dSToby Isaac     else {
3931415ce65aSMatthew G. Knepley       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr);
3932f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3933f30e825dSToby Isaac     }
3934f30e825dSToby Isaac 
3935f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3936f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3937f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3938f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3939f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3940f30e825dSToby Isaac       const PetscInt *childIndices;
3941f30e825dSToby Isaac 
3942f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3943f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3944f30e825dSToby Isaac       childId = rootIndices[offset++];
3945f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3946f30e825dSToby Isaac       numIndices--;
3947f30e825dSToby Isaac 
3948f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3949f30e825dSToby Isaac         PetscInt i;
3950f30e825dSToby Isaac 
3951f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3952f30e825dSToby Isaac           ierr = MatSetValue(mat,parentIndices[i],childIndices[i],1.,INSERT_VALUES);CHKERRQ(ierr);
39538d2f55e7SToby Isaac         }
39548d2f55e7SToby Isaac       }
39558d2f55e7SToby Isaac       else {
3956f30e825dSToby Isaac         PetscInt parentId, f, lim;
39578d2f55e7SToby Isaac 
3958f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3959f30e825dSToby Isaac 
3960f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3961f30e825dSToby Isaac         offsets[0] = 0;
39628d2f55e7SToby Isaac         if (numFields) {
3963f30e825dSToby Isaac           PetscInt f;
39648d2f55e7SToby Isaac 
3965f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3966f30e825dSToby Isaac             PetscInt fDof;
3967f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
3968f30e825dSToby Isaac 
3969f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
39708d2f55e7SToby Isaac           }
39718d2f55e7SToby Isaac         }
39728d2f55e7SToby Isaac         else {
3973f30e825dSToby Isaac           PetscInt cDof;
3974f30e825dSToby Isaac 
3975f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
3976f30e825dSToby Isaac           offsets[1] = cDof;
39778d2f55e7SToby Isaac         }
3978f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3979f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3980f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3981f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3982f30e825dSToby Isaac 
3983f30e825dSToby Isaac           ierr = MatSetValues(mat,rowOffsets[f+1]-rowOffsets[f],rowIndices,offsets[f+1]-offsets[f],colIndices,childMat,INSERT_VALUES);CHKERRQ(ierr);
39848d2f55e7SToby Isaac         }
39858d2f55e7SToby Isaac       }
39868d2f55e7SToby Isaac     }
39878d2f55e7SToby Isaac   }
3988ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
3989ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
3990ec92bd66SToby Isaac   ierr = PetscFree(parentIndices);CHKERRQ(ierr);
3991f30e825dSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
3992f30e825dSToby Isaac   ierr = PetscFree(rootIndices);CHKERRQ(ierr);
3993f30e825dSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
3994f30e825dSToby Isaac 
39958d2f55e7SToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
39968d2f55e7SToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
3997154bca37SToby Isaac   PetscFunctionReturn(0);
3998154bca37SToby Isaac }
399938fc2455SToby Isaac 
400038fc2455SToby Isaac #undef __FUNCT__
4001ebf164c7SToby Isaac #define __FUNCT__ "DMPlexTransferVecTree_Interpolate"
4002*0eb7e1eaSToby Isaac static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
4003ebf164c7SToby Isaac {
40044833aeb0SToby Isaac   PetscDS           ds;
400562095d54SToby Isaac   PetscSF           coarseToFineEmbedded;
400662095d54SToby Isaac   PetscSection      globalCoarse, globalFine;
400762095d54SToby Isaac   PetscSection      localCoarse, localFine;
400862095d54SToby Isaac   PetscSection      aSec, cSec;
400962095d54SToby Isaac   PetscSection      rootValuesSec;
401062095d54SToby Isaac   PetscSection      leafValuesSec;
401162095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
401262095d54SToby Isaac   IS                aIS;
401362095d54SToby Isaac   const PetscInt    *anchors;
401462095d54SToby Isaac   Mat               cMat;
401562095d54SToby Isaac   PetscInt          numFields;
4016*0eb7e1eaSToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
401762095d54SToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
401862095d54SToby Isaac   PetscInt          *maxChildIds;
401962095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
4020*0eb7e1eaSToby Isaac   PetscFV           fv = NULL;
4021*0eb7e1eaSToby Isaac   PetscInt          dim, numFVcomps = -1, fvField = -1;
4022*0eb7e1eaSToby Isaac   DM                cellDM = NULL, gradDM = NULL;
4023*0eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
4024*0eb7e1eaSToby Isaac   const PetscScalar *gradArray = NULL;
402562095d54SToby Isaac   PetscErrorCode    ierr;
402662095d54SToby Isaac 
4027ebf164c7SToby Isaac   PetscFunctionBegin;
402862095d54SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
4029*0eb7e1eaSToby Isaac   ierr = DMPlexGetHeightStratum(coarse,0,&cellStart,&cellEnd);CHKERRQ(ierr);
403062095d54SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
403162095d54SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
4032*0eb7e1eaSToby Isaac   ierr = DMGetCoordinateDim(coarse,&dim);CHKERRQ(ierr);
403362095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
4034e4a60869SToby Isaac     PetscInt       nleaves, l;
4035e4a60869SToby Isaac     const PetscInt *leaves;
403662095d54SToby Isaac     PetscInt       dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
403762095d54SToby Isaac 
4038e4a60869SToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
4039e4a60869SToby Isaac 
4040e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
4041e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
4042e4a60869SToby Isaac 
404362095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
404462095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
404562095d54SToby Isaac       if ((dof - cdof) > 0) {
404662095d54SToby Isaac         numPointsWithDofs++;
404762095d54SToby Isaac       }
404862095d54SToby Isaac     }
404962095d54SToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
40504833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
4051e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
4052e4a60869SToby Isaac 
405362095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
405462095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
405562095d54SToby Isaac       if ((dof - cdof) > 0) {
4056e4a60869SToby Isaac         pointsWithDofs[offset++] = l;
405762095d54SToby Isaac       }
405862095d54SToby Isaac     }
405962095d54SToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
406062095d54SToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
406162095d54SToby Isaac   }
406262095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
406362095d54SToby Isaac   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
406462095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) {
406562095d54SToby Isaac     maxChildIds[p - pStartC] = -2;
406662095d54SToby Isaac   }
406762095d54SToby Isaac   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
406862095d54SToby Isaac   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
406962095d54SToby Isaac 
407062095d54SToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
407162095d54SToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
407262095d54SToby Isaac 
407362095d54SToby Isaac   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
407462095d54SToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
407562095d54SToby Isaac   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
407662095d54SToby Isaac 
407762095d54SToby Isaac   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
407862095d54SToby Isaac   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
407962095d54SToby Isaac 
408062095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
408162095d54SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootValuesSec);CHKERRQ(ierr);
408262095d54SToby Isaac   ierr = PetscSectionSetChart(rootValuesSec,pStartC,pEndC);CHKERRQ(ierr);
408362095d54SToby Isaac   ierr = PetscSectionGetNumFields(globalCoarse,&numFields);CHKERRQ(ierr);
408462095d54SToby Isaac   {
408562095d54SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
408662095d54SToby Isaac     ierr = PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO);CHKERRQ(ierr);
408762095d54SToby Isaac   }
4088*0eb7e1eaSToby Isaac   if (grad) {
4089*0eb7e1eaSToby Isaac     PetscInt i;
4090*0eb7e1eaSToby Isaac 
4091*0eb7e1eaSToby Isaac     ierr = VecGetDM(cellGeom,&cellDM);CHKERRQ(ierr);
4092*0eb7e1eaSToby Isaac     ierr = VecGetArrayRead(cellGeom,&cellGeomArray);CHKERRQ(ierr);
4093*0eb7e1eaSToby Isaac     ierr = VecGetDM(grad,&gradDM);CHKERRQ(ierr);
4094*0eb7e1eaSToby Isaac     ierr = VecGetArrayRead(grad,&gradArray);CHKERRQ(ierr);
4095*0eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1,numFields); i++) {
4096*0eb7e1eaSToby Isaac       PetscObject  obj;
4097*0eb7e1eaSToby Isaac       PetscClassId id;
4098*0eb7e1eaSToby Isaac 
4099*0eb7e1eaSToby Isaac       ierr = DMGetField(coarse, i, &obj);CHKERRQ(ierr);
4100*0eb7e1eaSToby Isaac       ierr = PetscObjectGetClassId(obj,&id);CHKERRQ(ierr);
4101*0eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
4102*0eb7e1eaSToby Isaac         fv      = (PetscFV) obj;
4103*0eb7e1eaSToby Isaac         ierr    = PetscFVGetNumComponents(fv,&numFVcomps);CHKERRQ(ierr);
4104*0eb7e1eaSToby Isaac         fvField = i;
4105*0eb7e1eaSToby Isaac         break;
4106*0eb7e1eaSToby Isaac       }
4107*0eb7e1eaSToby Isaac     }
4108*0eb7e1eaSToby Isaac   }
410962095d54SToby Isaac 
411062095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
411162095d54SToby Isaac     PetscInt dof;
411262095d54SToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
411362095d54SToby Isaac     PetscInt numValues      = 0;
411462095d54SToby Isaac 
411562095d54SToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
411662095d54SToby Isaac     if (dof < 0) {
411762095d54SToby Isaac       dof = -(dof + 1);
411862095d54SToby Isaac     }
411962095d54SToby Isaac     offsets[0]    = 0;
412062095d54SToby Isaac     newOffsets[0] = 0;
412162095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
412262095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
412362095d54SToby Isaac 
41244833aeb0SToby Isaac       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
412562095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
412662095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
412762095d54SToby Isaac 
412862095d54SToby Isaac         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
412962095d54SToby Isaac         numValues += clDof;
413062095d54SToby Isaac       }
41314833aeb0SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
413262095d54SToby Isaac     }
413362095d54SToby Isaac     else if (maxChildId == -1) {
413462095d54SToby Isaac       ierr = PetscSectionGetDof(localCoarse,p,&numValues);CHKERRQ(ierr);
413562095d54SToby Isaac     }
413662095d54SToby Isaac     /* we will pack the column indices with the field offsets */
4137*0eb7e1eaSToby Isaac     if (maxChildId >= -1 && grad && p >= cellStart && p < cellEnd) {
4138*0eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
4139*0eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
4140*0eb7e1eaSToby Isaac     }
414162095d54SToby Isaac     ierr = PetscSectionSetDof(rootValuesSec,p,numValues);CHKERRQ(ierr);
414262095d54SToby Isaac   }
414362095d54SToby Isaac   ierr = PetscSectionSetUp(rootValuesSec);CHKERRQ(ierr);
414462095d54SToby Isaac   {
414562095d54SToby Isaac     PetscInt          numRootValues;
414662095d54SToby Isaac     const PetscScalar *coarseArray;
414762095d54SToby Isaac 
414862095d54SToby Isaac     ierr = PetscSectionGetStorageSize(rootValuesSec,&numRootValues);CHKERRQ(ierr);
414962095d54SToby Isaac     ierr = PetscMalloc1(numRootValues,&rootValues);CHKERRQ(ierr);
415062095d54SToby Isaac     ierr = VecGetArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr);
415162095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
415262095d54SToby Isaac       PetscInt    numValues;
415362095d54SToby Isaac       PetscInt    pValOff;
415462095d54SToby Isaac       PetscScalar *pVal;
415562095d54SToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
415662095d54SToby Isaac 
415762095d54SToby Isaac       ierr = PetscSectionGetDof(rootValuesSec,p,&numValues);CHKERRQ(ierr);
415862095d54SToby Isaac       if (!numValues) {
415962095d54SToby Isaac         continue;
416062095d54SToby Isaac       }
416162095d54SToby Isaac       ierr = PetscSectionGetOffset(rootValuesSec,p,&pValOff);CHKERRQ(ierr);
416262095d54SToby Isaac       pVal = &(rootValues[pValOff]);
416362095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
4164*0eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
4165*0eb7e1eaSToby Isaac         ierr = DMPlexVecGetClosure(coarse,NULL,vecCoarseLocal,p,&closureSize,&pVal);CHKERRQ(ierr);
416662095d54SToby Isaac       }
416762095d54SToby Isaac       else if (maxChildId == -1) {
416862095d54SToby Isaac         PetscInt lDof, lOff, i;
416962095d54SToby Isaac 
417062095d54SToby Isaac         ierr = PetscSectionGetDof(localCoarse,p,&lDof);CHKERRQ(ierr);
417162095d54SToby Isaac         ierr = PetscSectionGetOffset(localCoarse,p,&lOff);CHKERRQ(ierr);
417262095d54SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
417362095d54SToby Isaac       }
4174*0eb7e1eaSToby Isaac       if (grad && p >= cellStart && p < cellEnd) {
4175*0eb7e1eaSToby Isaac         const PetscFVCellGeom *cg;
4176*0eb7e1eaSToby Isaac         PetscScalar *gradVals;
4177*0eb7e1eaSToby Isaac         PetscInt i;
4178*0eb7e1eaSToby Isaac 
4179*0eb7e1eaSToby Isaac         pVal += (numValues - dim * (1 + numFVcomps));
4180*0eb7e1eaSToby Isaac 
4181*0eb7e1eaSToby Isaac         ierr = DMPlexPointLocalRead(cellDM,p,cellGeomArray,&cg);CHKERRQ(ierr);
4182*0eb7e1eaSToby Isaac         for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
4183*0eb7e1eaSToby Isaac         pVal += dim;
4184*0eb7e1eaSToby Isaac         ierr = DMPlexPointGlobalRead(gradDM,p,gradArray,&gradVals);CHKERRQ(ierr);
4185*0eb7e1eaSToby Isaac         for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
4186*0eb7e1eaSToby Isaac       }
418762095d54SToby Isaac     }
418862095d54SToby Isaac     ierr = VecRestoreArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr);
418962095d54SToby Isaac     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
419062095d54SToby Isaac   }
419162095d54SToby Isaac   {
419262095d54SToby Isaac     PetscSF  valuesSF;
419362095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
419462095d54SToby Isaac 
419562095d54SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafValuesSec);CHKERRQ(ierr);
419662095d54SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootValuesSec,&remoteOffsetsValues,leafValuesSec);CHKERRQ(ierr);
419762095d54SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootValuesSec,remoteOffsetsValues,leafValuesSec,&valuesSF);CHKERRQ(ierr);
419862095d54SToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
419962095d54SToby Isaac     ierr = PetscFree(remoteOffsetsValues);CHKERRQ(ierr);
420062095d54SToby Isaac     ierr = PetscSectionGetStorageSize(leafValuesSec,&numLeafValues);CHKERRQ(ierr);
420162095d54SToby Isaac     ierr = PetscMalloc1(numLeafValues,&leafValues);CHKERRQ(ierr);
420262095d54SToby Isaac     ierr = PetscSFBcastBegin(valuesSF,MPIU_SCALAR,rootValues,leafValues);CHKERRQ(ierr);
420362095d54SToby Isaac     ierr = PetscSFBcastEnd(valuesSF,MPIU_SCALAR,rootValues,leafValues);CHKERRQ(ierr);
420462095d54SToby Isaac     ierr = PetscSFDestroy(&valuesSF);CHKERRQ(ierr);
420562095d54SToby Isaac     ierr = PetscFree(rootValues);CHKERRQ(ierr);
420662095d54SToby Isaac     ierr = PetscSectionDestroy(&rootValuesSec);CHKERRQ(ierr);
420762095d54SToby Isaac   }
420862095d54SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
420962095d54SToby Isaac   {
421062095d54SToby Isaac     PetscInt    maxDof;
421162095d54SToby Isaac     PetscInt    *rowIndices;
421262095d54SToby Isaac     DM           refTree;
421362095d54SToby Isaac     PetscInt     **refPointFieldN;
421462095d54SToby Isaac     PetscScalar  ***refPointFieldMats;
421562095d54SToby Isaac     PetscSection refConSec, refAnSec;
4216*0eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,leafStart,leafEnd;
421762095d54SToby Isaac     PetscScalar  *pointWork;
421862095d54SToby Isaac 
421962095d54SToby Isaac     ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr);
422062095d54SToby Isaac     ierr = DMGetWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
422162095d54SToby Isaac     ierr = DMGetWorkArray(fine,maxDof,PETSC_SCALAR,&pointWork);CHKERRQ(ierr);
422262095d54SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
42234833aeb0SToby Isaac     ierr = DMGetDS(fine,&ds);CHKERRQ(ierr);
42244833aeb0SToby Isaac     ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
422562095d54SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
422662095d54SToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
422762095d54SToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
422862095d54SToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
4229*0eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafValuesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
4230*0eb7e1eaSToby Isaac     ierr = DMPlexGetHeightStratum(fine,0,&cellStart,&cellEnd);CHKERRQ(ierr);
4231*0eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
423262095d54SToby Isaac       PetscInt          gDof, gcDof, gOff, lDof;
423362095d54SToby Isaac       PetscInt          numValues, pValOff;
423462095d54SToby Isaac       PetscInt          childId;
423562095d54SToby Isaac       const PetscScalar *pVal;
4236*0eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
423762095d54SToby Isaac 
423862095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
423962095d54SToby Isaac       ierr = PetscSectionGetDof(localFine,p,&lDof);CHKERRQ(ierr);
424062095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
424162095d54SToby Isaac       if ((gDof - gcDof) <= 0) {
424262095d54SToby Isaac         continue;
424362095d54SToby Isaac       }
424462095d54SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
424562095d54SToby Isaac       ierr = PetscSectionGetDof(leafValuesSec,p,&numValues);CHKERRQ(ierr);
424662095d54SToby Isaac       if (!numValues) continue;
424762095d54SToby Isaac       ierr = PetscSectionGetOffset(leafValuesSec,p,&pValOff);CHKERRQ(ierr);
424862095d54SToby Isaac       pVal = &leafValues[pValOff];
424962095d54SToby Isaac       offsets[0]        = 0;
425062095d54SToby Isaac       offsetsCopy[0]    = 0;
425162095d54SToby Isaac       newOffsets[0]     = 0;
425262095d54SToby Isaac       newOffsetsCopy[0] = 0;
42534833aeb0SToby Isaac       childId           = cids[p - pStartF];
4254*0eb7e1eaSToby Isaac       if (grad && p >= cellStart && p < cellEnd) {
4255*0eb7e1eaSToby Isaac         numValues -= (dim * (1 + numFVcomps));
4256*0eb7e1eaSToby Isaac         fvGradData = &pVal[numValues];
4257*0eb7e1eaSToby Isaac       }
425862095d54SToby Isaac       if (numFields) {
425962095d54SToby Isaac         PetscInt f;
426062095d54SToby Isaac         for (f = 0; f < numFields; f++) {
426162095d54SToby Isaac           PetscInt rowDof;
426262095d54SToby Isaac 
426362095d54SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
426462095d54SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
426562095d54SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
426662095d54SToby Isaac           /* TODO: closure indices */
42679f4e70e1SToby Isaac           newOffsets[f + 1]     = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
426862095d54SToby Isaac         }
4269e9e67eccSMatthew G. Knepley         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr);
427062095d54SToby Isaac       }
427162095d54SToby Isaac       else {
42724833aeb0SToby Isaac         offsets[0]    = 0;
42734833aeb0SToby Isaac         offsets[1]    = lDof;
42744833aeb0SToby Isaac         newOffsets[0] = 0;
42754833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
4276e9e67eccSMatthew G. Knepley         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr);
427762095d54SToby Isaac       }
427862095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
427962095d54SToby Isaac         ierr = VecSetValues(vecFine,numValues,rowIndices,pVal,ADD_VALUES);CHKERRQ(ierr);
428062095d54SToby Isaac       } else {
428162095d54SToby Isaac         PetscInt f;
428262095d54SToby Isaac 
428362095d54SToby Isaac         for (f = 0; f < PetscMax(1,numFields); f++) {
428462095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
428562095d54SToby Isaac           PetscInt numRows = offsets[f+1] - offsets[f];
428662095d54SToby Isaac           PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
428762095d54SToby Isaac           const PetscScalar *cVal = &pVal[newOffsets[f]];
428862095d54SToby Isaac           PetscScalar *rVal = &pointWork[offsets[f]];
428962095d54SToby Isaac           PetscInt i, j;
429062095d54SToby Isaac 
429162095d54SToby Isaac           for (i = 0; i < numRows; i++) {
429262095d54SToby Isaac             PetscScalar val = 0.;
429362095d54SToby Isaac             for (j = 0; j < numCols; j++) {
429462095d54SToby Isaac               val += childMat[i * numCols + j] * cVal[j];
429562095d54SToby Isaac             }
429662095d54SToby Isaac             rVal[i] = val;
429762095d54SToby Isaac           }
4298*0eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
4299*0eb7e1eaSToby Isaac             PetscReal   centroid[3];
4300*0eb7e1eaSToby Isaac             PetscScalar diff[3];
4301*0eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
4302*0eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
4303*0eb7e1eaSToby Isaac 
4304*0eb7e1eaSToby Isaac             ierr = DMPlexComputeCellGeometryFVM(fine,p,NULL,centroid,NULL);CHKERRQ(ierr);
4305*0eb7e1eaSToby Isaac             for (i = 0; i < dim; i++) {
4306*0eb7e1eaSToby Isaac               diff[i] = centroid[i] - parentCentroid[i];
4307*0eb7e1eaSToby Isaac             }
4308*0eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
4309*0eb7e1eaSToby Isaac               PetscScalar val = 0.;
4310*0eb7e1eaSToby Isaac 
4311*0eb7e1eaSToby Isaac               for (j = 0; j < 3; j++) {
4312*0eb7e1eaSToby Isaac                 val += gradient[dim * i + j] * diff[j];
4313*0eb7e1eaSToby Isaac               }
4314*0eb7e1eaSToby Isaac               rVal[i] += val;
4315*0eb7e1eaSToby Isaac             }
4316*0eb7e1eaSToby Isaac           }
431762095d54SToby Isaac           ierr = VecSetValues(vecFine,numRows,&rowIndices[offsets[f]],rVal,ADD_VALUES);CHKERRQ(ierr);
431862095d54SToby Isaac         }
431962095d54SToby Isaac       }
432062095d54SToby Isaac     }
432162095d54SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
432262095d54SToby Isaac     ierr = DMRestoreWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
432362095d54SToby Isaac     ierr = DMRestoreWorkArray(fine,maxDof,PETSC_SCALAR,&pointWork);CHKERRQ(ierr);
432462095d54SToby Isaac   }
43254fe3dfefSToby Isaac   ierr = PetscFree(leafValues);CHKERRQ(ierr);
432662095d54SToby Isaac   ierr = PetscSectionDestroy(&leafValuesSec);CHKERRQ(ierr);
432762095d54SToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
432862095d54SToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
4329ebf164c7SToby Isaac   PetscFunctionReturn(0);
4330ebf164c7SToby Isaac }
4331ebf164c7SToby Isaac 
4332ebf164c7SToby Isaac #undef __FUNCT__
4333ebf164c7SToby Isaac #define __FUNCT__ "DMPlexTransferVecTree_Inject"
4334ebf164c7SToby Isaac static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4335ebf164c7SToby Isaac {
43364833aeb0SToby Isaac   PetscDS        ds;
4337c921d74cSToby Isaac   DM             refTree;
4338c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4339c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4340c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4341c921d74cSToby Isaac   PetscSection   cSecRef;
4342c921d74cSToby Isaac   PetscInt       *parentIndices, pRefStart, pRefEnd;
4343d3bc4906SToby Isaac   PetscScalar    *rootValues, *parentValues;
4344c921d74cSToby Isaac   Mat            injRef;
4345c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4346c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4347c921d74cSToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
4348c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4349c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4350c921d74cSToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4351c921d74cSToby Isaac   PetscErrorCode ierr;
4352c921d74cSToby Isaac 
4353ebf164c7SToby Isaac   PetscFunctionBegin;
4354c921d74cSToby Isaac 
4355c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
4356c921d74cSToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
43574833aeb0SToby Isaac   ierr = DMGetDS(coarse,&ds);CHKERRQ(ierr);
43584833aeb0SToby Isaac   ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
4359c921d74cSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
4360c921d74cSToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
4361c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
4362c921d74cSToby Isaac 
4363c921d74cSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
4364c921d74cSToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
4365c921d74cSToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
4366c921d74cSToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
4367c921d74cSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
4368c921d74cSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
4369c921d74cSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
4370c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
4371c921d74cSToby Isaac   {
4372c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
4373c921d74cSToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
4374c921d74cSToby Isaac   }
4375c921d74cSToby Isaac 
4376c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,cids,vecFine,numFields,offsets,&multiRootSec,&rootIndicesSec,NULL,&rootValues);CHKERRQ(ierr);
4377c921d74cSToby Isaac 
4378d3bc4906SToby Isaac   ierr = PetscMalloc2(maxDof,&parentIndices,maxDof,&parentValues);CHKERRQ(ierr);
4379c921d74cSToby Isaac 
4380c921d74cSToby Isaac   /* count indices */
438162095d54SToby Isaac   ierr = VecGetLayout(vecFine,&colMap);CHKERRQ(ierr);
438262095d54SToby Isaac   ierr = VecGetLayout(vecCoarse,&rowMap);CHKERRQ(ierr);
4383c921d74cSToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
4384c921d74cSToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
4385c921d74cSToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
4386c921d74cSToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
4387c921d74cSToby Isaac   /* insert values */
4388c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4389c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4390c921d74cSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
4391c921d74cSToby Isaac 
4392c921d74cSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
4393c921d74cSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
4394c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
4395c921d74cSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
4396c921d74cSToby Isaac 
4397c921d74cSToby Isaac     rowOffsets[0] = 0;
4398c921d74cSToby Isaac     offsetsCopy[0] = 0;
4399c921d74cSToby Isaac     if (numFields) {
4400c921d74cSToby Isaac       PetscInt f;
4401c921d74cSToby Isaac 
4402c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4403c921d74cSToby Isaac         PetscInt fDof;
4404c921d74cSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
4405c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4406c921d74cSToby Isaac       }
4407e9e67eccSMatthew G. Knepley       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr);
4408c921d74cSToby Isaac     }
4409c921d74cSToby Isaac     else {
4410e9e67eccSMatthew G. Knepley       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr);
4411c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4412c921d74cSToby Isaac     }
4413c921d74cSToby Isaac 
4414c921d74cSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
4415c921d74cSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
4416c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
4417c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4418c921d74cSToby Isaac       PetscInt numIndices, childId, offset;
4419c921d74cSToby Isaac       const PetscScalar *childValues;
4420c921d74cSToby Isaac 
4421c921d74cSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
4422c921d74cSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
4423c921d74cSToby Isaac       childId = (PetscInt) PetscRealPart(rootValues[offset++]);
4424c921d74cSToby Isaac       childValues = &rootValues[offset];
4425c921d74cSToby Isaac       numIndices--;
4426c921d74cSToby Isaac 
4427c921d74cSToby Isaac       if (childId == -2) { /* skip */
4428c921d74cSToby Isaac         continue;
4429c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
4430d3bc4906SToby Isaac         ierr = VecSetValues(vecCoarse,numIndices,parentIndices,childValues,ADD_VALUES);CHKERRQ(ierr);
4431c921d74cSToby Isaac       } else {
4432d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4433d3bc4906SToby Isaac 
4434d3bc4906SToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
4435d3bc4906SToby Isaac 
4436d3bc4906SToby Isaac         lim = PetscMax(1,numFields);
4437d3bc4906SToby Isaac         offsets[0] = 0;
4438d3bc4906SToby Isaac         if (numFields) {
4439d3bc4906SToby Isaac           PetscInt f;
4440d3bc4906SToby Isaac 
4441d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4442d3bc4906SToby Isaac             PetscInt fDof;
4443d3bc4906SToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
4444d3bc4906SToby Isaac 
4445d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4446d3bc4906SToby Isaac           }
4447d3bc4906SToby Isaac         }
4448d3bc4906SToby Isaac         else {
4449d3bc4906SToby Isaac           PetscInt cDof;
4450d3bc4906SToby Isaac 
4451d3bc4906SToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
4452d3bc4906SToby Isaac           offsets[1] = cDof;
4453d3bc4906SToby Isaac         }
4454d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4455d3bc4906SToby Isaac           PetscScalar       *childMat   = &childrenMats[childId - pRefStart][f][0];
4456d3bc4906SToby Isaac           PetscInt          *rowIndices = &parentIndices[rowOffsets[f]];
4457d3bc4906SToby Isaac           PetscInt          m           = rowOffsets[f+1]-rowOffsets[f];
4458d3bc4906SToby Isaac           PetscInt          n           = offsets[f+1]-offsets[f];
4459d3bc4906SToby Isaac           PetscInt          i, j;
4460d3bc4906SToby Isaac           const PetscScalar *colValues  = &childValues[offsets[f]];
4461d3bc4906SToby Isaac 
4462d3bc4906SToby Isaac           for (i = 0; i < m; i++) {
4463d3bc4906SToby Isaac             PetscScalar val = 0.;
4464d3bc4906SToby Isaac             for (j = 0; j < n; j++) {
4465d3bc4906SToby Isaac               val += childMat[n * i + j] * colValues[j];
4466d3bc4906SToby Isaac             }
4467d3bc4906SToby Isaac             parentValues[i] = val;
4468d3bc4906SToby Isaac           }
4469d3bc4906SToby Isaac           ierr = VecSetValues(vecCoarse,m,rowIndices,parentValues,ADD_VALUES);CHKERRQ(ierr);
4470d3bc4906SToby Isaac         }
4471c921d74cSToby Isaac       }
4472c921d74cSToby Isaac     }
4473c921d74cSToby Isaac   }
4474c921d74cSToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
4475c921d74cSToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
4476d3bc4906SToby Isaac   ierr = PetscFree2(parentIndices,parentValues);CHKERRQ(ierr);
4477c921d74cSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4478c921d74cSToby Isaac   ierr = PetscFree(rootValues);CHKERRQ(ierr);
4479c921d74cSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
4480ebf164c7SToby Isaac   PetscFunctionReturn(0);
4481ebf164c7SToby Isaac }
4482ebf164c7SToby Isaac 
4483ebf164c7SToby Isaac #undef __FUNCT__
448438fc2455SToby Isaac #define __FUNCT__ "DMPlexTransferVecTree"
4485*0eb7e1eaSToby Isaac PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfIn, PetscSF sfOut, PetscInt *cidsIn, PetscInt *cidsOut, PetscBool useBCs, PetscReal time)
448638fc2455SToby Isaac {
4487ebf164c7SToby Isaac   PetscErrorCode ierr;
4488ebf164c7SToby Isaac 
448938fc2455SToby Isaac   PetscFunctionBegin;
4490ebf164c7SToby Isaac   if (sfIn) {
4491fbfa57b9SToby Isaac     Vec vecInLocal;
4492*0eb7e1eaSToby Isaac     DM  dmGrad = NULL;
4493*0eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4494fbfa57b9SToby Isaac 
4495fbfa57b9SToby Isaac     ierr = DMGetLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
4496fbfa57b9SToby Isaac     ierr = VecSet(vecInLocal,0.0);CHKERRQ(ierr);
4497*0eb7e1eaSToby Isaac     {
4498*0eb7e1eaSToby Isaac       PetscInt  numFields, i;
4499*0eb7e1eaSToby Isaac 
4500*0eb7e1eaSToby Isaac       ierr = DMGetNumFields(dmIn, &numFields);CHKERRQ(ierr);
4501*0eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
4502*0eb7e1eaSToby Isaac         PetscObject  obj;
4503*0eb7e1eaSToby Isaac         PetscClassId classid;
4504*0eb7e1eaSToby Isaac 
4505*0eb7e1eaSToby Isaac         ierr = DMGetField(dmIn, i, &obj);CHKERRQ(ierr);
4506*0eb7e1eaSToby Isaac         ierr = PetscObjectGetClassId(obj, &classid);CHKERRQ(ierr);
4507*0eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
4508*0eb7e1eaSToby Isaac           ierr = DMPlexGetDataFVM(dmIn,(PetscFV)obj,&cellGeom,&faceGeom,&dmGrad);CHKERRQ(ierr);
4509*0eb7e1eaSToby Isaac           break;
4510*0eb7e1eaSToby Isaac         }
4511*0eb7e1eaSToby Isaac       }
4512*0eb7e1eaSToby Isaac     }
4513*0eb7e1eaSToby Isaac     if (useBCs) {
4514*0eb7e1eaSToby Isaac       ierr = DMPlexInsertBoundaryValues(dmIn,PETSC_TRUE,vecInLocal,time,faceGeom,cellGeom,NULL);CHKERRQ(ierr);
4515*0eb7e1eaSToby Isaac     }
4516fbfa57b9SToby Isaac     ierr = DMGlobalToLocalBegin(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
4517fbfa57b9SToby Isaac     ierr = DMGlobalToLocalEnd(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
4518*0eb7e1eaSToby Isaac     if (dmGrad) {
4519*0eb7e1eaSToby Isaac       ierr = DMGetGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
4520*0eb7e1eaSToby Isaac       ierr = DMPlexReconstructGradientsFVM(dmIn,vecInLocal,grad);CHKERRQ(ierr);
4521*0eb7e1eaSToby Isaac     }
4522*0eb7e1eaSToby Isaac     ierr = DMPlexTransferVecTree_Interpolate(dmIn,vecInLocal,dmOut,vecOut,sfIn,cidsIn,grad,cellGeom);CHKERRQ(ierr);
4523fbfa57b9SToby Isaac     ierr = DMRestoreLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
4524*0eb7e1eaSToby Isaac     if (dmGrad) {
4525*0eb7e1eaSToby Isaac       ierr = DMRestoreGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
4526*0eb7e1eaSToby Isaac     }
4527ebf164c7SToby Isaac   }
4528ebf164c7SToby Isaac   if (sfOut) {
4529ebf164c7SToby Isaac     ierr = DMPlexTransferVecTree_Inject(dmIn,vecIn,dmOut,vecOut,sfOut,cidsOut);CHKERRQ(ierr);
4530ebf164c7SToby Isaac   }
453138fc2455SToby Isaac   PetscFunctionReturn(0);
453238fc2455SToby Isaac }
4533