xref: /petsc/src/dm/impls/plex/plextree.c (revision 157782e238536ac400a6be1af1998aaf3bab9b86)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2af0996ceSBarry Smith #include <petsc/private/isimpl.h>
3af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
4d6a7ad0dSToby Isaac #include <petscsf.h>
50c37af3bSToby Isaac #include <petscds.h>
6d6a7ad0dSToby Isaac 
7d6a7ad0dSToby Isaac /** hierarchy routines */
8d6a7ad0dSToby Isaac 
9d6a7ad0dSToby Isaac /*@
10d6a7ad0dSToby Isaac   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
11d6a7ad0dSToby Isaac 
12d6a7ad0dSToby Isaac   Not collective
13d6a7ad0dSToby Isaac 
14d6a7ad0dSToby Isaac   Input Parameters:
15d6a7ad0dSToby Isaac + dm - The DMPlex object
16d6a7ad0dSToby Isaac - ref - The reference tree DMPlex object
17d6a7ad0dSToby Isaac 
180b7167a0SToby Isaac   Level: intermediate
19d6a7ad0dSToby Isaac 
20da43764aSToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexCreateDefaultReferenceTree()
21d6a7ad0dSToby Isaac @*/
22d6a7ad0dSToby Isaac PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
23d6a7ad0dSToby Isaac {
24d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
25d6a7ad0dSToby Isaac   PetscErrorCode  ierr;
26d6a7ad0dSToby Isaac 
27d6a7ad0dSToby Isaac   PetscFunctionBegin;
28d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2947a1df27SMatthew G. Knepley   if (ref) {PetscValidHeaderSpecific(ref, DM_CLASSID, 2);}
30d6a7ad0dSToby Isaac   ierr = PetscObjectReference((PetscObject)ref);CHKERRQ(ierr);
31d6a7ad0dSToby Isaac   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
32d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
33d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
34d6a7ad0dSToby Isaac }
35d6a7ad0dSToby Isaac 
36d6a7ad0dSToby Isaac /*@
37d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
38d6a7ad0dSToby Isaac 
39d6a7ad0dSToby Isaac   Not collective
40d6a7ad0dSToby Isaac 
41d6a7ad0dSToby Isaac   Input Parameters:
42d6a7ad0dSToby Isaac . dm - The DMPlex object
43d6a7ad0dSToby Isaac 
44d6a7ad0dSToby Isaac   Output Parameters
45d6a7ad0dSToby Isaac . ref - The reference tree DMPlex object
46d6a7ad0dSToby Isaac 
470b7167a0SToby Isaac   Level: intermediate
48d6a7ad0dSToby Isaac 
49da43764aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexCreateDefaultReferenceTree()
50d6a7ad0dSToby Isaac @*/
51d6a7ad0dSToby Isaac PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
52d6a7ad0dSToby Isaac {
53d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
54d6a7ad0dSToby Isaac 
55d6a7ad0dSToby Isaac   PetscFunctionBegin;
56d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
57d6a7ad0dSToby Isaac   PetscValidPointer(ref,2);
58d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
59d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
60d6a7ad0dSToby Isaac }
61d6a7ad0dSToby Isaac 
62dcbd3bf7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
63dcbd3bf7SToby Isaac {
64dcbd3bf7SToby Isaac   PetscInt       coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
65dcbd3bf7SToby Isaac   PetscErrorCode ierr;
66dcbd3bf7SToby Isaac 
67dcbd3bf7SToby Isaac   PetscFunctionBegin;
68dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
69dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
70dcbd3bf7SToby Isaac     if (childB) *childB = childA;
71dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
72dcbd3bf7SToby Isaac   }
73dcbd3bf7SToby Isaac   for (dim = 0; dim < 3; dim++) {
74dcbd3bf7SToby Isaac     ierr = DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd);CHKERRQ(ierr);
75dcbd3bf7SToby Isaac     if (parent >= dStart && parent <= dEnd) {
76dcbd3bf7SToby Isaac       break;
77dcbd3bf7SToby Isaac     }
78dcbd3bf7SToby Isaac   }
79dcbd3bf7SToby Isaac   if (dim > 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim);
80dcbd3bf7SToby Isaac   if (!dim) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
81dcbd3bf7SToby Isaac   if (childA < dStart || childA >= dEnd) {
82dcbd3bf7SToby Isaac     /* this is a lower-dimensional child: bootstrap */
83dcbd3bf7SToby Isaac     PetscInt size, i, sA = -1, sB, sOrientB, sConeSize;
84dcbd3bf7SToby Isaac     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
85dcbd3bf7SToby Isaac 
86dcbd3bf7SToby Isaac     ierr = DMPlexGetSupportSize(dm,childA,&size);CHKERRQ(ierr);
87dcbd3bf7SToby Isaac     ierr = DMPlexGetSupport(dm,childA,&supp);CHKERRQ(ierr);
88dcbd3bf7SToby Isaac 
89dcbd3bf7SToby Isaac     /* find a point sA in supp(childA) that has the same parent */
90dcbd3bf7SToby Isaac     for (i = 0; i < size; i++) {
91dcbd3bf7SToby Isaac       PetscInt sParent;
92dcbd3bf7SToby Isaac 
93dcbd3bf7SToby Isaac       sA   = supp[i];
94dcbd3bf7SToby Isaac       if (sA == parent) continue;
95dcbd3bf7SToby Isaac       ierr = DMPlexGetTreeParent(dm,sA,&sParent,NULL);CHKERRQ(ierr);
96dcbd3bf7SToby Isaac       if (sParent == parent) {
97dcbd3bf7SToby Isaac         break;
98dcbd3bf7SToby Isaac       }
99dcbd3bf7SToby Isaac     }
100dcbd3bf7SToby Isaac     if (i == size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
101dcbd3bf7SToby Isaac     /* find out which point sB is in an equivalent position to sA under
102dcbd3bf7SToby Isaac      * parentOrientB */
103dcbd3bf7SToby Isaac     ierr = DMPlexReferenceTreeGetChildSymmetry_Default(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB);CHKERRQ(ierr);
104dcbd3bf7SToby Isaac     ierr = DMPlexGetConeSize(dm,sA,&sConeSize);CHKERRQ(ierr);
105dcbd3bf7SToby Isaac     ierr = DMPlexGetCone(dm,sA,&coneA);CHKERRQ(ierr);
106dcbd3bf7SToby Isaac     ierr = DMPlexGetCone(dm,sB,&coneB);CHKERRQ(ierr);
107dcbd3bf7SToby Isaac     ierr = DMPlexGetConeOrientation(dm,sA,&oA);CHKERRQ(ierr);
108dcbd3bf7SToby Isaac     ierr = DMPlexGetConeOrientation(dm,sB,&oB);CHKERRQ(ierr);
109dcbd3bf7SToby Isaac     /* step through the cone of sA in natural order */
110dcbd3bf7SToby Isaac     for (i = 0; i < sConeSize; i++) {
111dcbd3bf7SToby Isaac       if (coneA[i] == childA) {
112dcbd3bf7SToby Isaac         /* if childA is at position i in coneA,
113dcbd3bf7SToby Isaac          * then we want the point that is at sOrientB*i in coneB */
114dcbd3bf7SToby Isaac         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
115dcbd3bf7SToby Isaac         if (childB) *childB = coneB[j];
116dcbd3bf7SToby Isaac         if (childOrientB) {
117dcbd3bf7SToby Isaac           PetscInt oBtrue;
118dcbd3bf7SToby Isaac 
119dcbd3bf7SToby Isaac           ierr          = DMPlexGetConeSize(dm,childA,&coneSize);CHKERRQ(ierr);
120dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
121dcbd3bf7SToby Isaac           if (coneSize != 0 && coneSize != 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
122dcbd3bf7SToby Isaac           /* we may have to flip an edge */
123dcbd3bf7SToby Isaac           oBtrue        = coneSize ? ((sOrientB >= 0) ? oB[j] : -(oB[j] + 2)) : 0;
124dcbd3bf7SToby Isaac           ABswap        = DihedralSwap(coneSize,oA[i],oBtrue);CHKERRQ(ierr);
125dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
126dcbd3bf7SToby Isaac         }
127dcbd3bf7SToby Isaac         break;
128dcbd3bf7SToby Isaac       }
129dcbd3bf7SToby Isaac     }
130dcbd3bf7SToby Isaac     if (i == sConeSize) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
131dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
132dcbd3bf7SToby Isaac   }
133dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
134dcbd3bf7SToby Isaac   ierr   = DMPlexGetConeSize(dm,parent,&coneSize);CHKERRQ(ierr);
135dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
136dcbd3bf7SToby Isaac   if (dim == 2) {
137dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
138dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
139dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
140dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
141dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
142dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
143947b95d8SBarry Smith   } else {
144dcbd3bf7SToby Isaac     ABswapVert = ABswap;
145dcbd3bf7SToby Isaac   }
146dcbd3bf7SToby Isaac   if (childB) {
147dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
148dcbd3bf7SToby Isaac     PetscInt p, posA = -1, numChildren, i;
149dcbd3bf7SToby Isaac     const PetscInt *children;
150dcbd3bf7SToby Isaac 
151dcbd3bf7SToby Isaac     /* count which position the child is in */
152dcbd3bf7SToby Isaac     ierr = DMPlexGetTreeChildren(dm,parent,&numChildren,&children);CHKERRQ(ierr);
153dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
154dcbd3bf7SToby Isaac       p = children[i];
155dcbd3bf7SToby Isaac       if (p == childA) {
156dcbd3bf7SToby Isaac         posA = i;
157dcbd3bf7SToby Isaac         break;
158dcbd3bf7SToby Isaac       }
159dcbd3bf7SToby Isaac     }
160dcbd3bf7SToby Isaac     if (posA >= coneSize) {
161dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
162dcbd3bf7SToby Isaac        * is invariant */
163dcbd3bf7SToby Isaac       if (dim != 2 || posA != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Expected a middle triangle, got something else");
164dcbd3bf7SToby Isaac       *childB = childA;
165dcbd3bf7SToby Isaac     }
166dcbd3bf7SToby Isaac     else {
167dcbd3bf7SToby Isaac       /* figure out position B by applying ABswapVert */
168dcbd3bf7SToby Isaac       PetscInt posB;
169dcbd3bf7SToby Isaac 
170dcbd3bf7SToby Isaac       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
171dcbd3bf7SToby Isaac       if (childB) *childB = children[posB];
172dcbd3bf7SToby Isaac     }
173dcbd3bf7SToby Isaac   }
174dcbd3bf7SToby Isaac   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
175dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
176dcbd3bf7SToby Isaac }
177dcbd3bf7SToby Isaac 
178dcbd3bf7SToby Isaac /*@
179dcbd3bf7SToby Isaac   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
180dcbd3bf7SToby Isaac 
181dcbd3bf7SToby Isaac   Input Parameters:
182dcbd3bf7SToby Isaac + dm - the reference tree DMPlex object
183dcbd3bf7SToby Isaac . parent - the parent point
184dcbd3bf7SToby Isaac . parentOrientA - the reference orientation for describing the parent
185dcbd3bf7SToby Isaac . childOrientA - the reference orientation for describing the child
186dcbd3bf7SToby Isaac . childA - the reference childID for describing the child
187dcbd3bf7SToby Isaac - parentOrientB - the new orientation for describing the parent
188dcbd3bf7SToby Isaac 
189dcbd3bf7SToby Isaac   Output Parameters:
190dcbd3bf7SToby Isaac + childOrientB - if not NULL, set to the new oreintation for describing the child
191ff1f73f7SToby Isaac - childB - if not NULL, the new childID for describing the child
192dcbd3bf7SToby Isaac 
193dcbd3bf7SToby Isaac   Level: developer
194dcbd3bf7SToby Isaac 
195dcbd3bf7SToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexSetReferenceTree(), DMPlexSetTree()
196dcbd3bf7SToby Isaac @*/
197dcbd3bf7SToby Isaac PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
198dcbd3bf7SToby Isaac {
199dcbd3bf7SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
200dcbd3bf7SToby Isaac   PetscErrorCode ierr;
201dcbd3bf7SToby Isaac 
202dcbd3bf7SToby Isaac   PetscFunctionBegin;
203dcbd3bf7SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
204dcbd3bf7SToby Isaac   if (!mesh->getchildsymmetry) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlexReferenceTreeGetChildSymmetry not implemented");
205dcbd3bf7SToby Isaac   ierr = mesh->getchildsymmetry(dm,parent,parentOrientA,childOrientA,childA,parentOrientB,childOrientB,childB);CHKERRQ(ierr);
206dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
207dcbd3bf7SToby Isaac }
208dcbd3bf7SToby Isaac 
209776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM,PetscSection,PetscInt*,PetscInt*,PetscBool,PetscBool);
210f9f063d4SToby Isaac 
2110e2cc29aSToby Isaac PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
212da43764aSToby Isaac {
2130e2cc29aSToby Isaac   MPI_Comm       comm;
2140e2cc29aSToby Isaac   PetscInt       dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
215da43764aSToby Isaac   PetscInt      *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
216da43764aSToby Isaac   DMLabel        identity, identityRef;
21710f7e118SToby Isaac   PetscSection   unionSection, unionConeSection, parentSection;
218da43764aSToby Isaac   PetscScalar   *unionCoords;
219da43764aSToby Isaac   IS             perm;
220da43764aSToby Isaac   PetscErrorCode ierr;
221da43764aSToby Isaac 
222da43764aSToby Isaac   PetscFunctionBegin;
2230e2cc29aSToby Isaac   comm = PetscObjectComm((PetscObject)K);
2240e2cc29aSToby Isaac   ierr = DMGetDimension(K, &dim);CHKERRQ(ierr);
225da43764aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
2260e2cc29aSToby Isaac   ierr = DMGetLabel(K, labelName, &identity);CHKERRQ(ierr);
2270e2cc29aSToby Isaac   ierr = DMGetLabel(Kref, labelName, &identityRef);CHKERRQ(ierr);
228da43764aSToby Isaac   ierr = DMPlexGetChart(Kref, &pRefStart, &pRefEnd);CHKERRQ(ierr);
229da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionSection);CHKERRQ(ierr);
230da43764aSToby Isaac   ierr = PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart));CHKERRQ(ierr);
231da43764aSToby Isaac   /* count points that will go in the union */
232da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
233da43764aSToby Isaac     ierr = PetscSectionSetDof(unionSection, p - pStart, 1);CHKERRQ(ierr);
234da43764aSToby Isaac   }
235da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
236da43764aSToby Isaac     PetscInt q, qSize;
237da43764aSToby Isaac     ierr = DMLabelGetValue(identityRef, p, &q);CHKERRQ(ierr);
238da43764aSToby Isaac     ierr = DMLabelGetStratumSize(identityRef, q, &qSize);CHKERRQ(ierr);
239da43764aSToby Isaac     if (qSize > 1) {
240da43764aSToby Isaac       ierr = PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1);CHKERRQ(ierr);
241da43764aSToby Isaac     }
242da43764aSToby Isaac   }
243854ce69bSBarry Smith   ierr = PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart,&permvals);CHKERRQ(ierr);
244da43764aSToby Isaac   offset = 0;
245da43764aSToby Isaac   /* stratify points in the union by topological dimension */
246da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
247da43764aSToby Isaac     PetscInt cStart, cEnd, c;
248da43764aSToby Isaac 
249da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K, d, &cStart, &cEnd);CHKERRQ(ierr);
250da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
251da43764aSToby Isaac       permvals[offset++] = c;
252da43764aSToby Isaac     }
253da43764aSToby Isaac 
254da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd);CHKERRQ(ierr);
255da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
256da43764aSToby Isaac       permvals[offset++] = c + (pEnd - pStart);
257da43764aSToby Isaac     }
258da43764aSToby Isaac   }
259da43764aSToby Isaac   ierr = ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm);CHKERRQ(ierr);
260da43764aSToby Isaac   ierr = PetscSectionSetPermutation(unionSection,perm);CHKERRQ(ierr);
261da43764aSToby Isaac   ierr = PetscSectionSetUp(unionSection);CHKERRQ(ierr);
262da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionSection,&numUnionPoints);CHKERRQ(ierr);
263da43764aSToby Isaac   ierr = PetscMalloc2(numUnionPoints,&coneSizes,dim+1,&numDimPoints);CHKERRQ(ierr);
264da43764aSToby Isaac   /* count dimension points */
265da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
266da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
267da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K,d,&cStart,NULL);CHKERRQ(ierr);
268da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff);CHKERRQ(ierr);
269da43764aSToby Isaac     if (d < dim) {
270da43764aSToby Isaac       ierr = DMPlexGetHeightStratum(K,d+1,&cStart,NULL);CHKERRQ(ierr);
271da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff2);CHKERRQ(ierr);
272da43764aSToby Isaac     }
273da43764aSToby Isaac     else {
274da43764aSToby Isaac       cOff2 = numUnionPoints;
275da43764aSToby Isaac     }
276da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
277da43764aSToby Isaac   }
278da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionConeSection);CHKERRQ(ierr);
279da43764aSToby Isaac   ierr = PetscSectionSetChart(unionConeSection, 0, numUnionPoints);CHKERRQ(ierr);
280da43764aSToby Isaac   /* count the cones in the union */
281da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
282da43764aSToby Isaac     PetscInt dof, uOff;
283da43764aSToby Isaac 
284da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
285da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
286da43764aSToby Isaac     ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
287da43764aSToby Isaac     coneSizes[uOff] = dof;
288da43764aSToby Isaac   }
289da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
290da43764aSToby Isaac     PetscInt dof, uDof, uOff;
291da43764aSToby Isaac 
292da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
293da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
294da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
295da43764aSToby Isaac     if (uDof) {
296da43764aSToby Isaac       ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
297da43764aSToby Isaac       coneSizes[uOff] = dof;
298da43764aSToby Isaac     }
299da43764aSToby Isaac   }
300da43764aSToby Isaac   ierr = PetscSectionSetUp(unionConeSection);CHKERRQ(ierr);
301da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionConeSection,&numCones);CHKERRQ(ierr);
302da43764aSToby Isaac   ierr = PetscMalloc2(numCones,&unionCones,numCones,&unionOrientations);CHKERRQ(ierr);
303da43764aSToby Isaac   /* write the cones in the union */
304da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
305da43764aSToby Isaac     PetscInt dof, uOff, c, cOff;
306da43764aSToby Isaac     const PetscInt *cone, *orientation;
307da43764aSToby Isaac 
308da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
309da43764aSToby Isaac     ierr = DMPlexGetCone(K, p, &cone);CHKERRQ(ierr);
310da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(K, p, &orientation);CHKERRQ(ierr);
311da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
312da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
313da43764aSToby Isaac     for (c = 0; c < dof; c++) {
314da43764aSToby Isaac       PetscInt e, eOff;
315da43764aSToby Isaac       e                           = cone[c];
316da43764aSToby Isaac       ierr                        = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
317da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
318da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
319da43764aSToby Isaac     }
320da43764aSToby Isaac   }
321da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
322da43764aSToby Isaac     PetscInt dof, uDof, uOff, c, cOff;
323da43764aSToby Isaac     const PetscInt *cone, *orientation;
324da43764aSToby Isaac 
325da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
326da43764aSToby Isaac     ierr = DMPlexGetCone(Kref, p, &cone);CHKERRQ(ierr);
327da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(Kref, p, &orientation);CHKERRQ(ierr);
328da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
329da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
330da43764aSToby Isaac     if (uDof) {
331da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
332da43764aSToby Isaac       for (c = 0; c < dof; c++) {
333da43764aSToby Isaac         PetscInt e, eOff, eDof;
334da43764aSToby Isaac 
335da43764aSToby Isaac         e    = cone[c];
336da43764aSToby Isaac         ierr = PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart),&eDof);CHKERRQ(ierr);
337da43764aSToby Isaac         if (eDof) {
338da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff);CHKERRQ(ierr);
339da43764aSToby Isaac         }
340da43764aSToby Isaac         else {
341da43764aSToby Isaac           ierr = DMLabelGetValue(identityRef, e, &e);CHKERRQ(ierr);
342da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
343da43764aSToby Isaac         }
344da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
345da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
346da43764aSToby Isaac       }
347da43764aSToby Isaac     }
348da43764aSToby Isaac   }
349da43764aSToby Isaac   /* get the coordinates */
350da43764aSToby Isaac   {
351da43764aSToby Isaac     PetscInt vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
352da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
353da43764aSToby Isaac     Vec      KcoordsVec, KrefCoordsVec;
354da43764aSToby Isaac     PetscScalar *Kcoords;
355da43764aSToby Isaac 
356da43764aSToby Isaac     DMGetCoordinateSection(K, &KcoordsSec);CHKERRQ(ierr);
357da43764aSToby Isaac     DMGetCoordinatesLocal(K, &KcoordsVec);CHKERRQ(ierr);
358da43764aSToby Isaac     DMGetCoordinateSection(Kref, &KrefCoordsSec);CHKERRQ(ierr);
359da43764aSToby Isaac     DMGetCoordinatesLocal(Kref, &KrefCoordsVec);CHKERRQ(ierr);
360da43764aSToby Isaac 
361da43764aSToby Isaac     numVerts = numDimPoints[0];
362da43764aSToby Isaac     ierr     = PetscMalloc1(numVerts * dim,&unionCoords);CHKERRQ(ierr);
363da43764aSToby Isaac     ierr     = DMPlexGetDepthStratum(K,0,&vStart,&vEnd);CHKERRQ(ierr);
364da43764aSToby Isaac 
365da43764aSToby Isaac     offset = 0;
366da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
367da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pStart,&vOff);CHKERRQ(ierr);
368da43764aSToby Isaac       ierr = VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords);CHKERRQ(ierr);
369da43764aSToby Isaac       for (d = 0; d < dim; d++) {
370da43764aSToby Isaac         unionCoords[offset * dim + d] = Kcoords[d];
371da43764aSToby Isaac       }
372da43764aSToby Isaac       offset++;
373da43764aSToby Isaac     }
374da43764aSToby Isaac     ierr = DMPlexGetDepthStratum(Kref,0,&vRefStart,&vRefEnd);CHKERRQ(ierr);
375da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
376da43764aSToby Isaac       ierr = PetscSectionGetDof(unionSection,v - pRefStart + (pEnd - pStart),&vDof);CHKERRQ(ierr);
377da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pRefStart + (pEnd - pStart),&vOff);CHKERRQ(ierr);
378da43764aSToby Isaac       ierr = VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords);CHKERRQ(ierr);
379da43764aSToby Isaac       if (vDof) {
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     }
386da43764aSToby Isaac   }
387da43764aSToby Isaac   ierr = DMCreate(comm,ref);CHKERRQ(ierr);
388da43764aSToby Isaac   ierr = DMSetType(*ref,DMPLEX);CHKERRQ(ierr);
38928f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ref,dim);CHKERRQ(ierr);
390da43764aSToby Isaac   ierr = DMPlexCreateFromDAG(*ref,dim,numDimPoints,coneSizes,unionCones,unionOrientations,unionCoords);CHKERRQ(ierr);
39110f7e118SToby Isaac   /* set the tree */
39210f7e118SToby Isaac   ierr = PetscSectionCreate(comm,&parentSection);CHKERRQ(ierr);
39310f7e118SToby Isaac   ierr = PetscSectionSetChart(parentSection,0,numUnionPoints);CHKERRQ(ierr);
39410f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
39510f7e118SToby Isaac     PetscInt uDof, uOff;
39610f7e118SToby Isaac 
39710f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
39810f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
39910f7e118SToby Isaac     if (uDof) {
40010f7e118SToby Isaac       PetscSectionSetDof(parentSection,uOff,1);CHKERRQ(ierr);
40110f7e118SToby Isaac     }
40210f7e118SToby Isaac   }
40310f7e118SToby Isaac   ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
40410f7e118SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&parentSize);CHKERRQ(ierr);
40510f7e118SToby Isaac   ierr = PetscMalloc2(parentSize,&parents,parentSize,&childIDs);CHKERRQ(ierr);
40610f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
40710f7e118SToby Isaac     PetscInt uDof, uOff;
40810f7e118SToby Isaac 
40910f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
41010f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
41110f7e118SToby Isaac     if (uDof) {
41210f7e118SToby Isaac       PetscInt pOff, parent, parentU;
41310f7e118SToby Isaac       PetscSectionGetOffset(parentSection,uOff,&pOff);CHKERRQ(ierr);
41410f7e118SToby Isaac       DMLabelGetValue(identityRef,p,&parent);CHKERRQ(ierr);
41510f7e118SToby Isaac       ierr = PetscSectionGetOffset(unionSection, parent - pStart,&parentU);CHKERRQ(ierr);
41610f7e118SToby Isaac       parents[pOff] = parentU;
41710f7e118SToby Isaac       childIDs[pOff] = uOff;
41810f7e118SToby Isaac     }
41910f7e118SToby Isaac   }
420776742edSToby Isaac   ierr = DMPlexSetTree_Internal(*ref,parentSection,parents,childIDs,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
42110f7e118SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
42210f7e118SToby Isaac   ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
42310f7e118SToby Isaac 
424da43764aSToby Isaac   /* clean up */
425da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionSection);CHKERRQ(ierr);
426da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionConeSection);CHKERRQ(ierr);
427da43764aSToby Isaac   ierr = ISDestroy(&perm);CHKERRQ(ierr);
428da43764aSToby Isaac   ierr = PetscFree(unionCoords);CHKERRQ(ierr);
429da43764aSToby Isaac   ierr = PetscFree2(unionCones,unionOrientations);CHKERRQ(ierr);
430da43764aSToby Isaac   ierr = PetscFree2(coneSizes,numDimPoints);CHKERRQ(ierr);
4310e2cc29aSToby Isaac   PetscFunctionReturn(0);
4320e2cc29aSToby Isaac }
4330e2cc29aSToby Isaac 
4340e2cc29aSToby Isaac /*@
4350e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4360e2cc29aSToby Isaac 
4370e2cc29aSToby Isaac   Collective on comm
4380e2cc29aSToby Isaac 
4390e2cc29aSToby Isaac   Input Parameters:
4400e2cc29aSToby Isaac + comm    - the MPI communicator
4410e2cc29aSToby Isaac . dim     - the spatial dimension
4420e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4430e2cc29aSToby Isaac 
4440e2cc29aSToby Isaac   Output Parameters:
4450e2cc29aSToby Isaac . ref     - the reference tree DMPlex object
4460e2cc29aSToby Isaac 
4470e2cc29aSToby Isaac   Level: intermediate
4480e2cc29aSToby Isaac 
4490e2cc29aSToby Isaac .keywords: reference cell
4500e2cc29aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree()
4510e2cc29aSToby Isaac @*/
4520e2cc29aSToby Isaac PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
4530e2cc29aSToby Isaac {
4540e2cc29aSToby Isaac   DM_Plex       *mesh;
4550e2cc29aSToby Isaac   DM             K, Kref;
4560e2cc29aSToby Isaac   PetscInt       p, pStart, pEnd;
4570e2cc29aSToby Isaac   DMLabel        identity;
4580e2cc29aSToby Isaac   PetscErrorCode ierr;
4590e2cc29aSToby Isaac 
4600e2cc29aSToby Isaac   PetscFunctionBegin;
4610e2cc29aSToby Isaac #if 1
4620e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4630e2cc29aSToby Isaac #endif
4640e2cc29aSToby Isaac   /* create a reference element */
4650e2cc29aSToby Isaac   ierr = DMPlexCreateReferenceCell(comm, dim, simplex, &K);CHKERRQ(ierr);
4660e2cc29aSToby Isaac   ierr = DMCreateLabel(K, "identity");CHKERRQ(ierr);
4670e2cc29aSToby Isaac   ierr = DMGetLabel(K, "identity", &identity);CHKERRQ(ierr);
4680e2cc29aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
4690e2cc29aSToby Isaac   for (p = pStart; p < pEnd; p++) {
4700e2cc29aSToby Isaac     ierr = DMLabelSetValue(identity, p, p);CHKERRQ(ierr);
4710e2cc29aSToby Isaac   }
4720e2cc29aSToby Isaac   /* refine it */
4730e2cc29aSToby Isaac   ierr = DMRefine(K,comm,&Kref);CHKERRQ(ierr);
4740e2cc29aSToby Isaac 
4750e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4760e2cc29aSToby Isaac    * points that appear in both */
4770e2cc29aSToby Isaac   ierr = DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref);CHKERRQ(ierr);
4780e2cc29aSToby Isaac   mesh = (DM_Plex *) (*ref)->data;
4790e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
480da43764aSToby Isaac   ierr = DMDestroy(&K);CHKERRQ(ierr);
481da43764aSToby Isaac   ierr = DMDestroy(&Kref);CHKERRQ(ierr);
482da43764aSToby Isaac   PetscFunctionReturn(0);
483da43764aSToby Isaac }
484da43764aSToby Isaac 
485878b19aaSToby Isaac static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
486878b19aaSToby Isaac {
487878b19aaSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
488878b19aaSToby Isaac   PetscSection   childSec, pSec;
489878b19aaSToby Isaac   PetscInt       p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
490878b19aaSToby Isaac   PetscInt       *offsets, *children, pStart, pEnd;
491878b19aaSToby Isaac   PetscErrorCode ierr;
492878b19aaSToby Isaac 
493878b19aaSToby Isaac   PetscFunctionBegin;
494878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
495878b19aaSToby Isaac   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
496878b19aaSToby Isaac   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
497878b19aaSToby Isaac   pSec = mesh->parentSection;
498878b19aaSToby Isaac   if (!pSec) PetscFunctionReturn(0);
499878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(pSec,&pSize);CHKERRQ(ierr);
500878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
501878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
502878b19aaSToby Isaac 
503878b19aaSToby Isaac     parMax = PetscMax(parMax,par+1);
504878b19aaSToby Isaac     parMin = PetscMin(parMin,par);
505878b19aaSToby Isaac   }
506878b19aaSToby Isaac   if (parMin > parMax) {
507878b19aaSToby Isaac     parMin = -1;
508878b19aaSToby Isaac     parMax = -1;
509878b19aaSToby Isaac   }
510878b19aaSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)pSec),&childSec);CHKERRQ(ierr);
511878b19aaSToby Isaac   ierr = PetscSectionSetChart(childSec,parMin,parMax);CHKERRQ(ierr);
512878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
513878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
514878b19aaSToby Isaac 
515878b19aaSToby Isaac     ierr = PetscSectionAddDof(childSec,par,1);CHKERRQ(ierr);
516878b19aaSToby Isaac   }
517878b19aaSToby Isaac   ierr = PetscSectionSetUp(childSec);CHKERRQ(ierr);
518878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(childSec,&cSize);CHKERRQ(ierr);
519878b19aaSToby Isaac   ierr = PetscMalloc1(cSize,&children);CHKERRQ(ierr);
520878b19aaSToby Isaac   ierr = PetscCalloc1(parMax-parMin,&offsets);CHKERRQ(ierr);
521878b19aaSToby Isaac   ierr = PetscSectionGetChart(pSec,&pStart,&pEnd);CHKERRQ(ierr);
522878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
523878b19aaSToby Isaac     PetscInt dof, off, i;
524878b19aaSToby Isaac 
525878b19aaSToby Isaac     ierr = PetscSectionGetDof(pSec,p,&dof);CHKERRQ(ierr);
526878b19aaSToby Isaac     ierr = PetscSectionGetOffset(pSec,p,&off);CHKERRQ(ierr);
527878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
528878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
529878b19aaSToby Isaac 
530878b19aaSToby Isaac       ierr = PetscSectionGetOffset(childSec,par,&cOff);CHKERRQ(ierr);
531878b19aaSToby Isaac       children[cOff + offsets[par-parMin]++] = p;
532878b19aaSToby Isaac     }
533878b19aaSToby Isaac   }
534878b19aaSToby Isaac   mesh->childSection = childSec;
535878b19aaSToby Isaac   mesh->children = children;
536878b19aaSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
537878b19aaSToby Isaac   PetscFunctionReturn(0);
538878b19aaSToby Isaac }
539878b19aaSToby Isaac 
5406dd5a8c8SToby Isaac static PetscErrorCode AnchorsFlatten (PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
5416dd5a8c8SToby Isaac {
5426dd5a8c8SToby Isaac   PetscInt       pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5436dd5a8c8SToby Isaac   const PetscInt *vals;
5446dd5a8c8SToby Isaac   PetscSection   secNew;
5456dd5a8c8SToby Isaac   PetscBool      anyNew, globalAnyNew;
5466dd5a8c8SToby Isaac   PetscBool      compress;
5476dd5a8c8SToby Isaac   PetscErrorCode ierr;
5486dd5a8c8SToby Isaac 
5496dd5a8c8SToby Isaac   PetscFunctionBegin;
5506dd5a8c8SToby Isaac   ierr = PetscSectionGetChart(section,&pStart,&pEnd);CHKERRQ(ierr);
5516dd5a8c8SToby Isaac   ierr = ISGetLocalSize(is,&size);CHKERRQ(ierr);
5526dd5a8c8SToby Isaac   ierr = ISGetIndices(is,&vals);CHKERRQ(ierr);
5536dd5a8c8SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secNew);CHKERRQ(ierr);
5546dd5a8c8SToby Isaac   ierr = PetscSectionSetChart(secNew,pStart,pEnd);CHKERRQ(ierr);
5556dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5566dd5a8c8SToby Isaac     PetscInt dof;
5576dd5a8c8SToby Isaac 
5586dd5a8c8SToby Isaac     p = vals[i];
5596dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5606dd5a8c8SToby Isaac     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5616dd5a8c8SToby Isaac     if (dof) break;
5626dd5a8c8SToby Isaac   }
5636dd5a8c8SToby Isaac   if (i == size) {
5646dd5a8c8SToby Isaac     ierr     = PetscSectionSetUp(secNew);CHKERRQ(ierr);
5656dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5666dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5676dd5a8c8SToby Isaac     sizeNew  = 0;
5686dd5a8c8SToby Isaac   }
5696dd5a8c8SToby Isaac   else {
5706dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5716dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5726dd5a8c8SToby Isaac       PetscInt dof, off;
5736dd5a8c8SToby Isaac 
5746dd5a8c8SToby Isaac       ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5756dd5a8c8SToby Isaac       ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
5766dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5776dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5786dd5a8c8SToby Isaac 
5796dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5806dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
5816dd5a8c8SToby Isaac         }
5826dd5a8c8SToby Isaac         if (qDof) {
5836dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, qDof);CHKERRQ(ierr);
5846dd5a8c8SToby Isaac         }
5856dd5a8c8SToby Isaac         else {
5866dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, 1);CHKERRQ(ierr);
5876dd5a8c8SToby Isaac         }
5886dd5a8c8SToby Isaac       }
5896dd5a8c8SToby Isaac     }
5906dd5a8c8SToby Isaac     ierr = PetscSectionSetUp(secNew);CHKERRQ(ierr);
5916dd5a8c8SToby Isaac     ierr = PetscSectionGetStorageSize(secNew,&sizeNew);CHKERRQ(ierr);
5926dd5a8c8SToby Isaac     ierr = PetscMalloc1(sizeNew,&valsNew);CHKERRQ(ierr);
5936dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5946dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5956dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
5966dd5a8c8SToby Isaac 
5976dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5986dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
5996dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(secNew, p, &dofNew);CHKERRQ(ierr);
6006dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(secNew, p, &offNew);CHKERRQ(ierr);
6016dd5a8c8SToby Isaac       count = 0;
6026dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
6036dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
6046dd5a8c8SToby Isaac 
6056dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
6066dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
6076dd5a8c8SToby Isaac           ierr = PetscSectionGetOffset(section, q, &qOff);CHKERRQ(ierr);
6086dd5a8c8SToby Isaac         }
6096dd5a8c8SToby Isaac         if (qDof) {
6106dd5a8c8SToby Isaac           PetscInt oldCount = count;
6116dd5a8c8SToby Isaac 
6126dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
6136dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
6146dd5a8c8SToby Isaac 
6156dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
6166dd5a8c8SToby Isaac               if (valsNew[offNew + k] == r) {
6176dd5a8c8SToby Isaac                 break;
6186dd5a8c8SToby Isaac               }
6196dd5a8c8SToby Isaac             }
6206dd5a8c8SToby Isaac             if (k == oldCount) {
6216dd5a8c8SToby Isaac               valsNew[offNew + count++] = r;
6226dd5a8c8SToby Isaac             }
6236dd5a8c8SToby Isaac           }
6246dd5a8c8SToby Isaac         }
6256dd5a8c8SToby Isaac         else {
6266dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
6276dd5a8c8SToby Isaac 
6286dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
6296dd5a8c8SToby Isaac             if (valsNew[offNew + k] == q) {
6306dd5a8c8SToby Isaac               break;
6316dd5a8c8SToby Isaac             }
6326dd5a8c8SToby Isaac           }
6336dd5a8c8SToby Isaac           if (k == oldCount) {
6346dd5a8c8SToby Isaac             valsNew[offNew + count++] = q;
6356dd5a8c8SToby Isaac           }
6366dd5a8c8SToby Isaac         }
6376dd5a8c8SToby Isaac       }
6386dd5a8c8SToby Isaac       if (count < dofNew) {
6396dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secNew, p, count);CHKERRQ(ierr);
6406dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6416dd5a8c8SToby Isaac       }
6426dd5a8c8SToby Isaac     }
6436dd5a8c8SToby Isaac   }
6446dd5a8c8SToby Isaac   ierr = ISRestoreIndices(is,&vals);CHKERRQ(ierr);
645b2566f29SBarry Smith   ierr = MPIU_Allreduce(&anyNew,&globalAnyNew,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
6466dd5a8c8SToby Isaac   if (!globalAnyNew) {
6476dd5a8c8SToby Isaac     ierr = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6486dd5a8c8SToby Isaac     *sectionNew = NULL;
6496dd5a8c8SToby Isaac     *isNew = NULL;
6506dd5a8c8SToby Isaac   }
6516dd5a8c8SToby Isaac   else {
6526dd5a8c8SToby Isaac     PetscBool globalCompress;
6536dd5a8c8SToby Isaac 
654b2566f29SBarry Smith     ierr = MPIU_Allreduce(&compress,&globalCompress,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
6556dd5a8c8SToby Isaac     if (compress) {
6566dd5a8c8SToby Isaac       PetscSection secComp;
6576dd5a8c8SToby Isaac       PetscInt *valsComp = NULL;
6586dd5a8c8SToby Isaac 
6596dd5a8c8SToby Isaac       ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secComp);CHKERRQ(ierr);
6606dd5a8c8SToby Isaac       ierr = PetscSectionSetChart(secComp,pStart,pEnd);CHKERRQ(ierr);
6616dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6626dd5a8c8SToby Isaac         PetscInt dof;
6636dd5a8c8SToby Isaac 
6646dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6656dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secComp, p, dof);CHKERRQ(ierr);
6666dd5a8c8SToby Isaac       }
6676dd5a8c8SToby Isaac       ierr = PetscSectionSetUp(secComp);CHKERRQ(ierr);
6686dd5a8c8SToby Isaac       ierr = PetscSectionGetStorageSize(secComp,&sizeNew);CHKERRQ(ierr);
6696dd5a8c8SToby Isaac       ierr = PetscMalloc1(sizeNew,&valsComp);CHKERRQ(ierr);
6706dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6716dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6726dd5a8c8SToby Isaac 
6736dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6746dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secNew, p, &off);CHKERRQ(ierr);
6756dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secComp, p, &offNew);CHKERRQ(ierr);
6766dd5a8c8SToby Isaac         for (j = 0; j < dof; j++) {
6776dd5a8c8SToby Isaac           valsComp[offNew + j] = valsNew[off + j];
6786dd5a8c8SToby Isaac         }
6796dd5a8c8SToby Isaac       }
6806dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6816dd5a8c8SToby Isaac       secNew  = secComp;
6826dd5a8c8SToby Isaac       ierr    = PetscFree(valsNew);CHKERRQ(ierr);
6836dd5a8c8SToby Isaac       valsNew = valsComp;
6846dd5a8c8SToby Isaac     }
6856dd5a8c8SToby Isaac     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is),sizeNew,valsNew,PETSC_OWN_POINTER,isNew);CHKERRQ(ierr);
6866dd5a8c8SToby Isaac   }
6876dd5a8c8SToby Isaac   PetscFunctionReturn(0);
6886dd5a8c8SToby Isaac }
6896dd5a8c8SToby Isaac 
690f7c74593SToby Isaac static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
69166af876cSToby Isaac {
69266af876cSToby Isaac   PetscInt       p, pStart, pEnd, *anchors, size;
69366af876cSToby Isaac   PetscInt       aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
69466af876cSToby Isaac   PetscSection   aSec;
695f9f063d4SToby Isaac   DMLabel        canonLabel;
69666af876cSToby Isaac   IS             aIS;
69766af876cSToby Isaac   PetscErrorCode ierr;
69866af876cSToby Isaac 
69966af876cSToby Isaac   PetscFunctionBegin;
70066af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
70166af876cSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
702c58f1c22SToby Isaac   ierr = DMGetLabel(dm,"canonical",&canonLabel);CHKERRQ(ierr);
70366af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
70466af876cSToby Isaac     PetscInt parent;
70566af876cSToby Isaac 
706f9f063d4SToby Isaac     if (canonLabel) {
707f9f063d4SToby Isaac       PetscInt canon;
708f9f063d4SToby Isaac 
709f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
710f9f063d4SToby Isaac       if (p != canon) continue;
711f9f063d4SToby Isaac     }
71266af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
71366af876cSToby Isaac     if (parent != p) {
71466af876cSToby Isaac       aMin = PetscMin(aMin,p);
71566af876cSToby Isaac       aMax = PetscMax(aMax,p+1);
71666af876cSToby Isaac     }
71766af876cSToby Isaac   }
71866af876cSToby Isaac   if (aMin > aMax) {
71966af876cSToby Isaac     aMin = -1;
72066af876cSToby Isaac     aMax = -1;
72166af876cSToby Isaac   }
722e228b242SToby Isaac   ierr = PetscSectionCreate(PETSC_COMM_SELF,&aSec);CHKERRQ(ierr);
72366af876cSToby Isaac   ierr = PetscSectionSetChart(aSec,aMin,aMax);CHKERRQ(ierr);
72466af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
72566af876cSToby Isaac     PetscInt parent, ancestor = p;
72666af876cSToby Isaac 
727f9f063d4SToby Isaac     if (canonLabel) {
728f9f063d4SToby Isaac       PetscInt canon;
729f9f063d4SToby Isaac 
730f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
731f9f063d4SToby Isaac       if (p != canon) continue;
732f9f063d4SToby Isaac     }
73366af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
73466af876cSToby Isaac     while (parent != ancestor) {
73566af876cSToby Isaac       ancestor = parent;
73666af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
73766af876cSToby Isaac     }
73866af876cSToby Isaac     if (ancestor != p) {
73966af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
74066af876cSToby Isaac 
74166af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
74266af876cSToby Isaac       ierr = PetscSectionSetDof(aSec,p,closureSize);CHKERRQ(ierr);
74366af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
74466af876cSToby Isaac     }
74566af876cSToby Isaac   }
74666af876cSToby Isaac   ierr = PetscSectionSetUp(aSec);CHKERRQ(ierr);
74766af876cSToby Isaac   ierr = PetscSectionGetStorageSize(aSec,&size);CHKERRQ(ierr);
74866af876cSToby Isaac   ierr = PetscMalloc1(size,&anchors);CHKERRQ(ierr);
74966af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
75066af876cSToby Isaac     PetscInt parent, ancestor = p;
75166af876cSToby Isaac 
752f9f063d4SToby Isaac     if (canonLabel) {
753f9f063d4SToby Isaac       PetscInt canon;
754f9f063d4SToby Isaac 
755f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
756f9f063d4SToby Isaac       if (p != canon) continue;
757f9f063d4SToby Isaac     }
75866af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
75966af876cSToby Isaac     while (parent != ancestor) {
76066af876cSToby Isaac       ancestor = parent;
76166af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
76266af876cSToby Isaac     }
76366af876cSToby Isaac     if (ancestor != p) {
76466af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
76566af876cSToby Isaac 
76666af876cSToby Isaac       ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
76766af876cSToby Isaac 
76866af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
76966af876cSToby Isaac       for (j = 0; j < closureSize; j++) {
77066af876cSToby Isaac         anchors[aOff + j] = closure[2*j];
77166af876cSToby Isaac       }
77266af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
77366af876cSToby Isaac     }
77466af876cSToby Isaac   }
775e228b242SToby Isaac   ierr = ISCreateGeneral(PETSC_COMM_SELF,size,anchors,PETSC_OWN_POINTER,&aIS);CHKERRQ(ierr);
7766dd5a8c8SToby Isaac   {
7776dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7786dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7796dd5a8c8SToby Isaac 
7806dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aSec);CHKERRQ(ierr);
7816dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aIS);CHKERRQ(ierr);
7826dd5a8c8SToby Isaac     while (aSecNew) {
7836dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
7846dd5a8c8SToby Isaac       ierr    = ISDestroy(&aIS);CHKERRQ(ierr);
7856dd5a8c8SToby Isaac       aSec    = aSecNew;
7866dd5a8c8SToby Isaac       aIS     = aISNew;
7876dd5a8c8SToby Isaac       aSecNew = NULL;
7886dd5a8c8SToby Isaac       aISNew  = NULL;
7896dd5a8c8SToby Isaac       ierr    = AnchorsFlatten(aSec,aIS,&aSecNew,&aISNew);CHKERRQ(ierr);
7906dd5a8c8SToby Isaac     }
7916dd5a8c8SToby Isaac   }
792a17985deSToby Isaac   ierr = DMPlexSetAnchors(dm,aSec,aIS);CHKERRQ(ierr);
79366af876cSToby Isaac   ierr = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
79466af876cSToby Isaac   ierr = ISDestroy(&aIS);CHKERRQ(ierr);
79566af876cSToby Isaac   PetscFunctionReturn(0);
79666af876cSToby Isaac }
79766af876cSToby Isaac 
7986461c1adSToby Isaac static PetscErrorCode DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt *dof,PetscInt *numTrueSupp)
7996461c1adSToby Isaac {
8006461c1adSToby Isaac   PetscErrorCode ierr;
8016461c1adSToby Isaac 
8026461c1adSToby Isaac   PetscFunctionBegin;
8036461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
8046461c1adSToby Isaac     PetscInt i, alldof;
8056461c1adSToby Isaac     const PetscInt *supp;
8066461c1adSToby Isaac     PetscInt count = 0;
8076461c1adSToby Isaac 
8086461c1adSToby Isaac     ierr = DMPlexGetSupportSize(dm,p,&alldof);CHKERRQ(ierr);
8096461c1adSToby Isaac     ierr = DMPlexGetSupport(dm,p,&supp);CHKERRQ(ierr);
8106461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
8116461c1adSToby Isaac       PetscInt q = supp[i], numCones, j;
8126461c1adSToby Isaac       const PetscInt *cone;
8136461c1adSToby Isaac 
8146461c1adSToby Isaac       ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
8156461c1adSToby Isaac       ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
8166461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
8176461c1adSToby Isaac         if (cone[j] == p) break;
8186461c1adSToby Isaac       }
8196461c1adSToby Isaac       if (j < numCones) count++;
8206461c1adSToby Isaac     }
8216461c1adSToby Isaac     numTrueSupp[p] = count;
8226461c1adSToby Isaac   }
8236461c1adSToby Isaac   *dof = numTrueSupp[p];
8246461c1adSToby Isaac   PetscFunctionReturn(0);
8256461c1adSToby Isaac }
8266461c1adSToby Isaac 
827776742edSToby Isaac static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
828776742edSToby Isaac {
829776742edSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
830776742edSToby Isaac   PetscSection newSupportSection;
831776742edSToby Isaac   PetscInt newSize, *newSupports, pStart, pEnd, p, d, depth;
8326461c1adSToby Isaac   PetscInt *numTrueSupp;
833776742edSToby Isaac   PetscInt *offsets;
834776742edSToby Isaac   PetscErrorCode ierr;
835776742edSToby Isaac 
836776742edSToby Isaac   PetscFunctionBegin;
837776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
838776742edSToby Isaac   /* symmetrize the hierarchy */
839776742edSToby Isaac   ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr);
840e228b242SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)),&newSupportSection);CHKERRQ(ierr);
841776742edSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
842776742edSToby Isaac   ierr = PetscSectionSetChart(newSupportSection,pStart,pEnd);CHKERRQ(ierr);
843776742edSToby Isaac   ierr = PetscCalloc1(pEnd,&offsets);CHKERRQ(ierr);
8446461c1adSToby Isaac   ierr = PetscMalloc1(pEnd,&numTrueSupp);CHKERRQ(ierr);
8456461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8466461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
847776742edSToby Isaac    * parent(q) */
848776742edSToby Isaac   for (d = 0; d <= depth; d++) {
849776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
850776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
851776742edSToby Isaac       PetscInt dof, q, qdof, parent;
852776742edSToby Isaac 
8536461c1adSToby Isaac       ierr = DMPlexGetTrueSupportSize(dm,p,&dof,numTrueSupp);CHKERRQ(ierr);
854776742edSToby Isaac       ierr = PetscSectionAddDof(newSupportSection, p, dof);CHKERRQ(ierr);
855776742edSToby Isaac       q    = p;
856776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
857776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
858776742edSToby Isaac         q = parent;
859776742edSToby Isaac 
8606461c1adSToby Isaac         ierr = DMPlexGetTrueSupportSize(dm,q,&qdof,numTrueSupp);CHKERRQ(ierr);
861776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,p,qdof);CHKERRQ(ierr);
862776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,q,dof);CHKERRQ(ierr);
863776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
864776742edSToby Isaac       }
865776742edSToby Isaac     }
866776742edSToby Isaac   }
867776742edSToby Isaac   ierr = PetscSectionSetUp(newSupportSection);CHKERRQ(ierr);
868776742edSToby Isaac   ierr = PetscSectionGetStorageSize(newSupportSection,&newSize);CHKERRQ(ierr);
869776742edSToby Isaac   ierr = PetscMalloc1(newSize,&newSupports);CHKERRQ(ierr);
870776742edSToby Isaac   for (d = 0; d <= depth; d++) {
871776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
872776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
873776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
874776742edSToby Isaac 
875776742edSToby Isaac       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
876776742edSToby Isaac       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
877776742edSToby Isaac       ierr = PetscSectionGetDof(newSupportSection, p, &newDof);CHKERRQ(ierr);
878776742edSToby Isaac       ierr = PetscSectionGetOffset(newSupportSection, p, &newOff);CHKERRQ(ierr);
879776742edSToby Isaac       for (i = 0; i < dof; i++) {
8806461c1adSToby Isaac         PetscInt numCones, j;
8816461c1adSToby Isaac         const PetscInt *cone;
8826461c1adSToby Isaac         PetscInt q = mesh->supports[off + i];
8836461c1adSToby Isaac 
8846461c1adSToby Isaac         ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
8856461c1adSToby Isaac         ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
8866461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8876461c1adSToby Isaac           if (cone[j] == p) break;
8886461c1adSToby Isaac         }
8896461c1adSToby Isaac         if (j < numCones) newSupports[newOff+offsets[p]++] = q;
890776742edSToby Isaac       }
891776742edSToby Isaac       mesh->maxSupportSize = PetscMax(mesh->maxSupportSize,newDof);
892776742edSToby Isaac 
893776742edSToby Isaac       q    = p;
894776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
895776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
896776742edSToby Isaac         q = parent;
897776742edSToby Isaac         ierr = PetscSectionGetDof(mesh->supportSection, q, &qdof);CHKERRQ(ierr);
898776742edSToby Isaac         ierr = PetscSectionGetOffset(mesh->supportSection, q, &qoff);CHKERRQ(ierr);
899776742edSToby Isaac         ierr = PetscSectionGetOffset(newSupportSection, q, &newqOff);CHKERRQ(ierr);
900776742edSToby Isaac         for (i = 0; i < qdof; i++) {
9016461c1adSToby Isaac           PetscInt numCones, j;
9026461c1adSToby Isaac           const PetscInt *cone;
9036461c1adSToby Isaac           PetscInt r = mesh->supports[qoff + i];
9046461c1adSToby Isaac 
9056461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9066461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9076461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9086461c1adSToby Isaac             if (cone[j] == q) break;
9096461c1adSToby Isaac           }
9106461c1adSToby Isaac           if (j < numCones) newSupports[newOff+offsets[p]++] = r;
911776742edSToby Isaac         }
912776742edSToby Isaac         for (i = 0; i < dof; i++) {
9136461c1adSToby Isaac           PetscInt numCones, j;
9146461c1adSToby Isaac           const PetscInt *cone;
9156461c1adSToby Isaac           PetscInt r = mesh->supports[off + i];
9166461c1adSToby Isaac 
9176461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9186461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9196461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9206461c1adSToby Isaac             if (cone[j] == p) break;
9216461c1adSToby Isaac           }
9226461c1adSToby Isaac           if (j < numCones) newSupports[newqOff+offsets[q]++] = r;
923776742edSToby Isaac         }
924776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
925776742edSToby Isaac       }
926776742edSToby Isaac     }
927776742edSToby Isaac   }
928776742edSToby Isaac   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
929776742edSToby Isaac   mesh->supportSection = newSupportSection;
930776742edSToby Isaac   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
931776742edSToby Isaac   mesh->supports = newSupports;
932776742edSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
9336461c1adSToby Isaac   ierr = PetscFree(numTrueSupp);CHKERRQ(ierr);
934776742edSToby Isaac 
935776742edSToby Isaac   PetscFunctionReturn(0);
936776742edSToby Isaac }
937776742edSToby Isaac 
938f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM,PetscSection,PetscSection,Mat);
939f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM,PetscSection,PetscSection,Mat);
940f7c74593SToby Isaac 
941776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
942f9f063d4SToby Isaac {
943f9f063d4SToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
944f9f063d4SToby Isaac   DM             refTree;
945f9f063d4SToby Isaac   PetscInt       size;
946f9f063d4SToby Isaac   PetscErrorCode ierr;
947f9f063d4SToby Isaac 
948f9f063d4SToby Isaac   PetscFunctionBegin;
949f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
950f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
951f9f063d4SToby Isaac   ierr = PetscObjectReference((PetscObject)parentSection);CHKERRQ(ierr);
952f9f063d4SToby Isaac   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
953f9f063d4SToby Isaac   mesh->parentSection = parentSection;
954f9f063d4SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&size);CHKERRQ(ierr);
955f9f063d4SToby Isaac   if (parents != mesh->parents) {
956f9f063d4SToby Isaac     ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
957f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->parents);CHKERRQ(ierr);
958f9f063d4SToby Isaac     ierr = PetscMemcpy(mesh->parents, parents, size * sizeof(*parents));CHKERRQ(ierr);
959f9f063d4SToby Isaac   }
960f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
961f9f063d4SToby Isaac     ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
962f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->childIDs);CHKERRQ(ierr);
963f9f063d4SToby Isaac     ierr = PetscMemcpy(mesh->childIDs, childIDs, size * sizeof(*childIDs));CHKERRQ(ierr);
964f9f063d4SToby Isaac   }
965f9f063d4SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
966f9f063d4SToby Isaac   if (refTree) {
967f9f063d4SToby Isaac     DMLabel canonLabel;
968f9f063d4SToby Isaac 
969c58f1c22SToby Isaac     ierr = DMGetLabel(refTree,"canonical",&canonLabel);CHKERRQ(ierr);
970f9f063d4SToby Isaac     if (canonLabel) {
971f9f063d4SToby Isaac       PetscInt i;
972f9f063d4SToby Isaac 
973f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
974f9f063d4SToby Isaac         PetscInt canon;
975f9f063d4SToby Isaac         ierr = DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon);CHKERRQ(ierr);
976f9f063d4SToby Isaac         if (canon >= 0) {
977f9f063d4SToby Isaac           mesh->childIDs[i] = canon;
978f9f063d4SToby Isaac         }
979f9f063d4SToby Isaac       }
980f9f063d4SToby Isaac     }
981f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
982f7c74593SToby Isaac   }
983f7c74593SToby Isaac   else {
984f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
985f9f063d4SToby Isaac   }
986f9f063d4SToby Isaac   ierr = DMPlexTreeSymmetrize(dm);CHKERRQ(ierr);
987f9f063d4SToby Isaac   if (computeCanonical) {
988f9f063d4SToby Isaac     PetscInt d, dim;
989f9f063d4SToby Isaac 
990f9f063d4SToby Isaac     /* add the canonical label */
99128f4b327SMatthew G. Knepley     ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
992c58f1c22SToby Isaac     ierr = DMCreateLabel(dm,"canonical");CHKERRQ(ierr);
993f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
994f9f063d4SToby Isaac       PetscInt p, dStart, dEnd, canon = -1, cNumChildren;
995f9f063d4SToby Isaac       const PetscInt *cChildren;
996f9f063d4SToby Isaac 
997f9f063d4SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
998f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
999f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&cNumChildren,&cChildren);CHKERRQ(ierr);
1000f9f063d4SToby Isaac         if (cNumChildren) {
1001f9f063d4SToby Isaac           canon = p;
1002f9f063d4SToby Isaac           break;
1003f9f063d4SToby Isaac         }
1004f9f063d4SToby Isaac       }
1005f9f063d4SToby Isaac       if (canon == -1) continue;
1006f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1007f9f063d4SToby Isaac         PetscInt numChildren, i;
1008f9f063d4SToby Isaac         const PetscInt *children;
1009f9f063d4SToby Isaac 
1010f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&numChildren,&children);CHKERRQ(ierr);
1011f9f063d4SToby Isaac         if (numChildren) {
1012f9f063d4SToby 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);
1013c58f1c22SToby Isaac           ierr = DMSetLabelValue(dm,"canonical",p,canon);CHKERRQ(ierr);
1014f9f063d4SToby Isaac           for (i = 0; i < numChildren; i++) {
1015c58f1c22SToby Isaac             ierr = DMSetLabelValue(dm,"canonical",children[i],cChildren[i]);CHKERRQ(ierr);
1016f9f063d4SToby Isaac           }
1017f9f063d4SToby Isaac         }
1018f9f063d4SToby Isaac       }
1019f9f063d4SToby Isaac     }
1020f9f063d4SToby Isaac   }
1021776742edSToby Isaac   if (exchangeSupports) {
1022776742edSToby Isaac     ierr = DMPlexTreeExchangeSupports(dm);CHKERRQ(ierr);
1023776742edSToby Isaac   }
1024f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
1025f7c74593SToby Isaac   /* reset anchors */
1026f7c74593SToby Isaac   ierr = DMPlexSetAnchors(dm,NULL,NULL);CHKERRQ(ierr);
1027f9f063d4SToby Isaac   PetscFunctionReturn(0);
1028f9f063d4SToby Isaac }
1029f9f063d4SToby Isaac 
10300b7167a0SToby Isaac /*@
10310b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
10320b7167a0SToby Isaac   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
10330b7167a0SToby Isaac   tree root.
10340b7167a0SToby Isaac 
10350b7167a0SToby Isaac   Collective on dm
10360b7167a0SToby Isaac 
10370b7167a0SToby Isaac   Input Parameters:
10380b7167a0SToby Isaac + dm - the DMPlex object
10390b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
10400b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
10410b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
10420b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
10430b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
10440b7167a0SToby Isaac 
10450b7167a0SToby Isaac   Level: intermediate
10460b7167a0SToby Isaac 
1047a17985deSToby Isaac .seealso: DMPlexGetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
10480b7167a0SToby Isaac @*/
1049b2f41788SToby Isaac PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
10500b7167a0SToby Isaac {
10510b7167a0SToby Isaac   PetscErrorCode ierr;
10520b7167a0SToby Isaac 
10530b7167a0SToby Isaac   PetscFunctionBegin;
1054776742edSToby Isaac   ierr = DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
10550b7167a0SToby Isaac   PetscFunctionReturn(0);
10560b7167a0SToby Isaac }
10570b7167a0SToby Isaac 
1058b2f41788SToby Isaac /*@
1059b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1060b2f41788SToby Isaac   Collective on dm
1061b2f41788SToby Isaac 
1062b2f41788SToby Isaac   Input Parameters:
1063b2f41788SToby Isaac . dm - the DMPlex object
1064b2f41788SToby Isaac 
1065b2f41788SToby Isaac   Output Parameters:
1066b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1067b2f41788SToby Isaac                   offset indexes the parent and childID list
1068b2f41788SToby Isaac . parents - a list of the point parents
1069b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1070b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1071b2f41788SToby Isaac . childSection - the inverse of the parent section
1072b2f41788SToby Isaac - children - a list of the point children
1073b2f41788SToby Isaac 
1074b2f41788SToby Isaac   Level: intermediate
1075b2f41788SToby Isaac 
1076a17985deSToby Isaac .seealso: DMPlexSetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
1077b2f41788SToby Isaac @*/
1078b2f41788SToby Isaac PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1079b2f41788SToby Isaac {
1080b2f41788SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
1081b2f41788SToby Isaac 
1082b2f41788SToby Isaac   PetscFunctionBegin;
1083b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1084b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1085b2f41788SToby Isaac   if (parents)       *parents       = mesh->parents;
1086b2f41788SToby Isaac   if (childIDs)      *childIDs      = mesh->childIDs;
1087b2f41788SToby Isaac   if (childSection)  *childSection  = mesh->childSection;
1088b2f41788SToby Isaac   if (children)      *children      = mesh->children;
1089b2f41788SToby Isaac   PetscFunctionReturn(0);
1090b2f41788SToby Isaac }
1091b2f41788SToby Isaac 
1092d961a43aSToby Isaac /*@
1093eaf898f9SPatrick Sanan   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)
1094d961a43aSToby Isaac 
1095d961a43aSToby Isaac   Input Parameters:
1096d961a43aSToby Isaac + dm - the DMPlex object
1097d961a43aSToby Isaac - point - the query point
1098d961a43aSToby Isaac 
1099d961a43aSToby Isaac   Output Parameters:
1100d961a43aSToby Isaac + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1101d961a43aSToby Isaac - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point
1102d961a43aSToby Isaac             does not have a parent
1103d961a43aSToby Isaac 
1104d961a43aSToby Isaac   Level: intermediate
1105d961a43aSToby Isaac 
1106d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeChildren()
1107d961a43aSToby Isaac @*/
1108d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1109d961a43aSToby Isaac {
1110d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1111d961a43aSToby Isaac   PetscSection   pSec;
1112d961a43aSToby Isaac   PetscErrorCode ierr;
1113d961a43aSToby Isaac 
1114d961a43aSToby Isaac   PetscFunctionBegin;
1115d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1116d961a43aSToby Isaac   pSec = mesh->parentSection;
1117d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1118d961a43aSToby Isaac     PetscInt dof;
1119d961a43aSToby Isaac 
1120d961a43aSToby Isaac     ierr = PetscSectionGetDof (pSec, point, &dof);CHKERRQ(ierr);
1121d961a43aSToby Isaac     if (dof) {
1122d961a43aSToby Isaac       PetscInt off;
1123d961a43aSToby Isaac 
1124d961a43aSToby Isaac       ierr = PetscSectionGetOffset (pSec, point, &off);CHKERRQ(ierr);
1125d961a43aSToby Isaac       if (parent)  *parent = mesh->parents[off];
1126d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
1127d961a43aSToby Isaac       PetscFunctionReturn(0);
1128d961a43aSToby Isaac     }
1129d961a43aSToby Isaac   }
1130d961a43aSToby Isaac   if (parent) {
1131d961a43aSToby Isaac     *parent = point;
1132d961a43aSToby Isaac   }
1133d961a43aSToby Isaac   if (childID) {
1134d961a43aSToby Isaac     *childID = 0;
1135d961a43aSToby Isaac   }
1136d961a43aSToby Isaac   PetscFunctionReturn(0);
1137d961a43aSToby Isaac }
1138d961a43aSToby Isaac 
1139d961a43aSToby Isaac /*@C
1140eaf898f9SPatrick Sanan   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)
1141d961a43aSToby Isaac 
1142d961a43aSToby Isaac   Input Parameters:
1143d961a43aSToby Isaac + dm - the DMPlex object
1144d961a43aSToby Isaac - point - the query point
1145d961a43aSToby Isaac 
1146d961a43aSToby Isaac   Output Parameters:
1147d961a43aSToby Isaac + numChildren - if not NULL, set to the number of children
1148d961a43aSToby Isaac - children - if not NULL, set to a list children, or set to NULL if the point has no children
1149d961a43aSToby Isaac 
1150d961a43aSToby Isaac   Level: intermediate
1151d961a43aSToby Isaac 
1152d961a43aSToby Isaac   Fortran Notes:
1153d961a43aSToby Isaac   Since it returns an array, this routine is only available in Fortran 90, and you must
1154d961a43aSToby Isaac   include petsc.h90 in your code.
1155d961a43aSToby Isaac 
1156d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeParent()
1157d961a43aSToby Isaac @*/
1158d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1159d961a43aSToby Isaac {
1160d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1161d961a43aSToby Isaac   PetscSection   childSec;
1162d961a43aSToby Isaac   PetscInt       dof = 0;
1163d961a43aSToby Isaac   PetscErrorCode ierr;
1164d961a43aSToby Isaac 
1165d961a43aSToby Isaac   PetscFunctionBegin;
1166d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1167d961a43aSToby Isaac   childSec = mesh->childSection;
1168d961a43aSToby Isaac   if (childSec && point >= childSec->pStart && point < childSec->pEnd) {
1169d961a43aSToby Isaac     ierr = PetscSectionGetDof (childSec, point, &dof);CHKERRQ(ierr);
1170d961a43aSToby Isaac   }
1171d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1172d961a43aSToby Isaac   if (children) {
1173d961a43aSToby Isaac     if (dof) {
1174d961a43aSToby Isaac       PetscInt off;
1175d961a43aSToby Isaac 
1176d961a43aSToby Isaac       ierr = PetscSectionGetOffset (childSec, point, &off);CHKERRQ(ierr);
1177d961a43aSToby Isaac       *children = &mesh->children[off];
1178d961a43aSToby Isaac     }
1179d961a43aSToby Isaac     else {
1180d961a43aSToby Isaac       *children = NULL;
1181d961a43aSToby Isaac     }
1182d961a43aSToby Isaac   }
1183d961a43aSToby Isaac   PetscFunctionReturn(0);
1184d961a43aSToby Isaac }
11850c37af3bSToby Isaac 
118652a3aeb4SToby Isaac static PetscErrorCode EvaluateBasis(PetscSpace space, PetscInt nBasis, PetscInt nFunctionals, PetscInt nComps, PetscInt nPoints, const PetscInt *pointsPerFn, const PetscReal *points, const PetscReal *weights, PetscReal *work, Mat basisAtPoints)
1187b3a4bf2aSToby Isaac {
118852a3aeb4SToby Isaac   PetscInt       f, b, p, c, offset, qPoints;
1189b3a4bf2aSToby Isaac   PetscErrorCode ierr;
1190b3a4bf2aSToby Isaac 
1191b3a4bf2aSToby Isaac   PetscFunctionBegin;
1192b3a4bf2aSToby Isaac   ierr = PetscSpaceEvaluate(space,nPoints,points,work,NULL,NULL);CHKERRQ(ierr);
119352a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
119452a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
119552a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1196b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1197b3a4bf2aSToby Isaac 
119852a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
119952a3aeb4SToby Isaac         for (c = 0; c < nComps; c++) {
120052a3aeb4SToby Isaac           val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
1201b3a4bf2aSToby Isaac         }
120252a3aeb4SToby Isaac       }
120352a3aeb4SToby Isaac       ierr = MatSetValue(basisAtPoints,b,f,val,INSERT_VALUES);CHKERRQ(ierr);
1204b3a4bf2aSToby Isaac     }
1205b3a4bf2aSToby Isaac     offset += qPoints;
1206b3a4bf2aSToby Isaac   }
1207b3a4bf2aSToby Isaac   ierr = MatAssemblyBegin(basisAtPoints,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1208b3a4bf2aSToby Isaac   ierr = MatAssemblyEnd(basisAtPoints,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1209b3a4bf2aSToby Isaac   PetscFunctionReturn(0);
1210b3a4bf2aSToby Isaac }
1211b3a4bf2aSToby Isaac 
1212f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
12130c37af3bSToby Isaac {
12140c37af3bSToby Isaac   PetscDS        ds;
12150c37af3bSToby Isaac   PetscInt       spdim;
12160c37af3bSToby Isaac   PetscInt       numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
12170c37af3bSToby Isaac   const PetscInt *anchors;
1218f7c74593SToby Isaac   PetscSection   aSec;
12190c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
12200c37af3bSToby Isaac   IS             aIS;
12210c37af3bSToby Isaac   PetscErrorCode ierr;
12220c37af3bSToby Isaac 
12230c37af3bSToby Isaac   PetscFunctionBegin;
12240c37af3bSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
12250c37af3bSToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
12260c37af3bSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
12270c37af3bSToby Isaac   ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
1228a17985deSToby Isaac   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
12290c37af3bSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
12300c37af3bSToby Isaac   ierr = PetscSectionGetChart(cSec,&conStart,&conEnd);CHKERRQ(ierr);
123128f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&spdim);CHKERRQ(ierr);
12320c37af3bSToby Isaac   ierr = PetscMalloc6(spdim,&v0,spdim,&v0parent,spdim,&vtmp,spdim*spdim,&J,spdim*spdim,&Jparent,spdim*spdim,&invJparent);CHKERRQ(ierr);
12330c37af3bSToby Isaac 
12340c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
12350dd1b1feSToby Isaac     PetscObject disc;
12360dd1b1feSToby Isaac     PetscClassId id;
1237b3a4bf2aSToby Isaac     PetscSpace     bspace;
1238b3a4bf2aSToby Isaac     PetscDualSpace dspace;
12399c3cf19fSMatthew G. Knepley     PetscInt i, j, k, nPoints, Nc, offset;
124052a3aeb4SToby Isaac     PetscInt fSize, maxDof;
1241b3a4bf2aSToby Isaac     PetscReal   *weights, *pointsRef, *pointsReal, *work;
12422c44ad04SToby Isaac     PetscScalar *scwork, *X;
12432c44ad04SToby Isaac     PetscInt  *sizes, *workIndRow, *workIndCol;
12440c37af3bSToby Isaac     Mat Amat, Bmat, Xmat;
12452c44ad04SToby Isaac     const PetscInt    *numDof  = NULL;
1246085f0adfSToby Isaac     const PetscInt    ***perms = NULL;
1247085f0adfSToby Isaac     const PetscScalar ***flips = NULL;
12480c37af3bSToby Isaac 
12490dd1b1feSToby Isaac     ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
12500dd1b1feSToby Isaac     ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
12510dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1252b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE) disc;
1253b3a4bf2aSToby Isaac 
1254b3a4bf2aSToby Isaac       ierr = PetscFEGetBasisSpace(fe,&bspace);CHKERRQ(ierr);
1255b3a4bf2aSToby Isaac       ierr = PetscFEGetDualSpace(fe,&dspace);CHKERRQ(ierr);
1256b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetDimension(dspace,&fSize);CHKERRQ(ierr);
125752a3aeb4SToby Isaac       ierr = PetscFEGetNumComponents(fe,&Nc);CHKERRQ(ierr);
12580dd1b1feSToby Isaac     }
12590dd1b1feSToby Isaac     else if (id == PETSCFV_CLASSID) {
1260b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV) disc;
1261b3a4bf2aSToby Isaac 
126252a3aeb4SToby Isaac       ierr = PetscFVGetNumComponents(fv,&Nc);CHKERRQ(ierr);
1263b3a4bf2aSToby Isaac       ierr = PetscSpaceCreate(PetscObjectComm((PetscObject)fv),&bspace);CHKERRQ(ierr);
1264b3a4bf2aSToby Isaac       ierr = PetscSpaceSetType(bspace,PETSCSPACEPOLYNOMIAL);CHKERRQ(ierr);
1265b3a4bf2aSToby Isaac       ierr = PetscSpaceSetOrder(bspace,0);CHKERRQ(ierr);
126652a3aeb4SToby Isaac       ierr = PetscSpaceSetNumComponents(bspace,Nc);CHKERRQ(ierr);
1267*157782e2SToby Isaac       ierr = PetscSpaceSetNumVariables(bspace,spdim);CHKERRQ(ierr);
1268b3a4bf2aSToby Isaac       ierr = PetscSpaceSetUp(bspace);CHKERRQ(ierr);
1269b3a4bf2aSToby Isaac       ierr = PetscFVGetDualSpace(fv,&dspace);CHKERRQ(ierr);
1270b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetDimension(dspace,&fSize);CHKERRQ(ierr);
12710dd1b1feSToby Isaac     }
12720dd1b1feSToby Isaac     else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
12732c44ad04SToby Isaac     ierr = PetscDualSpaceGetNumDof(dspace,&numDof);CHKERRQ(ierr);
12742c44ad04SToby Isaac     for (i = 0, maxDof = 0; i <= spdim; i++) {maxDof = PetscMax(maxDof,numDof[i]);}
1275085f0adfSToby Isaac     ierr = PetscDualSpaceGetSymmetries(dspace,&perms,&flips);CHKERRQ(ierr);
12760dd1b1feSToby Isaac 
12770c37af3bSToby Isaac     ierr = MatCreate(PETSC_COMM_SELF,&Amat);CHKERRQ(ierr);
12780c37af3bSToby Isaac     ierr = MatSetSizes(Amat,fSize,fSize,fSize,fSize);CHKERRQ(ierr);
12790c37af3bSToby Isaac     ierr = MatSetType(Amat,MATSEQDENSE);CHKERRQ(ierr);
12800c37af3bSToby Isaac     ierr = MatSetUp(Amat);CHKERRQ(ierr);
12810c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Bmat);CHKERRQ(ierr);
12820c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Xmat);CHKERRQ(ierr);
12830c37af3bSToby Isaac     nPoints = 0;
12840c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
128552a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
12860c37af3bSToby Isaac       PetscQuadrature quad;
12870c37af3bSToby Isaac 
1288b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetFunctional(dspace,i,&quad);CHKERRQ(ierr);
128952a3aeb4SToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,&thisNc,&qPoints,NULL,NULL);CHKERRQ(ierr);
129052a3aeb4SToby Isaac       if (thisNc != Nc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %D does not much basis dim %D\n",thisNc,Nc);
12910c37af3bSToby Isaac       nPoints += qPoints;
12920c37af3bSToby Isaac     }
129352a3aeb4SToby Isaac     ierr = PetscMalloc7(fSize,&sizes,nPoints*Nc,&weights,spdim*nPoints,&pointsRef,spdim*nPoints,&pointsReal,nPoints*fSize*Nc,&work,maxDof,&workIndRow,maxDof,&workIndCol);CHKERRQ(ierr);
12942c44ad04SToby Isaac     ierr = PetscMalloc1(maxDof * maxDof,&scwork);CHKERRQ(ierr);
12950c37af3bSToby Isaac     offset = 0;
12960c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12970c37af3bSToby Isaac       PetscInt        qPoints;
12980c37af3bSToby Isaac       const PetscReal    *p, *w;
12990c37af3bSToby Isaac       PetscQuadrature quad;
13000c37af3bSToby Isaac 
1301b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetFunctional(dspace,i,&quad);CHKERRQ(ierr);
130252a3aeb4SToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,NULL,&qPoints,&p,&w);CHKERRQ(ierr);
130352a3aeb4SToby Isaac       ierr = PetscMemcpy(weights+Nc*offset,w,Nc*qPoints*sizeof(*w));CHKERRQ(ierr);
13040c37af3bSToby Isaac       ierr = PetscMemcpy(pointsRef+spdim*offset,p,spdim*qPoints*sizeof(*p));CHKERRQ(ierr);
1305b3a4bf2aSToby Isaac       sizes[i] = qPoints;
13060c37af3bSToby Isaac       offset  += qPoints;
13070c37af3bSToby Isaac     }
130852a3aeb4SToby Isaac     ierr = EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsRef,weights,work,Amat);CHKERRQ(ierr);
13090c37af3bSToby Isaac     ierr = MatLUFactor(Amat,NULL,NULL,NULL);CHKERRQ(ierr);
13100c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
13110c37af3bSToby Isaac       PetscInt        parent;
13120c37af3bSToby Isaac       PetscInt        closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
13130c37af3bSToby Isaac       PetscInt        *childOffsets, *parentOffsets;
13140c37af3bSToby Isaac 
13150c37af3bSToby Isaac       ierr = DMPlexGetTreeParent(dm,c,&parent,NULL);CHKERRQ(ierr);
13160c37af3bSToby Isaac       if (parent == c) continue;
13170c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13180c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13190c37af3bSToby Isaac         PetscInt p = closure[2*i];
13200c37af3bSToby Isaac         PetscInt conDof;
13210c37af3bSToby Isaac 
13220c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1323085f0adfSToby Isaac         if (numFields) {
13240c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
13250c37af3bSToby Isaac         }
13260c37af3bSToby Isaac         else {
13270c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
13280c37af3bSToby Isaac         }
13290c37af3bSToby Isaac         if (conDof) break;
13300c37af3bSToby Isaac       }
13310c37af3bSToby Isaac       if (i == closureSize) {
13320c37af3bSToby Isaac         ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13330c37af3bSToby Isaac         continue;
13340c37af3bSToby Isaac       }
13350c37af3bSToby Isaac 
133673a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
133773a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent);CHKERRQ(ierr);
13380c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1339b3a4bf2aSToby Isaac         CoordinatesRefToReal(spdim, spdim, v0, J, &pointsRef[i*spdim],vtmp);
1340b3a4bf2aSToby Isaac         CoordinatesRealToRef(spdim, spdim, v0parent, invJparent, vtmp, &pointsReal[i*spdim]);
13410c37af3bSToby Isaac       }
134252a3aeb4SToby Isaac       ierr = EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsReal,weights,work,Bmat);CHKERRQ(ierr);
13430c37af3bSToby Isaac       ierr = MatMatSolve(Amat,Bmat,Xmat);CHKERRQ(ierr);
13442c44ad04SToby Isaac       ierr = MatDenseGetArray(Xmat,&X);CHKERRQ(ierr);
13450c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
13460c37af3bSToby Isaac       ierr = PetscMalloc2(closureSize+1,&childOffsets,closureSizeP+1,&parentOffsets);CHKERRQ(ierr);
13470c37af3bSToby Isaac       childOffsets[0] = 0;
13480c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13490c37af3bSToby Isaac         PetscInt p = closure[2*i];
13500c37af3bSToby Isaac         PetscInt dof;
13510c37af3bSToby Isaac 
1352085f0adfSToby Isaac         if (numFields) {
13530c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
13540c37af3bSToby Isaac         }
13550c37af3bSToby Isaac         else {
13560c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
13570c37af3bSToby Isaac         }
135852a3aeb4SToby Isaac         childOffsets[i+1]=childOffsets[i]+dof;
13590c37af3bSToby Isaac       }
13600c37af3bSToby Isaac       parentOffsets[0] = 0;
13610c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
13620c37af3bSToby Isaac         PetscInt p = closureP[2*i];
13630c37af3bSToby Isaac         PetscInt dof;
13640c37af3bSToby Isaac 
1365085f0adfSToby Isaac         if (numFields) {
13660c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
13670c37af3bSToby Isaac         }
13680c37af3bSToby Isaac         else {
13690c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
13700c37af3bSToby Isaac         }
137152a3aeb4SToby Isaac         parentOffsets[i+1]=parentOffsets[i]+dof;
13720c37af3bSToby Isaac       }
13730c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13742c44ad04SToby Isaac         PetscInt conDof, conOff, aDof, aOff, nWork;
13750c37af3bSToby Isaac         PetscInt p = closure[2*i];
13760c37af3bSToby Isaac         PetscInt o = closure[2*i+1];
1377085f0adfSToby Isaac         const PetscInt    *perm;
1378085f0adfSToby Isaac         const PetscScalar *flip;
13790c37af3bSToby Isaac 
13800c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1381085f0adfSToby Isaac         if (numFields) {
13820c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
13830c37af3bSToby Isaac           ierr = PetscSectionGetFieldOffset(cSec,p,f,&conOff);CHKERRQ(ierr);
13840c37af3bSToby Isaac         }
13850c37af3bSToby Isaac         else {
13860c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
13870c37af3bSToby Isaac           ierr = PetscSectionGetOffset(cSec,p,&conOff);CHKERRQ(ierr);
13880c37af3bSToby Isaac         }
13890c37af3bSToby Isaac         if (!conDof) continue;
1390085f0adfSToby Isaac         perm  = (perms && perms[i]) ? perms[i][o] : NULL;
1391085f0adfSToby Isaac         flip  = (flips && flips[i]) ? flips[i][o] : NULL;
13920c37af3bSToby Isaac         ierr  = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
13930c37af3bSToby Isaac         ierr  = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
13942c44ad04SToby Isaac         nWork = childOffsets[i+1]-childOffsets[i];
13950c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
13960c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
13970c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
13980c37af3bSToby Isaac 
1399085f0adfSToby Isaac           if (numFields) {
14000c37af3bSToby Isaac             ierr = PetscSectionGetFieldDof(section,a,f,&aSecDof);CHKERRQ(ierr);
14010c37af3bSToby Isaac             ierr = PetscSectionGetFieldOffset(section,a,f,&aSecOff);CHKERRQ(ierr);
14020c37af3bSToby Isaac           }
14030c37af3bSToby Isaac           else {
14040c37af3bSToby Isaac             ierr = PetscSectionGetDof(section,a,&aSecDof);CHKERRQ(ierr);
14050c37af3bSToby Isaac             ierr = PetscSectionGetOffset(section,a,&aSecOff);CHKERRQ(ierr);
14060c37af3bSToby Isaac           }
14070c37af3bSToby Isaac           if (!aSecDof) continue;
14080c37af3bSToby Isaac 
14090c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
14100c37af3bSToby Isaac             PetscInt q = closureP[2*j];
14110c37af3bSToby Isaac             PetscInt oq = closureP[2*j+1];
14122c44ad04SToby Isaac 
14132c44ad04SToby Isaac             if (q == a) {
141452a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1415085f0adfSToby Isaac               const PetscInt    *permP;
1416085f0adfSToby Isaac               const PetscScalar *flipP;
1417085f0adfSToby Isaac 
1418085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1419085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
14202c44ad04SToby Isaac               nWorkP = parentOffsets[j+1]-parentOffsets[j];
14212c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
14222c44ad04SToby Isaac                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArray is
14232c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
14242c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
14252c44ad04SToby Isaac                 for (s = 0; s < nWorkP; s++) {
14262c44ad04SToby Isaac                   scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
14272c44ad04SToby Isaac                 }
14282c44ad04SToby Isaac               }
142952a3aeb4SToby Isaac               for (r = 0; r < nWork; r++)  {workIndRow[perm  ? perm[r]  : r] = conOff  + r;}
143052a3aeb4SToby Isaac               for (s = 0; s < nWorkP; s++) {workIndCol[permP ? permP[s] : s] = aSecOff + s;}
14312c44ad04SToby Isaac               if (flip) {
14322c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14332c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14342c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flip[r];
14352c44ad04SToby Isaac                   }
14362c44ad04SToby Isaac                 }
14372c44ad04SToby Isaac               }
14382c44ad04SToby Isaac               if (flipP) {
14392c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14402c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14412c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flipP[s];
14422c44ad04SToby Isaac                   }
14432c44ad04SToby Isaac                 }
14442c44ad04SToby Isaac               }
14452c44ad04SToby Isaac               ierr = MatSetValues(cMat,nWork,workIndRow,nWorkP,workIndCol,scwork,INSERT_VALUES);CHKERRQ(ierr);
14462c44ad04SToby Isaac               break;
14470c37af3bSToby Isaac             }
14480c37af3bSToby Isaac           }
14490c37af3bSToby Isaac         }
14500c37af3bSToby Isaac       }
14512c44ad04SToby Isaac       ierr = MatDenseRestoreArray(Xmat,&X);CHKERRQ(ierr);
14520c37af3bSToby Isaac       ierr = PetscFree2(childOffsets,parentOffsets);CHKERRQ(ierr);
14530c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
14540c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
14550c37af3bSToby Isaac     }
14560c37af3bSToby Isaac     ierr = MatDestroy(&Amat);CHKERRQ(ierr);
14570c37af3bSToby Isaac     ierr = MatDestroy(&Bmat);CHKERRQ(ierr);
14580c37af3bSToby Isaac     ierr = MatDestroy(&Xmat);CHKERRQ(ierr);
14592c44ad04SToby Isaac     ierr = PetscFree(scwork);CHKERRQ(ierr);
14602c44ad04SToby Isaac     ierr = PetscFree7(sizes,weights,pointsRef,pointsReal,work,workIndRow,workIndCol);CHKERRQ(ierr);
1461b3a4bf2aSToby Isaac     if (id == PETSCFV_CLASSID) {
1462b3a4bf2aSToby Isaac       ierr = PetscSpaceDestroy(&bspace);CHKERRQ(ierr);
1463b3a4bf2aSToby Isaac     }
14640c37af3bSToby Isaac   }
14650c37af3bSToby Isaac   ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14660c37af3bSToby Isaac   ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14670c37af3bSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJparent);CHKERRQ(ierr);
14680c37af3bSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
14690c37af3bSToby Isaac 
14700c37af3bSToby Isaac   PetscFunctionReturn(0);
14710c37af3bSToby Isaac }
147295a0b26dSToby Isaac 
147321968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
147495a0b26dSToby Isaac {
1475f7c74593SToby Isaac   Mat               refCmat;
147621968bf8SToby Isaac   PetscDS           ds;
1477085f0adfSToby Isaac   PetscInt          numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
147821968bf8SToby Isaac   PetscScalar       ***refPointFieldMats;
147921968bf8SToby Isaac   PetscSection      refConSec, refAnSec, refSection;
148021968bf8SToby Isaac   IS                refAnIS;
148121968bf8SToby Isaac   const PetscInt    *refAnchors;
1482085f0adfSToby Isaac   const PetscInt    **perms;
1483085f0adfSToby Isaac   const PetscScalar **flips;
148495a0b26dSToby Isaac   PetscErrorCode    ierr;
148595a0b26dSToby Isaac 
148695a0b26dSToby Isaac   PetscFunctionBegin;
148721968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
148895a0b26dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1489085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
1490f7c74593SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
1491a17985deSToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
149295a0b26dSToby Isaac   ierr = ISGetIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
149395a0b26dSToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
149495a0b26dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
149595a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
149695a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldN);CHKERRQ(ierr);
149795a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
149895a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
149995a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
150095a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof*maxAnDof,&cols);CHKERRQ(ierr);
150195a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
150295a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
150395a0b26dSToby Isaac 
150495a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
150595a0b26dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
150695a0b26dSToby Isaac     if (!pDof || parent == p) continue;
150795a0b26dSToby Isaac 
1508085f0adfSToby Isaac     ierr = PetscMalloc1(maxFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
1509085f0adfSToby Isaac     ierr = PetscCalloc1(maxFields,&refPointFieldN[p-pRefStart]);CHKERRQ(ierr);
151095a0b26dSToby Isaac     ierr = DMPlexGetTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1511085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1512085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
151395a0b26dSToby Isaac 
1514085f0adfSToby Isaac       if (f < numFields) {
151595a0b26dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
151695a0b26dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
1517085f0adfSToby Isaac         ierr = PetscSectionGetFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1518085f0adfSToby Isaac       } else {
151995a0b26dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
152095a0b26dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
1521085f0adfSToby Isaac         ierr = PetscSectionGetPointSyms(refSection,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
152295a0b26dSToby Isaac       }
152395a0b26dSToby Isaac 
152495a0b26dSToby Isaac       for (r = 0; r < cDof; r++) {
152595a0b26dSToby Isaac         rows[r] = cOff + r;
152695a0b26dSToby Isaac       }
152795a0b26dSToby Isaac       numCols = 0;
152895a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
152995a0b26dSToby Isaac         PetscInt          q = closure[2*i];
153095a0b26dSToby Isaac         PetscInt          aDof, aOff, j;
1531085f0adfSToby Isaac         const PetscInt    *perm = perms ? perms[i] : NULL;
153295a0b26dSToby Isaac 
1533085f0adfSToby Isaac         if (numFields) {
153495a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
153595a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
153695a0b26dSToby Isaac         }
153795a0b26dSToby Isaac         else {
153895a0b26dSToby Isaac           ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
153995a0b26dSToby Isaac           ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
154095a0b26dSToby Isaac         }
154195a0b26dSToby Isaac 
154295a0b26dSToby Isaac         for (j = 0; j < aDof; j++) {
1543085f0adfSToby Isaac           cols[numCols++] = aOff + (perm ? perm[j] : j);
154495a0b26dSToby Isaac         }
154595a0b26dSToby Isaac       }
154695a0b26dSToby Isaac       refPointFieldN[p-pRefStart][f] = numCols;
154795a0b26dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
154895a0b26dSToby Isaac       ierr = MatGetValues(refCmat,cDof,rows,numCols,cols,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
1549085f0adfSToby Isaac       if (flips) {
1550085f0adfSToby Isaac         PetscInt colOff = 0;
1551085f0adfSToby Isaac 
1552085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1553085f0adfSToby Isaac           PetscInt          q = closure[2*i];
1554085f0adfSToby Isaac           PetscInt          aDof, aOff, j;
1555085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1556085f0adfSToby Isaac 
1557085f0adfSToby Isaac           if (numFields) {
1558085f0adfSToby Isaac             ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
1559085f0adfSToby Isaac             ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
1560085f0adfSToby Isaac           }
1561085f0adfSToby Isaac           else {
1562085f0adfSToby Isaac             ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
1563085f0adfSToby Isaac             ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
1564085f0adfSToby Isaac           }
1565085f0adfSToby Isaac           if (flip) {
1566085f0adfSToby Isaac             PetscInt k;
1567085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1568085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1569085f0adfSToby Isaac                 refPointFieldMats[p-pRefStart][f][k * numCols + colOff + j] *= flip[j];
1570085f0adfSToby Isaac               }
1571085f0adfSToby Isaac             }
1572085f0adfSToby Isaac           }
1573085f0adfSToby Isaac           colOff += aDof;
1574085f0adfSToby Isaac         }
1575085f0adfSToby Isaac       }
1576085f0adfSToby Isaac       if (numFields) {
1577085f0adfSToby Isaac         ierr = PetscSectionRestoreFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1578085f0adfSToby Isaac       } else {
1579085f0adfSToby Isaac         ierr = PetscSectionRestorePointSyms(refSection,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1580085f0adfSToby Isaac       }
158195a0b26dSToby Isaac     }
158295a0b26dSToby Isaac     ierr = DMPlexRestoreTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
158395a0b26dSToby Isaac   }
158421968bf8SToby Isaac   *childrenMats = refPointFieldMats;
158521968bf8SToby Isaac   *childrenN = refPointFieldN;
158621968bf8SToby Isaac   ierr = ISRestoreIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
158721968bf8SToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
158821968bf8SToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
158921968bf8SToby Isaac   PetscFunctionReturn(0);
159021968bf8SToby Isaac }
159121968bf8SToby Isaac 
159221968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
159321968bf8SToby Isaac {
159421968bf8SToby Isaac   PetscDS        ds;
159521968bf8SToby Isaac   PetscInt       **refPointFieldN;
159621968bf8SToby Isaac   PetscScalar    ***refPointFieldMats;
1597085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
159821968bf8SToby Isaac   PetscSection   refConSec;
159921968bf8SToby Isaac   PetscErrorCode ierr;
160021968bf8SToby Isaac 
160121968bf8SToby Isaac   PetscFunctionBegin;
160221968bf8SToby Isaac   refPointFieldN = *childrenN;
160321968bf8SToby Isaac   *childrenN = NULL;
160421968bf8SToby Isaac   refPointFieldMats = *childrenMats;
160521968bf8SToby Isaac   *childrenMats = NULL;
160621968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
160721968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1608085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);CHKERRQ(ierr);
160921968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
1610e44e4e7fSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
161121968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
161221968bf8SToby Isaac     PetscInt parent, pDof;
161321968bf8SToby Isaac 
161421968bf8SToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
161521968bf8SToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
161621968bf8SToby Isaac     if (!pDof || parent == p) continue;
161721968bf8SToby Isaac 
1618085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
161921968bf8SToby Isaac       PetscInt cDof;
162021968bf8SToby Isaac 
1621085f0adfSToby Isaac       if (numFields) {
162221968bf8SToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
162321968bf8SToby Isaac       }
162421968bf8SToby Isaac       else {
162521968bf8SToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
162621968bf8SToby Isaac       }
162721968bf8SToby Isaac 
162821968bf8SToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
162921968bf8SToby Isaac     }
163021968bf8SToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
163121968bf8SToby Isaac     ierr = PetscFree(refPointFieldN[p - pRefStart]);CHKERRQ(ierr);
163221968bf8SToby Isaac   }
163321968bf8SToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
163421968bf8SToby Isaac   ierr = PetscFree(refPointFieldN);CHKERRQ(ierr);
163521968bf8SToby Isaac   PetscFunctionReturn(0);
163621968bf8SToby Isaac }
163721968bf8SToby Isaac 
163821968bf8SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
163921968bf8SToby Isaac {
164021968bf8SToby Isaac   DM             refTree;
164121968bf8SToby Isaac   PetscDS        ds;
164221968bf8SToby Isaac   Mat            refCmat;
1643085f0adfSToby Isaac   PetscInt       numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
164421968bf8SToby Isaac   PetscScalar ***refPointFieldMats, *pointWork;
164521968bf8SToby Isaac   PetscSection   refConSec, refAnSec, anSec;
164621968bf8SToby Isaac   IS             refAnIS, anIS;
164721968bf8SToby Isaac   const PetscInt *anchors;
164821968bf8SToby Isaac   PetscErrorCode ierr;
164921968bf8SToby Isaac 
165021968bf8SToby Isaac   PetscFunctionBegin;
165121968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
165221968bf8SToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
165321968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1654085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
165521968bf8SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
165621968bf8SToby Isaac   ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
165721968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
165821968bf8SToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
165921968bf8SToby Isaac   ierr = DMPlexGetAnchors(dm,&anSec,&anIS);CHKERRQ(ierr);
166021968bf8SToby Isaac   ierr = ISGetIndices(anIS,&anchors);CHKERRQ(ierr);
166121968bf8SToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
166221968bf8SToby Isaac   ierr = PetscSectionGetChart(conSec,&conStart,&conEnd);CHKERRQ(ierr);
166321968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
166421968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
166521968bf8SToby Isaac   ierr = PetscMalloc1(maxDof*maxDof*maxAnDof,&pointWork);CHKERRQ(ierr);
166621968bf8SToby Isaac 
166721968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
166821968bf8SToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
166995a0b26dSToby Isaac 
167095a0b26dSToby Isaac   /* step 2: compute the preorder */
167195a0b26dSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
167295a0b26dSToby Isaac   ierr = PetscMalloc2(pEnd-pStart,&perm,pEnd-pStart,&iperm);CHKERRQ(ierr);
167395a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
167495a0b26dSToby Isaac     perm[p - pStart] = p;
167595a0b26dSToby Isaac     iperm[p - pStart] = p-pStart;
167695a0b26dSToby Isaac   }
167795a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
167895a0b26dSToby Isaac     PetscInt point = perm[p];
167995a0b26dSToby Isaac     PetscInt parent;
168095a0b26dSToby Isaac 
168195a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
168295a0b26dSToby Isaac     if (parent == point) {
168395a0b26dSToby Isaac       p++;
168495a0b26dSToby Isaac     }
168595a0b26dSToby Isaac     else {
168695a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
168795a0b26dSToby Isaac 
168895a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
168995a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
169095a0b26dSToby Isaac         PetscInt q = closure[2*i];
169195a0b26dSToby Isaac         if (iperm[q-pStart] > iperm[point-pStart]) {
169295a0b26dSToby Isaac           /* swap */
169395a0b26dSToby Isaac           perm[p]               = q;
169495a0b26dSToby Isaac           perm[iperm[q-pStart]] = point;
169595a0b26dSToby Isaac           iperm[point-pStart]   = iperm[q-pStart];
169695a0b26dSToby Isaac           iperm[q-pStart]       = p;
169795a0b26dSToby Isaac           break;
169895a0b26dSToby Isaac         }
169995a0b26dSToby Isaac       }
170095a0b26dSToby Isaac       size = closureSize;
170195a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
170295a0b26dSToby Isaac       if (i == size) {
170395a0b26dSToby Isaac         p++;
170495a0b26dSToby Isaac       }
170595a0b26dSToby Isaac     }
170695a0b26dSToby Isaac   }
170795a0b26dSToby Isaac 
170895a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
170995a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
171095a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
171195a0b26dSToby Isaac    * values outside of the Mat first.
171295a0b26dSToby Isaac    */
171395a0b26dSToby Isaac   {
171495a0b26dSToby Isaac     PetscInt nRows, row, nnz;
171595a0b26dSToby Isaac     PetscBool done;
171695a0b26dSToby Isaac     const PetscInt *ia, *ja;
171795a0b26dSToby Isaac     PetscScalar *vals;
171895a0b26dSToby Isaac 
171995a0b26dSToby Isaac     ierr = MatGetRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
172095a0b26dSToby Isaac     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not get RowIJ of constraint matrix");
172195a0b26dSToby Isaac     nnz  = ia[nRows];
172295a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
172395a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
172495a0b26dSToby Isaac     ierr = PetscMalloc1(nnz,&vals);CHKERRQ(ierr);
172595a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
172695a0b26dSToby Isaac       PetscInt        parent, childid, closureSize, *closure = NULL;
172795a0b26dSToby Isaac       PetscInt        point = perm[p], pointDof;
172895a0b26dSToby Isaac 
172995a0b26dSToby Isaac       ierr = DMPlexGetTreeParent(dm,point,&parent,&childid);CHKERRQ(ierr);
173095a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
173195a0b26dSToby Isaac       ierr = PetscSectionGetDof(conSec,point,&pointDof);CHKERRQ(ierr);
173295a0b26dSToby Isaac       if (!pointDof) continue;
173395a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1734085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1735085f0adfSToby Isaac         PetscInt cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
173695a0b26dSToby Isaac         PetscScalar *pointMat;
1737085f0adfSToby Isaac         const PetscInt    **perms;
1738085f0adfSToby Isaac         const PetscScalar **flips;
173995a0b26dSToby Isaac 
1740085f0adfSToby Isaac         if (numFields) {
174195a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(conSec,point,f,&cDof);CHKERRQ(ierr);
174295a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(conSec,point,f,&cOff);CHKERRQ(ierr);
174395a0b26dSToby Isaac         }
174495a0b26dSToby Isaac         else {
174595a0b26dSToby Isaac           ierr = PetscSectionGetDof(conSec,point,&cDof);CHKERRQ(ierr);
174695a0b26dSToby Isaac           ierr = PetscSectionGetOffset(conSec,point,&cOff);CHKERRQ(ierr);
174795a0b26dSToby Isaac         }
174895a0b26dSToby Isaac         if (!cDof) continue;
1749085f0adfSToby Isaac         if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);}
1750085f0adfSToby Isaac         else           {ierr = PetscSectionGetPointSyms(section,closureSize,closure,&perms,&flips);CHKERRQ(ierr);}
175195a0b26dSToby Isaac 
175295a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
175395a0b26dSToby Isaac #if defined(PETSC_USE_DEBUG)
175495a0b26dSToby Isaac         for (r = 0; r < cDof; r++) {
175595a0b26dSToby Isaac           if (cDof > 1 && r) {
175621968bf8SToby 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]));
175795a0b26dSToby Isaac           }
175895a0b26dSToby Isaac         }
175995a0b26dSToby Isaac #endif
176095a0b26dSToby Isaac         /* zero rows */
176195a0b26dSToby Isaac         for (i = ia[cOff] ; i< ia[cOff+cDof];i++) {
176295a0b26dSToby Isaac           vals[i] = 0.;
176395a0b26dSToby Isaac         }
176495a0b26dSToby Isaac         matOffset = ia[cOff];
176595a0b26dSToby Isaac         numFillCols = ia[cOff+1] - matOffset;
176695a0b26dSToby Isaac         pointMat = refPointFieldMats[childid-pRefStart][f];
176795a0b26dSToby Isaac         numCols = refPointFieldN[childid-pRefStart][f];
176895a0b26dSToby Isaac         offset = 0;
176995a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
177095a0b26dSToby Isaac           PetscInt q = closure[2*i];
177195a0b26dSToby Isaac           PetscInt aDof, aOff, j, k, qConDof, qConOff;
1772085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1773085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
177495a0b26dSToby Isaac 
177595a0b26dSToby Isaac           qConDof = qConOff = 0;
1776085f0adfSToby Isaac           if (numFields) {
177795a0b26dSToby Isaac             ierr = PetscSectionGetFieldDof(section,q,f,&aDof);CHKERRQ(ierr);
177895a0b26dSToby Isaac             ierr = PetscSectionGetFieldOffset(section,q,f,&aOff);CHKERRQ(ierr);
177995a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
178095a0b26dSToby Isaac               ierr = PetscSectionGetFieldDof(conSec,q,f,&qConDof);CHKERRQ(ierr);
178195a0b26dSToby Isaac               ierr = PetscSectionGetFieldOffset(conSec,q,f,&qConOff);CHKERRQ(ierr);
178295a0b26dSToby Isaac             }
178395a0b26dSToby Isaac           }
178495a0b26dSToby Isaac           else {
178595a0b26dSToby Isaac             ierr = PetscSectionGetDof(section,q,&aDof);CHKERRQ(ierr);
178695a0b26dSToby Isaac             ierr = PetscSectionGetOffset(section,q,&aOff);CHKERRQ(ierr);
178795a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
178895a0b26dSToby Isaac               ierr = PetscSectionGetDof(conSec,q,&qConDof);CHKERRQ(ierr);
178995a0b26dSToby Isaac               ierr = PetscSectionGetOffset(conSec,q,&qConOff);CHKERRQ(ierr);
179095a0b26dSToby Isaac             }
179195a0b26dSToby Isaac           }
179295a0b26dSToby Isaac           if (!aDof) continue;
179395a0b26dSToby Isaac           if (qConDof) {
179495a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
179595a0b26dSToby Isaac              * be filled, thanks to preordering */
179695a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
179795a0b26dSToby Isaac             PetscInt aMatOffset = ia[qConOff];
179895a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
179995a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
180095a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
180195a0b26dSToby Isaac                 PetscScalar inVal = 0;
180295a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1803085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
180495a0b26dSToby Isaac 
1805085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
180695a0b26dSToby Isaac                 }
180795a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
180895a0b26dSToby Isaac               }
180995a0b26dSToby Isaac             }
181095a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
181195a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
181295a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
181395a0b26dSToby Isaac               for (;k < numFillCols; k++) {
181495a0b26dSToby Isaac                 if (ja[matOffset + k] == col) {
181595a0b26dSToby Isaac                   break;
181695a0b26dSToby Isaac                 }
181795a0b26dSToby Isaac               }
181895a0b26dSToby Isaac               if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, col);
181995a0b26dSToby Isaac               for (r = 0; r < cDof; r++) {
182095a0b26dSToby Isaac                 vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
182195a0b26dSToby Isaac               }
182295a0b26dSToby Isaac             }
182395a0b26dSToby Isaac           }
182495a0b26dSToby Isaac           else {
182595a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
182695a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
182795a0b26dSToby Isaac               if (ja[matOffset + k] == aOff) {
182895a0b26dSToby Isaac                 break;
182995a0b26dSToby Isaac               }
183095a0b26dSToby Isaac             }
183195a0b26dSToby Isaac             if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, aOff);
183295a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1833085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1834085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1835085f0adfSToby Isaac 
1836085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
183795a0b26dSToby Isaac               }
183895a0b26dSToby Isaac             }
183995a0b26dSToby Isaac           }
184095a0b26dSToby Isaac           offset += aDof;
184195a0b26dSToby Isaac         }
1842085f0adfSToby Isaac         if (numFields) {
1843085f0adfSToby Isaac           ierr = PetscSectionRestoreFieldPointSyms(section,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1844085f0adfSToby Isaac         } else {
1845085f0adfSToby Isaac           ierr = PetscSectionRestorePointSyms(section,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1846085f0adfSToby Isaac         }
184795a0b26dSToby Isaac       }
184895a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
184995a0b26dSToby Isaac     }
185095a0b26dSToby Isaac     for (row = 0; row < nRows; row++) {
185195a0b26dSToby Isaac       ierr = MatSetValues(cMat,1,&row,ia[row+1]-ia[row],&ja[ia[row]],&vals[ia[row]],INSERT_VALUES);CHKERRQ(ierr);
185295a0b26dSToby Isaac     }
185395a0b26dSToby Isaac     ierr = MatRestoreRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
185495a0b26dSToby Isaac     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not restore RowIJ of constraint matrix");
185595a0b26dSToby Isaac     ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
185695a0b26dSToby Isaac     ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
185795a0b26dSToby Isaac     ierr = PetscFree(vals);CHKERRQ(ierr);
185895a0b26dSToby Isaac   }
185995a0b26dSToby Isaac 
186095a0b26dSToby Isaac   /* clean up */
186195a0b26dSToby Isaac   ierr = ISRestoreIndices(anIS,&anchors);CHKERRQ(ierr);
186295a0b26dSToby Isaac   ierr = PetscFree2(perm,iperm);CHKERRQ(ierr);
186395a0b26dSToby Isaac   ierr = PetscFree(pointWork);CHKERRQ(ierr);
186421968bf8SToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
186595a0b26dSToby Isaac   PetscFunctionReturn(0);
186695a0b26dSToby Isaac }
186795a0b26dSToby Isaac 
18686f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
18696f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
18706f5f1567SToby Isaac PetscErrorCode DMPlexTreeRefineCell (DM dm, PetscInt cell, DM *ncdm)
18716f5f1567SToby Isaac {
18726f5f1567SToby Isaac   DM K;
1873420f55faSMatthew G. Knepley   PetscMPIInt rank;
18746f5f1567SToby Isaac   PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
18756f5f1567SToby Isaac   PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations;
18766f5f1567SToby Isaac   PetscInt *Kembedding;
18776f5f1567SToby Isaac   PetscInt *cellClosure=NULL, nc;
18786f5f1567SToby Isaac   PetscScalar *newVertexCoords;
18796f5f1567SToby Isaac   PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
18806f5f1567SToby Isaac   PetscSection parentSection;
18816f5f1567SToby Isaac   PetscErrorCode ierr;
18826f5f1567SToby Isaac 
18836f5f1567SToby Isaac   PetscFunctionBegin;
18846f5f1567SToby Isaac   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRQ(ierr);
188528f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
18866f5f1567SToby Isaac   ierr = DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm);CHKERRQ(ierr);
188728f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ncdm,dim);CHKERRQ(ierr);
18886f5f1567SToby Isaac 
18896f5f1567SToby Isaac   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
18906f5f1567SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&parentSection);CHKERRQ(ierr);
18916f5f1567SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&K);CHKERRQ(ierr);
18926f5f1567SToby Isaac   if (!rank) {
18936f5f1567SToby Isaac     /* compute the new charts */
18946f5f1567SToby Isaac     ierr = PetscMalloc5(dim+1,&pNewCount,dim+1,&pNewStart,dim+1,&pNewEnd,dim+1,&pOldStart,dim+1,&pOldEnd);CHKERRQ(ierr);
18956f5f1567SToby Isaac     offset = 0;
18966f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18976f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
18986f5f1567SToby Isaac 
18996f5f1567SToby Isaac       pNewStart[d] = offset;
19006f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(dm,d,&pOldStart[d],&pOldEnd[d]);CHKERRQ(ierr);
19016f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
19026f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
19036f5f1567SToby Isaac       /* adding the new points */
19046f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
19056f5f1567SToby Isaac       if (!d) {
19066f5f1567SToby Isaac         /* removing the cell */
19076f5f1567SToby Isaac         pNewCount[d]--;
19086f5f1567SToby Isaac       }
19096f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19106f5f1567SToby Isaac         PetscInt parent;
19116f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&parent,NULL);CHKERRQ(ierr);
19126f5f1567SToby Isaac         if (parent == k) {
19136f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
19146f5f1567SToby Isaac           pNewCount[d]--;
19156f5f1567SToby Isaac         }
19166f5f1567SToby Isaac       }
19176f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
19186f5f1567SToby Isaac       offset = pNewEnd[d];
19196f5f1567SToby Isaac 
19206f5f1567SToby Isaac     }
19216f5f1567SToby 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]);
19226f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
19236f5f1567SToby Isaac     ierr = DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
19246f5f1567SToby Isaac 
19256f5f1567SToby Isaac     ierr = PetscMalloc1(pNewEnd[dim],&newConeSizes);CHKERRQ(ierr);
19266f5f1567SToby Isaac     {
19276f5f1567SToby Isaac       PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
19286f5f1567SToby Isaac 
19296f5f1567SToby Isaac       ierr = DMPlexGetChart(K,&kStart,&kEnd);CHKERRQ(ierr);
19306f5f1567SToby Isaac       ierr = PetscMalloc4(kEnd-kStart,&Kembedding,kEnd-kStart,&perm,kEnd-kStart,&iperm,kEnd-kStart,&preOrient);CHKERRQ(ierr);
19316f5f1567SToby Isaac 
19326f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19336f5f1567SToby Isaac         perm[k - kStart] = k;
19346f5f1567SToby Isaac         iperm [k - kStart] = k - kStart;
19356f5f1567SToby Isaac         preOrient[k - kStart] = 0;
19366f5f1567SToby Isaac       }
19376f5f1567SToby Isaac 
19386f5f1567SToby Isaac       ierr = DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
19396f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
19406f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2*j+1];
19416f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2*j+1];
19426f5f1567SToby Isaac         PetscInt p, q;
19436f5f1567SToby Isaac 
19446f5f1567SToby Isaac         p = closureK[2*j];
19456f5f1567SToby Isaac         q = cellClosure[2*j];
19466f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
19476f5f1567SToby Isaac           if (q >= pOldStart[d] && q < pOldEnd[d]) {
19486f5f1567SToby Isaac             Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
19496f5f1567SToby Isaac           }
19506f5f1567SToby Isaac         }
19516f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
19526f5f1567SToby Isaac           PetscInt numChildren, i;
19536f5f1567SToby Isaac           const PetscInt *children;
19546f5f1567SToby Isaac 
19556f5f1567SToby Isaac           ierr = DMPlexGetTreeChildren(K,p,&numChildren,&children);CHKERRQ(ierr);
19566f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
19576f5f1567SToby Isaac             PetscInt kPerm, oPerm;
19586f5f1567SToby Isaac 
19596f5f1567SToby Isaac             k    = children[i];
19606f5f1567SToby Isaac             ierr = DMPlexReferenceTreeGetChildSymmetry(K,p,parentOrientA,0,k,parentOrientB,&oPerm,&kPerm);CHKERRQ(ierr);
19616f5f1567SToby Isaac             /* perm = what refTree position I'm in */
19626f5f1567SToby Isaac             perm[kPerm-kStart]      = k;
19636f5f1567SToby Isaac             /* iperm = who is at this position */
19646f5f1567SToby Isaac             iperm[k-kStart]         = kPerm-kStart;
19656f5f1567SToby Isaac             preOrient[kPerm-kStart] = oPerm;
19666f5f1567SToby Isaac           }
19676f5f1567SToby Isaac         }
19686f5f1567SToby Isaac       }
19696f5f1567SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
19706f5f1567SToby Isaac     }
19716f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,0,pNewEnd[dim]);CHKERRQ(ierr);
19726f5f1567SToby Isaac     offset = 0;
19736f5f1567SToby Isaac     numNewCones = 0;
19746f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19756f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
19766f5f1567SToby Isaac       PetscInt p;
19776f5f1567SToby Isaac       PetscInt size;
19786f5f1567SToby Isaac 
19796f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19806f5f1567SToby Isaac         /* skip cell 0 */
19816f5f1567SToby Isaac         if (p == cell) continue;
19826f5f1567SToby Isaac         /* old cones to new cones */
19836f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
19846f5f1567SToby Isaac         newConeSizes[offset++] = size;
19856f5f1567SToby Isaac         numNewCones += size;
19866f5f1567SToby Isaac       }
19876f5f1567SToby Isaac 
19886f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
19896f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19906f5f1567SToby Isaac         PetscInt kParent;
19916f5f1567SToby Isaac 
19926f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
19936f5f1567SToby Isaac         if (kParent != k) {
19946f5f1567SToby Isaac           Kembedding[k] = offset;
19956f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
19966f5f1567SToby Isaac           newConeSizes[offset++] = size;
19976f5f1567SToby Isaac           numNewCones += size;
19986f5f1567SToby Isaac           if (kParent != 0) {
19996f5f1567SToby Isaac             ierr = PetscSectionSetDof(parentSection,Kembedding[k],1);CHKERRQ(ierr);
20006f5f1567SToby Isaac           }
20016f5f1567SToby Isaac         }
20026f5f1567SToby Isaac       }
20036f5f1567SToby Isaac     }
20046f5f1567SToby Isaac 
20056f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
20066f5f1567SToby Isaac     ierr = PetscSectionGetStorageSize(parentSection,&numPointsWithParents);CHKERRQ(ierr);
20076f5f1567SToby Isaac     ierr = PetscMalloc2(numNewCones,&newCones,numNewCones,&newOrientations);CHKERRQ(ierr);
20086f5f1567SToby Isaac     ierr = PetscMalloc2(numPointsWithParents,&parents,numPointsWithParents,&childIDs);CHKERRQ(ierr);
20096f5f1567SToby Isaac 
20106f5f1567SToby Isaac     /* fill new cones */
20116f5f1567SToby Isaac     offset = 0;
20126f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20136f5f1567SToby Isaac       PetscInt kStart, kEnd, k, l;
20146f5f1567SToby Isaac       PetscInt p;
20156f5f1567SToby Isaac       PetscInt size;
20166f5f1567SToby Isaac       const PetscInt *cone, *orientation;
20176f5f1567SToby Isaac 
20186f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
20196f5f1567SToby Isaac         /* skip cell 0 */
20206f5f1567SToby Isaac         if (p == cell) continue;
20216f5f1567SToby Isaac         /* old cones to new cones */
20226f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
20236f5f1567SToby Isaac         ierr = DMPlexGetCone(dm,p,&cone);CHKERRQ(ierr);
20246f5f1567SToby Isaac         ierr = DMPlexGetConeOrientation(dm,p,&orientation);CHKERRQ(ierr);
20256f5f1567SToby Isaac         for (l = 0; l < size; l++) {
20266f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
20276f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
20286f5f1567SToby Isaac         }
20296f5f1567SToby Isaac       }
20306f5f1567SToby Isaac 
20316f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
20326f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20336f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
20346f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
20356f5f1567SToby Isaac 
20366f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
20376f5f1567SToby Isaac         if (kParent != k) {
20386f5f1567SToby Isaac           /* embed new cones */
20396f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
20406f5f1567SToby Isaac           ierr = DMPlexGetCone(K,kPerm,&cone);CHKERRQ(ierr);
20416f5f1567SToby Isaac           ierr = DMPlexGetConeOrientation(K,kPerm,&orientation);CHKERRQ(ierr);
20426f5f1567SToby Isaac           for (l = 0; l < size; l++) {
20436f5f1567SToby Isaac             PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size -(preO + 1) - l) % size);
20446f5f1567SToby Isaac             PetscInt newO, lSize, oTrue;
20456f5f1567SToby Isaac 
20466f5f1567SToby Isaac             q                         = iperm[cone[m]];
20476f5f1567SToby Isaac             newCones[offset]          = Kembedding[q];
20486f5f1567SToby Isaac             ierr                      = DMPlexGetConeSize(K,q,&lSize);CHKERRQ(ierr);
20496f5f1567SToby Isaac             oTrue                     = orientation[m];
20506f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
20516f5f1567SToby Isaac             newO                      = DihedralCompose(lSize,oTrue,preOrient[q]);
20526f5f1567SToby Isaac             newOrientations[offset++] = newO;
20536f5f1567SToby Isaac           }
20546f5f1567SToby Isaac           if (kParent != 0) {
20556f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
20566f5f1567SToby Isaac             ierr              = PetscSectionGetOffset(parentSection,Kembedding[k],&pOffset);CHKERRQ(ierr);
20576f5f1567SToby Isaac             parents[pOffset]  = newPoint;
20586f5f1567SToby Isaac             childIDs[pOffset] = k;
20596f5f1567SToby Isaac           }
20606f5f1567SToby Isaac         }
20616f5f1567SToby Isaac       }
20626f5f1567SToby Isaac     }
20636f5f1567SToby Isaac 
20646f5f1567SToby Isaac     ierr = PetscMalloc1(dim*(pNewEnd[dim]-pNewStart[dim]),&newVertexCoords);CHKERRQ(ierr);
20656f5f1567SToby Isaac 
20666f5f1567SToby Isaac     /* fill coordinates */
20676f5f1567SToby Isaac     offset = 0;
20686f5f1567SToby Isaac     {
2069d90620a3SMatthew G. Knepley       PetscInt kStart, kEnd, l;
20706f5f1567SToby Isaac       PetscSection vSection;
20716f5f1567SToby Isaac       PetscInt v;
20726f5f1567SToby Isaac       Vec coords;
20736f5f1567SToby Isaac       PetscScalar *coordvals;
20746f5f1567SToby Isaac       PetscInt dof, off;
2075c111c6b7SMatthew G. Knepley       PetscReal v0[3], J[9], detJ;
20766f5f1567SToby Isaac 
20776f5f1567SToby Isaac #if defined(PETSC_USE_DEBUG)
2078d90620a3SMatthew G. Knepley       {
2079d90620a3SMatthew G. Knepley         PetscInt k;
20806f5f1567SToby Isaac         ierr = DMPlexGetHeightStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
20816f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
208273a7f2aaSMatthew G. Knepley           ierr = DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
20836f5f1567SToby Isaac           if (detJ <= 0.) SETERRQ1 (PETSC_COMM_SELF,PETSC_ERR_PLIB,"reference tree cell %d has bad determinant",k);
20846f5f1567SToby Isaac         }
2085d90620a3SMatthew G. Knepley       }
20866f5f1567SToby Isaac #endif
208773a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
20886f5f1567SToby Isaac       ierr = DMGetCoordinateSection(dm,&vSection);CHKERRQ(ierr);
20896f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr);
20906f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
20916f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
20926f5f1567SToby Isaac 
20936f5f1567SToby Isaac         ierr = PetscSectionGetDof(vSection,v,&dof);CHKERRQ(ierr);
20946f5f1567SToby Isaac         ierr = PetscSectionGetOffset(vSection,v,&off);CHKERRQ(ierr);
20956f5f1567SToby Isaac         for (l = 0; l < dof; l++) {
20966f5f1567SToby Isaac           newVertexCoords[offset++] = coordvals[off + l];
20976f5f1567SToby Isaac         }
20986f5f1567SToby Isaac       }
20996f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21006f5f1567SToby Isaac 
21016f5f1567SToby Isaac       ierr = DMGetCoordinateSection(K,&vSection);CHKERRQ(ierr);
21026f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(K,&coords);CHKERRQ(ierr);
21036f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
21046f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
21056f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
21069bc368c7SMatthew G. Knepley         PetscReal coord[3], newCoord[3];
21076f5f1567SToby Isaac         PetscInt  vPerm = perm[v];
21086f5f1567SToby Isaac         PetscInt  kParent;
21096f5f1567SToby Isaac 
21106f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,v,&kParent,NULL);CHKERRQ(ierr);
21116f5f1567SToby Isaac         if (kParent != v) {
21126f5f1567SToby Isaac           /* this is a new vertex */
21136f5f1567SToby Isaac           ierr = PetscSectionGetOffset(vSection,vPerm,&off);CHKERRQ(ierr);
21149bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off+l]);
21159bc368c7SMatthew G. Knepley           CoordinatesRefToReal(dim, dim, v0, J, coord, newCoord);CHKERRQ(ierr);
21169bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset+l] = newCoord[l];
21176f5f1567SToby Isaac           offset += dim;
21186f5f1567SToby Isaac         }
21196f5f1567SToby Isaac       }
21206f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21216f5f1567SToby Isaac     }
21226f5f1567SToby Isaac 
21236f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
21246f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
21256f5f1567SToby Isaac       PetscInt tmp;
21266f5f1567SToby Isaac 
21276f5f1567SToby Isaac       tmp = pNewCount[d];
21286f5f1567SToby Isaac       pNewCount[d] = pNewCount[dim - d];
21296f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
21306f5f1567SToby Isaac     }
21316f5f1567SToby Isaac 
21326f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,pNewCount,newConeSizes,newCones,newOrientations,newVertexCoords);CHKERRQ(ierr);
21336f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
21346f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,parents,childIDs);CHKERRQ(ierr);
21356f5f1567SToby Isaac 
21366f5f1567SToby Isaac     /* clean up */
21376f5f1567SToby Isaac     ierr = DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
21386f5f1567SToby Isaac     ierr = PetscFree5(pNewCount,pNewStart,pNewEnd,pOldStart,pOldEnd);CHKERRQ(ierr);
21396f5f1567SToby Isaac     ierr = PetscFree(newConeSizes);CHKERRQ(ierr);
21406f5f1567SToby Isaac     ierr = PetscFree2(newCones,newOrientations);CHKERRQ(ierr);
21416f5f1567SToby Isaac     ierr = PetscFree(newVertexCoords);CHKERRQ(ierr);
21426f5f1567SToby Isaac     ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
21436f5f1567SToby Isaac     ierr = PetscFree4(Kembedding,perm,iperm,preOrient);CHKERRQ(ierr);
21446f5f1567SToby Isaac   }
21456f5f1567SToby Isaac   else {
21466f5f1567SToby Isaac     PetscInt    p, counts[4];
21476f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
21486f5f1567SToby Isaac     Vec         coordVec;
21496f5f1567SToby Isaac     PetscScalar *coords;
21506f5f1567SToby Isaac 
21516f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
21526f5f1567SToby Isaac       PetscInt dStart, dEnd;
21536f5f1567SToby Isaac 
21546f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
21556f5f1567SToby Isaac       counts[d] = dEnd - dStart;
21566f5f1567SToby Isaac     }
21576f5f1567SToby Isaac     ierr = PetscMalloc1(pEnd-pStart,&coneSizes);CHKERRQ(ierr);
21586f5f1567SToby Isaac     for (p = pStart; p < pEnd; p++) {
21596f5f1567SToby Isaac       ierr = DMPlexGetConeSize(dm,p,&coneSizes[p-pStart]);CHKERRQ(ierr);
21606f5f1567SToby Isaac     }
21616f5f1567SToby Isaac     ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
21626f5f1567SToby Isaac     ierr = DMPlexGetConeOrientations(dm, &orientations);CHKERRQ(ierr);
21636f5f1567SToby Isaac     ierr = DMGetCoordinatesLocal(dm,&coordVec);CHKERRQ(ierr);
21646f5f1567SToby Isaac     ierr = VecGetArray(coordVec,&coords);CHKERRQ(ierr);
21656f5f1567SToby Isaac 
21666f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,pStart,pEnd);CHKERRQ(ierr);
21676f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
21686f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,counts,coneSizes,cones,orientations,NULL);CHKERRQ(ierr);
21696f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
21706f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,NULL,NULL);CHKERRQ(ierr);
21716f5f1567SToby Isaac     ierr = VecRestoreArray(coordVec,&coords);CHKERRQ(ierr);
21726f5f1567SToby Isaac   }
21736f5f1567SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
21746f5f1567SToby Isaac 
21756f5f1567SToby Isaac   PetscFunctionReturn(0);
21766f5f1567SToby Isaac }
21776ecaa68aSToby Isaac 
21786ecaa68aSToby Isaac PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
21796ecaa68aSToby Isaac {
21806ecaa68aSToby Isaac   PetscSF           coarseToFineEmbedded;
21816ecaa68aSToby Isaac   PetscSection      globalCoarse, globalFine;
21826ecaa68aSToby Isaac   PetscSection      localCoarse, localFine;
21836ecaa68aSToby Isaac   PetscSection      aSec, cSec;
21846ecaa68aSToby Isaac   PetscSection      rootIndicesSec, rootMatricesSec;
218546bdb399SToby Isaac   PetscSection      leafIndicesSec, leafMatricesSec;
218646bdb399SToby Isaac   PetscInt          *rootIndices, *leafIndices;
218746bdb399SToby Isaac   PetscScalar       *rootMatrices, *leafMatrices;
21886ecaa68aSToby Isaac   IS                aIS;
21896ecaa68aSToby Isaac   const PetscInt    *anchors;
21906ecaa68aSToby Isaac   Mat               cMat;
21914acb8e1eSToby Isaac   PetscInt          numFields, maxFields;
21926ecaa68aSToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p;
21936ecaa68aSToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
21941c58ffc4SToby Isaac   PetscInt          *maxChildIds;
2195e44e4e7fSToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
21964acb8e1eSToby Isaac   const PetscInt    ***perms;
21974acb8e1eSToby Isaac   const PetscScalar ***flips;
21986ecaa68aSToby Isaac   PetscErrorCode    ierr;
21996ecaa68aSToby Isaac 
22006ecaa68aSToby Isaac   PetscFunctionBegin;
22016ecaa68aSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
22026ecaa68aSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
22036ecaa68aSToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
22046ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
220589698031SToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
220689698031SToby Isaac     const PetscInt *leaves;
22076ecaa68aSToby Isaac 
220889698031SToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
220989698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
221089698031SToby Isaac       p = leaves ? leaves[l] : l;
22116ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22126ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22136ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
22146ecaa68aSToby Isaac         numPointsWithDofs++;
22156ecaa68aSToby Isaac       }
22166ecaa68aSToby Isaac     }
22176ecaa68aSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
22187cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
221989698031SToby Isaac       p = leaves ? leaves[l] : l;
22206ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22216ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22226ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
222389698031SToby Isaac         pointsWithDofs[offset++] = l;
22246ecaa68aSToby Isaac       }
22256ecaa68aSToby Isaac     }
22266ecaa68aSToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
2227ec92bd66SToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
22286ecaa68aSToby Isaac   }
22296ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
22306ecaa68aSToby Isaac   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
22316ecaa68aSToby Isaac   for (p = pStartC; p < pEndC; p++) {
22328d2f55e7SToby Isaac     maxChildIds[p - pStartC] = -2;
22336ecaa68aSToby Isaac   }
22346ecaa68aSToby Isaac   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
22356ecaa68aSToby Isaac   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
223646bdb399SToby Isaac 
22376ecaa68aSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
22386ecaa68aSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
223946bdb399SToby Isaac 
22406ecaa68aSToby Isaac   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
22416ecaa68aSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
22426ecaa68aSToby Isaac   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
224346bdb399SToby Isaac 
22446ecaa68aSToby Isaac   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
22456ecaa68aSToby Isaac   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
224646bdb399SToby Isaac 
224746bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
22486ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
22496ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootMatricesSec);CHKERRQ(ierr);
22506ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootIndicesSec,pStartC,pEndC);CHKERRQ(ierr);
22516ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootMatricesSec,pStartC,pEndC);CHKERRQ(ierr);
2252708c7f19SToby Isaac   ierr = PetscSectionGetNumFields(localCoarse,&numFields);CHKERRQ(ierr);
2253713c1c5dSToby Isaac   maxFields = PetscMax(1,numFields);
2254713c1c5dSToby Isaac   ierr = PetscMalloc7(maxFields+1,&offsets,maxFields+1,&offsetsCopy,maxFields+1,&newOffsets,maxFields+1,&newOffsetsCopy,maxFields+1,&rowOffsets,maxFields+1,&numD,maxFields+1,&numO);CHKERRQ(ierr);
2255f489ac74SBarry Smith   ierr = PetscMalloc2(maxFields+1,(PetscInt****)&perms,maxFields+1,(PetscScalar****)&flips);CHKERRQ(ierr);
2256713c1c5dSToby Isaac   ierr = PetscMemzero((void *) perms, (maxFields+1) * sizeof(const PetscInt **));CHKERRQ(ierr);
2257713c1c5dSToby Isaac   ierr = PetscMemzero((void *) flips, (maxFields+1) * sizeof(const PetscScalar **));CHKERRQ(ierr);
225846bdb399SToby Isaac 
225946bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
22608d2f55e7SToby Isaac     PetscInt dof, matSize   = 0;
22616ecaa68aSToby Isaac     PetscInt aDof           = 0;
22626ecaa68aSToby Isaac     PetscInt cDof           = 0;
22636ecaa68aSToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
22646ecaa68aSToby Isaac     PetscInt numRowIndices  = 0;
22656ecaa68aSToby Isaac     PetscInt numColIndices  = 0;
2266f13f9184SToby Isaac     PetscInt f;
22676ecaa68aSToby Isaac 
22686ecaa68aSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
22691cfc5b76SToby Isaac     if (dof < 0) {
22701cfc5b76SToby Isaac       dof = -(dof + 1);
22711cfc5b76SToby Isaac     }
22726ecaa68aSToby Isaac     if (p >= aStart && p < aEnd) {
22736ecaa68aSToby Isaac       ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
22746ecaa68aSToby Isaac     }
22756ecaa68aSToby Isaac     if (p >= cStart && p < cEnd) {
22766ecaa68aSToby Isaac       ierr = PetscSectionGetDof(cSec,p,&cDof);CHKERRQ(ierr);
22776ecaa68aSToby Isaac     }
2278f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2279f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
22806ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2281f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
22826ecaa68aSToby Isaac 
22836ecaa68aSToby Isaac       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
228446bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
22856ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
22866ecaa68aSToby Isaac 
22876ecaa68aSToby Isaac         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
22886ecaa68aSToby Isaac         numRowIndices += clDof;
22896ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
22906ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,c,f,&clDof);CHKERRQ(ierr);
22916ecaa68aSToby Isaac           offsets[f + 1] += clDof;
22926ecaa68aSToby Isaac         }
22936ecaa68aSToby Isaac       }
22946ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
22956ecaa68aSToby Isaac         offsets[f + 1]   += offsets[f];
22966ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
22976ecaa68aSToby Isaac       }
229846bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
22994acb8e1eSToby Isaac       ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,NULL,NULL,NULL,&numColIndices,NULL,NULL,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
23006ecaa68aSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
23016ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
23026ecaa68aSToby Isaac         numColIndices = numRowIndices;
23036ecaa68aSToby Isaac         matSize = 0;
23046ecaa68aSToby Isaac       }
230546bdb399SToby Isaac       else if (numFields) { /* we send one submat for each field: sum their sizes */
23066ecaa68aSToby Isaac         matSize = 0;
23076ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23086ecaa68aSToby Isaac           PetscInt numRow, numCol;
23096ecaa68aSToby Isaac 
23106ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2311f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
23126ecaa68aSToby Isaac           matSize += numRow * numCol;
23136ecaa68aSToby Isaac         }
23146ecaa68aSToby Isaac       }
23156ecaa68aSToby Isaac       else {
23166ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
23176ecaa68aSToby Isaac       }
2318f13f9184SToby Isaac     } else if (maxChildId == -1) {
23198d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2320f13f9184SToby Isaac         PetscInt aOff, a;
23216ecaa68aSToby Isaac 
23226ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
23236ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23246ecaa68aSToby Isaac           PetscInt fDof;
23256ecaa68aSToby Isaac 
23266ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
232721968bf8SToby Isaac           offsets[f+1] = fDof;
23286ecaa68aSToby Isaac         }
23296ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
23306ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
23316ecaa68aSToby Isaac 
23326ecaa68aSToby Isaac           ierr = PetscSectionGetDof(localCoarse,anchor,&aLocalDof);CHKERRQ(ierr);
23336ecaa68aSToby Isaac           numColIndices += aLocalDof;
23346ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23356ecaa68aSToby Isaac             PetscInt fDof;
23366ecaa68aSToby Isaac 
23376ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
233821968bf8SToby Isaac             newOffsets[f+1] += fDof;
23396ecaa68aSToby Isaac           }
23406ecaa68aSToby Isaac         }
23416ecaa68aSToby Isaac         if (numFields) {
23426ecaa68aSToby Isaac           matSize = 0;
23436ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
234421968bf8SToby Isaac             matSize += offsets[f+1] * newOffsets[f+1];
23456ecaa68aSToby Isaac           }
23466ecaa68aSToby Isaac         }
23476ecaa68aSToby Isaac         else {
23486ecaa68aSToby Isaac           matSize = numColIndices * dof;
23496ecaa68aSToby Isaac         }
23506ecaa68aSToby Isaac       }
23516ecaa68aSToby Isaac       else { /* no children, and no constraints on dofs: just get the global indices */
23526ecaa68aSToby Isaac         numColIndices = dof;
23536ecaa68aSToby Isaac         matSize       = 0;
23546ecaa68aSToby Isaac       }
23558d2f55e7SToby Isaac     }
235646bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
23576ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootIndicesSec,p,numColIndices ? numColIndices+2*numFields : 0);CHKERRQ(ierr);
23586ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootMatricesSec,p,matSize);CHKERRQ(ierr);
23596ecaa68aSToby Isaac   }
23606ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootIndicesSec);CHKERRQ(ierr);
23616ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootMatricesSec);CHKERRQ(ierr);
23626ecaa68aSToby Isaac   {
23636ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
23646ecaa68aSToby Isaac 
23656ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
23666ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootMatricesSec,&numRootMatrices);CHKERRQ(ierr);
23676ecaa68aSToby Isaac     ierr = PetscMalloc2(numRootIndices,&rootIndices,numRootMatrices,&rootMatrices);CHKERRQ(ierr);
23686ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
23696ecaa68aSToby Isaac       PetscInt    numRowIndices, numColIndices, matSize, dof;
2370f13f9184SToby Isaac       PetscInt    pIndOff, pMatOff, f;
23716ecaa68aSToby Isaac       PetscInt    *pInd;
23726ecaa68aSToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
23736ecaa68aSToby Isaac       PetscScalar *pMat = NULL;
23746ecaa68aSToby Isaac 
23756ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,p,&numColIndices);CHKERRQ(ierr);
23766ecaa68aSToby Isaac       if (!numColIndices) {
23776ecaa68aSToby Isaac         continue;
23786ecaa68aSToby Isaac       }
2379f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2380f13f9184SToby Isaac         offsets[f]        = 0;
2381f13f9184SToby Isaac         newOffsets[f]     = 0;
2382f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2383f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2384f13f9184SToby Isaac       }
23856ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
23866ecaa68aSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,p,&pIndOff);CHKERRQ(ierr);
23876ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
23886ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootMatricesSec,p,&matSize);CHKERRQ(ierr);
23896ecaa68aSToby Isaac       if (matSize) {
23906ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(rootMatricesSec,p,&pMatOff);CHKERRQ(ierr);
23916ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
23926ecaa68aSToby Isaac       }
23936ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
23941cfc5b76SToby Isaac       if (dof < 0) {
23951cfc5b76SToby Isaac         dof = -(dof + 1);
23961cfc5b76SToby Isaac       }
23976ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
23986ecaa68aSToby Isaac         PetscInt i, j;
23996ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
24006ecaa68aSToby Isaac 
24016ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
24026ecaa68aSToby Isaac           PetscInt numIndices, *indices;
24036ecaa68aSToby Isaac           ierr = DMPlexGetClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
24046ecaa68aSToby Isaac           if (numIndices != numColIndices) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"mismatching constraint indices calculations");
24056ecaa68aSToby Isaac           for (i = 0; i < numColIndices; i++) {
24066ecaa68aSToby Isaac             pInd[i] = indices[i];
24076ecaa68aSToby Isaac           }
24086ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
240946bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i+1];
241046bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i+1];
24116ecaa68aSToby Isaac           }
241246bdb399SToby Isaac           ierr = DMPlexRestoreClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
24136ecaa68aSToby Isaac         }
24146ecaa68aSToby Isaac         else {
24156ecaa68aSToby Isaac           PetscInt closureSize, *closure = NULL, cl;
24166ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
24176ecaa68aSToby Isaac           PetscInt numPoints,*points;
24186ecaa68aSToby Isaac 
241969291d52SBarry Smith           ierr = DMGetWorkArray(coarse,numRowIndices * numRowIndices,MPIU_SCALAR,&pMatIn);CHKERRQ(ierr);
24206ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
24216ecaa68aSToby Isaac             for (j = 0; j < numRowIndices; j++) {
24226ecaa68aSToby Isaac               pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
24236ecaa68aSToby Isaac             }
24246ecaa68aSToby Isaac           }
24256ecaa68aSToby Isaac           ierr = DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
24264acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24274acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionGetFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24284acb8e1eSToby Isaac             else           {ierr = PetscSectionGetPointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24294acb8e1eSToby Isaac           }
24306ecaa68aSToby Isaac           if (numFields) {
24316ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
24326ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
24336ecaa68aSToby Isaac 
24346ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
24356ecaa68aSToby Isaac                 PetscInt fDof;
24366ecaa68aSToby Isaac 
24376ecaa68aSToby Isaac                 ierr = PetscSectionGetFieldDof(localCoarse,c,f,&fDof);CHKERRQ(ierr);
24386ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
24396ecaa68aSToby Isaac               }
24406ecaa68aSToby Isaac             }
24416ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
24426ecaa68aSToby Isaac               offsets[f + 1]   += offsets[f];
24436ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
24446ecaa68aSToby Isaac             }
24456ecaa68aSToby Isaac           }
24464acb8e1eSToby Isaac           /* TODO : flips here ? */
24476ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
24484acb8e1eSToby Isaac           ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,perms,pMatIn,&numPoints,NULL,&points,&pMatModified,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
24494acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24504acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24514acb8e1eSToby Isaac             else           {ierr = PetscSectionRestorePointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24524acb8e1eSToby Isaac           }
24534acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24544acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionGetFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
24554acb8e1eSToby Isaac             else           {ierr = PetscSectionGetPointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
24564acb8e1eSToby Isaac           }
24576ecaa68aSToby Isaac           if (!numFields) {
24586ecaa68aSToby Isaac             for (i = 0; i < numRowIndices * numColIndices; i++) {
24596ecaa68aSToby Isaac               pMat[i] = pMatModified[i];
24606ecaa68aSToby Isaac             }
24616ecaa68aSToby Isaac           }
24626ecaa68aSToby Isaac           else {
2463f13f9184SToby Isaac             PetscInt i, j, count;
24646ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
24656ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f+1]; i++) {
24666ecaa68aSToby Isaac                 for (j = newOffsets[f]; j < newOffsets[f+1]; j++, count++) {
24676ecaa68aSToby Isaac                   pMat[count] = pMatModified[i * numColIndices + j];
24686ecaa68aSToby Isaac                 }
24696ecaa68aSToby Isaac               }
24706ecaa68aSToby Isaac             }
24716ecaa68aSToby Isaac           }
247269291d52SBarry Smith           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatModified);CHKERRQ(ierr);
24736ecaa68aSToby Isaac           ierr = DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
247469291d52SBarry Smith           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatIn);CHKERRQ(ierr);
24756ecaa68aSToby Isaac           if (numFields) {
247646bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
247746bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f+1];
247846bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f+1];
24796ecaa68aSToby Isaac             }
24804acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
24814acb8e1eSToby Isaac               PetscInt globalOff, c = points[2*cl];
24826ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
24834acb8e1eSToby Isaac               DMPlexGetIndicesPointFields_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, pInd);
24846ecaa68aSToby Isaac             }
24856ecaa68aSToby Isaac           } else {
24864acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
24874acb8e1eSToby Isaac               PetscInt c = points[2*cl], globalOff;
24884acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
24894acb8e1eSToby Isaac 
24906ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
24914acb8e1eSToby Isaac               DMPlexGetIndicesPoint_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perm, pInd);
24926ecaa68aSToby Isaac             }
24936ecaa68aSToby Isaac           }
24944acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24954acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
24964acb8e1eSToby Isaac             else           {ierr = PetscSectionRestorePointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
24974acb8e1eSToby Isaac           }
249869291d52SBarry Smith           ierr = DMRestoreWorkArray(coarse,numPoints,MPIU_SCALAR,&points);CHKERRQ(ierr);
24996ecaa68aSToby Isaac         }
25006ecaa68aSToby Isaac       }
25016ecaa68aSToby Isaac       else if (matSize) {
25026ecaa68aSToby Isaac         PetscInt cOff;
25036ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
25046ecaa68aSToby Isaac 
25056ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
2506628cbfb8SToby Isaac         if (numRowIndices != dof) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Miscounted dofs");
250769291d52SBarry Smith         ierr = DMGetWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices);CHKERRQ(ierr);
250869291d52SBarry Smith         ierr = DMGetWorkArray(coarse,numColIndices,MPIU_INT,&colIndices);CHKERRQ(ierr);
25096ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(cSec,p,&cOff);CHKERRQ(ierr);
25106ecaa68aSToby Isaac         ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
25116ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
25126ecaa68aSToby Isaac         if (numFields) {
25136ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25146ecaa68aSToby Isaac             PetscInt fDof;
2515f13f9184SToby Isaac 
25166ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(cSec,p,f,&fDof);CHKERRQ(ierr);
25176ecaa68aSToby Isaac             offsets[f + 1] = fDof;
25186ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
25196ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
25206ecaa68aSToby Isaac               ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
25216ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
25226ecaa68aSToby Isaac             }
25236ecaa68aSToby Isaac           }
25246ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25256ecaa68aSToby Isaac             offsets[f + 1]       += offsets[f];
25266ecaa68aSToby Isaac             offsetsCopy[f + 1]    = offsets[f + 1];
25276ecaa68aSToby Isaac             newOffsets[f + 1]    += newOffsets[f];
25286ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
25296ecaa68aSToby Isaac           }
25304acb8e1eSToby Isaac           DMPlexGetIndicesPointFields_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,NULL,-1,rowIndices);CHKERRQ(ierr);
25316ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25326ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25336ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
25344acb8e1eSToby Isaac             DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL,-1,colIndices);CHKERRQ(ierr);
25356ecaa68aSToby Isaac           }
25366ecaa68aSToby Isaac         }
25376ecaa68aSToby Isaac         else {
25384acb8e1eSToby Isaac           DMPlexGetIndicesPoint_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,NULL,rowIndices);CHKERRQ(ierr);
25396ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25406ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25416ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
25424acb8e1eSToby Isaac             DMPlexGetIndicesPoint_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL,colIndices);CHKERRQ(ierr);
25436ecaa68aSToby Isaac           }
25446ecaa68aSToby Isaac         }
25456ecaa68aSToby Isaac         if (numFields) {
2546f13f9184SToby Isaac           PetscInt count, a;
2547f13f9184SToby Isaac 
25486ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
25496ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
25506ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
25516ecaa68aSToby Isaac             ierr = MatGetValues(cMat,iSize,&rowIndices[offsets[f]],jSize,&colIndices[newOffsets[f]],&pMat[count]);CHKERRQ(ierr);
25526ecaa68aSToby Isaac             count += iSize * jSize;
255346bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
255446bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f+1];
25556ecaa68aSToby Isaac           }
25566ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25576ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25586ecaa68aSToby Isaac             PetscInt gOff;
25596ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
25604acb8e1eSToby Isaac             DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL,-1,pInd);CHKERRQ(ierr);
25616ecaa68aSToby Isaac           }
25626ecaa68aSToby Isaac         }
25636ecaa68aSToby Isaac         else {
25646ecaa68aSToby Isaac           PetscInt a;
25656ecaa68aSToby Isaac           ierr = MatGetValues(cMat,numRowIndices,rowIndices,numColIndices,colIndices,pMat);CHKERRQ(ierr);
25666ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25676ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25686ecaa68aSToby Isaac             PetscInt gOff;
25696ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
25704acb8e1eSToby Isaac             DMPlexGetIndicesPoint_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL,pInd);CHKERRQ(ierr);
25716ecaa68aSToby Isaac           }
25726ecaa68aSToby Isaac         }
257369291d52SBarry Smith         ierr = DMRestoreWorkArray(coarse,numColIndices,MPIU_INT,&colIndices);CHKERRQ(ierr);
257469291d52SBarry Smith         ierr = DMRestoreWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices);CHKERRQ(ierr);
25756ecaa68aSToby Isaac       }
25766ecaa68aSToby Isaac       else {
25776ecaa68aSToby Isaac         PetscInt gOff;
25786ecaa68aSToby Isaac 
25796ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
25806ecaa68aSToby Isaac         if (numFields) {
25816ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25826ecaa68aSToby Isaac             PetscInt fDof;
25836ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
25846ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
25856ecaa68aSToby Isaac           }
25866ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
258746bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
258846bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f+1];
25896ecaa68aSToby Isaac           }
25904acb8e1eSToby Isaac           DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1,pInd);CHKERRQ(ierr);
25916ecaa68aSToby Isaac         }
25926ecaa68aSToby Isaac         else {
25934acb8e1eSToby Isaac           DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,pInd);CHKERRQ(ierr);
25946ecaa68aSToby Isaac         }
25956ecaa68aSToby Isaac       }
25966ecaa68aSToby Isaac     }
2597e44e4e7fSToby Isaac     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
25986ecaa68aSToby Isaac   }
259946bdb399SToby Isaac   {
260046bdb399SToby Isaac     PetscSF  indicesSF, matricesSF;
260146bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
260246bdb399SToby Isaac 
260346bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
260446bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafMatricesSec);CHKERRQ(ierr);
260546bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootIndicesSec,&remoteOffsetsIndices,leafIndicesSec);CHKERRQ(ierr);
260646bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootMatricesSec,&remoteOffsetsMatrices,leafMatricesSec);CHKERRQ(ierr);
260746bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootIndicesSec,remoteOffsetsIndices,leafIndicesSec,&indicesSF);CHKERRQ(ierr);
260846bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootMatricesSec,remoteOffsetsMatrices,leafMatricesSec,&matricesSF);CHKERRQ(ierr);
2609e44e4e7fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
261046bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsIndices);CHKERRQ(ierr);
261146bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsMatrices);CHKERRQ(ierr);
261246bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numLeafIndices);CHKERRQ(ierr);
261346bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafMatricesSec,&numLeafMatrices);CHKERRQ(ierr);
261446bdb399SToby Isaac     ierr = PetscMalloc2(numLeafIndices,&leafIndices,numLeafMatrices,&leafMatrices);CHKERRQ(ierr);
261546bdb399SToby Isaac     ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2616267d4f3fSToby Isaac     ierr = PetscSFBcastBegin(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
261746bdb399SToby Isaac     ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2618267d4f3fSToby Isaac     ierr = PetscSFBcastEnd(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
261946bdb399SToby Isaac     ierr = PetscSFDestroy(&matricesSF);CHKERRQ(ierr);
262046bdb399SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
262146bdb399SToby Isaac     ierr = PetscFree2(rootIndices,rootMatrices);CHKERRQ(ierr);
262246bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
262346bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootMatricesSec);CHKERRQ(ierr);
262446bdb399SToby Isaac   }
262546bdb399SToby Isaac   /* count to preallocate */
262646bdb399SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
262746bdb399SToby Isaac   {
262846bdb399SToby Isaac     PetscInt    nGlobal;
262946bdb399SToby Isaac     PetscInt    *dnnz, *onnz;
2630b9a5774bSToby Isaac     PetscLayout rowMap, colMap;
2631b9a5774bSToby Isaac     PetscInt    rowStart, rowEnd, colStart, colEnd;
26321c58ffc4SToby Isaac     PetscInt    maxDof;
26331c58ffc4SToby Isaac     PetscInt    *rowIndices;
26341c58ffc4SToby Isaac     DM           refTree;
26351c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
26361c58ffc4SToby Isaac     PetscScalar  ***refPointFieldMats;
26371c58ffc4SToby Isaac     PetscSection refConSec, refAnSec;
26380eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,maxConDof,maxColumns,leafStart,leafEnd;
26391c58ffc4SToby Isaac     PetscScalar  *pointWork;
264046bdb399SToby Isaac 
264146bdb399SToby Isaac     ierr = PetscSectionGetConstrainedStorageSize(globalFine,&nGlobal);CHKERRQ(ierr);
264246bdb399SToby Isaac     ierr = PetscCalloc2(nGlobal,&dnnz,nGlobal,&onnz);CHKERRQ(ierr);
2643b9a5774bSToby Isaac     ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
2644b9a5774bSToby Isaac     ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
26451c58ffc4SToby Isaac     ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
2646b9a5774bSToby Isaac     ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
264746bdb399SToby Isaac     ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
26481c58ffc4SToby Isaac     ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr);
26490eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafIndicesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
265069291d52SBarry Smith     ierr = DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
26510eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
265246bdb399SToby Isaac       PetscInt    gDof, gcDof, gOff;
265346bdb399SToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
265446bdb399SToby Isaac       PetscInt    matSize;
265521968bf8SToby Isaac       PetscInt    i;
265646bdb399SToby Isaac 
265746bdb399SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
265846bdb399SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
265946bdb399SToby Isaac       if ((gDof - gcDof) <= 0) {
266046bdb399SToby Isaac         continue;
266146bdb399SToby Isaac       }
266246bdb399SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
266346bdb399SToby Isaac       if (gOff < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"I though having global dofs meant a non-negative offset");
2664b9a5774bSToby 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");
266546bdb399SToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
266646bdb399SToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
266746bdb399SToby Isaac       numColIndices -= 2 * numFields;
26681c58ffc4SToby Isaac       if (numColIndices <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"global fine dof with no dofs to interpolate from");
266946bdb399SToby Isaac       pInd = &leafIndices[pIndOff];
267021968bf8SToby Isaac       offsets[0]        = 0;
267121968bf8SToby Isaac       offsetsCopy[0]    = 0;
267221968bf8SToby Isaac       newOffsets[0]     = 0;
267321968bf8SToby Isaac       newOffsetsCopy[0] = 0;
267446bdb399SToby Isaac       if (numFields) {
267521968bf8SToby Isaac         PetscInt f;
267646bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
267746bdb399SToby Isaac           PetscInt rowDof;
267846bdb399SToby Isaac 
267946bdb399SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
268021968bf8SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
268121968bf8SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
268221968bf8SToby Isaac           newOffsets[f + 1]     = pInd[numColIndices + numFields + f];
268321968bf8SToby Isaac           numD[f] = 0;
268421968bf8SToby Isaac           numO[f] = 0;
268546bdb399SToby Isaac         }
26864acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,rowIndices);CHKERRQ(ierr);
268746bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
268821968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
268921968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
269046bdb399SToby Isaac 
269146bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
269246bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
269346bdb399SToby Isaac 
269446bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
269521968bf8SToby Isaac               numD[f]++;
269646bdb399SToby Isaac             }
269746bdb399SToby Isaac             else if (gInd >= 0) { /* negative means non-entry */
269821968bf8SToby Isaac               numO[f]++;
269946bdb399SToby Isaac             }
270046bdb399SToby Isaac           }
270146bdb399SToby Isaac         }
270246bdb399SToby Isaac       }
270346bdb399SToby Isaac       else {
27044acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,rowIndices);CHKERRQ(ierr);
270521968bf8SToby Isaac         numD[0] = 0;
270621968bf8SToby Isaac         numO[0] = 0;
270746bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
270846bdb399SToby Isaac           PetscInt gInd = pInd[i];
270946bdb399SToby Isaac 
271046bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
271121968bf8SToby Isaac             numD[0]++;
271246bdb399SToby Isaac           }
271346bdb399SToby Isaac           else if (gInd >= 0) { /* negative means non-entry */
271421968bf8SToby Isaac             numO[0]++;
271546bdb399SToby Isaac           }
271646bdb399SToby Isaac         }
271746bdb399SToby Isaac       }
271846bdb399SToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
271946bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
272046bdb399SToby Isaac         PetscInt childId;
272146bdb399SToby Isaac 
272246bdb399SToby Isaac         childId = childIds[p-pStartF];
272321968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
272446bdb399SToby Isaac           if (numFields) {
2725b9a5774bSToby Isaac             PetscInt f;
2726b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
272721968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
272846bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
272921968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
273021968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
273146bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2732b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2733b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
273446bdb399SToby Isaac                 }
273546bdb399SToby Isaac                 else if (gIndCoarse >= 0) { /* remote */
2736b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2737b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
273846bdb399SToby Isaac                 }
273946bdb399SToby Isaac                 else { /* constrained */
274046bdb399SToby Isaac                   if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
274146bdb399SToby Isaac                 }
274246bdb399SToby Isaac               }
274346bdb399SToby Isaac             }
274446bdb399SToby Isaac           }
274546bdb399SToby Isaac           else {
2746b9a5774bSToby Isaac             PetscInt i;
2747b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
274846bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
274946bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
275046bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2751b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2752b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
275346bdb399SToby Isaac               }
275446bdb399SToby Isaac               else if (gIndCoarse >= 0) { /* remote */
2755b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2756b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
275746bdb399SToby Isaac               }
275846bdb399SToby Isaac               else { /* constrained */
275946bdb399SToby Isaac                 if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
276046bdb399SToby Isaac               }
276146bdb399SToby Isaac             }
276246bdb399SToby Isaac           }
276346bdb399SToby Isaac         }
276446bdb399SToby Isaac         else { /* interpolate from all */
276546bdb399SToby Isaac           if (numFields) {
2766b9a5774bSToby Isaac             PetscInt f;
2767b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
276821968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
276946bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
277021968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
277146bdb399SToby Isaac                 if (gIndFine >= 0) {
2772b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2773b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2774b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
277546bdb399SToby Isaac                 }
277646bdb399SToby Isaac               }
277746bdb399SToby Isaac             }
277846bdb399SToby Isaac           }
277946bdb399SToby Isaac           else {
2780b9a5774bSToby Isaac             PetscInt i;
2781b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
278246bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
278346bdb399SToby Isaac               if (gIndFine >= 0) {
2784b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2785b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2786b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
278746bdb399SToby Isaac               }
278846bdb399SToby Isaac             }
278946bdb399SToby Isaac           }
279046bdb399SToby Isaac         }
279146bdb399SToby Isaac       }
279246bdb399SToby Isaac       else { /* interpolate from all */
279346bdb399SToby Isaac         if (numFields) {
2794b9a5774bSToby Isaac           PetscInt f;
2795b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
279621968bf8SToby Isaac             PetscInt numRows = offsets[f+1] - offsets[f], row;
279746bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
279821968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
279946bdb399SToby Isaac               if (gIndFine >= 0) {
2800b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2801b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2802b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
280346bdb399SToby Isaac               }
280446bdb399SToby Isaac             }
280546bdb399SToby Isaac           }
280646bdb399SToby Isaac         }
280746bdb399SToby Isaac         else { /* every dof get a full row */
2808b9a5774bSToby Isaac           PetscInt i;
2809b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
281046bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
281146bdb399SToby Isaac             if (gIndFine >= 0) {
2812b9a5774bSToby Isaac               if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2813b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2814b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
281546bdb399SToby Isaac             }
281646bdb399SToby Isaac           }
281746bdb399SToby Isaac         }
281846bdb399SToby Isaac       }
281946bdb399SToby Isaac     }
282046bdb399SToby Isaac     ierr = MatXAIJSetPreallocation(mat,1,dnnz,onnz,NULL,NULL);CHKERRQ(ierr);
282146bdb399SToby Isaac     ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
282221968bf8SToby Isaac 
282321968bf8SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
282421968bf8SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
2825e44e4e7fSToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
2826e44e4e7fSToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
2827e44e4e7fSToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
28281c58ffc4SToby Isaac     ierr = PetscSectionGetMaxDof(refConSec,&maxConDof);CHKERRQ(ierr);
28297c0540e0SToby Isaac     ierr = PetscSectionGetMaxDof(leafIndicesSec,&maxColumns);CHKERRQ(ierr);
28307c0540e0SToby Isaac     ierr = PetscMalloc1(maxConDof*maxColumns,&pointWork);CHKERRQ(ierr);
28310eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2832e44e4e7fSToby Isaac       PetscInt    gDof, gcDof, gOff;
2833e44e4e7fSToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
2834e44e4e7fSToby Isaac       PetscInt    matSize;
2835e44e4e7fSToby Isaac       PetscInt    childId;
2836e44e4e7fSToby Isaac 
2837e44e4e7fSToby Isaac 
2838e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
2839e44e4e7fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
2840e44e4e7fSToby Isaac       if ((gDof - gcDof) <= 0) {
2841e44e4e7fSToby Isaac         continue;
2842e44e4e7fSToby Isaac       }
2843e44e4e7fSToby Isaac       childId = childIds[p-pStartF];
2844e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
2845e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
2846e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
2847e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2848e44e4e7fSToby Isaac       pInd = &leafIndices[pIndOff];
2849e44e4e7fSToby Isaac       offsets[0]        = 0;
2850e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2851e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2852e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2853e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2854e44e4e7fSToby Isaac       if (numFields) {
2855e44e4e7fSToby Isaac         PetscInt f;
2856e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2857e44e4e7fSToby Isaac           PetscInt rowDof;
2858e44e4e7fSToby Isaac 
2859e44e4e7fSToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
2860e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2861e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2862e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2863e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2864e44e4e7fSToby Isaac         }
28654acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,rowIndices);CHKERRQ(ierr);
2866e44e4e7fSToby Isaac       }
28671c58ffc4SToby Isaac       else {
28684acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,rowIndices);CHKERRQ(ierr);
28691c58ffc4SToby Isaac       }
2870e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
2871e44e4e7fSToby Isaac       if (!matSize) { /* incoming matrix is identity */
2872e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2873e44e4e7fSToby Isaac           if (numFields) {
2874e44e4e7fSToby Isaac             PetscInt f;
2875e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2876e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
2877e44e4e7fSToby Isaac               for (row = 0; row < numRows; row++) {
2878e44e4e7fSToby Isaac                 ierr = MatSetValue(mat,rowIndices[offsets[f]+row],pInd[newOffsets[f]+row],1.,INSERT_VALUES);CHKERRQ(ierr);
287921968bf8SToby Isaac               }
288021968bf8SToby Isaac             }
2881e44e4e7fSToby Isaac           }
2882e44e4e7fSToby Isaac           else {
2883e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
2884e44e4e7fSToby Isaac             for (row = 0; row < numRows; row++) {
2885e44e4e7fSToby Isaac               ierr = MatSetValue(mat,rowIndices[row],pInd[row],1.,INSERT_VALUES);CHKERRQ(ierr);
2886e44e4e7fSToby Isaac             }
2887e44e4e7fSToby Isaac           }
2888e44e4e7fSToby Isaac         }
2889e44e4e7fSToby Isaac         else { /* interpolate from all */
2890e44e4e7fSToby Isaac           if (numFields) {
2891e44e4e7fSToby Isaac             PetscInt f;
2892e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2893e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f];
2894e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
2895e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],refPointFieldMats[childId - pRefStart][f],INSERT_VALUES);CHKERRQ(ierr);
2896e44e4e7fSToby Isaac             }
2897e44e4e7fSToby Isaac           }
2898e44e4e7fSToby Isaac           else {
2899e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,refPointFieldMats[childId - pRefStart][0],INSERT_VALUES);CHKERRQ(ierr);
2900e44e4e7fSToby Isaac           }
2901e44e4e7fSToby Isaac         }
2902e44e4e7fSToby Isaac       }
2903e44e4e7fSToby Isaac       else { /* interpolate from all */
2904e44e4e7fSToby Isaac         PetscInt    pMatOff;
2905e44e4e7fSToby Isaac         PetscScalar *pMat;
2906e44e4e7fSToby Isaac 
2907e44e4e7fSToby Isaac         ierr = PetscSectionGetOffset(leafMatricesSec,p,&pMatOff);CHKERRQ(ierr);
2908e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2909e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2910e44e4e7fSToby Isaac           if (numFields) {
2911e44e4e7fSToby Isaac             PetscInt f, count;
2912e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2913e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2914e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2915e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2916e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2917e44e4e7fSToby Isaac 
2918e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],inMat,INSERT_VALUES);CHKERRQ(ierr);
2919e44e4e7fSToby Isaac               count += numCols * numInRows;
2920e44e4e7fSToby Isaac             }
2921e44e4e7fSToby Isaac           }
2922e44e4e7fSToby Isaac           else {
2923e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,pMat,INSERT_VALUES);CHKERRQ(ierr);
2924e44e4e7fSToby Isaac           }
2925e44e4e7fSToby Isaac         }
2926e44e4e7fSToby Isaac         else { /* multiply the incoming matrix by the child interpolation */
2927e44e4e7fSToby Isaac           if (numFields) {
2928e44e4e7fSToby Isaac             PetscInt f, count;
2929e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2930e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2931e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2932e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2933e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2934e44e4e7fSToby Isaac               PetscInt i, j, k;
2935e44e4e7fSToby Isaac               if (refPointFieldN[childId - pRefStart][f] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2936e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2937e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2938e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2939e44e4e7fSToby Isaac                   for (k = 0; k < numInRows; k++) {
2940e44e4e7fSToby Isaac                     val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2941e44e4e7fSToby Isaac                   }
2942e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2943e44e4e7fSToby Isaac                 }
2944e44e4e7fSToby Isaac               }
2945e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],pointWork,INSERT_VALUES);CHKERRQ(ierr);
2946e44e4e7fSToby Isaac               count += numCols * numInRows;
2947e44e4e7fSToby Isaac             }
2948e44e4e7fSToby Isaac           }
2949267d4f3fSToby Isaac           else { /* every dof gets a full row */
2950e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2951e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2952e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2953e44e4e7fSToby Isaac             PetscInt i, j, k;
2954e44e4e7fSToby Isaac             if (refPointFieldN[childId - pRefStart][0] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2955e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2956e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2957e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2958e44e4e7fSToby Isaac                 for (k = 0; k < numInRows; k++) {
2959e44e4e7fSToby Isaac                   val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2960e44e4e7fSToby Isaac                 }
2961e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2962e44e4e7fSToby Isaac               }
2963e44e4e7fSToby Isaac             }
2964e44e4e7fSToby Isaac             ierr = MatSetValues(mat,numRows,rowIndices,numCols,pInd,pointWork,INSERT_VALUES);CHKERRQ(ierr);
2965e44e4e7fSToby Isaac           }
2966e44e4e7fSToby Isaac         }
2967e44e4e7fSToby Isaac       }
2968e44e4e7fSToby Isaac     }
29691c58ffc4SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
297069291d52SBarry Smith     ierr = DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
2971e44e4e7fSToby Isaac     ierr = PetscFree(pointWork);CHKERRQ(ierr);
2972e44e4e7fSToby Isaac   }
2973e44e4e7fSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2974e44e4e7fSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2975e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
2976e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafMatricesSec);CHKERRQ(ierr);
2977e44e4e7fSToby Isaac   ierr = PetscFree2(leafIndices,leafMatrices);CHKERRQ(ierr);
29782cd485c2SBarry Smith   ierr = PetscFree2(*(PetscInt****)&perms,*(PetscScalar****)&flips);CHKERRQ(ierr);
2979e44e4e7fSToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
29806ecaa68aSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
29816ecaa68aSToby Isaac   PetscFunctionReturn(0);
29826ecaa68aSToby Isaac }
2983154bca37SToby Isaac 
29848d2f55e7SToby Isaac /*
29858d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
29868d2f55e7SToby Isaac  *
29878d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
29888d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
29898d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
29908d2f55e7SToby Isaac  *       a_{i,j} = 0;
29918d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
29928d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
29938d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
29948d2f55e7SToby Isaac  */
29958d2f55e7SToby Isaac PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
29968d2f55e7SToby Isaac {
29978d2f55e7SToby Isaac   PetscDS        ds;
29988d2f55e7SToby Isaac   PetscSection   section, cSection;
29998d2f55e7SToby Isaac   DMLabel        canonical, depth;
30008d2f55e7SToby Isaac   Mat            cMat, mat;
30018d2f55e7SToby Isaac   PetscInt       *nnz;
30028d2f55e7SToby Isaac   PetscInt       f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
30038d2f55e7SToby Isaac   PetscInt       m, n;
30048d2f55e7SToby Isaac   PetscScalar    *pointScalar;
30058d2f55e7SToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
30068d2f55e7SToby Isaac   PetscErrorCode ierr;
30078d2f55e7SToby Isaac 
30088d2f55e7SToby Isaac   PetscFunctionBegin;
30098d2f55e7SToby Isaac   ierr = DMGetDefaultSection(refTree,&section);CHKERRQ(ierr);
30108d2f55e7SToby Isaac   ierr = DMGetDimension(refTree, &dim);CHKERRQ(ierr);
30118d2f55e7SToby Isaac   ierr = PetscMalloc6(dim,&v0,dim,&v0parent,dim,&vtmp,dim*dim,&J,dim*dim,&Jparent,dim*dim,&invJ);CHKERRQ(ierr);
30128d2f55e7SToby Isaac   ierr = PetscMalloc2(dim,&pointScalar,dim,&pointRef);CHKERRQ(ierr);
30138d2f55e7SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
30148d2f55e7SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
30158d2f55e7SToby Isaac   ierr = PetscSectionGetNumFields(section,&numSecFields);CHKERRQ(ierr);
30168d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"canonical",&canonical);CHKERRQ(ierr);
30178d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"depth",&depth);CHKERRQ(ierr);
30188d2f55e7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSection,&cMat);CHKERRQ(ierr);
30198d2f55e7SToby Isaac   ierr = DMPlexGetChart(refTree, &pStart, &pEnd);CHKERRQ(ierr);
30208d2f55e7SToby Isaac   ierr = DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd);CHKERRQ(ierr);
30218d2f55e7SToby Isaac   ierr = MatGetSize(cMat,&n,&m);CHKERRQ(ierr); /* the injector has transpose sizes from the constraint matrix */
30228d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
30238d2f55e7SToby Isaac   ierr = PetscCalloc1(m,&nnz);CHKERRQ(ierr);
30248d2f55e7SToby 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 */
30258d2f55e7SToby Isaac     const PetscInt *children;
30268d2f55e7SToby Isaac     PetscInt numChildren;
30278d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30288d2f55e7SToby Isaac 
30298d2f55e7SToby Isaac     if (canonical) {
30308d2f55e7SToby Isaac       PetscInt pCanonical;
30318d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
30328d2f55e7SToby Isaac       if (p != pCanonical) continue;
30338d2f55e7SToby Isaac     }
30348d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
30358d2f55e7SToby Isaac     if (!numChildren) continue;
30368d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30378d2f55e7SToby Isaac       PetscInt child = children[i];
30388d2f55e7SToby Isaac       PetscInt dof;
30398d2f55e7SToby Isaac 
30408d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
30418d2f55e7SToby Isaac       numChildDof += dof;
30428d2f55e7SToby Isaac     }
30438d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
30448d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30458d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
30468d2f55e7SToby Isaac       PetscInt selfOff;
30478d2f55e7SToby Isaac 
30488d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
30498d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
30508d2f55e7SToby Isaac           PetscInt child = children[i];
30518d2f55e7SToby Isaac           PetscInt dof;
30528d2f55e7SToby Isaac 
30538d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
30548d2f55e7SToby Isaac           numChildDof += dof;
30558d2f55e7SToby Isaac         }
30568d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
30578d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
30588d2f55e7SToby Isaac       }
30598d2f55e7SToby Isaac       else {
30608d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
30618d2f55e7SToby Isaac       }
30628d2f55e7SToby Isaac       for (i = 0; i < numSelfDof; i++) {
30638d2f55e7SToby Isaac         nnz[selfOff + i] = numChildDof;
30648d2f55e7SToby Isaac       }
30658d2f55e7SToby Isaac     }
30668d2f55e7SToby Isaac   }
30678d2f55e7SToby Isaac   ierr = MatCreateAIJ(PETSC_COMM_SELF,m,n,m,n,-1,nnz,-1,NULL,&mat);CHKERRQ(ierr);
30688d2f55e7SToby Isaac   ierr = PetscFree(nnz);CHKERRQ(ierr);
30698d2f55e7SToby Isaac   /* Setp 2: compute entries */
30708d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
30718d2f55e7SToby Isaac     const PetscInt *children;
30728d2f55e7SToby Isaac     PetscInt numChildren;
30738d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30748d2f55e7SToby Isaac 
30758d2f55e7SToby Isaac     /* same conditions about when entries occur */
30768d2f55e7SToby Isaac     if (canonical) {
30778d2f55e7SToby Isaac       PetscInt pCanonical;
30788d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
30798d2f55e7SToby Isaac       if (p != pCanonical) continue;
30808d2f55e7SToby Isaac     }
30818d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
30828d2f55e7SToby Isaac     if (!numChildren) continue;
30838d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30848d2f55e7SToby Isaac       PetscInt child = children[i];
30858d2f55e7SToby Isaac       PetscInt dof;
30868d2f55e7SToby Isaac 
30878d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
30888d2f55e7SToby Isaac       numChildDof += dof;
30898d2f55e7SToby Isaac     }
30908d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
30918d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30928d2f55e7SToby Isaac 
30938d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
309452a3aeb4SToby Isaac       PetscInt       selfOff, Nc, parentCell;
30958d2f55e7SToby Isaac       PetscInt       cellShapeOff;
30968d2f55e7SToby Isaac       PetscObject    disc;
30978d2f55e7SToby Isaac       PetscDualSpace dsp;
30988d2f55e7SToby Isaac       PetscClassId   classId;
30998d2f55e7SToby Isaac       PetscScalar    *pointMat;
31003b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
31018d2f55e7SToby Isaac       PetscInt       pO = PETSC_MIN_INT;
31028d2f55e7SToby Isaac       const PetscInt *depthNumDof;
31038d2f55e7SToby Isaac 
31048d2f55e7SToby Isaac       if (numSecFields) {
31058d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
31068d2f55e7SToby Isaac           PetscInt child = children[i];
31078d2f55e7SToby Isaac           PetscInt dof;
31088d2f55e7SToby Isaac 
31098d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
31108d2f55e7SToby Isaac           numChildDof += dof;
31118d2f55e7SToby Isaac         }
31128d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
31138d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
31148d2f55e7SToby Isaac       }
31158d2f55e7SToby Isaac       else {
31168d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
31178d2f55e7SToby Isaac       }
31188d2f55e7SToby Isaac 
31193b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
31208d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
31218d2f55e7SToby Isaac         parentCell = p;
31228d2f55e7SToby Isaac       }
31238d2f55e7SToby Isaac       else {
31248d2f55e7SToby Isaac         PetscInt *star = NULL;
31258d2f55e7SToby Isaac         PetscInt numStar;
31268d2f55e7SToby Isaac 
31278d2f55e7SToby Isaac         parentCell = -1;
31288d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31298d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
31308d2f55e7SToby Isaac           PetscInt c = star[2 * i];
31318d2f55e7SToby Isaac 
31328d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
31338d2f55e7SToby Isaac             parentCell = c;
31348d2f55e7SToby Isaac             break;
31358d2f55e7SToby Isaac           }
31368d2f55e7SToby Isaac         }
31378d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31388d2f55e7SToby Isaac       }
31398d2f55e7SToby Isaac       /* determine the offset of p's shape functions withing parentCell's shape functions */
3140c5356c36SToby Isaac       ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
3141c5356c36SToby Isaac       ierr = PetscObjectGetClassId(disc,&classId);CHKERRQ(ierr);
3142c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
3143c5356c36SToby Isaac         ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
3144c5356c36SToby Isaac       }
3145c5356c36SToby Isaac       else if (classId == PETSCFV_CLASSID) {
3146c5356c36SToby Isaac         ierr = PetscFVGetDualSpace((PetscFV)disc,&dsp);CHKERRQ(ierr);
3147c5356c36SToby Isaac       }
3148c5356c36SToby Isaac       else {
31499b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported discretization object");
3150c5356c36SToby Isaac       }
31518d2f55e7SToby Isaac       ierr = PetscDualSpaceGetNumDof(dsp,&depthNumDof);CHKERRQ(ierr);
315252a3aeb4SToby Isaac       ierr = PetscDualSpaceGetNumComponents(dsp,&Nc);CHKERRQ(ierr);
31538d2f55e7SToby Isaac       {
31548d2f55e7SToby Isaac         PetscInt *closure = NULL;
31558d2f55e7SToby Isaac         PetscInt numClosure;
31568d2f55e7SToby Isaac 
31578d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
31588d2f55e7SToby Isaac         for (i = 0, cellShapeOff = 0; i < numClosure; i++) {
31598d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
31608d2f55e7SToby Isaac 
31618d2f55e7SToby Isaac           pO = closure[2 * i + 1];
31628d2f55e7SToby Isaac           if (point == p) break;
31638d2f55e7SToby Isaac           ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
31648d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
31658d2f55e7SToby Isaac         }
31668d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
31678d2f55e7SToby Isaac       }
31688d2f55e7SToby Isaac 
316969291d52SBarry Smith       ierr = DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat);CHKERRQ(ierr);
317069291d52SBarry Smith       ierr = DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows);CHKERRQ(ierr);
317152a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
317252a3aeb4SToby Isaac       for (i = 0; i < numSelfDof; i++) {
317352a3aeb4SToby Isaac         matRows[i] = selfOff + i;
31743b1c2a6aSToby Isaac       }
317552a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
31763b1c2a6aSToby Isaac       {
31773b1c2a6aSToby Isaac         PetscInt colOff = 0;
31783b1c2a6aSToby Isaac 
31793b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
31803b1c2a6aSToby Isaac           PetscInt child = children[i];
31813b1c2a6aSToby Isaac           PetscInt dof, off, j;
31823b1c2a6aSToby Isaac 
31833b1c2a6aSToby Isaac           if (numSecFields) {
3184c5356c36SToby Isaac             ierr = PetscSectionGetFieldDof(cSection,child,f,&dof);CHKERRQ(ierr);
3185c5356c36SToby Isaac             ierr = PetscSectionGetFieldOffset(cSection,child,f,&off);CHKERRQ(ierr);
31863b1c2a6aSToby Isaac           }
31873b1c2a6aSToby Isaac           else {
3188c5356c36SToby Isaac             ierr = PetscSectionGetDof(cSection,child,&dof);CHKERRQ(ierr);
3189c5356c36SToby Isaac             ierr = PetscSectionGetOffset(cSection,child,&off);CHKERRQ(ierr);
31903b1c2a6aSToby Isaac           }
31913b1c2a6aSToby Isaac 
319252a3aeb4SToby Isaac           for (j = 0; j < dof; j++) {
319352a3aeb4SToby Isaac             matCols[colOff++] = off + j;
31943b1c2a6aSToby Isaac           }
31953b1c2a6aSToby Isaac         }
31963b1c2a6aSToby Isaac       }
31978d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
31988d2f55e7SToby Isaac         PetscFE        fe = (PetscFE) disc;
31998d2f55e7SToby Isaac         PetscInt       fSize;
32008d2f55e7SToby Isaac 
32018d2f55e7SToby Isaac         ierr = PetscFEGetDualSpace(fe,&dsp);CHKERRQ(ierr);
32023b1c2a6aSToby Isaac         ierr = PetscDualSpaceGetDimension(dsp,&fSize);CHKERRQ(ierr);
320352a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
32048d2f55e7SToby Isaac           PetscQuadrature q;
320552a3aeb4SToby Isaac           PetscInt        dim, thisNc, numPoints, j, k;
32068d2f55e7SToby Isaac           const PetscReal *points;
32078d2f55e7SToby Isaac           const PetscReal *weights;
32088d2f55e7SToby Isaac           PetscInt        *closure = NULL;
32098d2f55e7SToby Isaac           PetscInt        numClosure;
321052a3aeb4SToby Isaac           PetscInt        parentCellShapeDof = cellShapeOff + (pO < 0 ? (numSelfDof - 1 - i) : i);
32118d2f55e7SToby Isaac           PetscReal       *Bparent;
32128d2f55e7SToby Isaac 
32133b1c2a6aSToby Isaac           ierr = PetscDualSpaceGetFunctional(dsp,parentCellShapeDof,&q);CHKERRQ(ierr);
321452a3aeb4SToby Isaac           ierr = PetscQuadratureGetData(q,&dim,&thisNc,&numPoints,&points,&weights);CHKERRQ(ierr);
321552a3aeb4SToby Isaac           if (thisNc != Nc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %D does not much basis dim %D\n",thisNc,Nc);
32163b1c2a6aSToby Isaac           ierr = PetscFEGetTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
32173b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
32188d2f55e7SToby Isaac             PetscInt          childCell = -1;
321952a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
32208d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
32218d2f55e7SToby Isaac             const PetscScalar *point;
32228d2f55e7SToby Isaac             PetscReal         *Bchild;
32238d2f55e7SToby Isaac             PetscInt          childCellShapeOff, pointMatOff;
32248d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
32258d2f55e7SToby Isaac             PetscInt          d;
32268d2f55e7SToby Isaac 
32278d2f55e7SToby Isaac             for (d = 0; d < dim; d++) {
32288d2f55e7SToby Isaac               pointScalar[d] = points[dim * j + d];
32298d2f55e7SToby Isaac             }
32308d2f55e7SToby Isaac             point = pointScalar;
32318d2f55e7SToby Isaac #else
32328d2f55e7SToby Isaac             point = pointReal;
32338d2f55e7SToby Isaac #endif
32348d2f55e7SToby Isaac 
323552a3aeb4SToby Isaac             parentValAtPoint = &Bparent[(fSize * j + parentCellShapeDof) * Nc];
32363b1c2a6aSToby Isaac 
32373b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
32388d2f55e7SToby Isaac               PetscInt child = children[k];
32398d2f55e7SToby Isaac               PetscInt *star = NULL;
32408d2f55e7SToby Isaac               PetscInt numStar, s;
32418d2f55e7SToby Isaac 
32428d2f55e7SToby Isaac               ierr = DMPlexGetTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
32438d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
32448d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
32458d2f55e7SToby Isaac 
32468d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
32478d2f55e7SToby Isaac                 ierr = DMPlexLocatePoint_Internal(refTree,dim,point,c,&childCell);CHKERRQ(ierr);
32488d2f55e7SToby Isaac                 if (childCell >= 0) break;
32498d2f55e7SToby Isaac               }
32508d2f55e7SToby Isaac               ierr = DMPlexRestoreTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
32518d2f55e7SToby Isaac               if (childCell >= 0) break;
32528d2f55e7SToby Isaac             }
325313903a91SSatish Balay             if (childCell < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not locate quadrature point");
32548d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
32558d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent);CHKERRQ(ierr);
32568d2f55e7SToby Isaac             CoordinatesRefToReal(dim, dim, v0parent, Jparent, pointReal, vtmp);
32578d2f55e7SToby Isaac             CoordinatesRealToRef(dim, dim, v0, invJ, vtmp, pointRef);
32588d2f55e7SToby Isaac 
32598d2f55e7SToby Isaac             ierr = PetscFEGetTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr);
32608d2f55e7SToby Isaac             ierr = DMPlexGetTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
32613b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3262c5356c36SToby Isaac               PetscInt child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
32638d2f55e7SToby Isaac               PetscInt l;
32648d2f55e7SToby Isaac 
32658d2f55e7SToby Isaac               ierr = DMLabelGetValue(depth,child,&childDepth);CHKERRQ(ierr);
32668d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
32678d2f55e7SToby Isaac               for (l = 0, childCellShapeOff = 0; l < numClosure; l++) {
32688d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
32698d2f55e7SToby Isaac                 PetscInt pointDepth;
32708d2f55e7SToby Isaac 
32718d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
32728d2f55e7SToby Isaac                 if (point == child) break;
32738d2f55e7SToby Isaac                 ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
32748d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
32758d2f55e7SToby Isaac               }
32768d2f55e7SToby Isaac               if (l == numClosure) {
32778d2f55e7SToby Isaac                 pointMatOff += childDof;
32788d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
32798d2f55e7SToby Isaac               }
32808d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
328152a3aeb4SToby Isaac                 PetscInt    childCellDof = childCellShapeOff + (childO ? (childDof - 1 - l) : l), m;
328252a3aeb4SToby Isaac                 PetscReal   *childValAtPoint;
328352a3aeb4SToby Isaac                 PetscReal   val = 0.;
32848d2f55e7SToby Isaac 
328552a3aeb4SToby Isaac                 childValAtPoint = &Bchild[childCellDof * Nc];
328652a3aeb4SToby Isaac                 for (m = 0; m < Nc; m++) {
328752a3aeb4SToby Isaac                   val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
328852a3aeb4SToby Isaac                 }
328952a3aeb4SToby Isaac 
329052a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
32918d2f55e7SToby Isaac               }
32928d2f55e7SToby Isaac               pointMatOff += childDof;
32938d2f55e7SToby Isaac             }
32948d2f55e7SToby Isaac             ierr = DMPlexRestoreTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
32958d2f55e7SToby Isaac             ierr = PetscFERestoreTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr);
32968d2f55e7SToby Isaac           }
32978d2f55e7SToby Isaac           ierr = PetscFERestoreTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr);
32988d2f55e7SToby Isaac         }
32998d2f55e7SToby Isaac       }
3300c5356c36SToby Isaac       else { /* just the volume-weighted averages of the children */
33013b1c2a6aSToby Isaac         PetscReal parentVol;
3302bfaa5bdcSToby Isaac         PetscInt  childCell;
33033b1c2a6aSToby Isaac 
33043b1c2a6aSToby Isaac         ierr = DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL);CHKERRQ(ierr);
3305bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
330652a3aeb4SToby Isaac           PetscInt  child = children[i], j;
33073b1c2a6aSToby Isaac           PetscReal childVol;
33083b1c2a6aSToby Isaac 
33093b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
33103b1c2a6aSToby Isaac           ierr = DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL);CHKERRQ(ierr);
331152a3aeb4SToby Isaac           for (j = 0; j < Nc; j++) {
3312bfaa5bdcSToby Isaac             pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
331352a3aeb4SToby Isaac           }
3314bfaa5bdcSToby Isaac           childCell++;
33153b1c2a6aSToby Isaac         }
33168d2f55e7SToby Isaac       }
33173b1c2a6aSToby Isaac       /* Insert pointMat into mat */
331852a3aeb4SToby Isaac       ierr = MatSetValues(mat,numSelfDof,matRows,numChildDof,matCols,pointMat,INSERT_VALUES);CHKERRQ(ierr);
331969291d52SBarry Smith       ierr = DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows);CHKERRQ(ierr);
332069291d52SBarry Smith       ierr = DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat);CHKERRQ(ierr);
33218d2f55e7SToby Isaac     }
33228d2f55e7SToby Isaac   }
33233b1c2a6aSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJ);CHKERRQ(ierr);
33248d2f55e7SToby Isaac   ierr = PetscFree2(pointScalar,pointRef);CHKERRQ(ierr);
33253b1c2a6aSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33263b1c2a6aSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33278d2f55e7SToby Isaac   *inj = mat;
33288d2f55e7SToby Isaac   PetscFunctionReturn(0);
33298d2f55e7SToby Isaac }
33308d2f55e7SToby Isaac 
3331f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3332f30e825dSToby Isaac {
3333f30e825dSToby Isaac   PetscDS        ds;
3334f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3335f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3336f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3337f30e825dSToby Isaac   PetscErrorCode ierr;
3338f30e825dSToby Isaac 
3339f30e825dSToby Isaac   PetscFunctionBegin;
3340f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
3341f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3342f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
3343f30e825dSToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
3344f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3345f30e825dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
3346f30e825dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
3347f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
3348f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof*maxDof,&cols);CHKERRQ(ierr);
3349f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3350f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3351f30e825dSToby Isaac 
3352f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3353f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3354c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3355f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3356f30e825dSToby Isaac 
3357f30e825dSToby Isaac     ierr = PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
3358f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
335952a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3360f30e825dSToby Isaac 
3361f30e825dSToby Isaac       if (numFields > 1) {
3362f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3363f30e825dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
3364f30e825dSToby Isaac       }
3365f30e825dSToby Isaac       else {
3366f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3367f30e825dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
3368f30e825dSToby Isaac       }
3369f30e825dSToby Isaac 
3370f30e825dSToby Isaac       for (r = 0; r < cDof; r++) {
3371f30e825dSToby Isaac         rows[r] = cOff + r;
3372f30e825dSToby Isaac       }
3373f30e825dSToby Isaac       numCols = 0;
3374f30e825dSToby Isaac       {
3375f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3376f30e825dSToby Isaac 
3377f30e825dSToby Isaac         if (numFields > 1) {
3378f30e825dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,parent,f,&aDof);CHKERRQ(ierr);
3379f30e825dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,parent,f,&aOff);CHKERRQ(ierr);
3380f30e825dSToby Isaac         }
3381f30e825dSToby Isaac         else {
3382f30e825dSToby Isaac           ierr = PetscSectionGetDof(refSection,parent,&aDof);CHKERRQ(ierr);
3383f30e825dSToby Isaac           ierr = PetscSectionGetOffset(refSection,parent,&aOff);CHKERRQ(ierr);
3384f30e825dSToby Isaac         }
3385f30e825dSToby Isaac 
3386f30e825dSToby Isaac         for (j = 0; j < aDof; j++) {
3387f30e825dSToby Isaac           cols[numCols++] = aOff + j;
3388f30e825dSToby Isaac         }
3389f30e825dSToby Isaac       }
3390f30e825dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3391f30e825dSToby Isaac       /* transpose of constraint matrix */
3392f30e825dSToby Isaac       ierr = MatGetValues(inj,numCols,cols,cDof,rows,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3393f30e825dSToby Isaac     }
3394f30e825dSToby Isaac   }
3395f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
3396f30e825dSToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
3397f30e825dSToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
3398f30e825dSToby Isaac   PetscFunctionReturn(0);
3399f30e825dSToby Isaac }
3400f30e825dSToby Isaac 
3401f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3402f30e825dSToby Isaac {
3403f30e825dSToby Isaac   PetscDS        ds;
3404f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3405f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3406c6154584SToby Isaac   PetscSection   refConSec, refSection;
3407f30e825dSToby Isaac   PetscErrorCode ierr;
3408f30e825dSToby Isaac 
3409f30e825dSToby Isaac   PetscFunctionBegin;
3410f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3411f30e825dSToby Isaac   *childrenMats = NULL;
3412f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
3413c6154584SToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
3414f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3415f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
3416f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3417f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3418f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3419f30e825dSToby Isaac 
3420f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3421f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3422c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3423f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3424f30e825dSToby Isaac 
3425f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3426f30e825dSToby Isaac       PetscInt cDof;
3427f30e825dSToby Isaac 
3428f30e825dSToby Isaac       if (numFields > 1) {
3429f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3430f30e825dSToby Isaac       }
3431f30e825dSToby Isaac       else {
3432f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3433f30e825dSToby Isaac       }
3434f30e825dSToby Isaac 
3435f30e825dSToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
3436f30e825dSToby Isaac     }
3437f30e825dSToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
3438f30e825dSToby Isaac   }
3439f30e825dSToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
3440f30e825dSToby Isaac   PetscFunctionReturn(0);
3441f30e825dSToby Isaac }
3442f30e825dSToby Isaac 
3443ebf164c7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree,Mat *injRef)
3444154bca37SToby Isaac {
3445ebf164c7SToby Isaac   Mat            cMatRef;
34466148253fSToby Isaac   PetscObject    injRefObj;
34478d2f55e7SToby Isaac   PetscErrorCode ierr;
34488d2f55e7SToby Isaac 
3449154bca37SToby Isaac   PetscFunctionBegin;
3450ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,NULL,&cMatRef);CHKERRQ(ierr);
34516148253fSToby Isaac   ierr = PetscObjectQuery((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",&injRefObj);CHKERRQ(ierr);
3452ebf164c7SToby Isaac   *injRef = (Mat) injRefObj;
3453ebf164c7SToby Isaac   if (!*injRef) {
3454ebf164c7SToby Isaac     ierr = DMPlexComputeInjectorReferenceTree(refTree,injRef);CHKERRQ(ierr);
3455ebf164c7SToby Isaac     ierr = PetscObjectCompose((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",(PetscObject)*injRef);CHKERRQ(ierr);
3456ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
3457ebf164c7SToby Isaac     ierr = PetscObjectDereference((PetscObject)*injRef);CHKERRQ(ierr);
3458ebf164c7SToby Isaac   }
3459ebf164c7SToby Isaac   PetscFunctionReturn(0);
34606148253fSToby Isaac }
3461f30e825dSToby Isaac 
3462c921d74cSToby 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)
3463ebf164c7SToby Isaac {
3464c921d74cSToby Isaac   PetscInt       pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3465ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3466ebf164c7SToby Isaac   PetscSection   localCoarse, localFine, leafIndicesSec;
3467c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3468c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3469c921d74cSToby Isaac   const PetscInt *rootDegrees;
3470c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3471ebf164c7SToby Isaac   PetscSF        coarseToFineEmbedded;
3472ebf164c7SToby Isaac   PetscErrorCode ierr;
3473ebf164c7SToby Isaac 
3474ebf164c7SToby Isaac   PetscFunctionBegin;
3475ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
34768d2f55e7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
3477f30e825dSToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
34788d2f55e7SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3479f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
3480f30e825dSToby Isaac   ierr = PetscSectionSetChart(leafIndicesSec,pStartF, pEndF);CHKERRQ(ierr);
3481c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localFine,&maxDof);CHKERRQ(ierr);
34828d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
34837e96bdafSToby Isaac     PetscInt l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
34847e96bdafSToby Isaac     const PetscInt *leaves;
34858d2f55e7SToby Isaac 
34867e96bdafSToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
34877e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
34887e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
34898d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
34908d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
34918d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
34928d2f55e7SToby Isaac         numPointsWithDofs++;
3493f30e825dSToby Isaac 
3494f30e825dSToby Isaac         ierr = PetscSectionGetDof(localFine,p,&dof);CHKERRQ(ierr);
3495f30e825dSToby Isaac         ierr = PetscSectionSetDof(leafIndicesSec,p,dof + 1);CHKERRQ(ierr);
34968d2f55e7SToby Isaac       }
34978d2f55e7SToby Isaac     }
34988d2f55e7SToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
3499f30e825dSToby Isaac     ierr = PetscSectionSetUp(leafIndicesSec);CHKERRQ(ierr);
3500f30e825dSToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numIndices);CHKERRQ(ierr);
3501c921d74cSToby Isaac     ierr = PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1),&leafInds);CHKERRQ(ierr);
3502c921d74cSToby Isaac     if (gatheredValues)  {ierr = PetscMalloc1(numIndices,&leafVals);CHKERRQ(ierr);}
35037e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
35047e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35058d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
35068d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
35078d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3508f30e825dSToby Isaac         PetscInt    off, gOff;
3509f30e825dSToby Isaac         PetscInt    *pInd;
3510c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3511f30e825dSToby Isaac 
35127e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3513f30e825dSToby Isaac 
3514f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3515f30e825dSToby Isaac 
3516c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3517c921d74cSToby Isaac         if (gatheredValues) {
3518c921d74cSToby Isaac           PetscInt i;
3519c921d74cSToby Isaac 
3520c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3521c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3522c921d74cSToby Isaac         }
3523f30e825dSToby Isaac         ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
3524f30e825dSToby Isaac 
3525f30e825dSToby Isaac         offsets[0] = 0;
3526f30e825dSToby Isaac         if (numFields) {
3527f30e825dSToby Isaac           PetscInt f;
3528f30e825dSToby Isaac 
3529f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3530f30e825dSToby Isaac             PetscInt fDof;
3531f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(localFine,p,f,&fDof);CHKERRQ(ierr);
3532f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3533f30e825dSToby Isaac           }
35344acb8e1eSToby Isaac           DMPlexGetIndicesPointFields_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1,pInd);CHKERRQ(ierr);
3535f30e825dSToby Isaac         }
3536f30e825dSToby Isaac         else {
35374acb8e1eSToby Isaac           DMPlexGetIndicesPoint_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,pInd);CHKERRQ(ierr);
3538f30e825dSToby Isaac         }
3539c921d74cSToby Isaac         if (gatheredValues) {ierr = VecGetValues(fineVec,dof,pInd,pVal);CHKERRQ(ierr);}
35408d2f55e7SToby Isaac       }
35418d2f55e7SToby Isaac     }
35428d2f55e7SToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
3543f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
35448d2f55e7SToby Isaac   }
3545f30e825dSToby Isaac 
3546f30e825dSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
3547f30e825dSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
3548f30e825dSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3549f30e825dSToby Isaac 
35506148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
35516148253fSToby Isaac     MPI_Datatype threeInt;
35526148253fSToby Isaac     PetscMPIInt  rank;
35536148253fSToby Isaac     PetscInt     (*parentNodeAndIdCoarse)[3];
35546148253fSToby Isaac     PetscInt     (*parentNodeAndIdFine)[3];
35556148253fSToby Isaac     PetscInt     p, nleaves, nleavesToParents;
35566148253fSToby Isaac     PetscSF      pointSF, sfToParents;
35576148253fSToby Isaac     const PetscInt *ilocal;
35586148253fSToby Isaac     const PetscSFNode *iremote;
35596148253fSToby Isaac     PetscSFNode  *iremoteToParents;
35606148253fSToby Isaac     PetscInt     *ilocalToParents;
35616148253fSToby Isaac 
35626148253fSToby Isaac     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)coarse),&rank);CHKERRQ(ierr);
35636148253fSToby Isaac     ierr = MPI_Type_contiguous(3,MPIU_INT,&threeInt);CHKERRQ(ierr);
35646148253fSToby Isaac     ierr = MPI_Type_commit(&threeInt);CHKERRQ(ierr);
35656148253fSToby Isaac     ierr = PetscMalloc2(pEndC-pStartC,&parentNodeAndIdCoarse,pEndF-pStartF,&parentNodeAndIdFine);CHKERRQ(ierr);
35666148253fSToby Isaac     ierr = DMGetPointSF(coarse,&pointSF);CHKERRQ(ierr);
35676148253fSToby Isaac     ierr = PetscSFGetGraph(pointSF,NULL,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
35686148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
35696148253fSToby Isaac       PetscInt parent, childId;
35706148253fSToby Isaac       ierr = DMPlexGetTreeParent(coarse,p,&parent,&childId);CHKERRQ(ierr);
35716148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
35726148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
35736148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
35746148253fSToby Isaac       if (nleaves > 0) {
35756148253fSToby Isaac         PetscInt leaf = -1;
35766148253fSToby Isaac 
35776148253fSToby Isaac         if (ilocal) {
35786148253fSToby Isaac           ierr  = PetscFindInt(parent,nleaves,ilocal,&leaf);CHKERRQ(ierr);
35796148253fSToby Isaac         }
35806148253fSToby Isaac         else {
35816148253fSToby Isaac           leaf = p - pStartC;
35826148253fSToby Isaac         }
35836148253fSToby Isaac         if (leaf >= 0) {
35846148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
35856148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
35866148253fSToby Isaac         }
35876148253fSToby Isaac       }
35886148253fSToby Isaac     }
35896148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
35906148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
35916148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
35926148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
35936148253fSToby Isaac     }
35946148253fSToby Isaac     ierr = PetscSFBcastBegin(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
35956148253fSToby Isaac     ierr = PetscSFBcastEnd(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
35966148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3597f30e825dSToby Isaac       PetscInt dof;
3598f30e825dSToby Isaac 
3599f30e825dSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&dof);CHKERRQ(ierr);
3600f30e825dSToby Isaac       if (dof) {
3601f30e825dSToby Isaac         PetscInt off;
3602f30e825dSToby Isaac 
3603f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3604c921d74cSToby Isaac         if (gatheredIndices) {
3605c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3606c921d74cSToby Isaac         } else if (gatheredValues) {
3607c921d74cSToby Isaac           leafVals[off] = (PetscScalar) PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3608c921d74cSToby Isaac         }
3609f30e825dSToby Isaac       }
36106148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36116148253fSToby Isaac         nleavesToParents++;
36126148253fSToby Isaac       }
36136148253fSToby Isaac     }
36146148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&ilocalToParents);CHKERRQ(ierr);
36156148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&iremoteToParents);CHKERRQ(ierr);
36166148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
36176148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36186148253fSToby Isaac         ilocalToParents[nleavesToParents] = p - pStartF;
36196148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p-pStartF][0];
36206148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p-pStartF][1];
36216148253fSToby Isaac         nleavesToParents++;
36226148253fSToby Isaac       }
36236148253fSToby Isaac     }
36246148253fSToby Isaac     ierr = PetscSFCreate(PetscObjectComm((PetscObject)coarse),&sfToParents);CHKERRQ(ierr);
36256148253fSToby Isaac     ierr = PetscSFSetGraph(sfToParents,pEndC-pStartC,nleavesToParents,ilocalToParents,PETSC_OWN_POINTER,iremoteToParents,PETSC_OWN_POINTER);CHKERRQ(ierr);
36266148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
36276148253fSToby Isaac 
36286148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
36296148253fSToby Isaac 
36306148253fSToby Isaac     ierr = PetscFree2(parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36316148253fSToby Isaac     ierr = MPI_Type_free(&threeInt);CHKERRQ(ierr);
36326148253fSToby Isaac   }
3633f30e825dSToby Isaac 
36346148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
36356148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
36366148253fSToby Isaac     PetscSF  sfDofsOnly;
36376148253fSToby Isaac 
36386148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
36396148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
36406148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
36416148253fSToby Isaac       if ((dof - cdof) > 0) {
36426148253fSToby Isaac         numPointsWithDofs++;
36436148253fSToby Isaac       }
36446148253fSToby Isaac     }
36456148253fSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
36466148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
36476148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
36486148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
36496148253fSToby Isaac       if ((dof - cdof) > 0) {
3650e03d9830SToby Isaac         pointsWithDofs[offset++] = p - pStartC;
36516148253fSToby Isaac       }
36526148253fSToby Isaac     }
36536148253fSToby Isaac     ierr = PetscSFCreateEmbeddedSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly);CHKERRQ(ierr);
36546148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3655f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
36566148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
36576148253fSToby Isaac   }
3658f30e825dSToby Isaac 
36596148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
3660f30e825dSToby Isaac   ierr = PetscSFComputeDegreeBegin(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3661f30e825dSToby Isaac   ierr = PetscSFComputeDegreeEnd(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3662f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&multiRootSec);CHKERRQ(ierr);
3663f30e825dSToby Isaac   ierr = PetscSectionSetChart(multiRootSec,pStartC,pEndC);CHKERRQ(ierr);
36648d2f55e7SToby Isaac   for (p = pStartC; p < pEndC; p++) {
3665f30e825dSToby Isaac     ierr = PetscSectionSetDof(multiRootSec,p,rootDegrees[p-pStartC]);CHKERRQ(ierr);
36668d2f55e7SToby Isaac   }
3667f30e825dSToby Isaac   ierr = PetscSectionSetUp(multiRootSec);CHKERRQ(ierr);
3668f30e825dSToby Isaac   ierr = PetscSectionGetStorageSize(multiRootSec,&numMulti);CHKERRQ(ierr);
36698d2f55e7SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
3670f30e825dSToby Isaac   { /* distribute the leaf section */
3671f30e825dSToby Isaac     PetscSF multi, multiInv, indicesSF;
3672f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
36738d2f55e7SToby Isaac 
3674f30e825dSToby Isaac     ierr = PetscSFGetMultiSF(coarseToFineEmbedded,&multi);CHKERRQ(ierr);
3675f30e825dSToby Isaac     ierr = PetscSFCreateInverseSF(multi,&multiInv);CHKERRQ(ierr);
3676f30e825dSToby Isaac     ierr = PetscSFDistributeSection(multiInv,leafIndicesSec,&remoteOffsets,rootIndicesSec);CHKERRQ(ierr);
3677f30e825dSToby Isaac     ierr = PetscSFCreateSectionSF(multiInv,leafIndicesSec,remoteOffsets,rootIndicesSec,&indicesSF);CHKERRQ(ierr);
3678f30e825dSToby Isaac     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
3679f30e825dSToby Isaac     ierr = PetscSFDestroy(&multiInv);CHKERRQ(ierr);
36808d2f55e7SToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
3681c921d74cSToby Isaac     if (gatheredIndices) {
3682c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootInds);CHKERRQ(ierr);
3683c921d74cSToby Isaac       ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr);
3684c921d74cSToby Isaac       ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr);
3685c921d74cSToby Isaac     }
3686c921d74cSToby Isaac     if (gatheredValues) {
3687c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootVals);CHKERRQ(ierr);
3688c921d74cSToby Isaac       ierr = PetscSFBcastBegin(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr);
3689c921d74cSToby Isaac       ierr = PetscSFBcastEnd(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr);
3690c921d74cSToby Isaac     }
36918d2f55e7SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
36928d2f55e7SToby Isaac   }
3693ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
3694c921d74cSToby Isaac   ierr = PetscFree(leafInds);CHKERRQ(ierr);
3695c921d74cSToby Isaac   ierr = PetscFree(leafVals);CHKERRQ(ierr);
3696f30e825dSToby Isaac   ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3697c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3698c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3699c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3700c921d74cSToby Isaac   if (gatheredValues)  *gatheredValues  = rootVals;
3701ebf164c7SToby Isaac   PetscFunctionReturn(0);
3702ebf164c7SToby Isaac }
3703ebf164c7SToby Isaac 
3704ebf164c7SToby Isaac PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3705ebf164c7SToby Isaac {
3706ebf164c7SToby Isaac   DM             refTree;
3707c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3708ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3709ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3710ebf164c7SToby Isaac   PetscSection   cSecRef;
3711c921d74cSToby Isaac   PetscInt       *rootIndices, *parentIndices, pRefStart, pRefEnd;
3712ebf164c7SToby Isaac   Mat            injRef;
3713c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3714ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3715ebf164c7SToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
3716ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3717ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3718ebf164c7SToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3719ebf164c7SToby Isaac   PetscErrorCode ierr;
3720ebf164c7SToby Isaac 
3721ebf164c7SToby Isaac   PetscFunctionBegin;
3722ebf164c7SToby Isaac 
3723ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
3724ebf164c7SToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
3725ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
3726ebf164c7SToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3727ebf164c7SToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
3728ebf164c7SToby Isaac 
3729ebf164c7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
3730ebf164c7SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
3731ebf164c7SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3732ebf164c7SToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
3733ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
3734ebf164c7SToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
3735ebf164c7SToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3736ebf164c7SToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
3737ebf164c7SToby Isaac   {
3738ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
3739ebf164c7SToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
3740ebf164c7SToby Isaac   }
3741ebf164c7SToby Isaac 
3742c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,childIds,NULL,numFields,offsets,&multiRootSec,&rootIndicesSec,&rootIndices,NULL);CHKERRQ(ierr);
37438d2f55e7SToby Isaac 
3744f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&parentIndices);CHKERRQ(ierr);
3745f30e825dSToby Isaac 
3746f30e825dSToby Isaac   /* count indices */
37478d2f55e7SToby Isaac   ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
3748c6154584SToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
3749c6154584SToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
37508d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
37518d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
3752f30e825dSToby Isaac   ierr = PetscCalloc2(rowEnd-rowStart,&nnzD,rowEnd-rowStart,&nnzO);CHKERRQ(ierr);
3753f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3754f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
37558d2f55e7SToby Isaac 
3756f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3757f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3758f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3759f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
37608d2f55e7SToby Isaac 
37618d2f55e7SToby Isaac     rowOffsets[0] = 0;
3762f30e825dSToby Isaac     offsetsCopy[0] = 0;
37638d2f55e7SToby Isaac     if (numFields) {
37648d2f55e7SToby Isaac       PetscInt f;
37658d2f55e7SToby Isaac 
3766f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3767f30e825dSToby Isaac         PetscInt fDof;
3768f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3769f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
37708d2f55e7SToby Isaac       }
37714acb8e1eSToby Isaac       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,parentIndices);CHKERRQ(ierr);
37728d2f55e7SToby Isaac     }
37738d2f55e7SToby Isaac     else {
37744acb8e1eSToby Isaac       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,parentIndices);CHKERRQ(ierr);
3775f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
37768d2f55e7SToby Isaac     }
3777f30e825dSToby Isaac 
3778f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3779f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3780f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3781f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3782f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3783f30e825dSToby Isaac       const PetscInt *childIndices;
3784f30e825dSToby Isaac 
3785f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3786f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3787f30e825dSToby Isaac       childId = rootIndices[offset++];
3788f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3789f30e825dSToby Isaac       numIndices--;
3790f30e825dSToby Isaac 
3791f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3792f30e825dSToby Isaac         PetscInt i;
3793f30e825dSToby Isaac 
3794f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3795f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3796f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3797f30e825dSToby Isaac           if (rowIndex < 0) continue;
3798f30e825dSToby Isaac           if (colIndex < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unconstrained fine and constrained coarse");
3799a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3800f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
3801f30e825dSToby Isaac           }
3802f30e825dSToby Isaac           else {
3803f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3804f30e825dSToby Isaac           }
3805f30e825dSToby Isaac         }
3806f30e825dSToby Isaac       }
3807f30e825dSToby Isaac       else {
3808f30e825dSToby Isaac         PetscInt parentId, f, lim;
3809f30e825dSToby Isaac 
3810f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3811f30e825dSToby Isaac 
3812f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3813f30e825dSToby Isaac         offsets[0] = 0;
38148d2f55e7SToby Isaac         if (numFields) {
38158d2f55e7SToby Isaac           PetscInt f;
3816f30e825dSToby Isaac 
38178d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3818f30e825dSToby Isaac             PetscInt fDof;
3819f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
3820f30e825dSToby Isaac 
3821f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
38228d2f55e7SToby Isaac           }
38238d2f55e7SToby Isaac         }
38248d2f55e7SToby Isaac         else {
3825f30e825dSToby Isaac           PetscInt cDof;
3826f30e825dSToby Isaac 
3827f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
3828f30e825dSToby Isaac           offsets[1] = cDof;
3829f30e825dSToby Isaac         }
3830f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3831f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3832f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3833f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3834f30e825dSToby Isaac 
3835f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3836f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3837f30e825dSToby Isaac 
3838f30e825dSToby Isaac             if (colIndex < 0) continue;
3839f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3840f30e825dSToby Isaac               numD++;
3841f30e825dSToby Isaac             }
3842f30e825dSToby Isaac             else {
3843f30e825dSToby Isaac               numO++;
3844f30e825dSToby Isaac             }
3845f30e825dSToby Isaac           }
3846f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3847f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3848f30e825dSToby Isaac 
3849f30e825dSToby Isaac             if (rowIndex < 0) continue;
3850f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3851f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
38528d2f55e7SToby Isaac           }
38538d2f55e7SToby Isaac         }
38548d2f55e7SToby Isaac       }
3855f30e825dSToby Isaac     }
3856f30e825dSToby Isaac   }
3857f30e825dSToby Isaac   /* preallocate */
3858f30e825dSToby Isaac   ierr = MatXAIJSetPreallocation(mat,1,nnzD,nnzO,NULL,NULL);CHKERRQ(ierr);
3859f30e825dSToby Isaac   ierr = PetscFree2(nnzD,nnzO);CHKERRQ(ierr);
3860f30e825dSToby Isaac   /* insert values */
3861f30e825dSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
3862f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3863f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3864f30e825dSToby Isaac 
3865f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3866f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3867f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3868f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
3869f30e825dSToby Isaac 
3870f30e825dSToby Isaac     rowOffsets[0] = 0;
3871f30e825dSToby Isaac     offsetsCopy[0] = 0;
38728d2f55e7SToby Isaac     if (numFields) {
38738d2f55e7SToby Isaac       PetscInt f;
3874f30e825dSToby Isaac 
38758d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3876f30e825dSToby Isaac         PetscInt fDof;
3877f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3878f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3879f30e825dSToby Isaac       }
38804acb8e1eSToby Isaac       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,parentIndices);CHKERRQ(ierr);
3881f30e825dSToby Isaac     }
3882f30e825dSToby Isaac     else {
38834acb8e1eSToby Isaac       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,parentIndices);CHKERRQ(ierr);
3884f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3885f30e825dSToby Isaac     }
3886f30e825dSToby Isaac 
3887f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3888f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3889f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3890f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3891f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3892f30e825dSToby Isaac       const PetscInt *childIndices;
3893f30e825dSToby Isaac 
3894f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3895f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3896f30e825dSToby Isaac       childId = rootIndices[offset++];
3897f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3898f30e825dSToby Isaac       numIndices--;
3899f30e825dSToby Isaac 
3900f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3901f30e825dSToby Isaac         PetscInt i;
3902f30e825dSToby Isaac 
3903f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3904f30e825dSToby Isaac           ierr = MatSetValue(mat,parentIndices[i],childIndices[i],1.,INSERT_VALUES);CHKERRQ(ierr);
39058d2f55e7SToby Isaac         }
39068d2f55e7SToby Isaac       }
39078d2f55e7SToby Isaac       else {
3908f30e825dSToby Isaac         PetscInt parentId, f, lim;
39098d2f55e7SToby Isaac 
3910f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3911f30e825dSToby Isaac 
3912f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3913f30e825dSToby Isaac         offsets[0] = 0;
39148d2f55e7SToby Isaac         if (numFields) {
3915f30e825dSToby Isaac           PetscInt f;
39168d2f55e7SToby Isaac 
3917f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3918f30e825dSToby Isaac             PetscInt fDof;
3919f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
3920f30e825dSToby Isaac 
3921f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
39228d2f55e7SToby Isaac           }
39238d2f55e7SToby Isaac         }
39248d2f55e7SToby Isaac         else {
3925f30e825dSToby Isaac           PetscInt cDof;
3926f30e825dSToby Isaac 
3927f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
3928f30e825dSToby Isaac           offsets[1] = cDof;
39298d2f55e7SToby Isaac         }
3930f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3931f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3932f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3933f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3934f30e825dSToby Isaac 
3935f30e825dSToby Isaac           ierr = MatSetValues(mat,rowOffsets[f+1]-rowOffsets[f],rowIndices,offsets[f+1]-offsets[f],colIndices,childMat,INSERT_VALUES);CHKERRQ(ierr);
39368d2f55e7SToby Isaac         }
39378d2f55e7SToby Isaac       }
39388d2f55e7SToby Isaac     }
39398d2f55e7SToby Isaac   }
3940ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
3941ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
3942ec92bd66SToby Isaac   ierr = PetscFree(parentIndices);CHKERRQ(ierr);
3943f30e825dSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
3944f30e825dSToby Isaac   ierr = PetscFree(rootIndices);CHKERRQ(ierr);
3945f30e825dSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
3946f30e825dSToby Isaac 
39478d2f55e7SToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
39488d2f55e7SToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
3949154bca37SToby Isaac   PetscFunctionReturn(0);
3950154bca37SToby Isaac }
395138fc2455SToby Isaac 
39520eb7e1eaSToby Isaac static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3953ebf164c7SToby Isaac {
39544833aeb0SToby Isaac   PetscDS           ds;
395562095d54SToby Isaac   PetscSF           coarseToFineEmbedded;
395662095d54SToby Isaac   PetscSection      globalCoarse, globalFine;
395762095d54SToby Isaac   PetscSection      localCoarse, localFine;
395862095d54SToby Isaac   PetscSection      aSec, cSec;
395962095d54SToby Isaac   PetscSection      rootValuesSec;
396062095d54SToby Isaac   PetscSection      leafValuesSec;
396162095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
396262095d54SToby Isaac   IS                aIS;
396362095d54SToby Isaac   const PetscInt    *anchors;
396462095d54SToby Isaac   Mat               cMat;
396562095d54SToby Isaac   PetscInt          numFields;
396689698031SToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd, cellEndInterior;
396762095d54SToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
396862095d54SToby Isaac   PetscInt          *maxChildIds;
396962095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
39700eb7e1eaSToby Isaac   PetscFV           fv = NULL;
39710eb7e1eaSToby Isaac   PetscInt          dim, numFVcomps = -1, fvField = -1;
39720eb7e1eaSToby Isaac   DM                cellDM = NULL, gradDM = NULL;
39730eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
39740eb7e1eaSToby Isaac   const PetscScalar *gradArray = NULL;
397562095d54SToby Isaac   PetscErrorCode    ierr;
397662095d54SToby Isaac 
3977ebf164c7SToby Isaac   PetscFunctionBegin;
3978708c7f19SToby Isaac   ierr = VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
397962095d54SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
39800eb7e1eaSToby Isaac   ierr = DMPlexGetHeightStratum(coarse,0,&cellStart,&cellEnd);CHKERRQ(ierr);
398189698031SToby Isaac   ierr = DMPlexGetHybridBounds(coarse,&cellEndInterior,NULL,NULL,NULL);CHKERRQ(ierr);
398289698031SToby Isaac   cellEnd = (cellEndInterior < 0) ? cellEnd : cellEndInterior;
398362095d54SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
398462095d54SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
39850eb7e1eaSToby Isaac   ierr = DMGetCoordinateDim(coarse,&dim);CHKERRQ(ierr);
398662095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3987e4a60869SToby Isaac     PetscInt       nleaves, l;
3988e4a60869SToby Isaac     const PetscInt *leaves;
398962095d54SToby Isaac     PetscInt       dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
399062095d54SToby Isaac 
3991e4a60869SToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
3992e4a60869SToby Isaac 
3993e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3994e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3995e4a60869SToby Isaac 
399662095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
399762095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
399862095d54SToby Isaac       if ((dof - cdof) > 0) {
399962095d54SToby Isaac         numPointsWithDofs++;
400062095d54SToby Isaac       }
400162095d54SToby Isaac     }
400262095d54SToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
40034833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
4004e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
4005e4a60869SToby Isaac 
400662095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
400762095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
400862095d54SToby Isaac       if ((dof - cdof) > 0) {
4009e4a60869SToby Isaac         pointsWithDofs[offset++] = l;
401062095d54SToby Isaac       }
401162095d54SToby Isaac     }
401262095d54SToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
401362095d54SToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
401462095d54SToby Isaac   }
401562095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
401662095d54SToby Isaac   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
401762095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) {
401862095d54SToby Isaac     maxChildIds[p - pStartC] = -2;
401962095d54SToby Isaac   }
402062095d54SToby Isaac   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
402162095d54SToby Isaac   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
402262095d54SToby Isaac 
402362095d54SToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
402462095d54SToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
402562095d54SToby Isaac 
402662095d54SToby Isaac   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
402762095d54SToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
402862095d54SToby Isaac   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
402962095d54SToby Isaac 
403062095d54SToby Isaac   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
403162095d54SToby Isaac   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
403262095d54SToby Isaac 
403362095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
403462095d54SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootValuesSec);CHKERRQ(ierr);
403562095d54SToby Isaac   ierr = PetscSectionSetChart(rootValuesSec,pStartC,pEndC);CHKERRQ(ierr);
4036708c7f19SToby Isaac   ierr = PetscSectionGetNumFields(localCoarse,&numFields);CHKERRQ(ierr);
403762095d54SToby Isaac   {
403862095d54SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
403962095d54SToby Isaac     ierr = PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO);CHKERRQ(ierr);
404062095d54SToby Isaac   }
40410eb7e1eaSToby Isaac   if (grad) {
40420eb7e1eaSToby Isaac     PetscInt i;
40430eb7e1eaSToby Isaac 
40440eb7e1eaSToby Isaac     ierr = VecGetDM(cellGeom,&cellDM);CHKERRQ(ierr);
40450eb7e1eaSToby Isaac     ierr = VecGetArrayRead(cellGeom,&cellGeomArray);CHKERRQ(ierr);
40460eb7e1eaSToby Isaac     ierr = VecGetDM(grad,&gradDM);CHKERRQ(ierr);
40470eb7e1eaSToby Isaac     ierr = VecGetArrayRead(grad,&gradArray);CHKERRQ(ierr);
40480eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1,numFields); i++) {
40490eb7e1eaSToby Isaac       PetscObject  obj;
40500eb7e1eaSToby Isaac       PetscClassId id;
40510eb7e1eaSToby Isaac 
40520eb7e1eaSToby Isaac       ierr = DMGetField(coarse, i, &obj);CHKERRQ(ierr);
40530eb7e1eaSToby Isaac       ierr = PetscObjectGetClassId(obj,&id);CHKERRQ(ierr);
40540eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
40550eb7e1eaSToby Isaac         fv      = (PetscFV) obj;
40560eb7e1eaSToby Isaac         ierr    = PetscFVGetNumComponents(fv,&numFVcomps);CHKERRQ(ierr);
40570eb7e1eaSToby Isaac         fvField = i;
40580eb7e1eaSToby Isaac         break;
40590eb7e1eaSToby Isaac       }
40600eb7e1eaSToby Isaac     }
40610eb7e1eaSToby Isaac   }
406262095d54SToby Isaac 
406362095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
406462095d54SToby Isaac     PetscInt dof;
406562095d54SToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
406662095d54SToby Isaac     PetscInt numValues      = 0;
406762095d54SToby Isaac 
406862095d54SToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
406962095d54SToby Isaac     if (dof < 0) {
407062095d54SToby Isaac       dof = -(dof + 1);
407162095d54SToby Isaac     }
407262095d54SToby Isaac     offsets[0]    = 0;
407362095d54SToby Isaac     newOffsets[0] = 0;
407462095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
407562095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
407662095d54SToby Isaac 
40774833aeb0SToby Isaac       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
407862095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
407962095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
408062095d54SToby Isaac 
408162095d54SToby Isaac         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
408262095d54SToby Isaac         numValues += clDof;
408362095d54SToby Isaac       }
40844833aeb0SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
408562095d54SToby Isaac     }
408662095d54SToby Isaac     else if (maxChildId == -1) {
408762095d54SToby Isaac       ierr = PetscSectionGetDof(localCoarse,p,&numValues);CHKERRQ(ierr);
408862095d54SToby Isaac     }
408962095d54SToby Isaac     /* we will pack the column indices with the field offsets */
409078b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
40910eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
40920eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
40930eb7e1eaSToby Isaac     }
409462095d54SToby Isaac     ierr = PetscSectionSetDof(rootValuesSec,p,numValues);CHKERRQ(ierr);
409562095d54SToby Isaac   }
409662095d54SToby Isaac   ierr = PetscSectionSetUp(rootValuesSec);CHKERRQ(ierr);
409762095d54SToby Isaac   {
409862095d54SToby Isaac     PetscInt          numRootValues;
409962095d54SToby Isaac     const PetscScalar *coarseArray;
410062095d54SToby Isaac 
410162095d54SToby Isaac     ierr = PetscSectionGetStorageSize(rootValuesSec,&numRootValues);CHKERRQ(ierr);
410262095d54SToby Isaac     ierr = PetscMalloc1(numRootValues,&rootValues);CHKERRQ(ierr);
410362095d54SToby Isaac     ierr = VecGetArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr);
410462095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
410562095d54SToby Isaac       PetscInt    numValues;
410662095d54SToby Isaac       PetscInt    pValOff;
410762095d54SToby Isaac       PetscScalar *pVal;
410862095d54SToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
410962095d54SToby Isaac 
411062095d54SToby Isaac       ierr = PetscSectionGetDof(rootValuesSec,p,&numValues);CHKERRQ(ierr);
411162095d54SToby Isaac       if (!numValues) {
411262095d54SToby Isaac         continue;
411362095d54SToby Isaac       }
411462095d54SToby Isaac       ierr = PetscSectionGetOffset(rootValuesSec,p,&pValOff);CHKERRQ(ierr);
411562095d54SToby Isaac       pVal = &(rootValues[pValOff]);
411662095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
41170eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
41180eb7e1eaSToby Isaac         ierr = DMPlexVecGetClosure(coarse,NULL,vecCoarseLocal,p,&closureSize,&pVal);CHKERRQ(ierr);
41190eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
4120193eb951SToby Isaac           PetscFVCellGeom *cg;
41216dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
41220eb7e1eaSToby Isaac           PetscInt        i;
41230eb7e1eaSToby Isaac 
41240eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
41250eb7e1eaSToby Isaac 
4126193eb951SToby Isaac           ierr = DMPlexPointLocalRead(cellDM,p,cellGeomArray,(void *) &cg);CHKERRQ(ierr);
41270eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
41280eb7e1eaSToby Isaac           pVal += dim;
4129193eb951SToby Isaac           ierr = DMPlexPointGlobalRead(gradDM,p,gradArray,(void *) &gradVals);CHKERRQ(ierr);
41300eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
41310eb7e1eaSToby Isaac         }
413262095d54SToby Isaac       }
413378b7adb5SToby Isaac       else if (maxChildId == -1) {
413478b7adb5SToby Isaac         PetscInt lDof, lOff, i;
413578b7adb5SToby Isaac 
413678b7adb5SToby Isaac         ierr = PetscSectionGetDof(localCoarse,p,&lDof);CHKERRQ(ierr);
413778b7adb5SToby Isaac         ierr = PetscSectionGetOffset(localCoarse,p,&lOff);CHKERRQ(ierr);
413878b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
413978b7adb5SToby Isaac       }
414078b7adb5SToby Isaac     }
414162095d54SToby Isaac     ierr = VecRestoreArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr);
414262095d54SToby Isaac     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
414362095d54SToby Isaac   }
414462095d54SToby Isaac   {
414562095d54SToby Isaac     PetscSF  valuesSF;
414662095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
414762095d54SToby Isaac 
414862095d54SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafValuesSec);CHKERRQ(ierr);
414962095d54SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootValuesSec,&remoteOffsetsValues,leafValuesSec);CHKERRQ(ierr);
415062095d54SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootValuesSec,remoteOffsetsValues,leafValuesSec,&valuesSF);CHKERRQ(ierr);
415162095d54SToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
415262095d54SToby Isaac     ierr = PetscFree(remoteOffsetsValues);CHKERRQ(ierr);
415362095d54SToby Isaac     ierr = PetscSectionGetStorageSize(leafValuesSec,&numLeafValues);CHKERRQ(ierr);
415462095d54SToby Isaac     ierr = PetscMalloc1(numLeafValues,&leafValues);CHKERRQ(ierr);
415562095d54SToby Isaac     ierr = PetscSFBcastBegin(valuesSF,MPIU_SCALAR,rootValues,leafValues);CHKERRQ(ierr);
415662095d54SToby Isaac     ierr = PetscSFBcastEnd(valuesSF,MPIU_SCALAR,rootValues,leafValues);CHKERRQ(ierr);
415762095d54SToby Isaac     ierr = PetscSFDestroy(&valuesSF);CHKERRQ(ierr);
415862095d54SToby Isaac     ierr = PetscFree(rootValues);CHKERRQ(ierr);
415962095d54SToby Isaac     ierr = PetscSectionDestroy(&rootValuesSec);CHKERRQ(ierr);
416062095d54SToby Isaac   }
416162095d54SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
416262095d54SToby Isaac   {
416362095d54SToby Isaac     PetscInt    maxDof;
416462095d54SToby Isaac     PetscInt    *rowIndices;
416562095d54SToby Isaac     DM           refTree;
416662095d54SToby Isaac     PetscInt     **refPointFieldN;
416762095d54SToby Isaac     PetscScalar  ***refPointFieldMats;
416862095d54SToby Isaac     PetscSection refConSec, refAnSec;
41690eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,leafStart,leafEnd;
417062095d54SToby Isaac     PetscScalar  *pointWork;
417162095d54SToby Isaac 
417262095d54SToby Isaac     ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr);
417369291d52SBarry Smith     ierr = DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
417469291d52SBarry Smith     ierr = DMGetWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork);CHKERRQ(ierr);
417562095d54SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
41764833aeb0SToby Isaac     ierr = DMGetDS(fine,&ds);CHKERRQ(ierr);
41774833aeb0SToby Isaac     ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
417862095d54SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
417962095d54SToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
418062095d54SToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
418162095d54SToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
41820eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafValuesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
41830eb7e1eaSToby Isaac     ierr = DMPlexGetHeightStratum(fine,0,&cellStart,&cellEnd);CHKERRQ(ierr);
418489698031SToby Isaac     ierr = DMPlexGetHybridBounds(fine,&cellEndInterior,NULL,NULL,NULL);CHKERRQ(ierr);
418589698031SToby Isaac     cellEnd = (cellEndInterior < 0) ? cellEnd : cellEndInterior;
41860eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
418762095d54SToby Isaac       PetscInt          gDof, gcDof, gOff, lDof;
418862095d54SToby Isaac       PetscInt          numValues, pValOff;
418962095d54SToby Isaac       PetscInt          childId;
419062095d54SToby Isaac       const PetscScalar *pVal;
41910eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
419262095d54SToby Isaac 
419362095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
419462095d54SToby Isaac       ierr = PetscSectionGetDof(localFine,p,&lDof);CHKERRQ(ierr);
419562095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
419662095d54SToby Isaac       if ((gDof - gcDof) <= 0) {
419762095d54SToby Isaac         continue;
419862095d54SToby Isaac       }
419962095d54SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
420062095d54SToby Isaac       ierr = PetscSectionGetDof(leafValuesSec,p,&numValues);CHKERRQ(ierr);
420162095d54SToby Isaac       if (!numValues) continue;
420262095d54SToby Isaac       ierr = PetscSectionGetOffset(leafValuesSec,p,&pValOff);CHKERRQ(ierr);
420362095d54SToby Isaac       pVal = &leafValues[pValOff];
420462095d54SToby Isaac       offsets[0]        = 0;
420562095d54SToby Isaac       offsetsCopy[0]    = 0;
420662095d54SToby Isaac       newOffsets[0]     = 0;
420762095d54SToby Isaac       newOffsetsCopy[0] = 0;
42084833aeb0SToby Isaac       childId           = cids[p - pStartF];
420962095d54SToby Isaac       if (numFields) {
421062095d54SToby Isaac         PetscInt f;
421162095d54SToby Isaac         for (f = 0; f < numFields; f++) {
421262095d54SToby Isaac           PetscInt rowDof;
421362095d54SToby Isaac 
421462095d54SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
421562095d54SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
421662095d54SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
421762095d54SToby Isaac           /* TODO: closure indices */
42189f4e70e1SToby Isaac           newOffsets[f + 1]     = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
421962095d54SToby Isaac         }
42204acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,rowIndices);CHKERRQ(ierr);
422162095d54SToby Isaac       }
422262095d54SToby Isaac       else {
42234833aeb0SToby Isaac         offsets[0]    = 0;
42244833aeb0SToby Isaac         offsets[1]    = lDof;
42254833aeb0SToby Isaac         newOffsets[0] = 0;
42264833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
42274acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,rowIndices);CHKERRQ(ierr);
422862095d54SToby Isaac       }
422962095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
42302f65e181SToby Isaac         ierr = VecSetValues(vecFine,numValues,rowIndices,pVal,INSERT_VALUES);CHKERRQ(ierr);
423162095d54SToby Isaac       } else {
423262095d54SToby Isaac         PetscInt f;
423362095d54SToby Isaac 
423478b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
423578b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
423678b7adb5SToby Isaac           fvGradData = &pVal[numValues];
423778b7adb5SToby Isaac         }
423862095d54SToby Isaac         for (f = 0; f < PetscMax(1,numFields); f++) {
423962095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
424062095d54SToby Isaac           PetscInt numRows = offsets[f+1] - offsets[f];
424162095d54SToby Isaac           PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
424262095d54SToby Isaac           const PetscScalar *cVal = &pVal[newOffsets[f]];
424362095d54SToby Isaac           PetscScalar *rVal = &pointWork[offsets[f]];
424462095d54SToby Isaac           PetscInt i, j;
424562095d54SToby Isaac 
4246708c7f19SToby Isaac #if 0
4247708c7f19SToby Isaac           ierr = PetscInfo6(coarse,"field %D, numFields %D, childId %D, numRows %D, numCols %D, refPointFieldN %D\n",f,numFields,childId,numRows,numCols,refPointFieldN[childId - pRefStart][f]);CHKERRQ(ierr);
4248708c7f19SToby Isaac #endif
424962095d54SToby Isaac           for (i = 0; i < numRows; i++) {
425062095d54SToby Isaac             PetscScalar val = 0.;
425162095d54SToby Isaac             for (j = 0; j < numCols; j++) {
425262095d54SToby Isaac               val += childMat[i * numCols + j] * cVal[j];
425362095d54SToby Isaac             }
425462095d54SToby Isaac             rVal[i] = val;
425562095d54SToby Isaac           }
42560eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
42570eb7e1eaSToby Isaac             PetscReal   centroid[3];
42580eb7e1eaSToby Isaac             PetscScalar diff[3];
42590eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
42600eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
42610eb7e1eaSToby Isaac 
42620eb7e1eaSToby Isaac             ierr = DMPlexComputeCellGeometryFVM(fine,p,NULL,centroid,NULL);CHKERRQ(ierr);
42630eb7e1eaSToby Isaac             for (i = 0; i < dim; i++) {
42640eb7e1eaSToby Isaac               diff[i] = centroid[i] - parentCentroid[i];
42650eb7e1eaSToby Isaac             }
42660eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
42670eb7e1eaSToby Isaac               PetscScalar val = 0.;
42680eb7e1eaSToby Isaac 
426989698031SToby Isaac               for (j = 0; j < dim; j++) {
42700eb7e1eaSToby Isaac                 val += gradient[dim * i + j] * diff[j];
42710eb7e1eaSToby Isaac               }
42720eb7e1eaSToby Isaac               rVal[i] += val;
42730eb7e1eaSToby Isaac             }
42740eb7e1eaSToby Isaac           }
42752f65e181SToby Isaac           ierr = VecSetValues(vecFine,numRows,&rowIndices[offsets[f]],rVal,INSERT_VALUES);CHKERRQ(ierr);
427662095d54SToby Isaac         }
427762095d54SToby Isaac       }
427862095d54SToby Isaac     }
427962095d54SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
428069291d52SBarry Smith     ierr = DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
428169291d52SBarry Smith     ierr = DMRestoreWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork);CHKERRQ(ierr);
428262095d54SToby Isaac   }
42834fe3dfefSToby Isaac   ierr = PetscFree(leafValues);CHKERRQ(ierr);
428462095d54SToby Isaac   ierr = PetscSectionDestroy(&leafValuesSec);CHKERRQ(ierr);
428562095d54SToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
428662095d54SToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
4287ebf164c7SToby Isaac   PetscFunctionReturn(0);
4288ebf164c7SToby Isaac }
4289ebf164c7SToby Isaac 
4290ebf164c7SToby Isaac static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4291ebf164c7SToby Isaac {
42924833aeb0SToby Isaac   PetscDS        ds;
4293c921d74cSToby Isaac   DM             refTree;
4294c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4295c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4296c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4297c921d74cSToby Isaac   PetscSection   cSecRef;
4298c921d74cSToby Isaac   PetscInt       *parentIndices, pRefStart, pRefEnd;
4299d3bc4906SToby Isaac   PetscScalar    *rootValues, *parentValues;
4300c921d74cSToby Isaac   Mat            injRef;
4301c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4302c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4303c921d74cSToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
4304c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4305c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4306c921d74cSToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4307c921d74cSToby Isaac   PetscErrorCode ierr;
4308c921d74cSToby Isaac 
4309ebf164c7SToby Isaac   PetscFunctionBegin;
4310c921d74cSToby Isaac 
4311c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
4312708c7f19SToby Isaac   ierr = VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
4313708c7f19SToby Isaac   ierr = VecSetOption(vecCoarse,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
4314c921d74cSToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
43154833aeb0SToby Isaac   ierr = DMGetDS(coarse,&ds);CHKERRQ(ierr);
43164833aeb0SToby Isaac   ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
4317c921d74cSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
4318c921d74cSToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
4319c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
4320c921d74cSToby Isaac 
4321c921d74cSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
4322c921d74cSToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
4323c921d74cSToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
4324c921d74cSToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
4325c921d74cSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
4326c921d74cSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
4327c921d74cSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
4328c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
4329c921d74cSToby Isaac   {
4330c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
4331c921d74cSToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
4332c921d74cSToby Isaac   }
4333c921d74cSToby Isaac 
4334c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,cids,vecFine,numFields,offsets,&multiRootSec,&rootIndicesSec,NULL,&rootValues);CHKERRQ(ierr);
4335c921d74cSToby Isaac 
4336d3bc4906SToby Isaac   ierr = PetscMalloc2(maxDof,&parentIndices,maxDof,&parentValues);CHKERRQ(ierr);
4337c921d74cSToby Isaac 
4338c921d74cSToby Isaac   /* count indices */
433962095d54SToby Isaac   ierr = VecGetLayout(vecFine,&colMap);CHKERRQ(ierr);
434062095d54SToby Isaac   ierr = VecGetLayout(vecCoarse,&rowMap);CHKERRQ(ierr);
4341c921d74cSToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
4342c921d74cSToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
4343c921d74cSToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
4344c921d74cSToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
4345c921d74cSToby Isaac   /* insert values */
4346c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4347c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4348c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
434978b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4350c921d74cSToby Isaac 
4351c921d74cSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
4352c921d74cSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
4353c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
43542f65e181SToby Isaac     ierr = PetscSectionGetDof(localCoarse,p,&dof);CHKERRQ(ierr);
4355c921d74cSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
4356c921d74cSToby Isaac 
4357c921d74cSToby Isaac     rowOffsets[0] = 0;
4358c921d74cSToby Isaac     offsetsCopy[0] = 0;
4359c921d74cSToby Isaac     if (numFields) {
4360c921d74cSToby Isaac       PetscInt f;
4361c921d74cSToby Isaac 
4362c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4363c921d74cSToby Isaac         PetscInt fDof;
4364c921d74cSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
4365c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4366c921d74cSToby Isaac       }
43674acb8e1eSToby Isaac       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,parentIndices);CHKERRQ(ierr);
4368c921d74cSToby Isaac     }
4369c921d74cSToby Isaac     else {
43704acb8e1eSToby Isaac       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,parentIndices);CHKERRQ(ierr);
4371c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4372c921d74cSToby Isaac     }
4373c921d74cSToby Isaac 
4374c921d74cSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
4375c921d74cSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
4376c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
43772f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4378c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4379c921d74cSToby Isaac       PetscInt numIndices, childId, offset;
4380c921d74cSToby Isaac       const PetscScalar *childValues;
4381c921d74cSToby Isaac 
4382c921d74cSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
4383c921d74cSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
4384c921d74cSToby Isaac       childId = (PetscInt) PetscRealPart(rootValues[offset++]);
4385c921d74cSToby Isaac       childValues = &rootValues[offset];
4386c921d74cSToby Isaac       numIndices--;
4387c921d74cSToby Isaac 
4388c921d74cSToby Isaac       if (childId == -2) { /* skip */
4389c921d74cSToby Isaac         continue;
4390c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
43912f65e181SToby Isaac         PetscInt m;
43922f65e181SToby Isaac 
439378b7adb5SToby Isaac         contribute = PETSC_TRUE;
43942f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4395beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4396d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4397d3bc4906SToby Isaac 
439878b7adb5SToby Isaac         contribute = PETSC_TRUE;
4399d3bc4906SToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
4400d3bc4906SToby Isaac 
4401d3bc4906SToby Isaac         lim = PetscMax(1,numFields);
4402d3bc4906SToby Isaac         offsets[0] = 0;
4403d3bc4906SToby Isaac         if (numFields) {
4404d3bc4906SToby Isaac           PetscInt f;
4405d3bc4906SToby Isaac 
4406d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4407d3bc4906SToby Isaac             PetscInt fDof;
4408d3bc4906SToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
4409d3bc4906SToby Isaac 
4410d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4411d3bc4906SToby Isaac           }
4412d3bc4906SToby Isaac         }
4413d3bc4906SToby Isaac         else {
4414d3bc4906SToby Isaac           PetscInt cDof;
4415d3bc4906SToby Isaac 
4416d3bc4906SToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
4417d3bc4906SToby Isaac           offsets[1] = cDof;
4418d3bc4906SToby Isaac         }
4419d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4420d3bc4906SToby Isaac           PetscScalar       *childMat   = &childrenMats[childId - pRefStart][f][0];
4421d3bc4906SToby Isaac           PetscInt          n           = offsets[f+1]-offsets[f];
4422e328ff09SToby Isaac           PetscInt          m           = rowOffsets[f+1]-rowOffsets[f];
4423d3bc4906SToby Isaac           PetscInt          i, j;
4424d3bc4906SToby Isaac           const PetscScalar *colValues  = &childValues[offsets[f]];
4425d3bc4906SToby Isaac 
4426e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4427d3bc4906SToby Isaac             PetscScalar val = 0.;
4428d3bc4906SToby Isaac             for (j = 0; j < n; j++) {
4429d3bc4906SToby Isaac               val += childMat[n * i + j] * colValues[j];
4430d3bc4906SToby Isaac             }
4431e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4432d3bc4906SToby Isaac           }
4433d3bc4906SToby Isaac         }
4434c921d74cSToby Isaac       }
4435c921d74cSToby Isaac     }
443678b7adb5SToby Isaac     if (contribute) {ierr = VecSetValues(vecCoarse,dof,parentIndices,parentValues,INSERT_VALUES);CHKERRQ(ierr);}
4437c921d74cSToby Isaac   }
4438c921d74cSToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
4439c921d74cSToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
4440d3bc4906SToby Isaac   ierr = PetscFree2(parentIndices,parentValues);CHKERRQ(ierr);
4441c921d74cSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4442c921d74cSToby Isaac   ierr = PetscFree(rootValues);CHKERRQ(ierr);
4443c921d74cSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
4444ebf164c7SToby Isaac   PetscFunctionReturn(0);
4445ebf164c7SToby Isaac }
4446ebf164c7SToby Isaac 
4447ff1f73f7SToby Isaac /*@
4448ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4449ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4450ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4451ff1f73f7SToby Isaac 
4452ff1f73f7SToby Isaac   collective
4453ff1f73f7SToby Isaac 
4454ff1f73f7SToby Isaac   Input Parameters:
4455ff1f73f7SToby Isaac + dmIn        - The DMPlex mesh for the input vector
4456ff1f73f7SToby Isaac . vecIn       - The input vector
4457ff1f73f7SToby Isaac . sfRefine    - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4458ff1f73f7SToby Isaac                 the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4459ff1f73f7SToby Isaac . sfCoarsen   - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4460ff1f73f7SToby Isaac                 the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4461ff1f73f7SToby Isaac . cidsRefine  - The childIds of the points in dmOut.  These childIds relate back to the reference tree: childid[j] = k implies
4462ff1f73f7SToby Isaac                 that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4463ff1f73f7SToby Isaac                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in dmOut is exactly
4464ff1f73f7SToby Isaac                 equivalent to its root in dmIn, so no interpolation is necessary.  childid[j] = -2 indicates that this
4465ff1f73f7SToby Isaac                 point j in dmOut is not a leaf of sfRefine.
4466ff1f73f7SToby Isaac . cidsCoarsen - The childIds of the points in dmIn.  These childIds relate back to the reference tree: childid[j] = k implies
4467ff1f73f7SToby Isaac                 that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4468ff1f73f7SToby Isaac                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4469ff1f73f7SToby Isaac . useBCs      - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4470ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4471ff1f73f7SToby Isaac 
4472ff1f73f7SToby Isaac   Output Parameters:
4473ff1f73f7SToby Isaac . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transfered
4474ff1f73f7SToby Isaac                 projection of vecIn from dmIn to dmOut.  Note that any field discretized with a PetscFV finite volume
4475ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4476ff1f73f7SToby Isaac                 coarse points to fine points.
4477ff1f73f7SToby Isaac 
4478ff1f73f7SToby Isaac   Level: developer
4479ff1f73f7SToby Isaac 
4480ff1f73f7SToby Isaac .seealso(): DMPlexSetReferenceTree(), DMPlexGetReferenceTree(), PetscFVGetComputeGradients()
4481ff1f73f7SToby Isaac @*/
4482ff1f73f7SToby Isaac PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
448338fc2455SToby Isaac {
4484ebf164c7SToby Isaac   PetscErrorCode ierr;
4485ebf164c7SToby Isaac 
448638fc2455SToby Isaac   PetscFunctionBegin;
448778b7adb5SToby Isaac   ierr = VecSet(vecOut,0.0);CHKERRQ(ierr);
4488ff1f73f7SToby Isaac   if (sfRefine) {
4489fbfa57b9SToby Isaac     Vec vecInLocal;
44900eb7e1eaSToby Isaac     DM  dmGrad = NULL;
44910eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4492fbfa57b9SToby Isaac 
4493fbfa57b9SToby Isaac     ierr = DMGetLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
4494fbfa57b9SToby Isaac     ierr = VecSet(vecInLocal,0.0);CHKERRQ(ierr);
44950eb7e1eaSToby Isaac     {
44960eb7e1eaSToby Isaac       PetscInt  numFields, i;
44970eb7e1eaSToby Isaac 
44980eb7e1eaSToby Isaac       ierr = DMGetNumFields(dmIn, &numFields);CHKERRQ(ierr);
44990eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
45000eb7e1eaSToby Isaac         PetscObject  obj;
45010eb7e1eaSToby Isaac         PetscClassId classid;
45020eb7e1eaSToby Isaac 
45030eb7e1eaSToby Isaac         ierr = DMGetField(dmIn, i, &obj);CHKERRQ(ierr);
45040eb7e1eaSToby Isaac         ierr = PetscObjectGetClassId(obj, &classid);CHKERRQ(ierr);
45050eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
45060eb7e1eaSToby Isaac           ierr = DMPlexGetDataFVM(dmIn,(PetscFV)obj,&cellGeom,&faceGeom,&dmGrad);CHKERRQ(ierr);
45070eb7e1eaSToby Isaac           break;
45080eb7e1eaSToby Isaac         }
45090eb7e1eaSToby Isaac       }
45100eb7e1eaSToby Isaac     }
45110eb7e1eaSToby Isaac     if (useBCs) {
45120eb7e1eaSToby Isaac       ierr = DMPlexInsertBoundaryValues(dmIn,PETSC_TRUE,vecInLocal,time,faceGeom,cellGeom,NULL);CHKERRQ(ierr);
45130eb7e1eaSToby Isaac     }
4514fbfa57b9SToby Isaac     ierr = DMGlobalToLocalBegin(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
4515fbfa57b9SToby Isaac     ierr = DMGlobalToLocalEnd(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
45160eb7e1eaSToby Isaac     if (dmGrad) {
45170eb7e1eaSToby Isaac       ierr = DMGetGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
45180eb7e1eaSToby Isaac       ierr = DMPlexReconstructGradientsFVM(dmIn,vecInLocal,grad);CHKERRQ(ierr);
45190eb7e1eaSToby Isaac     }
4520ff1f73f7SToby Isaac     ierr = DMPlexTransferVecTree_Interpolate(dmIn,vecInLocal,dmOut,vecOut,sfRefine,cidsRefine,grad,cellGeom);CHKERRQ(ierr);
4521fbfa57b9SToby Isaac     ierr = DMRestoreLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
45220eb7e1eaSToby Isaac     if (dmGrad) {
45230eb7e1eaSToby Isaac       ierr = DMRestoreGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
45240eb7e1eaSToby Isaac     }
4525ebf164c7SToby Isaac   }
4526ff1f73f7SToby Isaac   if (sfCoarsen) {
4527ff1f73f7SToby Isaac     ierr = DMPlexTransferVecTree_Inject(dmIn,vecIn,dmOut,vecOut,sfCoarsen,cidsCoarsen);CHKERRQ(ierr);
4528ebf164c7SToby Isaac   }
45292f65e181SToby Isaac   ierr = VecAssemblyBegin(vecOut);CHKERRQ(ierr);
45302f65e181SToby Isaac   ierr = VecAssemblyEnd(vecOut);CHKERRQ(ierr);
453138fc2455SToby Isaac   PetscFunctionReturn(0);
453238fc2455SToby Isaac }
4533