xref: /petsc/src/dm/impls/plex/plextree.c (revision e328ff0963cb8a02a9bca3d62d74fa7dad4b66f9)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2d6a7ad0dSToby Isaac #include <../src/sys/utils/hash.h>
3af0996ceSBarry Smith #include <petsc/private/isimpl.h>
4af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
5d6a7ad0dSToby Isaac #include <petscsf.h>
60c37af3bSToby Isaac #include <petscds.h>
7d6a7ad0dSToby Isaac 
8d6a7ad0dSToby Isaac /** hierarchy routines */
9d6a7ad0dSToby Isaac 
10d6a7ad0dSToby Isaac /*@
11d6a7ad0dSToby Isaac   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
12d6a7ad0dSToby Isaac 
13d6a7ad0dSToby Isaac   Not collective
14d6a7ad0dSToby Isaac 
15d6a7ad0dSToby Isaac   Input Parameters:
16d6a7ad0dSToby Isaac + dm - The DMPlex object
17d6a7ad0dSToby Isaac - ref - The reference tree DMPlex object
18d6a7ad0dSToby Isaac 
190b7167a0SToby Isaac   Level: intermediate
20d6a7ad0dSToby Isaac 
21da43764aSToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexCreateDefaultReferenceTree()
22d6a7ad0dSToby Isaac @*/
23d6a7ad0dSToby Isaac PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
24d6a7ad0dSToby Isaac {
25d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
26d6a7ad0dSToby Isaac   PetscErrorCode  ierr;
27d6a7ad0dSToby Isaac 
28d6a7ad0dSToby Isaac   PetscFunctionBegin;
29d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3047a1df27SMatthew G. Knepley   if (ref) {PetscValidHeaderSpecific(ref, DM_CLASSID, 2);}
31d6a7ad0dSToby Isaac   ierr = PetscObjectReference((PetscObject)ref);CHKERRQ(ierr);
32d6a7ad0dSToby Isaac   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
33d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
34d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
35d6a7ad0dSToby Isaac }
36d6a7ad0dSToby Isaac 
37d6a7ad0dSToby Isaac /*@
38d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
39d6a7ad0dSToby Isaac 
40d6a7ad0dSToby Isaac   Not collective
41d6a7ad0dSToby Isaac 
42d6a7ad0dSToby Isaac   Input Parameters:
43d6a7ad0dSToby Isaac . dm - The DMPlex object
44d6a7ad0dSToby Isaac 
45d6a7ad0dSToby Isaac   Output Parameters
46d6a7ad0dSToby Isaac . ref - The reference tree DMPlex object
47d6a7ad0dSToby Isaac 
480b7167a0SToby Isaac   Level: intermediate
49d6a7ad0dSToby Isaac 
50da43764aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexCreateDefaultReferenceTree()
51d6a7ad0dSToby Isaac @*/
52d6a7ad0dSToby Isaac PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
53d6a7ad0dSToby Isaac {
54d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
55d6a7ad0dSToby Isaac 
56d6a7ad0dSToby Isaac   PetscFunctionBegin;
57d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
58d6a7ad0dSToby Isaac   PetscValidPointer(ref,2);
59d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
60d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
61d6a7ad0dSToby Isaac }
62d6a7ad0dSToby Isaac 
63dcbd3bf7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
64dcbd3bf7SToby Isaac {
65dcbd3bf7SToby Isaac   PetscInt       coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
66dcbd3bf7SToby Isaac   PetscErrorCode ierr;
67dcbd3bf7SToby Isaac 
68dcbd3bf7SToby Isaac   PetscFunctionBegin;
69dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
70dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
71dcbd3bf7SToby Isaac     if (childB) *childB = childA;
72dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
73dcbd3bf7SToby Isaac   }
74dcbd3bf7SToby Isaac   for (dim = 0; dim < 3; dim++) {
75dcbd3bf7SToby Isaac     ierr = DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd);CHKERRQ(ierr);
76dcbd3bf7SToby Isaac     if (parent >= dStart && parent <= dEnd) {
77dcbd3bf7SToby Isaac       break;
78dcbd3bf7SToby Isaac     }
79dcbd3bf7SToby Isaac   }
80dcbd3bf7SToby Isaac   if (dim > 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim);
81dcbd3bf7SToby Isaac   if (!dim) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
82dcbd3bf7SToby Isaac   if (childA < dStart || childA >= dEnd) {
83dcbd3bf7SToby Isaac     /* this is a lower-dimensional child: bootstrap */
84dcbd3bf7SToby Isaac     PetscInt size, i, sA = -1, sB, sOrientB, sConeSize;
85dcbd3bf7SToby Isaac     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
86dcbd3bf7SToby Isaac 
87dcbd3bf7SToby Isaac     ierr = DMPlexGetSupportSize(dm,childA,&size);CHKERRQ(ierr);
88dcbd3bf7SToby Isaac     ierr = DMPlexGetSupport(dm,childA,&supp);CHKERRQ(ierr);
89dcbd3bf7SToby Isaac 
90dcbd3bf7SToby Isaac     /* find a point sA in supp(childA) that has the same parent */
91dcbd3bf7SToby Isaac     for (i = 0; i < size; i++) {
92dcbd3bf7SToby Isaac       PetscInt sParent;
93dcbd3bf7SToby Isaac 
94dcbd3bf7SToby Isaac       sA   = supp[i];
95dcbd3bf7SToby Isaac       if (sA == parent) continue;
96dcbd3bf7SToby Isaac       ierr = DMPlexGetTreeParent(dm,sA,&sParent,NULL);CHKERRQ(ierr);
97dcbd3bf7SToby Isaac       if (sParent == parent) {
98dcbd3bf7SToby Isaac         break;
99dcbd3bf7SToby Isaac       }
100dcbd3bf7SToby Isaac     }
101dcbd3bf7SToby Isaac     if (i == size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
102dcbd3bf7SToby Isaac     /* find out which point sB is in an equivalent position to sA under
103dcbd3bf7SToby Isaac      * parentOrientB */
104dcbd3bf7SToby Isaac     ierr = DMPlexReferenceTreeGetChildSymmetry_Default(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB);CHKERRQ(ierr);
105dcbd3bf7SToby Isaac     ierr = DMPlexGetConeSize(dm,sA,&sConeSize);CHKERRQ(ierr);
106dcbd3bf7SToby Isaac     ierr = DMPlexGetCone(dm,sA,&coneA);CHKERRQ(ierr);
107dcbd3bf7SToby Isaac     ierr = DMPlexGetCone(dm,sB,&coneB);CHKERRQ(ierr);
108dcbd3bf7SToby Isaac     ierr = DMPlexGetConeOrientation(dm,sA,&oA);CHKERRQ(ierr);
109dcbd3bf7SToby Isaac     ierr = DMPlexGetConeOrientation(dm,sB,&oB);CHKERRQ(ierr);
110dcbd3bf7SToby Isaac     /* step through the cone of sA in natural order */
111dcbd3bf7SToby Isaac     for (i = 0; i < sConeSize; i++) {
112dcbd3bf7SToby Isaac       if (coneA[i] == childA) {
113dcbd3bf7SToby Isaac         /* if childA is at position i in coneA,
114dcbd3bf7SToby Isaac          * then we want the point that is at sOrientB*i in coneB */
115dcbd3bf7SToby Isaac         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
116dcbd3bf7SToby Isaac         if (childB) *childB = coneB[j];
117dcbd3bf7SToby Isaac         if (childOrientB) {
118dcbd3bf7SToby Isaac           PetscInt oBtrue;
119dcbd3bf7SToby Isaac 
120dcbd3bf7SToby Isaac           ierr          = DMPlexGetConeSize(dm,childA,&coneSize);CHKERRQ(ierr);
121dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
122dcbd3bf7SToby Isaac           if (coneSize != 0 && coneSize != 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
123dcbd3bf7SToby Isaac           /* we may have to flip an edge */
124dcbd3bf7SToby Isaac           oBtrue        = coneSize ? ((sOrientB >= 0) ? oB[j] : -(oB[j] + 2)) : 0;
125dcbd3bf7SToby Isaac           ABswap        = DihedralSwap(coneSize,oA[i],oBtrue);CHKERRQ(ierr);
126dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
127dcbd3bf7SToby Isaac         }
128dcbd3bf7SToby Isaac         break;
129dcbd3bf7SToby Isaac       }
130dcbd3bf7SToby Isaac     }
131dcbd3bf7SToby Isaac     if (i == sConeSize) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
132dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
133dcbd3bf7SToby Isaac   }
134dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
135dcbd3bf7SToby Isaac   ierr   = DMPlexGetConeSize(dm,parent,&coneSize);CHKERRQ(ierr);
136dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
137dcbd3bf7SToby Isaac   if (dim == 2) {
138dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
139dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
140dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
141dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
142dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
143dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
144947b95d8SBarry Smith   } else {
145dcbd3bf7SToby Isaac     ABswapVert = ABswap;
146dcbd3bf7SToby Isaac   }
147dcbd3bf7SToby Isaac   if (childB) {
148dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
149dcbd3bf7SToby Isaac     PetscInt p, posA = -1, numChildren, i;
150dcbd3bf7SToby Isaac     const PetscInt *children;
151dcbd3bf7SToby Isaac 
152dcbd3bf7SToby Isaac     /* count which position the child is in */
153dcbd3bf7SToby Isaac     ierr = DMPlexGetTreeChildren(dm,parent,&numChildren,&children);CHKERRQ(ierr);
154dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
155dcbd3bf7SToby Isaac       p = children[i];
156dcbd3bf7SToby Isaac       if (p == childA) {
157dcbd3bf7SToby Isaac         posA = i;
158dcbd3bf7SToby Isaac         break;
159dcbd3bf7SToby Isaac       }
160dcbd3bf7SToby Isaac     }
161dcbd3bf7SToby Isaac     if (posA >= coneSize) {
162dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
163dcbd3bf7SToby Isaac        * is invariant */
164dcbd3bf7SToby Isaac       if (dim != 2 || posA != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Expected a middle triangle, got something else");
165dcbd3bf7SToby Isaac       *childB = childA;
166dcbd3bf7SToby Isaac     }
167dcbd3bf7SToby Isaac     else {
168dcbd3bf7SToby Isaac       /* figure out position B by applying ABswapVert */
169dcbd3bf7SToby Isaac       PetscInt posB;
170dcbd3bf7SToby Isaac 
171dcbd3bf7SToby Isaac       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
172dcbd3bf7SToby Isaac       if (childB) *childB = children[posB];
173dcbd3bf7SToby Isaac     }
174dcbd3bf7SToby Isaac   }
175dcbd3bf7SToby Isaac   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
176dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
177dcbd3bf7SToby Isaac }
178dcbd3bf7SToby Isaac 
179dcbd3bf7SToby Isaac /*@
180dcbd3bf7SToby Isaac   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
181dcbd3bf7SToby Isaac 
182dcbd3bf7SToby Isaac   Input Parameters:
183dcbd3bf7SToby Isaac + dm - the reference tree DMPlex object
184dcbd3bf7SToby Isaac . parent - the parent point
185dcbd3bf7SToby Isaac . parentOrientA - the reference orientation for describing the parent
186dcbd3bf7SToby Isaac . childOrientA - the reference orientation for describing the child
187dcbd3bf7SToby Isaac . childA - the reference childID for describing the child
188dcbd3bf7SToby Isaac - parentOrientB - the new orientation for describing the parent
189dcbd3bf7SToby Isaac 
190dcbd3bf7SToby Isaac   Output Parameters:
191dcbd3bf7SToby Isaac + childOrientB - if not NULL, set to the new oreintation for describing the child
192ff1f73f7SToby Isaac - childB - if not NULL, the new childID for describing the child
193dcbd3bf7SToby Isaac 
194dcbd3bf7SToby Isaac   Level: developer
195dcbd3bf7SToby Isaac 
196dcbd3bf7SToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexSetReferenceTree(), DMPlexSetTree()
197dcbd3bf7SToby Isaac @*/
198dcbd3bf7SToby Isaac PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
199dcbd3bf7SToby Isaac {
200dcbd3bf7SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
201dcbd3bf7SToby Isaac   PetscErrorCode ierr;
202dcbd3bf7SToby Isaac 
203dcbd3bf7SToby Isaac   PetscFunctionBegin;
204dcbd3bf7SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
205dcbd3bf7SToby Isaac   if (!mesh->getchildsymmetry) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlexReferenceTreeGetChildSymmetry not implemented");
206dcbd3bf7SToby Isaac   ierr = mesh->getchildsymmetry(dm,parent,parentOrientA,childOrientA,childA,parentOrientB,childOrientB,childB);CHKERRQ(ierr);
207dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
208dcbd3bf7SToby Isaac }
209dcbd3bf7SToby Isaac 
210776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM,PetscSection,PetscInt*,PetscInt*,PetscBool,PetscBool);
211f9f063d4SToby Isaac 
2120e2cc29aSToby Isaac PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
213da43764aSToby Isaac {
2140e2cc29aSToby Isaac   MPI_Comm       comm;
2150e2cc29aSToby Isaac   PetscInt       dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
216da43764aSToby Isaac   PetscInt      *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
217da43764aSToby Isaac   DMLabel        identity, identityRef;
21810f7e118SToby Isaac   PetscSection   unionSection, unionConeSection, parentSection;
219da43764aSToby Isaac   PetscScalar   *unionCoords;
220da43764aSToby Isaac   IS             perm;
221da43764aSToby Isaac   PetscErrorCode ierr;
222da43764aSToby Isaac 
223da43764aSToby Isaac   PetscFunctionBegin;
2240e2cc29aSToby Isaac   comm = PetscObjectComm((PetscObject)K);
2250e2cc29aSToby Isaac   ierr = DMGetDimension(K, &dim);CHKERRQ(ierr);
226da43764aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
2270e2cc29aSToby Isaac   ierr = DMGetLabel(K, labelName, &identity);CHKERRQ(ierr);
2280e2cc29aSToby Isaac   ierr = DMGetLabel(Kref, labelName, &identityRef);CHKERRQ(ierr);
229da43764aSToby Isaac   ierr = DMPlexGetChart(Kref, &pRefStart, &pRefEnd);CHKERRQ(ierr);
230da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionSection);CHKERRQ(ierr);
231da43764aSToby Isaac   ierr = PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart));CHKERRQ(ierr);
232da43764aSToby Isaac   /* count points that will go in the union */
233da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
234da43764aSToby Isaac     ierr = PetscSectionSetDof(unionSection, p - pStart, 1);CHKERRQ(ierr);
235da43764aSToby Isaac   }
236da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
237da43764aSToby Isaac     PetscInt q, qSize;
238da43764aSToby Isaac     ierr = DMLabelGetValue(identityRef, p, &q);CHKERRQ(ierr);
239da43764aSToby Isaac     ierr = DMLabelGetStratumSize(identityRef, q, &qSize);CHKERRQ(ierr);
240da43764aSToby Isaac     if (qSize > 1) {
241da43764aSToby Isaac       ierr = PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1);CHKERRQ(ierr);
242da43764aSToby Isaac     }
243da43764aSToby Isaac   }
244854ce69bSBarry Smith   ierr = PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart,&permvals);CHKERRQ(ierr);
245da43764aSToby Isaac   offset = 0;
246da43764aSToby Isaac   /* stratify points in the union by topological dimension */
247da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
248da43764aSToby Isaac     PetscInt cStart, cEnd, c;
249da43764aSToby Isaac 
250da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K, d, &cStart, &cEnd);CHKERRQ(ierr);
251da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
252da43764aSToby Isaac       permvals[offset++] = c;
253da43764aSToby Isaac     }
254da43764aSToby Isaac 
255da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd);CHKERRQ(ierr);
256da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
257da43764aSToby Isaac       permvals[offset++] = c + (pEnd - pStart);
258da43764aSToby Isaac     }
259da43764aSToby Isaac   }
260da43764aSToby Isaac   ierr = ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm);CHKERRQ(ierr);
261da43764aSToby Isaac   ierr = PetscSectionSetPermutation(unionSection,perm);CHKERRQ(ierr);
262da43764aSToby Isaac   ierr = PetscSectionSetUp(unionSection);CHKERRQ(ierr);
263da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionSection,&numUnionPoints);CHKERRQ(ierr);
264da43764aSToby Isaac   ierr = PetscMalloc2(numUnionPoints,&coneSizes,dim+1,&numDimPoints);CHKERRQ(ierr);
265da43764aSToby Isaac   /* count dimension points */
266da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
267da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
268da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K,d,&cStart,NULL);CHKERRQ(ierr);
269da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff);CHKERRQ(ierr);
270da43764aSToby Isaac     if (d < dim) {
271da43764aSToby Isaac       ierr = DMPlexGetHeightStratum(K,d+1,&cStart,NULL);CHKERRQ(ierr);
272da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff2);CHKERRQ(ierr);
273da43764aSToby Isaac     }
274da43764aSToby Isaac     else {
275da43764aSToby Isaac       cOff2 = numUnionPoints;
276da43764aSToby Isaac     }
277da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
278da43764aSToby Isaac   }
279da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionConeSection);CHKERRQ(ierr);
280da43764aSToby Isaac   ierr = PetscSectionSetChart(unionConeSection, 0, numUnionPoints);CHKERRQ(ierr);
281da43764aSToby Isaac   /* count the cones in the union */
282da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
283da43764aSToby Isaac     PetscInt dof, uOff;
284da43764aSToby Isaac 
285da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
286da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
287da43764aSToby Isaac     ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
288da43764aSToby Isaac     coneSizes[uOff] = dof;
289da43764aSToby Isaac   }
290da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
291da43764aSToby Isaac     PetscInt dof, uDof, uOff;
292da43764aSToby Isaac 
293da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
294da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
295da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
296da43764aSToby Isaac     if (uDof) {
297da43764aSToby Isaac       ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
298da43764aSToby Isaac       coneSizes[uOff] = dof;
299da43764aSToby Isaac     }
300da43764aSToby Isaac   }
301da43764aSToby Isaac   ierr = PetscSectionSetUp(unionConeSection);CHKERRQ(ierr);
302da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionConeSection,&numCones);CHKERRQ(ierr);
303da43764aSToby Isaac   ierr = PetscMalloc2(numCones,&unionCones,numCones,&unionOrientations);CHKERRQ(ierr);
304da43764aSToby Isaac   /* write the cones in the union */
305da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
306da43764aSToby Isaac     PetscInt dof, uOff, c, cOff;
307da43764aSToby Isaac     const PetscInt *cone, *orientation;
308da43764aSToby Isaac 
309da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
310da43764aSToby Isaac     ierr = DMPlexGetCone(K, p, &cone);CHKERRQ(ierr);
311da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(K, p, &orientation);CHKERRQ(ierr);
312da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
313da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
314da43764aSToby Isaac     for (c = 0; c < dof; c++) {
315da43764aSToby Isaac       PetscInt e, eOff;
316da43764aSToby Isaac       e                           = cone[c];
317da43764aSToby Isaac       ierr                        = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
318da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
319da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
320da43764aSToby Isaac     }
321da43764aSToby Isaac   }
322da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
323da43764aSToby Isaac     PetscInt dof, uDof, uOff, c, cOff;
324da43764aSToby Isaac     const PetscInt *cone, *orientation;
325da43764aSToby Isaac 
326da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
327da43764aSToby Isaac     ierr = DMPlexGetCone(Kref, p, &cone);CHKERRQ(ierr);
328da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(Kref, p, &orientation);CHKERRQ(ierr);
329da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
330da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
331da43764aSToby Isaac     if (uDof) {
332da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
333da43764aSToby Isaac       for (c = 0; c < dof; c++) {
334da43764aSToby Isaac         PetscInt e, eOff, eDof;
335da43764aSToby Isaac 
336da43764aSToby Isaac         e    = cone[c];
337da43764aSToby Isaac         ierr = PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart),&eDof);CHKERRQ(ierr);
338da43764aSToby Isaac         if (eDof) {
339da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff);CHKERRQ(ierr);
340da43764aSToby Isaac         }
341da43764aSToby Isaac         else {
342da43764aSToby Isaac           ierr = DMLabelGetValue(identityRef, e, &e);CHKERRQ(ierr);
343da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
344da43764aSToby Isaac         }
345da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
346da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
347da43764aSToby Isaac       }
348da43764aSToby Isaac     }
349da43764aSToby Isaac   }
350da43764aSToby Isaac   /* get the coordinates */
351da43764aSToby Isaac   {
352da43764aSToby Isaac     PetscInt vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
353da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
354da43764aSToby Isaac     Vec      KcoordsVec, KrefCoordsVec;
355da43764aSToby Isaac     PetscScalar *Kcoords;
356da43764aSToby Isaac 
357da43764aSToby Isaac     DMGetCoordinateSection(K, &KcoordsSec);CHKERRQ(ierr);
358da43764aSToby Isaac     DMGetCoordinatesLocal(K, &KcoordsVec);CHKERRQ(ierr);
359da43764aSToby Isaac     DMGetCoordinateSection(Kref, &KrefCoordsSec);CHKERRQ(ierr);
360da43764aSToby Isaac     DMGetCoordinatesLocal(Kref, &KrefCoordsVec);CHKERRQ(ierr);
361da43764aSToby Isaac 
362da43764aSToby Isaac     numVerts = numDimPoints[0];
363da43764aSToby Isaac     ierr     = PetscMalloc1(numVerts * dim,&unionCoords);CHKERRQ(ierr);
364da43764aSToby Isaac     ierr     = DMPlexGetDepthStratum(K,0,&vStart,&vEnd);CHKERRQ(ierr);
365da43764aSToby Isaac 
366da43764aSToby Isaac     offset = 0;
367da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
368da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pStart,&vOff);CHKERRQ(ierr);
369da43764aSToby Isaac       ierr = VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords);CHKERRQ(ierr);
370da43764aSToby Isaac       for (d = 0; d < dim; d++) {
371da43764aSToby Isaac         unionCoords[offset * dim + d] = Kcoords[d];
372da43764aSToby Isaac       }
373da43764aSToby Isaac       offset++;
374da43764aSToby Isaac     }
375da43764aSToby Isaac     ierr = DMPlexGetDepthStratum(Kref,0,&vRefStart,&vRefEnd);CHKERRQ(ierr);
376da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
377da43764aSToby Isaac       ierr = PetscSectionGetDof(unionSection,v - pRefStart + (pEnd - pStart),&vDof);CHKERRQ(ierr);
378da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pRefStart + (pEnd - pStart),&vOff);CHKERRQ(ierr);
379da43764aSToby Isaac       ierr = VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords);CHKERRQ(ierr);
380da43764aSToby Isaac       if (vDof) {
381da43764aSToby Isaac         for (d = 0; d < dim; d++) {
382da43764aSToby Isaac           unionCoords[offset * dim + d] = Kcoords[d];
383da43764aSToby Isaac         }
384da43764aSToby Isaac         offset++;
385da43764aSToby Isaac       }
386da43764aSToby Isaac     }
387da43764aSToby Isaac   }
388da43764aSToby Isaac   ierr = DMCreate(comm,ref);CHKERRQ(ierr);
389da43764aSToby Isaac   ierr = DMSetType(*ref,DMPLEX);CHKERRQ(ierr);
39028f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ref,dim);CHKERRQ(ierr);
391da43764aSToby Isaac   ierr = DMPlexCreateFromDAG(*ref,dim,numDimPoints,coneSizes,unionCones,unionOrientations,unionCoords);CHKERRQ(ierr);
39210f7e118SToby Isaac   /* set the tree */
39310f7e118SToby Isaac   ierr = PetscSectionCreate(comm,&parentSection);CHKERRQ(ierr);
39410f7e118SToby Isaac   ierr = PetscSectionSetChart(parentSection,0,numUnionPoints);CHKERRQ(ierr);
39510f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
39610f7e118SToby Isaac     PetscInt uDof, uOff;
39710f7e118SToby Isaac 
39810f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
39910f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
40010f7e118SToby Isaac     if (uDof) {
40110f7e118SToby Isaac       PetscSectionSetDof(parentSection,uOff,1);CHKERRQ(ierr);
40210f7e118SToby Isaac     }
40310f7e118SToby Isaac   }
40410f7e118SToby Isaac   ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
40510f7e118SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&parentSize);CHKERRQ(ierr);
40610f7e118SToby Isaac   ierr = PetscMalloc2(parentSize,&parents,parentSize,&childIDs);CHKERRQ(ierr);
40710f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
40810f7e118SToby Isaac     PetscInt uDof, uOff;
40910f7e118SToby Isaac 
41010f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
41110f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
41210f7e118SToby Isaac     if (uDof) {
41310f7e118SToby Isaac       PetscInt pOff, parent, parentU;
41410f7e118SToby Isaac       PetscSectionGetOffset(parentSection,uOff,&pOff);CHKERRQ(ierr);
41510f7e118SToby Isaac       DMLabelGetValue(identityRef,p,&parent);CHKERRQ(ierr);
41610f7e118SToby Isaac       ierr = PetscSectionGetOffset(unionSection, parent - pStart,&parentU);CHKERRQ(ierr);
41710f7e118SToby Isaac       parents[pOff] = parentU;
41810f7e118SToby Isaac       childIDs[pOff] = uOff;
41910f7e118SToby Isaac     }
42010f7e118SToby Isaac   }
421776742edSToby Isaac   ierr = DMPlexSetTree_Internal(*ref,parentSection,parents,childIDs,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
42210f7e118SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
42310f7e118SToby Isaac   ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
42410f7e118SToby Isaac 
425da43764aSToby Isaac   /* clean up */
426da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionSection);CHKERRQ(ierr);
427da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionConeSection);CHKERRQ(ierr);
428da43764aSToby Isaac   ierr = ISDestroy(&perm);CHKERRQ(ierr);
429da43764aSToby Isaac   ierr = PetscFree(unionCoords);CHKERRQ(ierr);
430da43764aSToby Isaac   ierr = PetscFree2(unionCones,unionOrientations);CHKERRQ(ierr);
431da43764aSToby Isaac   ierr = PetscFree2(coneSizes,numDimPoints);CHKERRQ(ierr);
4320e2cc29aSToby Isaac   PetscFunctionReturn(0);
4330e2cc29aSToby Isaac }
4340e2cc29aSToby Isaac 
4350e2cc29aSToby Isaac /*@
4360e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4370e2cc29aSToby Isaac 
4380e2cc29aSToby Isaac   Collective on comm
4390e2cc29aSToby Isaac 
4400e2cc29aSToby Isaac   Input Parameters:
4410e2cc29aSToby Isaac + comm    - the MPI communicator
4420e2cc29aSToby Isaac . dim     - the spatial dimension
4430e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4440e2cc29aSToby Isaac 
4450e2cc29aSToby Isaac   Output Parameters:
4460e2cc29aSToby Isaac . ref     - the reference tree DMPlex object
4470e2cc29aSToby Isaac 
4480e2cc29aSToby Isaac   Level: intermediate
4490e2cc29aSToby Isaac 
4500e2cc29aSToby Isaac .keywords: reference cell
4510e2cc29aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree()
4520e2cc29aSToby Isaac @*/
4530e2cc29aSToby Isaac PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
4540e2cc29aSToby Isaac {
4550e2cc29aSToby Isaac   DM_Plex       *mesh;
4560e2cc29aSToby Isaac   DM             K, Kref;
4570e2cc29aSToby Isaac   PetscInt       p, pStart, pEnd;
4580e2cc29aSToby Isaac   DMLabel        identity;
4590e2cc29aSToby Isaac   PetscErrorCode ierr;
4600e2cc29aSToby Isaac 
4610e2cc29aSToby Isaac   PetscFunctionBegin;
4620e2cc29aSToby Isaac #if 1
4630e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4640e2cc29aSToby Isaac #endif
4650e2cc29aSToby Isaac   /* create a reference element */
4660e2cc29aSToby Isaac   ierr = DMPlexCreateReferenceCell(comm, dim, simplex, &K);CHKERRQ(ierr);
4670e2cc29aSToby Isaac   ierr = DMCreateLabel(K, "identity");CHKERRQ(ierr);
4680e2cc29aSToby Isaac   ierr = DMGetLabel(K, "identity", &identity);CHKERRQ(ierr);
4690e2cc29aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
4700e2cc29aSToby Isaac   for (p = pStart; p < pEnd; p++) {
4710e2cc29aSToby Isaac     ierr = DMLabelSetValue(identity, p, p);CHKERRQ(ierr);
4720e2cc29aSToby Isaac   }
4730e2cc29aSToby Isaac   /* refine it */
4740e2cc29aSToby Isaac   ierr = DMRefine(K,comm,&Kref);CHKERRQ(ierr);
4750e2cc29aSToby Isaac 
4760e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4770e2cc29aSToby Isaac    * points that appear in both */
4780e2cc29aSToby Isaac   ierr = DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref);CHKERRQ(ierr);
4790e2cc29aSToby Isaac   mesh = (DM_Plex *) (*ref)->data;
4800e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
481da43764aSToby Isaac   ierr = DMDestroy(&K);CHKERRQ(ierr);
482da43764aSToby Isaac   ierr = DMDestroy(&Kref);CHKERRQ(ierr);
483da43764aSToby Isaac   PetscFunctionReturn(0);
484da43764aSToby Isaac }
485da43764aSToby Isaac 
486878b19aaSToby Isaac static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
487878b19aaSToby Isaac {
488878b19aaSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
489878b19aaSToby Isaac   PetscSection   childSec, pSec;
490878b19aaSToby Isaac   PetscInt       p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
491878b19aaSToby Isaac   PetscInt       *offsets, *children, pStart, pEnd;
492878b19aaSToby Isaac   PetscErrorCode ierr;
493878b19aaSToby Isaac 
494878b19aaSToby Isaac   PetscFunctionBegin;
495878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
496878b19aaSToby Isaac   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
497878b19aaSToby Isaac   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
498878b19aaSToby Isaac   pSec = mesh->parentSection;
499878b19aaSToby Isaac   if (!pSec) PetscFunctionReturn(0);
500878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(pSec,&pSize);CHKERRQ(ierr);
501878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
502878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
503878b19aaSToby Isaac 
504878b19aaSToby Isaac     parMax = PetscMax(parMax,par+1);
505878b19aaSToby Isaac     parMin = PetscMin(parMin,par);
506878b19aaSToby Isaac   }
507878b19aaSToby Isaac   if (parMin > parMax) {
508878b19aaSToby Isaac     parMin = -1;
509878b19aaSToby Isaac     parMax = -1;
510878b19aaSToby Isaac   }
511878b19aaSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)pSec),&childSec);CHKERRQ(ierr);
512878b19aaSToby Isaac   ierr = PetscSectionSetChart(childSec,parMin,parMax);CHKERRQ(ierr);
513878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
514878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
515878b19aaSToby Isaac 
516878b19aaSToby Isaac     ierr = PetscSectionAddDof(childSec,par,1);CHKERRQ(ierr);
517878b19aaSToby Isaac   }
518878b19aaSToby Isaac   ierr = PetscSectionSetUp(childSec);CHKERRQ(ierr);
519878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(childSec,&cSize);CHKERRQ(ierr);
520878b19aaSToby Isaac   ierr = PetscMalloc1(cSize,&children);CHKERRQ(ierr);
521878b19aaSToby Isaac   ierr = PetscCalloc1(parMax-parMin,&offsets);CHKERRQ(ierr);
522878b19aaSToby Isaac   ierr = PetscSectionGetChart(pSec,&pStart,&pEnd);CHKERRQ(ierr);
523878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
524878b19aaSToby Isaac     PetscInt dof, off, i;
525878b19aaSToby Isaac 
526878b19aaSToby Isaac     ierr = PetscSectionGetDof(pSec,p,&dof);CHKERRQ(ierr);
527878b19aaSToby Isaac     ierr = PetscSectionGetOffset(pSec,p,&off);CHKERRQ(ierr);
528878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
529878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
530878b19aaSToby Isaac 
531878b19aaSToby Isaac       ierr = PetscSectionGetOffset(childSec,par,&cOff);CHKERRQ(ierr);
532878b19aaSToby Isaac       children[cOff + offsets[par-parMin]++] = p;
533878b19aaSToby Isaac     }
534878b19aaSToby Isaac   }
535878b19aaSToby Isaac   mesh->childSection = childSec;
536878b19aaSToby Isaac   mesh->children = children;
537878b19aaSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
538878b19aaSToby Isaac   PetscFunctionReturn(0);
539878b19aaSToby Isaac }
540878b19aaSToby Isaac 
5416dd5a8c8SToby Isaac static PetscErrorCode AnchorsFlatten (PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
5426dd5a8c8SToby Isaac {
5436dd5a8c8SToby Isaac   PetscInt       pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5446dd5a8c8SToby Isaac   const PetscInt *vals;
5456dd5a8c8SToby Isaac   PetscSection   secNew;
5466dd5a8c8SToby Isaac   PetscBool      anyNew, globalAnyNew;
5476dd5a8c8SToby Isaac   PetscBool      compress;
5486dd5a8c8SToby Isaac   PetscErrorCode ierr;
5496dd5a8c8SToby Isaac 
5506dd5a8c8SToby Isaac   PetscFunctionBegin;
5516dd5a8c8SToby Isaac   ierr = PetscSectionGetChart(section,&pStart,&pEnd);CHKERRQ(ierr);
5526dd5a8c8SToby Isaac   ierr = ISGetLocalSize(is,&size);CHKERRQ(ierr);
5536dd5a8c8SToby Isaac   ierr = ISGetIndices(is,&vals);CHKERRQ(ierr);
5546dd5a8c8SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secNew);CHKERRQ(ierr);
5556dd5a8c8SToby Isaac   ierr = PetscSectionSetChart(secNew,pStart,pEnd);CHKERRQ(ierr);
5566dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5576dd5a8c8SToby Isaac     PetscInt dof;
5586dd5a8c8SToby Isaac 
5596dd5a8c8SToby Isaac     p = vals[i];
5606dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5616dd5a8c8SToby Isaac     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5626dd5a8c8SToby Isaac     if (dof) break;
5636dd5a8c8SToby Isaac   }
5646dd5a8c8SToby Isaac   if (i == size) {
5656dd5a8c8SToby Isaac     ierr     = PetscSectionSetUp(secNew);CHKERRQ(ierr);
5666dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5676dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5686dd5a8c8SToby Isaac     sizeNew  = 0;
5696dd5a8c8SToby Isaac   }
5706dd5a8c8SToby Isaac   else {
5716dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5726dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5736dd5a8c8SToby Isaac       PetscInt dof, off;
5746dd5a8c8SToby Isaac 
5756dd5a8c8SToby Isaac       ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5766dd5a8c8SToby Isaac       ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
5776dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5786dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5796dd5a8c8SToby Isaac 
5806dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5816dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
5826dd5a8c8SToby Isaac         }
5836dd5a8c8SToby Isaac         if (qDof) {
5846dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, qDof);CHKERRQ(ierr);
5856dd5a8c8SToby Isaac         }
5866dd5a8c8SToby Isaac         else {
5876dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, 1);CHKERRQ(ierr);
5886dd5a8c8SToby Isaac         }
5896dd5a8c8SToby Isaac       }
5906dd5a8c8SToby Isaac     }
5916dd5a8c8SToby Isaac     ierr = PetscSectionSetUp(secNew);CHKERRQ(ierr);
5926dd5a8c8SToby Isaac     ierr = PetscSectionGetStorageSize(secNew,&sizeNew);CHKERRQ(ierr);
5936dd5a8c8SToby Isaac     ierr = PetscMalloc1(sizeNew,&valsNew);CHKERRQ(ierr);
5946dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5956dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5966dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
5976dd5a8c8SToby Isaac 
5986dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5996dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
6006dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(secNew, p, &dofNew);CHKERRQ(ierr);
6016dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(secNew, p, &offNew);CHKERRQ(ierr);
6026dd5a8c8SToby Isaac       count = 0;
6036dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
6046dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
6056dd5a8c8SToby Isaac 
6066dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
6076dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
6086dd5a8c8SToby Isaac           ierr = PetscSectionGetOffset(section, q, &qOff);CHKERRQ(ierr);
6096dd5a8c8SToby Isaac         }
6106dd5a8c8SToby Isaac         if (qDof) {
6116dd5a8c8SToby Isaac           PetscInt oldCount = count;
6126dd5a8c8SToby Isaac 
6136dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
6146dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
6156dd5a8c8SToby Isaac 
6166dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
6176dd5a8c8SToby Isaac               if (valsNew[offNew + k] == r) {
6186dd5a8c8SToby Isaac                 break;
6196dd5a8c8SToby Isaac               }
6206dd5a8c8SToby Isaac             }
6216dd5a8c8SToby Isaac             if (k == oldCount) {
6226dd5a8c8SToby Isaac               valsNew[offNew + count++] = r;
6236dd5a8c8SToby Isaac             }
6246dd5a8c8SToby Isaac           }
6256dd5a8c8SToby Isaac         }
6266dd5a8c8SToby Isaac         else {
6276dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
6286dd5a8c8SToby Isaac 
6296dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
6306dd5a8c8SToby Isaac             if (valsNew[offNew + k] == q) {
6316dd5a8c8SToby Isaac               break;
6326dd5a8c8SToby Isaac             }
6336dd5a8c8SToby Isaac           }
6346dd5a8c8SToby Isaac           if (k == oldCount) {
6356dd5a8c8SToby Isaac             valsNew[offNew + count++] = q;
6366dd5a8c8SToby Isaac           }
6376dd5a8c8SToby Isaac         }
6386dd5a8c8SToby Isaac       }
6396dd5a8c8SToby Isaac       if (count < dofNew) {
6406dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secNew, p, count);CHKERRQ(ierr);
6416dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6426dd5a8c8SToby Isaac       }
6436dd5a8c8SToby Isaac     }
6446dd5a8c8SToby Isaac   }
6456dd5a8c8SToby Isaac   ierr = ISRestoreIndices(is,&vals);CHKERRQ(ierr);
646b2566f29SBarry Smith   ierr = MPIU_Allreduce(&anyNew,&globalAnyNew,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
6476dd5a8c8SToby Isaac   if (!globalAnyNew) {
6486dd5a8c8SToby Isaac     ierr = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6496dd5a8c8SToby Isaac     *sectionNew = NULL;
6506dd5a8c8SToby Isaac     *isNew = NULL;
6516dd5a8c8SToby Isaac   }
6526dd5a8c8SToby Isaac   else {
6536dd5a8c8SToby Isaac     PetscBool globalCompress;
6546dd5a8c8SToby Isaac 
655b2566f29SBarry Smith     ierr = MPIU_Allreduce(&compress,&globalCompress,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
6566dd5a8c8SToby Isaac     if (compress) {
6576dd5a8c8SToby Isaac       PetscSection secComp;
6586dd5a8c8SToby Isaac       PetscInt *valsComp = NULL;
6596dd5a8c8SToby Isaac 
6606dd5a8c8SToby Isaac       ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secComp);CHKERRQ(ierr);
6616dd5a8c8SToby Isaac       ierr = PetscSectionSetChart(secComp,pStart,pEnd);CHKERRQ(ierr);
6626dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6636dd5a8c8SToby Isaac         PetscInt dof;
6646dd5a8c8SToby Isaac 
6656dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6666dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secComp, p, dof);CHKERRQ(ierr);
6676dd5a8c8SToby Isaac       }
6686dd5a8c8SToby Isaac       ierr = PetscSectionSetUp(secComp);CHKERRQ(ierr);
6696dd5a8c8SToby Isaac       ierr = PetscSectionGetStorageSize(secComp,&sizeNew);CHKERRQ(ierr);
6706dd5a8c8SToby Isaac       ierr = PetscMalloc1(sizeNew,&valsComp);CHKERRQ(ierr);
6716dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6726dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6736dd5a8c8SToby Isaac 
6746dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6756dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secNew, p, &off);CHKERRQ(ierr);
6766dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secComp, p, &offNew);CHKERRQ(ierr);
6776dd5a8c8SToby Isaac         for (j = 0; j < dof; j++) {
6786dd5a8c8SToby Isaac           valsComp[offNew + j] = valsNew[off + j];
6796dd5a8c8SToby Isaac         }
6806dd5a8c8SToby Isaac       }
6816dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6826dd5a8c8SToby Isaac       secNew  = secComp;
6836dd5a8c8SToby Isaac       ierr    = PetscFree(valsNew);CHKERRQ(ierr);
6846dd5a8c8SToby Isaac       valsNew = valsComp;
6856dd5a8c8SToby Isaac     }
6866dd5a8c8SToby Isaac     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is),sizeNew,valsNew,PETSC_OWN_POINTER,isNew);CHKERRQ(ierr);
6876dd5a8c8SToby Isaac   }
6886dd5a8c8SToby Isaac   PetscFunctionReturn(0);
6896dd5a8c8SToby Isaac }
6906dd5a8c8SToby Isaac 
691f7c74593SToby Isaac static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
69266af876cSToby Isaac {
69366af876cSToby Isaac   PetscInt       p, pStart, pEnd, *anchors, size;
69466af876cSToby Isaac   PetscInt       aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
69566af876cSToby Isaac   PetscSection   aSec;
696f9f063d4SToby Isaac   DMLabel        canonLabel;
69766af876cSToby Isaac   IS             aIS;
69866af876cSToby Isaac   PetscErrorCode ierr;
69966af876cSToby Isaac 
70066af876cSToby Isaac   PetscFunctionBegin;
70166af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
70266af876cSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
703c58f1c22SToby Isaac   ierr = DMGetLabel(dm,"canonical",&canonLabel);CHKERRQ(ierr);
70466af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
70566af876cSToby Isaac     PetscInt parent;
70666af876cSToby Isaac 
707f9f063d4SToby Isaac     if (canonLabel) {
708f9f063d4SToby Isaac       PetscInt canon;
709f9f063d4SToby Isaac 
710f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
711f9f063d4SToby Isaac       if (p != canon) continue;
712f9f063d4SToby Isaac     }
71366af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
71466af876cSToby Isaac     if (parent != p) {
71566af876cSToby Isaac       aMin = PetscMin(aMin,p);
71666af876cSToby Isaac       aMax = PetscMax(aMax,p+1);
71766af876cSToby Isaac     }
71866af876cSToby Isaac   }
71966af876cSToby Isaac   if (aMin > aMax) {
72066af876cSToby Isaac     aMin = -1;
72166af876cSToby Isaac     aMax = -1;
72266af876cSToby Isaac   }
723e228b242SToby Isaac   ierr = PetscSectionCreate(PETSC_COMM_SELF,&aSec);CHKERRQ(ierr);
72466af876cSToby Isaac   ierr = PetscSectionSetChart(aSec,aMin,aMax);CHKERRQ(ierr);
72566af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
72666af876cSToby Isaac     PetscInt parent, ancestor = p;
72766af876cSToby Isaac 
728f9f063d4SToby Isaac     if (canonLabel) {
729f9f063d4SToby Isaac       PetscInt canon;
730f9f063d4SToby Isaac 
731f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
732f9f063d4SToby Isaac       if (p != canon) continue;
733f9f063d4SToby Isaac     }
73466af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
73566af876cSToby Isaac     while (parent != ancestor) {
73666af876cSToby Isaac       ancestor = parent;
73766af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
73866af876cSToby Isaac     }
73966af876cSToby Isaac     if (ancestor != p) {
74066af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
74166af876cSToby Isaac 
74266af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
74366af876cSToby Isaac       ierr = PetscSectionSetDof(aSec,p,closureSize);CHKERRQ(ierr);
74466af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
74566af876cSToby Isaac     }
74666af876cSToby Isaac   }
74766af876cSToby Isaac   ierr = PetscSectionSetUp(aSec);CHKERRQ(ierr);
74866af876cSToby Isaac   ierr = PetscSectionGetStorageSize(aSec,&size);CHKERRQ(ierr);
74966af876cSToby Isaac   ierr = PetscMalloc1(size,&anchors);CHKERRQ(ierr);
75066af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
75166af876cSToby Isaac     PetscInt parent, ancestor = p;
75266af876cSToby Isaac 
753f9f063d4SToby Isaac     if (canonLabel) {
754f9f063d4SToby Isaac       PetscInt canon;
755f9f063d4SToby Isaac 
756f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
757f9f063d4SToby Isaac       if (p != canon) continue;
758f9f063d4SToby Isaac     }
75966af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
76066af876cSToby Isaac     while (parent != ancestor) {
76166af876cSToby Isaac       ancestor = parent;
76266af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
76366af876cSToby Isaac     }
76466af876cSToby Isaac     if (ancestor != p) {
76566af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
76666af876cSToby Isaac 
76766af876cSToby Isaac       ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
76866af876cSToby Isaac 
76966af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
77066af876cSToby Isaac       for (j = 0; j < closureSize; j++) {
77166af876cSToby Isaac         anchors[aOff + j] = closure[2*j];
77266af876cSToby Isaac       }
77366af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
77466af876cSToby Isaac     }
77566af876cSToby Isaac   }
776e228b242SToby Isaac   ierr = ISCreateGeneral(PETSC_COMM_SELF,size,anchors,PETSC_OWN_POINTER,&aIS);CHKERRQ(ierr);
7776dd5a8c8SToby Isaac   {
7786dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7796dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7806dd5a8c8SToby Isaac 
7816dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aSec);CHKERRQ(ierr);
7826dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aIS);CHKERRQ(ierr);
7836dd5a8c8SToby Isaac     while (aSecNew) {
7846dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
7856dd5a8c8SToby Isaac       ierr    = ISDestroy(&aIS);CHKERRQ(ierr);
7866dd5a8c8SToby Isaac       aSec    = aSecNew;
7876dd5a8c8SToby Isaac       aIS     = aISNew;
7886dd5a8c8SToby Isaac       aSecNew = NULL;
7896dd5a8c8SToby Isaac       aISNew  = NULL;
7906dd5a8c8SToby Isaac       ierr    = AnchorsFlatten(aSec,aIS,&aSecNew,&aISNew);CHKERRQ(ierr);
7916dd5a8c8SToby Isaac     }
7926dd5a8c8SToby Isaac   }
793a17985deSToby Isaac   ierr = DMPlexSetAnchors(dm,aSec,aIS);CHKERRQ(ierr);
79466af876cSToby Isaac   ierr = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
79566af876cSToby Isaac   ierr = ISDestroy(&aIS);CHKERRQ(ierr);
79666af876cSToby Isaac   PetscFunctionReturn(0);
79766af876cSToby Isaac }
79866af876cSToby Isaac 
7996461c1adSToby Isaac static PetscErrorCode DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt *dof,PetscInt *numTrueSupp)
8006461c1adSToby Isaac {
8016461c1adSToby Isaac   PetscErrorCode ierr;
8026461c1adSToby Isaac 
8036461c1adSToby Isaac   PetscFunctionBegin;
8046461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
8056461c1adSToby Isaac     PetscInt i, alldof;
8066461c1adSToby Isaac     const PetscInt *supp;
8076461c1adSToby Isaac     PetscInt count = 0;
8086461c1adSToby Isaac 
8096461c1adSToby Isaac     ierr = DMPlexGetSupportSize(dm,p,&alldof);CHKERRQ(ierr);
8106461c1adSToby Isaac     ierr = DMPlexGetSupport(dm,p,&supp);CHKERRQ(ierr);
8116461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
8126461c1adSToby Isaac       PetscInt q = supp[i], numCones, j;
8136461c1adSToby Isaac       const PetscInt *cone;
8146461c1adSToby Isaac 
8156461c1adSToby Isaac       ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
8166461c1adSToby Isaac       ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
8176461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
8186461c1adSToby Isaac         if (cone[j] == p) break;
8196461c1adSToby Isaac       }
8206461c1adSToby Isaac       if (j < numCones) count++;
8216461c1adSToby Isaac     }
8226461c1adSToby Isaac     numTrueSupp[p] = count;
8236461c1adSToby Isaac   }
8246461c1adSToby Isaac   *dof = numTrueSupp[p];
8256461c1adSToby Isaac   PetscFunctionReturn(0);
8266461c1adSToby Isaac }
8276461c1adSToby Isaac 
828776742edSToby Isaac static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
829776742edSToby Isaac {
830776742edSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
831776742edSToby Isaac   PetscSection newSupportSection;
832776742edSToby Isaac   PetscInt newSize, *newSupports, pStart, pEnd, p, d, depth;
8336461c1adSToby Isaac   PetscInt *numTrueSupp;
834776742edSToby Isaac   PetscInt *offsets;
835776742edSToby Isaac   PetscErrorCode ierr;
836776742edSToby Isaac 
837776742edSToby Isaac   PetscFunctionBegin;
838776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
839776742edSToby Isaac   /* symmetrize the hierarchy */
840776742edSToby Isaac   ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr);
841e228b242SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)),&newSupportSection);CHKERRQ(ierr);
842776742edSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
843776742edSToby Isaac   ierr = PetscSectionSetChart(newSupportSection,pStart,pEnd);CHKERRQ(ierr);
844776742edSToby Isaac   ierr = PetscCalloc1(pEnd,&offsets);CHKERRQ(ierr);
8456461c1adSToby Isaac   ierr = PetscMalloc1(pEnd,&numTrueSupp);CHKERRQ(ierr);
8466461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8476461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
848776742edSToby Isaac    * parent(q) */
849776742edSToby Isaac   for (d = 0; d <= depth; d++) {
850776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
851776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
852776742edSToby Isaac       PetscInt dof, q, qdof, parent;
853776742edSToby Isaac 
8546461c1adSToby Isaac       ierr = DMPlexGetTrueSupportSize(dm,p,&dof,numTrueSupp);CHKERRQ(ierr);
855776742edSToby Isaac       ierr = PetscSectionAddDof(newSupportSection, p, dof);CHKERRQ(ierr);
856776742edSToby Isaac       q    = p;
857776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
858776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
859776742edSToby Isaac         q = parent;
860776742edSToby Isaac 
8616461c1adSToby Isaac         ierr = DMPlexGetTrueSupportSize(dm,q,&qdof,numTrueSupp);CHKERRQ(ierr);
862776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,p,qdof);CHKERRQ(ierr);
863776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,q,dof);CHKERRQ(ierr);
864776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
865776742edSToby Isaac       }
866776742edSToby Isaac     }
867776742edSToby Isaac   }
868776742edSToby Isaac   ierr = PetscSectionSetUp(newSupportSection);CHKERRQ(ierr);
869776742edSToby Isaac   ierr = PetscSectionGetStorageSize(newSupportSection,&newSize);CHKERRQ(ierr);
870776742edSToby Isaac   ierr = PetscMalloc1(newSize,&newSupports);CHKERRQ(ierr);
871776742edSToby Isaac   for (d = 0; d <= depth; d++) {
872776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
873776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
874776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
875776742edSToby Isaac 
876776742edSToby Isaac       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
877776742edSToby Isaac       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
878776742edSToby Isaac       ierr = PetscSectionGetDof(newSupportSection, p, &newDof);CHKERRQ(ierr);
879776742edSToby Isaac       ierr = PetscSectionGetOffset(newSupportSection, p, &newOff);CHKERRQ(ierr);
880776742edSToby Isaac       for (i = 0; i < dof; i++) {
8816461c1adSToby Isaac         PetscInt numCones, j;
8826461c1adSToby Isaac         const PetscInt *cone;
8836461c1adSToby Isaac         PetscInt q = mesh->supports[off + i];
8846461c1adSToby Isaac 
8856461c1adSToby Isaac         ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
8866461c1adSToby Isaac         ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
8876461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8886461c1adSToby Isaac           if (cone[j] == p) break;
8896461c1adSToby Isaac         }
8906461c1adSToby Isaac         if (j < numCones) newSupports[newOff+offsets[p]++] = q;
891776742edSToby Isaac       }
892776742edSToby Isaac       mesh->maxSupportSize = PetscMax(mesh->maxSupportSize,newDof);
893776742edSToby Isaac 
894776742edSToby Isaac       q    = p;
895776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
896776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
897776742edSToby Isaac         q = parent;
898776742edSToby Isaac         ierr = PetscSectionGetDof(mesh->supportSection, q, &qdof);CHKERRQ(ierr);
899776742edSToby Isaac         ierr = PetscSectionGetOffset(mesh->supportSection, q, &qoff);CHKERRQ(ierr);
900776742edSToby Isaac         ierr = PetscSectionGetOffset(newSupportSection, q, &newqOff);CHKERRQ(ierr);
901776742edSToby Isaac         for (i = 0; i < qdof; i++) {
9026461c1adSToby Isaac           PetscInt numCones, j;
9036461c1adSToby Isaac           const PetscInt *cone;
9046461c1adSToby Isaac           PetscInt r = mesh->supports[qoff + i];
9056461c1adSToby Isaac 
9066461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9076461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9086461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9096461c1adSToby Isaac             if (cone[j] == q) break;
9106461c1adSToby Isaac           }
9116461c1adSToby Isaac           if (j < numCones) newSupports[newOff+offsets[p]++] = r;
912776742edSToby Isaac         }
913776742edSToby Isaac         for (i = 0; i < dof; i++) {
9146461c1adSToby Isaac           PetscInt numCones, j;
9156461c1adSToby Isaac           const PetscInt *cone;
9166461c1adSToby Isaac           PetscInt r = mesh->supports[off + i];
9176461c1adSToby Isaac 
9186461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9196461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9206461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9216461c1adSToby Isaac             if (cone[j] == p) break;
9226461c1adSToby Isaac           }
9236461c1adSToby Isaac           if (j < numCones) newSupports[newqOff+offsets[q]++] = r;
924776742edSToby Isaac         }
925776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
926776742edSToby Isaac       }
927776742edSToby Isaac     }
928776742edSToby Isaac   }
929776742edSToby Isaac   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
930776742edSToby Isaac   mesh->supportSection = newSupportSection;
931776742edSToby Isaac   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
932776742edSToby Isaac   mesh->supports = newSupports;
933776742edSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
9346461c1adSToby Isaac   ierr = PetscFree(numTrueSupp);CHKERRQ(ierr);
935776742edSToby Isaac 
936776742edSToby Isaac   PetscFunctionReturn(0);
937776742edSToby Isaac }
938776742edSToby Isaac 
939f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM,PetscSection,PetscSection,Mat);
940f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM,PetscSection,PetscSection,Mat);
941f7c74593SToby Isaac 
942776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
943f9f063d4SToby Isaac {
944f9f063d4SToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
945f9f063d4SToby Isaac   DM             refTree;
946f9f063d4SToby Isaac   PetscInt       size;
947f9f063d4SToby Isaac   PetscErrorCode ierr;
948f9f063d4SToby Isaac 
949f9f063d4SToby Isaac   PetscFunctionBegin;
950f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
951f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
952f9f063d4SToby Isaac   ierr = PetscObjectReference((PetscObject)parentSection);CHKERRQ(ierr);
953f9f063d4SToby Isaac   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
954f9f063d4SToby Isaac   mesh->parentSection = parentSection;
955f9f063d4SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&size);CHKERRQ(ierr);
956f9f063d4SToby Isaac   if (parents != mesh->parents) {
957f9f063d4SToby Isaac     ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
958f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->parents);CHKERRQ(ierr);
959f9f063d4SToby Isaac     ierr = PetscMemcpy(mesh->parents, parents, size * sizeof(*parents));CHKERRQ(ierr);
960f9f063d4SToby Isaac   }
961f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
962f9f063d4SToby Isaac     ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
963f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->childIDs);CHKERRQ(ierr);
964f9f063d4SToby Isaac     ierr = PetscMemcpy(mesh->childIDs, childIDs, size * sizeof(*childIDs));CHKERRQ(ierr);
965f9f063d4SToby Isaac   }
966f9f063d4SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
967f9f063d4SToby Isaac   if (refTree) {
968f9f063d4SToby Isaac     DMLabel canonLabel;
969f9f063d4SToby Isaac 
970c58f1c22SToby Isaac     ierr = DMGetLabel(refTree,"canonical",&canonLabel);CHKERRQ(ierr);
971f9f063d4SToby Isaac     if (canonLabel) {
972f9f063d4SToby Isaac       PetscInt i;
973f9f063d4SToby Isaac 
974f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
975f9f063d4SToby Isaac         PetscInt canon;
976f9f063d4SToby Isaac         ierr = DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon);CHKERRQ(ierr);
977f9f063d4SToby Isaac         if (canon >= 0) {
978f9f063d4SToby Isaac           mesh->childIDs[i] = canon;
979f9f063d4SToby Isaac         }
980f9f063d4SToby Isaac       }
981f9f063d4SToby Isaac     }
982f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
983f7c74593SToby Isaac   }
984f7c74593SToby Isaac   else {
985f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
986f9f063d4SToby Isaac   }
987f9f063d4SToby Isaac   ierr = DMPlexTreeSymmetrize(dm);CHKERRQ(ierr);
988f9f063d4SToby Isaac   if (computeCanonical) {
989f9f063d4SToby Isaac     PetscInt d, dim;
990f9f063d4SToby Isaac 
991f9f063d4SToby Isaac     /* add the canonical label */
99228f4b327SMatthew G. Knepley     ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
993c58f1c22SToby Isaac     ierr = DMCreateLabel(dm,"canonical");CHKERRQ(ierr);
994f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
995f9f063d4SToby Isaac       PetscInt p, dStart, dEnd, canon = -1, cNumChildren;
996f9f063d4SToby Isaac       const PetscInt *cChildren;
997f9f063d4SToby Isaac 
998f9f063d4SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
999f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1000f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&cNumChildren,&cChildren);CHKERRQ(ierr);
1001f9f063d4SToby Isaac         if (cNumChildren) {
1002f9f063d4SToby Isaac           canon = p;
1003f9f063d4SToby Isaac           break;
1004f9f063d4SToby Isaac         }
1005f9f063d4SToby Isaac       }
1006f9f063d4SToby Isaac       if (canon == -1) continue;
1007f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1008f9f063d4SToby Isaac         PetscInt numChildren, i;
1009f9f063d4SToby Isaac         const PetscInt *children;
1010f9f063d4SToby Isaac 
1011f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&numChildren,&children);CHKERRQ(ierr);
1012f9f063d4SToby Isaac         if (numChildren) {
1013f9f063d4SToby 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);
1014c58f1c22SToby Isaac           ierr = DMSetLabelValue(dm,"canonical",p,canon);CHKERRQ(ierr);
1015f9f063d4SToby Isaac           for (i = 0; i < numChildren; i++) {
1016c58f1c22SToby Isaac             ierr = DMSetLabelValue(dm,"canonical",children[i],cChildren[i]);CHKERRQ(ierr);
1017f9f063d4SToby Isaac           }
1018f9f063d4SToby Isaac         }
1019f9f063d4SToby Isaac       }
1020f9f063d4SToby Isaac     }
1021f9f063d4SToby Isaac   }
1022776742edSToby Isaac   if (exchangeSupports) {
1023776742edSToby Isaac     ierr = DMPlexTreeExchangeSupports(dm);CHKERRQ(ierr);
1024776742edSToby Isaac   }
1025f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
1026f7c74593SToby Isaac   /* reset anchors */
1027f7c74593SToby Isaac   ierr = DMPlexSetAnchors(dm,NULL,NULL);CHKERRQ(ierr);
1028f9f063d4SToby Isaac   PetscFunctionReturn(0);
1029f9f063d4SToby Isaac }
1030f9f063d4SToby Isaac 
10310b7167a0SToby Isaac /*@
10320b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
10330b7167a0SToby Isaac   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
10340b7167a0SToby Isaac   tree root.
10350b7167a0SToby Isaac 
10360b7167a0SToby Isaac   Collective on dm
10370b7167a0SToby Isaac 
10380b7167a0SToby Isaac   Input Parameters:
10390b7167a0SToby Isaac + dm - the DMPlex object
10400b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
10410b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
10420b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
10430b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
10440b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
10450b7167a0SToby Isaac 
10460b7167a0SToby Isaac   Level: intermediate
10470b7167a0SToby Isaac 
1048a17985deSToby Isaac .seealso: DMPlexGetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
10490b7167a0SToby Isaac @*/
1050b2f41788SToby Isaac PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
10510b7167a0SToby Isaac {
10520b7167a0SToby Isaac   PetscErrorCode ierr;
10530b7167a0SToby Isaac 
10540b7167a0SToby Isaac   PetscFunctionBegin;
1055776742edSToby Isaac   ierr = DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
10560b7167a0SToby Isaac   PetscFunctionReturn(0);
10570b7167a0SToby Isaac }
10580b7167a0SToby Isaac 
1059b2f41788SToby Isaac /*@
1060b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1061b2f41788SToby Isaac   Collective on dm
1062b2f41788SToby Isaac 
1063b2f41788SToby Isaac   Input Parameters:
1064b2f41788SToby Isaac . dm - the DMPlex object
1065b2f41788SToby Isaac 
1066b2f41788SToby Isaac   Output Parameters:
1067b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1068b2f41788SToby Isaac                   offset indexes the parent and childID list
1069b2f41788SToby Isaac . parents - a list of the point parents
1070b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1071b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1072b2f41788SToby Isaac . childSection - the inverse of the parent section
1073b2f41788SToby Isaac - children - a list of the point children
1074b2f41788SToby Isaac 
1075b2f41788SToby Isaac   Level: intermediate
1076b2f41788SToby Isaac 
1077a17985deSToby Isaac .seealso: DMPlexSetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
1078b2f41788SToby Isaac @*/
1079b2f41788SToby Isaac PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1080b2f41788SToby Isaac {
1081b2f41788SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
1082b2f41788SToby Isaac 
1083b2f41788SToby Isaac   PetscFunctionBegin;
1084b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1085b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1086b2f41788SToby Isaac   if (parents)       *parents       = mesh->parents;
1087b2f41788SToby Isaac   if (childIDs)      *childIDs      = mesh->childIDs;
1088b2f41788SToby Isaac   if (childSection)  *childSection  = mesh->childSection;
1089b2f41788SToby Isaac   if (children)      *children      = mesh->children;
1090b2f41788SToby Isaac   PetscFunctionReturn(0);
1091b2f41788SToby Isaac }
1092b2f41788SToby Isaac 
1093d961a43aSToby Isaac /*@
1094d961a43aSToby Isaac   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the Sieve DAG)
1095d961a43aSToby Isaac 
1096d961a43aSToby Isaac   Input Parameters:
1097d961a43aSToby Isaac + dm - the DMPlex object
1098d961a43aSToby Isaac - point - the query point
1099d961a43aSToby Isaac 
1100d961a43aSToby Isaac   Output Parameters:
1101d961a43aSToby Isaac + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1102d961a43aSToby Isaac - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point
1103d961a43aSToby Isaac             does not have a parent
1104d961a43aSToby Isaac 
1105d961a43aSToby Isaac   Level: intermediate
1106d961a43aSToby Isaac 
1107d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeChildren()
1108d961a43aSToby Isaac @*/
1109d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1110d961a43aSToby Isaac {
1111d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1112d961a43aSToby Isaac   PetscSection   pSec;
1113d961a43aSToby Isaac   PetscErrorCode ierr;
1114d961a43aSToby Isaac 
1115d961a43aSToby Isaac   PetscFunctionBegin;
1116d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1117d961a43aSToby Isaac   pSec = mesh->parentSection;
1118d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1119d961a43aSToby Isaac     PetscInt dof;
1120d961a43aSToby Isaac 
1121d961a43aSToby Isaac     ierr = PetscSectionGetDof (pSec, point, &dof);CHKERRQ(ierr);
1122d961a43aSToby Isaac     if (dof) {
1123d961a43aSToby Isaac       PetscInt off;
1124d961a43aSToby Isaac 
1125d961a43aSToby Isaac       ierr = PetscSectionGetOffset (pSec, point, &off);CHKERRQ(ierr);
1126d961a43aSToby Isaac       if (parent)  *parent = mesh->parents[off];
1127d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
1128d961a43aSToby Isaac       PetscFunctionReturn(0);
1129d961a43aSToby Isaac     }
1130d961a43aSToby Isaac   }
1131d961a43aSToby Isaac   if (parent) {
1132d961a43aSToby Isaac     *parent = point;
1133d961a43aSToby Isaac   }
1134d961a43aSToby Isaac   if (childID) {
1135d961a43aSToby Isaac     *childID = 0;
1136d961a43aSToby Isaac   }
1137d961a43aSToby Isaac   PetscFunctionReturn(0);
1138d961a43aSToby Isaac }
1139d961a43aSToby Isaac 
1140d961a43aSToby Isaac /*@C
1141d961a43aSToby Isaac   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the Sieve DAG)
1142d961a43aSToby Isaac 
1143d961a43aSToby Isaac   Input Parameters:
1144d961a43aSToby Isaac + dm - the DMPlex object
1145d961a43aSToby Isaac - point - the query point
1146d961a43aSToby Isaac 
1147d961a43aSToby Isaac   Output Parameters:
1148d961a43aSToby Isaac + numChildren - if not NULL, set to the number of children
1149d961a43aSToby Isaac - children - if not NULL, set to a list children, or set to NULL if the point has no children
1150d961a43aSToby Isaac 
1151d961a43aSToby Isaac   Level: intermediate
1152d961a43aSToby Isaac 
1153d961a43aSToby Isaac   Fortran Notes:
1154d961a43aSToby Isaac   Since it returns an array, this routine is only available in Fortran 90, and you must
1155d961a43aSToby Isaac   include petsc.h90 in your code.
1156d961a43aSToby Isaac 
1157d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeParent()
1158d961a43aSToby Isaac @*/
1159d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1160d961a43aSToby Isaac {
1161d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1162d961a43aSToby Isaac   PetscSection   childSec;
1163d961a43aSToby Isaac   PetscInt       dof = 0;
1164d961a43aSToby Isaac   PetscErrorCode ierr;
1165d961a43aSToby Isaac 
1166d961a43aSToby Isaac   PetscFunctionBegin;
1167d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1168d961a43aSToby Isaac   childSec = mesh->childSection;
1169d961a43aSToby Isaac   if (childSec && point >= childSec->pStart && point < childSec->pEnd) {
1170d961a43aSToby Isaac     ierr = PetscSectionGetDof (childSec, point, &dof);CHKERRQ(ierr);
1171d961a43aSToby Isaac   }
1172d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1173d961a43aSToby Isaac   if (children) {
1174d961a43aSToby Isaac     if (dof) {
1175d961a43aSToby Isaac       PetscInt off;
1176d961a43aSToby Isaac 
1177d961a43aSToby Isaac       ierr = PetscSectionGetOffset (childSec, point, &off);CHKERRQ(ierr);
1178d961a43aSToby Isaac       *children = &mesh->children[off];
1179d961a43aSToby Isaac     }
1180d961a43aSToby Isaac     else {
1181d961a43aSToby Isaac       *children = NULL;
1182d961a43aSToby Isaac     }
1183d961a43aSToby Isaac   }
1184d961a43aSToby Isaac   PetscFunctionReturn(0);
1185d961a43aSToby Isaac }
11860c37af3bSToby Isaac 
1187b3a4bf2aSToby Isaac static PetscErrorCode EvaluateBasis(PetscSpace space, PetscInt nFunctionals, PetscInt nPoints, const PetscInt *pointsPerFn, const PetscReal *points, const PetscReal *weights, PetscReal *work, Mat basisAtPoints)
1188b3a4bf2aSToby Isaac {
1189b3a4bf2aSToby Isaac   PetscInt       i, j, k, offset, qPoints;
1190b3a4bf2aSToby Isaac   PetscErrorCode ierr;
1191b3a4bf2aSToby Isaac 
1192b3a4bf2aSToby Isaac   PetscFunctionBegin;
1193b3a4bf2aSToby Isaac   ierr = PetscSpaceEvaluate(space,nPoints,points,work,NULL,NULL);CHKERRQ(ierr);
1194b3a4bf2aSToby Isaac   for (i = 0, offset = 0; i < nFunctionals; i++) {
1195b3a4bf2aSToby Isaac     qPoints = pointsPerFn[i];
1196b3a4bf2aSToby Isaac     for (j = 0; j < nFunctionals; j++) {
1197b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1198b3a4bf2aSToby Isaac 
1199b3a4bf2aSToby Isaac       for (k = 0; k < qPoints; k++) {
1200b3a4bf2aSToby Isaac         val += work[(offset + k) * nFunctionals + j] * weights[k];
1201b3a4bf2aSToby Isaac       }
1202b3a4bf2aSToby Isaac       ierr = MatSetValue(basisAtPoints,j,i,val,INSERT_VALUES);CHKERRQ(ierr);
1203b3a4bf2aSToby Isaac     }
1204b3a4bf2aSToby Isaac     offset += qPoints;
1205b3a4bf2aSToby Isaac   }
1206b3a4bf2aSToby Isaac   ierr = MatAssemblyBegin(basisAtPoints,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1207b3a4bf2aSToby Isaac   ierr = MatAssemblyEnd(basisAtPoints,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1208b3a4bf2aSToby Isaac   PetscFunctionReturn(0);
1209b3a4bf2aSToby Isaac }
1210b3a4bf2aSToby Isaac 
1211f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
12120c37af3bSToby Isaac {
12130c37af3bSToby Isaac   PetscDS        ds;
12140c37af3bSToby Isaac   PetscInt       spdim;
12150c37af3bSToby Isaac   PetscInt       numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
12160c37af3bSToby Isaac   const PetscInt *anchors;
1217f7c74593SToby Isaac   PetscSection   aSec;
12180c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
12190c37af3bSToby Isaac   IS             aIS;
12200c37af3bSToby Isaac   PetscErrorCode ierr;
12210c37af3bSToby Isaac 
12220c37af3bSToby Isaac   PetscFunctionBegin;
12230c37af3bSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
12240c37af3bSToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
12250c37af3bSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
12260c37af3bSToby Isaac   ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
1227a17985deSToby Isaac   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
12280c37af3bSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
12290c37af3bSToby Isaac   ierr = PetscSectionGetChart(cSec,&conStart,&conEnd);CHKERRQ(ierr);
123028f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&spdim);CHKERRQ(ierr);
12310c37af3bSToby Isaac   ierr = PetscMalloc6(spdim,&v0,spdim,&v0parent,spdim,&vtmp,spdim*spdim,&J,spdim*spdim,&Jparent,spdim*spdim,&invJparent);CHKERRQ(ierr);
12320c37af3bSToby Isaac 
12330c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
12340dd1b1feSToby Isaac     PetscObject disc;
12350dd1b1feSToby Isaac     PetscClassId id;
1236b3a4bf2aSToby Isaac     PetscSpace     bspace;
1237b3a4bf2aSToby Isaac     PetscDualSpace dspace;
12380c37af3bSToby Isaac     PetscInt i, j, k, nPoints, offset;
12392c44ad04SToby Isaac     PetscInt fSize, fComp, maxDof;
1240b3a4bf2aSToby Isaac     PetscReal   *weights, *pointsRef, *pointsReal, *work;
12412c44ad04SToby Isaac     PetscScalar *scwork, *X;
12422c44ad04SToby Isaac     PetscInt  *sizes, *workIndRow, *workIndCol;
12430c37af3bSToby Isaac     Mat Amat, Bmat, Xmat;
12442c44ad04SToby Isaac     const PetscInt    *numDof  = NULL;
1245085f0adfSToby Isaac     const PetscInt    ***perms = NULL;
1246085f0adfSToby Isaac     const PetscScalar ***flips = NULL;
12470c37af3bSToby Isaac 
12480dd1b1feSToby Isaac     ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
12490dd1b1feSToby Isaac     ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
12500dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1251b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE) disc;
1252b3a4bf2aSToby Isaac 
1253b3a4bf2aSToby Isaac       ierr = PetscFEGetBasisSpace(fe,&bspace);CHKERRQ(ierr);
1254b3a4bf2aSToby Isaac       ierr = PetscFEGetDualSpace(fe,&dspace);CHKERRQ(ierr);
1255b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetDimension(dspace,&fSize);CHKERRQ(ierr);
12560c37af3bSToby Isaac       ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr);
12570dd1b1feSToby Isaac     }
12580dd1b1feSToby Isaac     else if (id == PETSCFV_CLASSID) {
1259b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV) disc;
1260b3a4bf2aSToby Isaac 
1261b3a4bf2aSToby Isaac       ierr = PetscSpaceCreate(PetscObjectComm((PetscObject)fv),&bspace);CHKERRQ(ierr);
1262b3a4bf2aSToby Isaac       ierr = PetscSpaceSetType(bspace,PETSCSPACEPOLYNOMIAL);CHKERRQ(ierr);
1263b3a4bf2aSToby Isaac       ierr = PetscSpaceSetOrder(bspace,0);CHKERRQ(ierr);
1264b3a4bf2aSToby Isaac       ierr = PetscSpacePolynomialSetNumVariables(bspace,spdim);CHKERRQ(ierr);
1265b3a4bf2aSToby Isaac       ierr = PetscSpaceSetUp(bspace);CHKERRQ(ierr);
1266b3a4bf2aSToby Isaac       ierr = PetscFVGetDualSpace(fv,&dspace);CHKERRQ(ierr);
1267b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetDimension(dspace,&fSize);CHKERRQ(ierr);
12680dd1b1feSToby Isaac       ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr);
12690dd1b1feSToby Isaac     }
12700dd1b1feSToby Isaac     else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
12712c44ad04SToby Isaac     ierr = PetscDualSpaceGetNumDof(dspace,&numDof);CHKERRQ(ierr);
12722c44ad04SToby Isaac     for (i = 0, maxDof = 0; i <= spdim; i++) {maxDof = PetscMax(maxDof,numDof[i]);}
1273085f0adfSToby Isaac     ierr = PetscDualSpaceGetSymmetries(dspace,&perms,&flips);CHKERRQ(ierr);
12740dd1b1feSToby Isaac 
12750c37af3bSToby Isaac     ierr = MatCreate(PETSC_COMM_SELF,&Amat);CHKERRQ(ierr);
12760c37af3bSToby Isaac     ierr = MatSetSizes(Amat,fSize,fSize,fSize,fSize);CHKERRQ(ierr);
12770c37af3bSToby Isaac     ierr = MatSetType(Amat,MATSEQDENSE);CHKERRQ(ierr);
12780c37af3bSToby Isaac     ierr = MatSetUp(Amat);CHKERRQ(ierr);
12790c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Bmat);CHKERRQ(ierr);
12800c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Xmat);CHKERRQ(ierr);
12810c37af3bSToby Isaac     nPoints = 0;
12820c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12830c37af3bSToby Isaac       PetscInt        qPoints;
12840c37af3bSToby Isaac       PetscQuadrature quad;
12850c37af3bSToby Isaac 
1286b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetFunctional(dspace,i,&quad);CHKERRQ(ierr);
12870c37af3bSToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,&qPoints,NULL,NULL);CHKERRQ(ierr);
12880c37af3bSToby Isaac       nPoints += qPoints;
12890c37af3bSToby Isaac     }
12902c44ad04SToby Isaac     ierr = PetscMalloc7(fSize,&sizes,nPoints,&weights,spdim*nPoints,&pointsRef,spdim*nPoints,&pointsReal,fSize*nPoints,&work,maxDof,&workIndRow,maxDof,&workIndCol);CHKERRQ(ierr);
12912c44ad04SToby Isaac     ierr = PetscMalloc1(maxDof * maxDof,&scwork);CHKERRQ(ierr);
12920c37af3bSToby Isaac     offset = 0;
12930c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12940c37af3bSToby Isaac       PetscInt        qPoints;
12950c37af3bSToby Isaac       const PetscReal    *p, *w;
12960c37af3bSToby Isaac       PetscQuadrature quad;
12970c37af3bSToby Isaac 
1298b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetFunctional(dspace,i,&quad);CHKERRQ(ierr);
12990c37af3bSToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,&qPoints,&p,&w);CHKERRQ(ierr);
13000c37af3bSToby Isaac       ierr = PetscMemcpy(weights+offset,w,qPoints*sizeof(*w));CHKERRQ(ierr);
13010c37af3bSToby Isaac       ierr = PetscMemcpy(pointsRef+spdim*offset,p,spdim*qPoints*sizeof(*p));CHKERRQ(ierr);
1302b3a4bf2aSToby Isaac       sizes[i] = qPoints;
13030c37af3bSToby Isaac       offset  += qPoints;
13040c37af3bSToby Isaac     }
1305b3a4bf2aSToby Isaac     ierr = EvaluateBasis(bspace,fSize,nPoints,sizes,pointsRef,weights,work,Amat);CHKERRQ(ierr);
13060c37af3bSToby Isaac     ierr = MatLUFactor(Amat,NULL,NULL,NULL);CHKERRQ(ierr);
13070c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
13080c37af3bSToby Isaac       PetscInt        parent;
13090c37af3bSToby Isaac       PetscInt        closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
13100c37af3bSToby Isaac       PetscInt        *childOffsets, *parentOffsets;
13110c37af3bSToby Isaac 
13120c37af3bSToby Isaac       ierr = DMPlexGetTreeParent(dm,c,&parent,NULL);CHKERRQ(ierr);
13130c37af3bSToby Isaac       if (parent == c) continue;
13140c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13150c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13160c37af3bSToby Isaac         PetscInt p = closure[2*i];
13170c37af3bSToby Isaac         PetscInt conDof;
13180c37af3bSToby Isaac 
13190c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1320085f0adfSToby Isaac         if (numFields) {
13210c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
13220c37af3bSToby Isaac         }
13230c37af3bSToby Isaac         else {
13240c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
13250c37af3bSToby Isaac         }
13260c37af3bSToby Isaac         if (conDof) break;
13270c37af3bSToby Isaac       }
13280c37af3bSToby Isaac       if (i == closureSize) {
13290c37af3bSToby Isaac         ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13300c37af3bSToby Isaac         continue;
13310c37af3bSToby Isaac       }
13320c37af3bSToby Isaac 
133373a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
133473a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent);CHKERRQ(ierr);
13350c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1336b3a4bf2aSToby Isaac         CoordinatesRefToReal(spdim, spdim, v0, J, &pointsRef[i*spdim],vtmp);
1337b3a4bf2aSToby Isaac         CoordinatesRealToRef(spdim, spdim, v0parent, invJparent, vtmp, &pointsReal[i*spdim]);
13380c37af3bSToby Isaac       }
1339b3a4bf2aSToby Isaac       ierr = EvaluateBasis(bspace,fSize,nPoints,sizes,pointsReal,weights,work,Bmat);CHKERRQ(ierr);
13400c37af3bSToby Isaac       ierr = MatMatSolve(Amat,Bmat,Xmat);CHKERRQ(ierr);
13412c44ad04SToby Isaac       ierr = MatDenseGetArray(Xmat,&X);CHKERRQ(ierr);
13420c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
13430c37af3bSToby Isaac       ierr = PetscMalloc2(closureSize+1,&childOffsets,closureSizeP+1,&parentOffsets);CHKERRQ(ierr);
13440c37af3bSToby Isaac       childOffsets[0] = 0;
13450c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13460c37af3bSToby Isaac         PetscInt p = closure[2*i];
13470c37af3bSToby Isaac         PetscInt dof;
13480c37af3bSToby Isaac 
1349085f0adfSToby Isaac         if (numFields) {
13500c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
13510c37af3bSToby Isaac         }
13520c37af3bSToby Isaac         else {
13530c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
13540c37af3bSToby Isaac         }
13550c37af3bSToby Isaac         childOffsets[i+1]=childOffsets[i]+dof / fComp;
13560c37af3bSToby Isaac       }
13570c37af3bSToby Isaac       parentOffsets[0] = 0;
13580c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
13590c37af3bSToby Isaac         PetscInt p = closureP[2*i];
13600c37af3bSToby Isaac         PetscInt dof;
13610c37af3bSToby Isaac 
1362085f0adfSToby Isaac         if (numFields) {
13630c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
13640c37af3bSToby Isaac         }
13650c37af3bSToby Isaac         else {
13660c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
13670c37af3bSToby Isaac         }
13680c37af3bSToby Isaac         parentOffsets[i+1]=parentOffsets[i]+dof / fComp;
13690c37af3bSToby Isaac       }
13700c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13712c44ad04SToby Isaac         PetscInt conDof, conOff, aDof, aOff, nWork;
13720c37af3bSToby Isaac         PetscInt p = closure[2*i];
13730c37af3bSToby Isaac         PetscInt o = closure[2*i+1];
1374085f0adfSToby Isaac         const PetscInt    *perm;
1375085f0adfSToby Isaac         const PetscScalar *flip;
13760c37af3bSToby Isaac 
13770c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1378085f0adfSToby Isaac         if (numFields) {
13790c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
13800c37af3bSToby Isaac           ierr = PetscSectionGetFieldOffset(cSec,p,f,&conOff);CHKERRQ(ierr);
13810c37af3bSToby Isaac         }
13820c37af3bSToby Isaac         else {
13830c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
13840c37af3bSToby Isaac           ierr = PetscSectionGetOffset(cSec,p,&conOff);CHKERRQ(ierr);
13850c37af3bSToby Isaac         }
13860c37af3bSToby Isaac         if (!conDof) continue;
1387085f0adfSToby Isaac         perm  = (perms && perms[i]) ? perms[i][o] : NULL;
1388085f0adfSToby Isaac         flip  = (flips && flips[i]) ? flips[i][o] : NULL;
13890c37af3bSToby Isaac         ierr  = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
13900c37af3bSToby Isaac         ierr  = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
13912c44ad04SToby Isaac         nWork = childOffsets[i+1]-childOffsets[i];
13920c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
13930c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
13940c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
13950c37af3bSToby Isaac 
1396085f0adfSToby Isaac           if (numFields) {
13970c37af3bSToby Isaac             ierr = PetscSectionGetFieldDof(section,a,f,&aSecDof);CHKERRQ(ierr);
13980c37af3bSToby Isaac             ierr = PetscSectionGetFieldOffset(section,a,f,&aSecOff);CHKERRQ(ierr);
13990c37af3bSToby Isaac           }
14000c37af3bSToby Isaac           else {
14010c37af3bSToby Isaac             ierr = PetscSectionGetDof(section,a,&aSecDof);CHKERRQ(ierr);
14020c37af3bSToby Isaac             ierr = PetscSectionGetOffset(section,a,&aSecOff);CHKERRQ(ierr);
14030c37af3bSToby Isaac           }
14040c37af3bSToby Isaac           if (!aSecDof) continue;
14050c37af3bSToby Isaac 
14060c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
14070c37af3bSToby Isaac             PetscInt q = closureP[2*j];
14080c37af3bSToby Isaac             PetscInt oq = closureP[2*j+1];
14092c44ad04SToby Isaac 
14102c44ad04SToby Isaac             if (q == a) {
14112c44ad04SToby Isaac               PetscInt r, s, t, nWorkP;
1412085f0adfSToby Isaac               const PetscInt    *permP;
1413085f0adfSToby Isaac               const PetscScalar *flipP;
1414085f0adfSToby Isaac 
1415085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1416085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
14172c44ad04SToby Isaac               nWorkP = parentOffsets[j+1]-parentOffsets[j];
14182c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
14192c44ad04SToby Isaac                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArray is
14202c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
14212c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
14222c44ad04SToby Isaac                 for (s = 0; s < nWorkP; s++) {
14232c44ad04SToby Isaac                   scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
14242c44ad04SToby Isaac                 }
14252c44ad04SToby Isaac               }
14262c44ad04SToby Isaac               for (r = 0; r < nWork; r++)  {workIndRow[perm  ? perm[r]  : r] = conOff  + fComp * r;}
14272c44ad04SToby Isaac               for (s = 0; s < nWorkP; s++) {workIndCol[permP ? permP[s] : s] = aSecOff + fComp * s;}
14282c44ad04SToby Isaac               if (flip) {
14292c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14302c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14312c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flip[r];
14322c44ad04SToby Isaac                   }
14332c44ad04SToby Isaac                 }
14342c44ad04SToby Isaac               }
14352c44ad04SToby Isaac               if (flipP) {
14362c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14372c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14382c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flipP[s];
14392c44ad04SToby Isaac                   }
14402c44ad04SToby Isaac                 }
14412c44ad04SToby Isaac               }
14420c37af3bSToby Isaac               for (t = 0; t < fComp; t++) {
14432c44ad04SToby Isaac                 ierr = MatSetValues(cMat,nWork,workIndRow,nWorkP,workIndCol,scwork,INSERT_VALUES);CHKERRQ(ierr);
14442c44ad04SToby Isaac                 if (t < fComp - 1) {
14452c44ad04SToby Isaac                   for (r = 0; r < nWork;  r++) {workIndRow[r]++;}
14462c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {workIndCol[s]++;}
14472c44ad04SToby Isaac                 }
14482c44ad04SToby Isaac               }
14492c44ad04SToby Isaac               break;
14500c37af3bSToby Isaac             }
14510c37af3bSToby Isaac           }
14520c37af3bSToby Isaac         }
14530c37af3bSToby Isaac       }
14542c44ad04SToby Isaac       ierr = MatDenseRestoreArray(Xmat,&X);CHKERRQ(ierr);
14550c37af3bSToby Isaac       ierr = PetscFree2(childOffsets,parentOffsets);CHKERRQ(ierr);
14560c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
14570c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
14580c37af3bSToby Isaac     }
14590c37af3bSToby Isaac     ierr = MatDestroy(&Amat);CHKERRQ(ierr);
14600c37af3bSToby Isaac     ierr = MatDestroy(&Bmat);CHKERRQ(ierr);
14610c37af3bSToby Isaac     ierr = MatDestroy(&Xmat);CHKERRQ(ierr);
14622c44ad04SToby Isaac     ierr = PetscFree(scwork);CHKERRQ(ierr);
14632c44ad04SToby Isaac     ierr = PetscFree7(sizes,weights,pointsRef,pointsReal,work,workIndRow,workIndCol);CHKERRQ(ierr);
1464b3a4bf2aSToby Isaac     if (id == PETSCFV_CLASSID) {
1465b3a4bf2aSToby Isaac       ierr = PetscSpaceDestroy(&bspace);CHKERRQ(ierr);
1466b3a4bf2aSToby Isaac     }
14670c37af3bSToby Isaac   }
14680c37af3bSToby Isaac   ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14690c37af3bSToby Isaac   ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14700c37af3bSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJparent);CHKERRQ(ierr);
14710c37af3bSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
14720c37af3bSToby Isaac 
14730c37af3bSToby Isaac   PetscFunctionReturn(0);
14740c37af3bSToby Isaac }
147595a0b26dSToby Isaac 
147621968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
147795a0b26dSToby Isaac {
1478f7c74593SToby Isaac   Mat               refCmat;
147921968bf8SToby Isaac   PetscDS           ds;
1480085f0adfSToby Isaac   PetscInt          numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
148121968bf8SToby Isaac   PetscScalar       ***refPointFieldMats;
148221968bf8SToby Isaac   PetscSection      refConSec, refAnSec, refSection;
148321968bf8SToby Isaac   IS                refAnIS;
148421968bf8SToby Isaac   const PetscInt    *refAnchors;
1485085f0adfSToby Isaac   const PetscInt    **perms;
1486085f0adfSToby Isaac   const PetscScalar **flips;
148795a0b26dSToby Isaac   PetscErrorCode    ierr;
148895a0b26dSToby Isaac 
148995a0b26dSToby Isaac   PetscFunctionBegin;
149021968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
149195a0b26dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1492085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
1493f7c74593SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
1494a17985deSToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
149595a0b26dSToby Isaac   ierr = ISGetIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
149695a0b26dSToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
149795a0b26dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
149895a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
149995a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldN);CHKERRQ(ierr);
150095a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
150195a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
150295a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
150395a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof*maxAnDof,&cols);CHKERRQ(ierr);
150495a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
150595a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
150695a0b26dSToby Isaac 
150795a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
150895a0b26dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
150995a0b26dSToby Isaac     if (!pDof || parent == p) continue;
151095a0b26dSToby Isaac 
1511085f0adfSToby Isaac     ierr = PetscMalloc1(maxFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
1512085f0adfSToby Isaac     ierr = PetscCalloc1(maxFields,&refPointFieldN[p-pRefStart]);CHKERRQ(ierr);
151395a0b26dSToby Isaac     ierr = DMPlexGetTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1514085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1515085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
151695a0b26dSToby Isaac 
1517085f0adfSToby Isaac       if (f < numFields) {
151895a0b26dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
151995a0b26dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
1520085f0adfSToby Isaac         ierr = PetscSectionGetFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1521085f0adfSToby Isaac       } else {
152295a0b26dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
152395a0b26dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
1524085f0adfSToby Isaac         ierr = PetscSectionGetPointSyms(refSection,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
152595a0b26dSToby Isaac       }
152695a0b26dSToby Isaac 
152795a0b26dSToby Isaac       for (r = 0; r < cDof; r++) {
152895a0b26dSToby Isaac         rows[r] = cOff + r;
152995a0b26dSToby Isaac       }
153095a0b26dSToby Isaac       numCols = 0;
153195a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
153295a0b26dSToby Isaac         PetscInt          q = closure[2*i];
153395a0b26dSToby Isaac         PetscInt          aDof, aOff, j;
1534085f0adfSToby Isaac         const PetscInt    *perm = perms ? perms[i] : NULL;
153595a0b26dSToby Isaac 
1536085f0adfSToby Isaac         if (numFields) {
153795a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
153895a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
153995a0b26dSToby Isaac         }
154095a0b26dSToby Isaac         else {
154195a0b26dSToby Isaac           ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
154295a0b26dSToby Isaac           ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
154395a0b26dSToby Isaac         }
154495a0b26dSToby Isaac 
154595a0b26dSToby Isaac         for (j = 0; j < aDof; j++) {
1546085f0adfSToby Isaac           cols[numCols++] = aOff + (perm ? perm[j] : j);
154795a0b26dSToby Isaac         }
154895a0b26dSToby Isaac       }
154995a0b26dSToby Isaac       refPointFieldN[p-pRefStart][f] = numCols;
155095a0b26dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
155195a0b26dSToby Isaac       ierr = MatGetValues(refCmat,cDof,rows,numCols,cols,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
1552085f0adfSToby Isaac       if (flips) {
1553085f0adfSToby Isaac         PetscInt colOff = 0;
1554085f0adfSToby Isaac 
1555085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1556085f0adfSToby Isaac           PetscInt          q = closure[2*i];
1557085f0adfSToby Isaac           PetscInt          aDof, aOff, j;
1558085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1559085f0adfSToby Isaac 
1560085f0adfSToby Isaac           if (numFields) {
1561085f0adfSToby Isaac             ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
1562085f0adfSToby Isaac             ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
1563085f0adfSToby Isaac           }
1564085f0adfSToby Isaac           else {
1565085f0adfSToby Isaac             ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
1566085f0adfSToby Isaac             ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
1567085f0adfSToby Isaac           }
1568085f0adfSToby Isaac           if (flip) {
1569085f0adfSToby Isaac             PetscInt k;
1570085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1571085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1572085f0adfSToby Isaac                 refPointFieldMats[p-pRefStart][f][k * numCols + colOff + j] *= flip[j];
1573085f0adfSToby Isaac               }
1574085f0adfSToby Isaac             }
1575085f0adfSToby Isaac           }
1576085f0adfSToby Isaac           colOff += aDof;
1577085f0adfSToby Isaac         }
1578085f0adfSToby Isaac       }
1579085f0adfSToby Isaac       if (numFields) {
1580085f0adfSToby Isaac         ierr = PetscSectionRestoreFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1581085f0adfSToby Isaac       } else {
1582085f0adfSToby Isaac         ierr = PetscSectionRestorePointSyms(refSection,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1583085f0adfSToby Isaac       }
158495a0b26dSToby Isaac     }
158595a0b26dSToby Isaac     ierr = DMPlexRestoreTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
158695a0b26dSToby Isaac   }
158721968bf8SToby Isaac   *childrenMats = refPointFieldMats;
158821968bf8SToby Isaac   *childrenN = refPointFieldN;
158921968bf8SToby Isaac   ierr = ISRestoreIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
159021968bf8SToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
159121968bf8SToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
159221968bf8SToby Isaac   PetscFunctionReturn(0);
159321968bf8SToby Isaac }
159421968bf8SToby Isaac 
159521968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
159621968bf8SToby Isaac {
159721968bf8SToby Isaac   PetscDS        ds;
159821968bf8SToby Isaac   PetscInt       **refPointFieldN;
159921968bf8SToby Isaac   PetscScalar    ***refPointFieldMats;
1600085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
160121968bf8SToby Isaac   PetscSection   refConSec;
160221968bf8SToby Isaac   PetscErrorCode ierr;
160321968bf8SToby Isaac 
160421968bf8SToby Isaac   PetscFunctionBegin;
160521968bf8SToby Isaac   refPointFieldN = *childrenN;
160621968bf8SToby Isaac   *childrenN = NULL;
160721968bf8SToby Isaac   refPointFieldMats = *childrenMats;
160821968bf8SToby Isaac   *childrenMats = NULL;
160921968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
161021968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1611085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);CHKERRQ(ierr);
161221968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
1613e44e4e7fSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
161421968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
161521968bf8SToby Isaac     PetscInt parent, pDof;
161621968bf8SToby Isaac 
161721968bf8SToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
161821968bf8SToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
161921968bf8SToby Isaac     if (!pDof || parent == p) continue;
162021968bf8SToby Isaac 
1621085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
162221968bf8SToby Isaac       PetscInt cDof;
162321968bf8SToby Isaac 
1624085f0adfSToby Isaac       if (numFields) {
162521968bf8SToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
162621968bf8SToby Isaac       }
162721968bf8SToby Isaac       else {
162821968bf8SToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
162921968bf8SToby Isaac       }
163021968bf8SToby Isaac 
163121968bf8SToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
163221968bf8SToby Isaac     }
163321968bf8SToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
163421968bf8SToby Isaac     ierr = PetscFree(refPointFieldN[p - pRefStart]);CHKERRQ(ierr);
163521968bf8SToby Isaac   }
163621968bf8SToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
163721968bf8SToby Isaac   ierr = PetscFree(refPointFieldN);CHKERRQ(ierr);
163821968bf8SToby Isaac   PetscFunctionReturn(0);
163921968bf8SToby Isaac }
164021968bf8SToby Isaac 
164121968bf8SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
164221968bf8SToby Isaac {
164321968bf8SToby Isaac   DM             refTree;
164421968bf8SToby Isaac   PetscDS        ds;
164521968bf8SToby Isaac   Mat            refCmat;
1646085f0adfSToby Isaac   PetscInt       numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
164721968bf8SToby Isaac   PetscScalar ***refPointFieldMats, *pointWork;
164821968bf8SToby Isaac   PetscSection   refConSec, refAnSec, anSec;
164921968bf8SToby Isaac   IS             refAnIS, anIS;
165021968bf8SToby Isaac   const PetscInt *anchors;
165121968bf8SToby Isaac   PetscErrorCode ierr;
165221968bf8SToby Isaac 
165321968bf8SToby Isaac   PetscFunctionBegin;
165421968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
165521968bf8SToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
165621968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1657085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
165821968bf8SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
165921968bf8SToby Isaac   ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
166021968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
166121968bf8SToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
166221968bf8SToby Isaac   ierr = DMPlexGetAnchors(dm,&anSec,&anIS);CHKERRQ(ierr);
166321968bf8SToby Isaac   ierr = ISGetIndices(anIS,&anchors);CHKERRQ(ierr);
166421968bf8SToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
166521968bf8SToby Isaac   ierr = PetscSectionGetChart(conSec,&conStart,&conEnd);CHKERRQ(ierr);
166621968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
166721968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
166821968bf8SToby Isaac   ierr = PetscMalloc1(maxDof*maxDof*maxAnDof,&pointWork);CHKERRQ(ierr);
166921968bf8SToby Isaac 
167021968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
167121968bf8SToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
167295a0b26dSToby Isaac 
167395a0b26dSToby Isaac   /* step 2: compute the preorder */
167495a0b26dSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
167595a0b26dSToby Isaac   ierr = PetscMalloc2(pEnd-pStart,&perm,pEnd-pStart,&iperm);CHKERRQ(ierr);
167695a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
167795a0b26dSToby Isaac     perm[p - pStart] = p;
167895a0b26dSToby Isaac     iperm[p - pStart] = p-pStart;
167995a0b26dSToby Isaac   }
168095a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
168195a0b26dSToby Isaac     PetscInt point = perm[p];
168295a0b26dSToby Isaac     PetscInt parent;
168395a0b26dSToby Isaac 
168495a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
168595a0b26dSToby Isaac     if (parent == point) {
168695a0b26dSToby Isaac       p++;
168795a0b26dSToby Isaac     }
168895a0b26dSToby Isaac     else {
168995a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
169095a0b26dSToby Isaac 
169195a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
169295a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
169395a0b26dSToby Isaac         PetscInt q = closure[2*i];
169495a0b26dSToby Isaac         if (iperm[q-pStart] > iperm[point-pStart]) {
169595a0b26dSToby Isaac           /* swap */
169695a0b26dSToby Isaac           perm[p]               = q;
169795a0b26dSToby Isaac           perm[iperm[q-pStart]] = point;
169895a0b26dSToby Isaac           iperm[point-pStart]   = iperm[q-pStart];
169995a0b26dSToby Isaac           iperm[q-pStart]       = p;
170095a0b26dSToby Isaac           break;
170195a0b26dSToby Isaac         }
170295a0b26dSToby Isaac       }
170395a0b26dSToby Isaac       size = closureSize;
170495a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
170595a0b26dSToby Isaac       if (i == size) {
170695a0b26dSToby Isaac         p++;
170795a0b26dSToby Isaac       }
170895a0b26dSToby Isaac     }
170995a0b26dSToby Isaac   }
171095a0b26dSToby Isaac 
171195a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
171295a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
171395a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
171495a0b26dSToby Isaac    * values outside of the Mat first.
171595a0b26dSToby Isaac    */
171695a0b26dSToby Isaac   {
171795a0b26dSToby Isaac     PetscInt nRows, row, nnz;
171895a0b26dSToby Isaac     PetscBool done;
171995a0b26dSToby Isaac     const PetscInt *ia, *ja;
172095a0b26dSToby Isaac     PetscScalar *vals;
172195a0b26dSToby Isaac 
172295a0b26dSToby Isaac     ierr = MatGetRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
172395a0b26dSToby Isaac     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not get RowIJ of constraint matrix");
172495a0b26dSToby Isaac     nnz  = ia[nRows];
172595a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
172695a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
172795a0b26dSToby Isaac     ierr = PetscMalloc1(nnz,&vals);CHKERRQ(ierr);
172895a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
172995a0b26dSToby Isaac       PetscInt        parent, childid, closureSize, *closure = NULL;
173095a0b26dSToby Isaac       PetscInt        point = perm[p], pointDof;
173195a0b26dSToby Isaac 
173295a0b26dSToby Isaac       ierr = DMPlexGetTreeParent(dm,point,&parent,&childid);CHKERRQ(ierr);
173395a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
173495a0b26dSToby Isaac       ierr = PetscSectionGetDof(conSec,point,&pointDof);CHKERRQ(ierr);
173595a0b26dSToby Isaac       if (!pointDof) continue;
173695a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1737085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1738085f0adfSToby Isaac         PetscInt cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
173995a0b26dSToby Isaac         PetscScalar *pointMat;
1740085f0adfSToby Isaac         const PetscInt    **perms;
1741085f0adfSToby Isaac         const PetscScalar **flips;
174295a0b26dSToby Isaac 
1743085f0adfSToby Isaac         if (numFields) {
174495a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(conSec,point,f,&cDof);CHKERRQ(ierr);
174595a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(conSec,point,f,&cOff);CHKERRQ(ierr);
174695a0b26dSToby Isaac         }
174795a0b26dSToby Isaac         else {
174895a0b26dSToby Isaac           ierr = PetscSectionGetDof(conSec,point,&cDof);CHKERRQ(ierr);
174995a0b26dSToby Isaac           ierr = PetscSectionGetOffset(conSec,point,&cOff);CHKERRQ(ierr);
175095a0b26dSToby Isaac         }
175195a0b26dSToby Isaac         if (!cDof) continue;
1752085f0adfSToby Isaac         if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);}
1753085f0adfSToby Isaac         else           {ierr = PetscSectionGetPointSyms(section,closureSize,closure,&perms,&flips);CHKERRQ(ierr);}
175495a0b26dSToby Isaac 
175595a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
175695a0b26dSToby Isaac #if defined(PETSC_USE_DEBUG)
175795a0b26dSToby Isaac         for (r = 0; r < cDof; r++) {
175895a0b26dSToby Isaac           if (cDof > 1 && r) {
175921968bf8SToby 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]));
176095a0b26dSToby Isaac           }
176195a0b26dSToby Isaac         }
176295a0b26dSToby Isaac #endif
176395a0b26dSToby Isaac         /* zero rows */
176495a0b26dSToby Isaac         for (i = ia[cOff] ; i< ia[cOff+cDof];i++) {
176595a0b26dSToby Isaac           vals[i] = 0.;
176695a0b26dSToby Isaac         }
176795a0b26dSToby Isaac         matOffset = ia[cOff];
176895a0b26dSToby Isaac         numFillCols = ia[cOff+1] - matOffset;
176995a0b26dSToby Isaac         pointMat = refPointFieldMats[childid-pRefStart][f];
177095a0b26dSToby Isaac         numCols = refPointFieldN[childid-pRefStart][f];
177195a0b26dSToby Isaac         offset = 0;
177295a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
177395a0b26dSToby Isaac           PetscInt q = closure[2*i];
177495a0b26dSToby Isaac           PetscInt aDof, aOff, j, k, qConDof, qConOff;
1775085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1776085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
177795a0b26dSToby Isaac 
177895a0b26dSToby Isaac           qConDof = qConOff = 0;
1779085f0adfSToby Isaac           if (numFields) {
178095a0b26dSToby Isaac             ierr = PetscSectionGetFieldDof(section,q,f,&aDof);CHKERRQ(ierr);
178195a0b26dSToby Isaac             ierr = PetscSectionGetFieldOffset(section,q,f,&aOff);CHKERRQ(ierr);
178295a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
178395a0b26dSToby Isaac               ierr = PetscSectionGetFieldDof(conSec,q,f,&qConDof);CHKERRQ(ierr);
178495a0b26dSToby Isaac               ierr = PetscSectionGetFieldOffset(conSec,q,f,&qConOff);CHKERRQ(ierr);
178595a0b26dSToby Isaac             }
178695a0b26dSToby Isaac           }
178795a0b26dSToby Isaac           else {
178895a0b26dSToby Isaac             ierr = PetscSectionGetDof(section,q,&aDof);CHKERRQ(ierr);
178995a0b26dSToby Isaac             ierr = PetscSectionGetOffset(section,q,&aOff);CHKERRQ(ierr);
179095a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
179195a0b26dSToby Isaac               ierr = PetscSectionGetDof(conSec,q,&qConDof);CHKERRQ(ierr);
179295a0b26dSToby Isaac               ierr = PetscSectionGetOffset(conSec,q,&qConOff);CHKERRQ(ierr);
179395a0b26dSToby Isaac             }
179495a0b26dSToby Isaac           }
179595a0b26dSToby Isaac           if (!aDof) continue;
179695a0b26dSToby Isaac           if (qConDof) {
179795a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
179895a0b26dSToby Isaac              * be filled, thanks to preordering */
179995a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
180095a0b26dSToby Isaac             PetscInt aMatOffset = ia[qConOff];
180195a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
180295a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
180395a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
180495a0b26dSToby Isaac                 PetscScalar inVal = 0;
180595a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1806085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
180795a0b26dSToby Isaac 
1808085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
180995a0b26dSToby Isaac                 }
181095a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
181195a0b26dSToby Isaac               }
181295a0b26dSToby Isaac             }
181395a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
181495a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
181595a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
181695a0b26dSToby Isaac               for (;k < numFillCols; k++) {
181795a0b26dSToby Isaac                 if (ja[matOffset + k] == col) {
181895a0b26dSToby Isaac                   break;
181995a0b26dSToby Isaac                 }
182095a0b26dSToby Isaac               }
182195a0b26dSToby Isaac               if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, col);
182295a0b26dSToby Isaac               for (r = 0; r < cDof; r++) {
182395a0b26dSToby Isaac                 vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
182495a0b26dSToby Isaac               }
182595a0b26dSToby Isaac             }
182695a0b26dSToby Isaac           }
182795a0b26dSToby Isaac           else {
182895a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
182995a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
183095a0b26dSToby Isaac               if (ja[matOffset + k] == aOff) {
183195a0b26dSToby Isaac                 break;
183295a0b26dSToby Isaac               }
183395a0b26dSToby Isaac             }
183495a0b26dSToby Isaac             if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, aOff);
183595a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1836085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1837085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1838085f0adfSToby Isaac 
1839085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
184095a0b26dSToby Isaac               }
184195a0b26dSToby Isaac             }
184295a0b26dSToby Isaac           }
184395a0b26dSToby Isaac           offset += aDof;
184495a0b26dSToby Isaac         }
1845085f0adfSToby Isaac         if (numFields) {
1846085f0adfSToby Isaac           ierr = PetscSectionRestoreFieldPointSyms(section,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1847085f0adfSToby Isaac         } else {
1848085f0adfSToby Isaac           ierr = PetscSectionRestorePointSyms(section,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1849085f0adfSToby Isaac         }
185095a0b26dSToby Isaac       }
185195a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
185295a0b26dSToby Isaac     }
185395a0b26dSToby Isaac     for (row = 0; row < nRows; row++) {
185495a0b26dSToby Isaac       ierr = MatSetValues(cMat,1,&row,ia[row+1]-ia[row],&ja[ia[row]],&vals[ia[row]],INSERT_VALUES);CHKERRQ(ierr);
185595a0b26dSToby Isaac     }
185695a0b26dSToby Isaac     ierr = MatRestoreRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
185795a0b26dSToby Isaac     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not restore RowIJ of constraint matrix");
185895a0b26dSToby Isaac     ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
185995a0b26dSToby Isaac     ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
186095a0b26dSToby Isaac     ierr = PetscFree(vals);CHKERRQ(ierr);
186195a0b26dSToby Isaac   }
186295a0b26dSToby Isaac 
186395a0b26dSToby Isaac   /* clean up */
186495a0b26dSToby Isaac   ierr = ISRestoreIndices(anIS,&anchors);CHKERRQ(ierr);
186595a0b26dSToby Isaac   ierr = PetscFree2(perm,iperm);CHKERRQ(ierr);
186695a0b26dSToby Isaac   ierr = PetscFree(pointWork);CHKERRQ(ierr);
186721968bf8SToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
186895a0b26dSToby Isaac   PetscFunctionReturn(0);
186995a0b26dSToby Isaac }
187095a0b26dSToby Isaac 
18716f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
18726f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
18736f5f1567SToby Isaac PetscErrorCode DMPlexTreeRefineCell (DM dm, PetscInt cell, DM *ncdm)
18746f5f1567SToby Isaac {
18756f5f1567SToby Isaac   DM K;
1876420f55faSMatthew G. Knepley   PetscMPIInt rank;
18776f5f1567SToby Isaac   PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
18786f5f1567SToby Isaac   PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations;
18796f5f1567SToby Isaac   PetscInt *Kembedding;
18806f5f1567SToby Isaac   PetscInt *cellClosure=NULL, nc;
18816f5f1567SToby Isaac   PetscScalar *newVertexCoords;
18826f5f1567SToby Isaac   PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
18836f5f1567SToby Isaac   PetscSection parentSection;
18846f5f1567SToby Isaac   PetscErrorCode ierr;
18856f5f1567SToby Isaac 
18866f5f1567SToby Isaac   PetscFunctionBegin;
18876f5f1567SToby Isaac   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRQ(ierr);
188828f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
18896f5f1567SToby Isaac   ierr = DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm);CHKERRQ(ierr);
189028f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ncdm,dim);CHKERRQ(ierr);
18916f5f1567SToby Isaac 
18926f5f1567SToby Isaac   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
18936f5f1567SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&parentSection);CHKERRQ(ierr);
18946f5f1567SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&K);CHKERRQ(ierr);
18956f5f1567SToby Isaac   if (!rank) {
18966f5f1567SToby Isaac     /* compute the new charts */
18976f5f1567SToby Isaac     ierr = PetscMalloc5(dim+1,&pNewCount,dim+1,&pNewStart,dim+1,&pNewEnd,dim+1,&pOldStart,dim+1,&pOldEnd);CHKERRQ(ierr);
18986f5f1567SToby Isaac     offset = 0;
18996f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19006f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
19016f5f1567SToby Isaac 
19026f5f1567SToby Isaac       pNewStart[d] = offset;
19036f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(dm,d,&pOldStart[d],&pOldEnd[d]);CHKERRQ(ierr);
19046f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
19056f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
19066f5f1567SToby Isaac       /* adding the new points */
19076f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
19086f5f1567SToby Isaac       if (!d) {
19096f5f1567SToby Isaac         /* removing the cell */
19106f5f1567SToby Isaac         pNewCount[d]--;
19116f5f1567SToby Isaac       }
19126f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19136f5f1567SToby Isaac         PetscInt parent;
19146f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&parent,NULL);CHKERRQ(ierr);
19156f5f1567SToby Isaac         if (parent == k) {
19166f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
19176f5f1567SToby Isaac           pNewCount[d]--;
19186f5f1567SToby Isaac         }
19196f5f1567SToby Isaac       }
19206f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
19216f5f1567SToby Isaac       offset = pNewEnd[d];
19226f5f1567SToby Isaac 
19236f5f1567SToby Isaac     }
19246f5f1567SToby 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]);
19256f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
19266f5f1567SToby Isaac     ierr = DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
19276f5f1567SToby Isaac 
19286f5f1567SToby Isaac     ierr = PetscMalloc1(pNewEnd[dim],&newConeSizes);CHKERRQ(ierr);
19296f5f1567SToby Isaac     {
19306f5f1567SToby Isaac       PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
19316f5f1567SToby Isaac 
19326f5f1567SToby Isaac       ierr = DMPlexGetChart(K,&kStart,&kEnd);CHKERRQ(ierr);
19336f5f1567SToby Isaac       ierr = PetscMalloc4(kEnd-kStart,&Kembedding,kEnd-kStart,&perm,kEnd-kStart,&iperm,kEnd-kStart,&preOrient);CHKERRQ(ierr);
19346f5f1567SToby Isaac 
19356f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19366f5f1567SToby Isaac         perm[k - kStart] = k;
19376f5f1567SToby Isaac         iperm [k - kStart] = k - kStart;
19386f5f1567SToby Isaac         preOrient[k - kStart] = 0;
19396f5f1567SToby Isaac       }
19406f5f1567SToby Isaac 
19416f5f1567SToby Isaac       ierr = DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
19426f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
19436f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2*j+1];
19446f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2*j+1];
19456f5f1567SToby Isaac         PetscInt p, q;
19466f5f1567SToby Isaac 
19476f5f1567SToby Isaac         p = closureK[2*j];
19486f5f1567SToby Isaac         q = cellClosure[2*j];
19496f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
19506f5f1567SToby Isaac           if (q >= pOldStart[d] && q < pOldEnd[d]) {
19516f5f1567SToby Isaac             Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
19526f5f1567SToby Isaac           }
19536f5f1567SToby Isaac         }
19546f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
19556f5f1567SToby Isaac           PetscInt numChildren, i;
19566f5f1567SToby Isaac           const PetscInt *children;
19576f5f1567SToby Isaac 
19586f5f1567SToby Isaac           ierr = DMPlexGetTreeChildren(K,p,&numChildren,&children);CHKERRQ(ierr);
19596f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
19606f5f1567SToby Isaac             PetscInt kPerm, oPerm;
19616f5f1567SToby Isaac 
19626f5f1567SToby Isaac             k    = children[i];
19636f5f1567SToby Isaac             ierr = DMPlexReferenceTreeGetChildSymmetry(K,p,parentOrientA,0,k,parentOrientB,&oPerm,&kPerm);CHKERRQ(ierr);
19646f5f1567SToby Isaac             /* perm = what refTree position I'm in */
19656f5f1567SToby Isaac             perm[kPerm-kStart]      = k;
19666f5f1567SToby Isaac             /* iperm = who is at this position */
19676f5f1567SToby Isaac             iperm[k-kStart]         = kPerm-kStart;
19686f5f1567SToby Isaac             preOrient[kPerm-kStart] = oPerm;
19696f5f1567SToby Isaac           }
19706f5f1567SToby Isaac         }
19716f5f1567SToby Isaac       }
19726f5f1567SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
19736f5f1567SToby Isaac     }
19746f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,0,pNewEnd[dim]);CHKERRQ(ierr);
19756f5f1567SToby Isaac     offset = 0;
19766f5f1567SToby Isaac     numNewCones = 0;
19776f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19786f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
19796f5f1567SToby Isaac       PetscInt p;
19806f5f1567SToby Isaac       PetscInt size;
19816f5f1567SToby Isaac 
19826f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19836f5f1567SToby Isaac         /* skip cell 0 */
19846f5f1567SToby Isaac         if (p == cell) continue;
19856f5f1567SToby Isaac         /* old cones to new cones */
19866f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
19876f5f1567SToby Isaac         newConeSizes[offset++] = size;
19886f5f1567SToby Isaac         numNewCones += size;
19896f5f1567SToby Isaac       }
19906f5f1567SToby Isaac 
19916f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
19926f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19936f5f1567SToby Isaac         PetscInt kParent;
19946f5f1567SToby Isaac 
19956f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
19966f5f1567SToby Isaac         if (kParent != k) {
19976f5f1567SToby Isaac           Kembedding[k] = offset;
19986f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
19996f5f1567SToby Isaac           newConeSizes[offset++] = size;
20006f5f1567SToby Isaac           numNewCones += size;
20016f5f1567SToby Isaac           if (kParent != 0) {
20026f5f1567SToby Isaac             ierr = PetscSectionSetDof(parentSection,Kembedding[k],1);CHKERRQ(ierr);
20036f5f1567SToby Isaac           }
20046f5f1567SToby Isaac         }
20056f5f1567SToby Isaac       }
20066f5f1567SToby Isaac     }
20076f5f1567SToby Isaac 
20086f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
20096f5f1567SToby Isaac     ierr = PetscSectionGetStorageSize(parentSection,&numPointsWithParents);CHKERRQ(ierr);
20106f5f1567SToby Isaac     ierr = PetscMalloc2(numNewCones,&newCones,numNewCones,&newOrientations);CHKERRQ(ierr);
20116f5f1567SToby Isaac     ierr = PetscMalloc2(numPointsWithParents,&parents,numPointsWithParents,&childIDs);CHKERRQ(ierr);
20126f5f1567SToby Isaac 
20136f5f1567SToby Isaac     /* fill new cones */
20146f5f1567SToby Isaac     offset = 0;
20156f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20166f5f1567SToby Isaac       PetscInt kStart, kEnd, k, l;
20176f5f1567SToby Isaac       PetscInt p;
20186f5f1567SToby Isaac       PetscInt size;
20196f5f1567SToby Isaac       const PetscInt *cone, *orientation;
20206f5f1567SToby Isaac 
20216f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
20226f5f1567SToby Isaac         /* skip cell 0 */
20236f5f1567SToby Isaac         if (p == cell) continue;
20246f5f1567SToby Isaac         /* old cones to new cones */
20256f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
20266f5f1567SToby Isaac         ierr = DMPlexGetCone(dm,p,&cone);CHKERRQ(ierr);
20276f5f1567SToby Isaac         ierr = DMPlexGetConeOrientation(dm,p,&orientation);CHKERRQ(ierr);
20286f5f1567SToby Isaac         for (l = 0; l < size; l++) {
20296f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
20306f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
20316f5f1567SToby Isaac         }
20326f5f1567SToby Isaac       }
20336f5f1567SToby Isaac 
20346f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
20356f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20366f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
20376f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
20386f5f1567SToby Isaac 
20396f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
20406f5f1567SToby Isaac         if (kParent != k) {
20416f5f1567SToby Isaac           /* embed new cones */
20426f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
20436f5f1567SToby Isaac           ierr = DMPlexGetCone(K,kPerm,&cone);CHKERRQ(ierr);
20446f5f1567SToby Isaac           ierr = DMPlexGetConeOrientation(K,kPerm,&orientation);CHKERRQ(ierr);
20456f5f1567SToby Isaac           for (l = 0; l < size; l++) {
20466f5f1567SToby Isaac             PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size -(preO + 1) - l) % size);
20476f5f1567SToby Isaac             PetscInt newO, lSize, oTrue;
20486f5f1567SToby Isaac 
20496f5f1567SToby Isaac             q                         = iperm[cone[m]];
20506f5f1567SToby Isaac             newCones[offset]          = Kembedding[q];
20516f5f1567SToby Isaac             ierr                      = DMPlexGetConeSize(K,q,&lSize);CHKERRQ(ierr);
20526f5f1567SToby Isaac             oTrue                     = orientation[m];
20536f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
20546f5f1567SToby Isaac             newO                      = DihedralCompose(lSize,oTrue,preOrient[q]);
20556f5f1567SToby Isaac             newOrientations[offset++] = newO;
20566f5f1567SToby Isaac           }
20576f5f1567SToby Isaac           if (kParent != 0) {
20586f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
20596f5f1567SToby Isaac             ierr              = PetscSectionGetOffset(parentSection,Kembedding[k],&pOffset);CHKERRQ(ierr);
20606f5f1567SToby Isaac             parents[pOffset]  = newPoint;
20616f5f1567SToby Isaac             childIDs[pOffset] = k;
20626f5f1567SToby Isaac           }
20636f5f1567SToby Isaac         }
20646f5f1567SToby Isaac       }
20656f5f1567SToby Isaac     }
20666f5f1567SToby Isaac 
20676f5f1567SToby Isaac     ierr = PetscMalloc1(dim*(pNewEnd[dim]-pNewStart[dim]),&newVertexCoords);CHKERRQ(ierr);
20686f5f1567SToby Isaac 
20696f5f1567SToby Isaac     /* fill coordinates */
20706f5f1567SToby Isaac     offset = 0;
20716f5f1567SToby Isaac     {
2072d90620a3SMatthew G. Knepley       PetscInt kStart, kEnd, l;
20736f5f1567SToby Isaac       PetscSection vSection;
20746f5f1567SToby Isaac       PetscInt v;
20756f5f1567SToby Isaac       Vec coords;
20766f5f1567SToby Isaac       PetscScalar *coordvals;
20776f5f1567SToby Isaac       PetscInt dof, off;
2078c111c6b7SMatthew G. Knepley       PetscReal v0[3], J[9], detJ;
20796f5f1567SToby Isaac 
20806f5f1567SToby Isaac #if defined(PETSC_USE_DEBUG)
2081d90620a3SMatthew G. Knepley       {
2082d90620a3SMatthew G. Knepley         PetscInt k;
20836f5f1567SToby Isaac         ierr = DMPlexGetHeightStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
20846f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
208573a7f2aaSMatthew G. Knepley           ierr = DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
20866f5f1567SToby Isaac           if (detJ <= 0.) SETERRQ1 (PETSC_COMM_SELF,PETSC_ERR_PLIB,"reference tree cell %d has bad determinant",k);
20876f5f1567SToby Isaac         }
2088d90620a3SMatthew G. Knepley       }
20896f5f1567SToby Isaac #endif
209073a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
20916f5f1567SToby Isaac       ierr = DMGetCoordinateSection(dm,&vSection);CHKERRQ(ierr);
20926f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr);
20936f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
20946f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
20956f5f1567SToby Isaac 
20966f5f1567SToby Isaac         ierr = PetscSectionGetDof(vSection,v,&dof);CHKERRQ(ierr);
20976f5f1567SToby Isaac         ierr = PetscSectionGetOffset(vSection,v,&off);CHKERRQ(ierr);
20986f5f1567SToby Isaac         for (l = 0; l < dof; l++) {
20996f5f1567SToby Isaac           newVertexCoords[offset++] = coordvals[off + l];
21006f5f1567SToby Isaac         }
21016f5f1567SToby Isaac       }
21026f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21036f5f1567SToby Isaac 
21046f5f1567SToby Isaac       ierr = DMGetCoordinateSection(K,&vSection);CHKERRQ(ierr);
21056f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(K,&coords);CHKERRQ(ierr);
21066f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
21076f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
21086f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
21099bc368c7SMatthew G. Knepley         PetscReal coord[3], newCoord[3];
21106f5f1567SToby Isaac         PetscInt  vPerm = perm[v];
21116f5f1567SToby Isaac         PetscInt  kParent;
21126f5f1567SToby Isaac 
21136f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,v,&kParent,NULL);CHKERRQ(ierr);
21146f5f1567SToby Isaac         if (kParent != v) {
21156f5f1567SToby Isaac           /* this is a new vertex */
21166f5f1567SToby Isaac           ierr = PetscSectionGetOffset(vSection,vPerm,&off);CHKERRQ(ierr);
21179bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off+l]);
21189bc368c7SMatthew G. Knepley           CoordinatesRefToReal(dim, dim, v0, J, coord, newCoord);CHKERRQ(ierr);
21199bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset+l] = newCoord[l];
21206f5f1567SToby Isaac           offset += dim;
21216f5f1567SToby Isaac         }
21226f5f1567SToby Isaac       }
21236f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21246f5f1567SToby Isaac     }
21256f5f1567SToby Isaac 
21266f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
21276f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
21286f5f1567SToby Isaac       PetscInt tmp;
21296f5f1567SToby Isaac 
21306f5f1567SToby Isaac       tmp = pNewCount[d];
21316f5f1567SToby Isaac       pNewCount[d] = pNewCount[dim - d];
21326f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
21336f5f1567SToby Isaac     }
21346f5f1567SToby Isaac 
21356f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,pNewCount,newConeSizes,newCones,newOrientations,newVertexCoords);CHKERRQ(ierr);
21366f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
21376f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,parents,childIDs);CHKERRQ(ierr);
21386f5f1567SToby Isaac 
21396f5f1567SToby Isaac     /* clean up */
21406f5f1567SToby Isaac     ierr = DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
21416f5f1567SToby Isaac     ierr = PetscFree5(pNewCount,pNewStart,pNewEnd,pOldStart,pOldEnd);CHKERRQ(ierr);
21426f5f1567SToby Isaac     ierr = PetscFree(newConeSizes);CHKERRQ(ierr);
21436f5f1567SToby Isaac     ierr = PetscFree2(newCones,newOrientations);CHKERRQ(ierr);
21446f5f1567SToby Isaac     ierr = PetscFree(newVertexCoords);CHKERRQ(ierr);
21456f5f1567SToby Isaac     ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
21466f5f1567SToby Isaac     ierr = PetscFree4(Kembedding,perm,iperm,preOrient);CHKERRQ(ierr);
21476f5f1567SToby Isaac   }
21486f5f1567SToby Isaac   else {
21496f5f1567SToby Isaac     PetscInt    p, counts[4];
21506f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
21516f5f1567SToby Isaac     Vec         coordVec;
21526f5f1567SToby Isaac     PetscScalar *coords;
21536f5f1567SToby Isaac 
21546f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
21556f5f1567SToby Isaac       PetscInt dStart, dEnd;
21566f5f1567SToby Isaac 
21576f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
21586f5f1567SToby Isaac       counts[d] = dEnd - dStart;
21596f5f1567SToby Isaac     }
21606f5f1567SToby Isaac     ierr = PetscMalloc1(pEnd-pStart,&coneSizes);CHKERRQ(ierr);
21616f5f1567SToby Isaac     for (p = pStart; p < pEnd; p++) {
21626f5f1567SToby Isaac       ierr = DMPlexGetConeSize(dm,p,&coneSizes[p-pStart]);CHKERRQ(ierr);
21636f5f1567SToby Isaac     }
21646f5f1567SToby Isaac     ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
21656f5f1567SToby Isaac     ierr = DMPlexGetConeOrientations(dm, &orientations);CHKERRQ(ierr);
21666f5f1567SToby Isaac     ierr = DMGetCoordinatesLocal(dm,&coordVec);CHKERRQ(ierr);
21676f5f1567SToby Isaac     ierr = VecGetArray(coordVec,&coords);CHKERRQ(ierr);
21686f5f1567SToby Isaac 
21696f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,pStart,pEnd);CHKERRQ(ierr);
21706f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
21716f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,counts,coneSizes,cones,orientations,NULL);CHKERRQ(ierr);
21726f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
21736f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,NULL,NULL);CHKERRQ(ierr);
21746f5f1567SToby Isaac     ierr = VecRestoreArray(coordVec,&coords);CHKERRQ(ierr);
21756f5f1567SToby Isaac   }
21766f5f1567SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
21776f5f1567SToby Isaac 
21786f5f1567SToby Isaac   PetscFunctionReturn(0);
21796f5f1567SToby Isaac }
21806ecaa68aSToby Isaac 
21816ecaa68aSToby Isaac PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
21826ecaa68aSToby Isaac {
21836ecaa68aSToby Isaac   PetscSF           coarseToFineEmbedded;
21846ecaa68aSToby Isaac   PetscSection      globalCoarse, globalFine;
21856ecaa68aSToby Isaac   PetscSection      localCoarse, localFine;
21866ecaa68aSToby Isaac   PetscSection      aSec, cSec;
21876ecaa68aSToby Isaac   PetscSection      rootIndicesSec, rootMatricesSec;
218846bdb399SToby Isaac   PetscSection      leafIndicesSec, leafMatricesSec;
218946bdb399SToby Isaac   PetscInt          *rootIndices, *leafIndices;
219046bdb399SToby Isaac   PetscScalar       *rootMatrices, *leafMatrices;
21916ecaa68aSToby Isaac   IS                aIS;
21926ecaa68aSToby Isaac   const PetscInt    *anchors;
21936ecaa68aSToby Isaac   Mat               cMat;
21944acb8e1eSToby Isaac   PetscInt          numFields, maxFields;
21956ecaa68aSToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p;
21966ecaa68aSToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
21971c58ffc4SToby Isaac   PetscInt          *maxChildIds;
2198e44e4e7fSToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
21994acb8e1eSToby Isaac   const PetscInt    ***perms;
22004acb8e1eSToby Isaac   const PetscScalar ***flips;
22016ecaa68aSToby Isaac   PetscErrorCode    ierr;
22026ecaa68aSToby Isaac 
22036ecaa68aSToby Isaac   PetscFunctionBegin;
22046ecaa68aSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
22056ecaa68aSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
22066ecaa68aSToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
22076ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
220889698031SToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
220989698031SToby Isaac     const PetscInt *leaves;
22106ecaa68aSToby Isaac 
221189698031SToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
221289698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
221389698031SToby Isaac       p = leaves ? leaves[l] : l;
22146ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22156ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22166ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
22176ecaa68aSToby Isaac         numPointsWithDofs++;
22186ecaa68aSToby Isaac       }
22196ecaa68aSToby Isaac     }
22206ecaa68aSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
22217cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
222289698031SToby Isaac       p = leaves ? leaves[l] : l;
22236ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22246ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22256ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
222689698031SToby Isaac         pointsWithDofs[offset++] = l;
22276ecaa68aSToby Isaac       }
22286ecaa68aSToby Isaac     }
22296ecaa68aSToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
2230ec92bd66SToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
22316ecaa68aSToby Isaac   }
22326ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
22336ecaa68aSToby Isaac   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
22346ecaa68aSToby Isaac   for (p = pStartC; p < pEndC; p++) {
22358d2f55e7SToby Isaac     maxChildIds[p - pStartC] = -2;
22366ecaa68aSToby Isaac   }
22376ecaa68aSToby Isaac   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
22386ecaa68aSToby Isaac   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
223946bdb399SToby Isaac 
22406ecaa68aSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
22416ecaa68aSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
224246bdb399SToby Isaac 
22436ecaa68aSToby Isaac   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
22446ecaa68aSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
22456ecaa68aSToby Isaac   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
224646bdb399SToby Isaac 
22476ecaa68aSToby Isaac   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
22486ecaa68aSToby Isaac   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
224946bdb399SToby Isaac 
225046bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
22516ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
22526ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootMatricesSec);CHKERRQ(ierr);
22536ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootIndicesSec,pStartC,pEndC);CHKERRQ(ierr);
22546ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootMatricesSec,pStartC,pEndC);CHKERRQ(ierr);
2255708c7f19SToby Isaac   ierr = PetscSectionGetNumFields(localCoarse,&numFields);CHKERRQ(ierr);
2256713c1c5dSToby Isaac   maxFields = PetscMax(1,numFields);
2257713c1c5dSToby 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);
2258713c1c5dSToby Isaac   ierr = PetscMalloc2(maxFields+1,&perms,maxFields+1,&flips);CHKERRQ(ierr);
2259713c1c5dSToby Isaac   ierr = PetscMemzero((void *) perms, (maxFields+1) * sizeof(const PetscInt **));CHKERRQ(ierr);
2260713c1c5dSToby Isaac   ierr = PetscMemzero((void *) flips, (maxFields+1) * sizeof(const PetscScalar **));CHKERRQ(ierr);
226146bdb399SToby Isaac 
226246bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
22638d2f55e7SToby Isaac     PetscInt dof, matSize   = 0;
22646ecaa68aSToby Isaac     PetscInt aDof           = 0;
22656ecaa68aSToby Isaac     PetscInt cDof           = 0;
22666ecaa68aSToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
22676ecaa68aSToby Isaac     PetscInt numRowIndices  = 0;
22686ecaa68aSToby Isaac     PetscInt numColIndices  = 0;
2269f13f9184SToby Isaac     PetscInt f;
22706ecaa68aSToby Isaac 
22716ecaa68aSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
22721cfc5b76SToby Isaac     if (dof < 0) {
22731cfc5b76SToby Isaac       dof = -(dof + 1);
22741cfc5b76SToby Isaac     }
22756ecaa68aSToby Isaac     if (p >= aStart && p < aEnd) {
22766ecaa68aSToby Isaac       ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
22776ecaa68aSToby Isaac     }
22786ecaa68aSToby Isaac     if (p >= cStart && p < cEnd) {
22796ecaa68aSToby Isaac       ierr = PetscSectionGetDof(cSec,p,&cDof);CHKERRQ(ierr);
22806ecaa68aSToby Isaac     }
2281f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2282f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
22836ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2284f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
22856ecaa68aSToby Isaac 
22866ecaa68aSToby Isaac       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
228746bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
22886ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
22896ecaa68aSToby Isaac 
22906ecaa68aSToby Isaac         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
22916ecaa68aSToby Isaac         numRowIndices += clDof;
22926ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
22936ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,c,f,&clDof);CHKERRQ(ierr);
22946ecaa68aSToby Isaac           offsets[f + 1] += clDof;
22956ecaa68aSToby Isaac         }
22966ecaa68aSToby Isaac       }
22976ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
22986ecaa68aSToby Isaac         offsets[f + 1]   += offsets[f];
22996ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
23006ecaa68aSToby Isaac       }
230146bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
23024acb8e1eSToby Isaac       ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,NULL,NULL,NULL,&numColIndices,NULL,NULL,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
23036ecaa68aSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
23046ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
23056ecaa68aSToby Isaac         numColIndices = numRowIndices;
23066ecaa68aSToby Isaac         matSize = 0;
23076ecaa68aSToby Isaac       }
230846bdb399SToby Isaac       else if (numFields) { /* we send one submat for each field: sum their sizes */
23096ecaa68aSToby Isaac         matSize = 0;
23106ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23116ecaa68aSToby Isaac           PetscInt numRow, numCol;
23126ecaa68aSToby Isaac 
23136ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2314f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
23156ecaa68aSToby Isaac           matSize += numRow * numCol;
23166ecaa68aSToby Isaac         }
23176ecaa68aSToby Isaac       }
23186ecaa68aSToby Isaac       else {
23196ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
23206ecaa68aSToby Isaac       }
2321f13f9184SToby Isaac     } else if (maxChildId == -1) {
23228d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2323f13f9184SToby Isaac         PetscInt aOff, a;
23246ecaa68aSToby Isaac 
23256ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
23266ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23276ecaa68aSToby Isaac           PetscInt fDof;
23286ecaa68aSToby Isaac 
23296ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
233021968bf8SToby Isaac           offsets[f+1] = fDof;
23316ecaa68aSToby Isaac         }
23326ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
23336ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
23346ecaa68aSToby Isaac 
23356ecaa68aSToby Isaac           ierr = PetscSectionGetDof(localCoarse,anchor,&aLocalDof);CHKERRQ(ierr);
23366ecaa68aSToby Isaac           numColIndices += aLocalDof;
23376ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23386ecaa68aSToby Isaac             PetscInt fDof;
23396ecaa68aSToby Isaac 
23406ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
234121968bf8SToby Isaac             newOffsets[f+1] += fDof;
23426ecaa68aSToby Isaac           }
23436ecaa68aSToby Isaac         }
23446ecaa68aSToby Isaac         if (numFields) {
23456ecaa68aSToby Isaac           matSize = 0;
23466ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
234721968bf8SToby Isaac             matSize += offsets[f+1] * newOffsets[f+1];
23486ecaa68aSToby Isaac           }
23496ecaa68aSToby Isaac         }
23506ecaa68aSToby Isaac         else {
23516ecaa68aSToby Isaac           matSize = numColIndices * dof;
23526ecaa68aSToby Isaac         }
23536ecaa68aSToby Isaac       }
23546ecaa68aSToby Isaac       else { /* no children, and no constraints on dofs: just get the global indices */
23556ecaa68aSToby Isaac         numColIndices = dof;
23566ecaa68aSToby Isaac         matSize       = 0;
23576ecaa68aSToby Isaac       }
23588d2f55e7SToby Isaac     }
235946bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
23606ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootIndicesSec,p,numColIndices ? numColIndices+2*numFields : 0);CHKERRQ(ierr);
23616ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootMatricesSec,p,matSize);CHKERRQ(ierr);
23626ecaa68aSToby Isaac   }
23636ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootIndicesSec);CHKERRQ(ierr);
23646ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootMatricesSec);CHKERRQ(ierr);
23656ecaa68aSToby Isaac   {
23666ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
23676ecaa68aSToby Isaac 
23686ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
23696ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootMatricesSec,&numRootMatrices);CHKERRQ(ierr);
23706ecaa68aSToby Isaac     ierr = PetscMalloc2(numRootIndices,&rootIndices,numRootMatrices,&rootMatrices);CHKERRQ(ierr);
23716ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
23726ecaa68aSToby Isaac       PetscInt    numRowIndices, numColIndices, matSize, dof;
2373f13f9184SToby Isaac       PetscInt    pIndOff, pMatOff, f;
23746ecaa68aSToby Isaac       PetscInt    *pInd;
23756ecaa68aSToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
23766ecaa68aSToby Isaac       PetscScalar *pMat = NULL;
23776ecaa68aSToby Isaac 
23786ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,p,&numColIndices);CHKERRQ(ierr);
23796ecaa68aSToby Isaac       if (!numColIndices) {
23806ecaa68aSToby Isaac         continue;
23816ecaa68aSToby Isaac       }
2382f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2383f13f9184SToby Isaac         offsets[f]        = 0;
2384f13f9184SToby Isaac         newOffsets[f]     = 0;
2385f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2386f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2387f13f9184SToby Isaac       }
23886ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
23896ecaa68aSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,p,&pIndOff);CHKERRQ(ierr);
23906ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
23916ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootMatricesSec,p,&matSize);CHKERRQ(ierr);
23926ecaa68aSToby Isaac       if (matSize) {
23936ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(rootMatricesSec,p,&pMatOff);CHKERRQ(ierr);
23946ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
23956ecaa68aSToby Isaac       }
23966ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
23971cfc5b76SToby Isaac       if (dof < 0) {
23981cfc5b76SToby Isaac         dof = -(dof + 1);
23991cfc5b76SToby Isaac       }
24006ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
24016ecaa68aSToby Isaac         PetscInt i, j;
24026ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
24036ecaa68aSToby Isaac 
24046ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
24056ecaa68aSToby Isaac           PetscInt numIndices, *indices;
24066ecaa68aSToby Isaac           ierr = DMPlexGetClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
24076ecaa68aSToby Isaac           if (numIndices != numColIndices) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"mismatching constraint indices calculations");
24086ecaa68aSToby Isaac           for (i = 0; i < numColIndices; i++) {
24096ecaa68aSToby Isaac             pInd[i] = indices[i];
24106ecaa68aSToby Isaac           }
24116ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
241246bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i+1];
241346bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i+1];
24146ecaa68aSToby Isaac           }
241546bdb399SToby Isaac           ierr = DMPlexRestoreClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
24166ecaa68aSToby Isaac         }
24176ecaa68aSToby Isaac         else {
24186ecaa68aSToby Isaac           PetscInt closureSize, *closure = NULL, cl;
24196ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
24206ecaa68aSToby Isaac           PetscInt numPoints,*points;
24216ecaa68aSToby Isaac 
24226ecaa68aSToby Isaac           ierr = DMGetWorkArray(coarse,numRowIndices * numRowIndices,PETSC_SCALAR,&pMatIn);CHKERRQ(ierr);
24236ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
24246ecaa68aSToby Isaac             for (j = 0; j < numRowIndices; j++) {
24256ecaa68aSToby Isaac               pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
24266ecaa68aSToby Isaac             }
24276ecaa68aSToby Isaac           }
24286ecaa68aSToby Isaac           ierr = DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
24294acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24304acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionGetFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24314acb8e1eSToby Isaac             else           {ierr = PetscSectionGetPointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24324acb8e1eSToby Isaac           }
24336ecaa68aSToby Isaac           if (numFields) {
24346ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
24356ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
24366ecaa68aSToby Isaac 
24376ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
24386ecaa68aSToby Isaac                 PetscInt fDof;
24396ecaa68aSToby Isaac 
24406ecaa68aSToby Isaac                 ierr = PetscSectionGetFieldDof(localCoarse,c,f,&fDof);CHKERRQ(ierr);
24416ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
24426ecaa68aSToby Isaac               }
24436ecaa68aSToby Isaac             }
24446ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
24456ecaa68aSToby Isaac               offsets[f + 1]   += offsets[f];
24466ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
24476ecaa68aSToby Isaac             }
24486ecaa68aSToby Isaac           }
24494acb8e1eSToby Isaac           /* TODO : flips here ? */
24506ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
24514acb8e1eSToby Isaac           ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,perms,pMatIn,&numPoints,NULL,&points,&pMatModified,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
24524acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24534acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24544acb8e1eSToby Isaac             else           {ierr = PetscSectionRestorePointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24554acb8e1eSToby Isaac           }
24564acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24574acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionGetFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
24584acb8e1eSToby Isaac             else           {ierr = PetscSectionGetPointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
24594acb8e1eSToby Isaac           }
24606ecaa68aSToby Isaac           if (!numFields) {
24616ecaa68aSToby Isaac             for (i = 0; i < numRowIndices * numColIndices; i++) {
24626ecaa68aSToby Isaac               pMat[i] = pMatModified[i];
24636ecaa68aSToby Isaac             }
24646ecaa68aSToby Isaac           }
24656ecaa68aSToby Isaac           else {
2466f13f9184SToby Isaac             PetscInt i, j, count;
24676ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
24686ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f+1]; i++) {
24696ecaa68aSToby Isaac                 for (j = newOffsets[f]; j < newOffsets[f+1]; j++, count++) {
24706ecaa68aSToby Isaac                   pMat[count] = pMatModified[i * numColIndices + j];
24716ecaa68aSToby Isaac                 }
24726ecaa68aSToby Isaac               }
24736ecaa68aSToby Isaac             }
24746ecaa68aSToby Isaac           }
24756ecaa68aSToby Isaac           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,PETSC_SCALAR,&pMatModified);CHKERRQ(ierr);
24766ecaa68aSToby Isaac           ierr = DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
24776ecaa68aSToby Isaac           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,PETSC_SCALAR,&pMatIn);CHKERRQ(ierr);
24786ecaa68aSToby Isaac           if (numFields) {
247946bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
248046bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f+1];
248146bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f+1];
24826ecaa68aSToby Isaac             }
24834acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
24844acb8e1eSToby Isaac               PetscInt globalOff, c = points[2*cl];
24856ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
24864acb8e1eSToby Isaac               DMPlexGetIndicesPointFields_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, pInd);
24876ecaa68aSToby Isaac             }
24886ecaa68aSToby Isaac           } else {
24894acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
24904acb8e1eSToby Isaac               PetscInt c = points[2*cl], globalOff;
24914acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
24924acb8e1eSToby Isaac 
24936ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
24944acb8e1eSToby Isaac               DMPlexGetIndicesPoint_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perm, pInd);
24956ecaa68aSToby Isaac             }
24966ecaa68aSToby Isaac           }
24974acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24984acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
24994acb8e1eSToby Isaac             else           {ierr = PetscSectionRestorePointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
25004acb8e1eSToby Isaac           }
250128552ed4SToby Isaac           ierr = DMRestoreWorkArray(coarse,numPoints,PETSC_SCALAR,&points);CHKERRQ(ierr);
25026ecaa68aSToby Isaac         }
25036ecaa68aSToby Isaac       }
25046ecaa68aSToby Isaac       else if (matSize) {
25056ecaa68aSToby Isaac         PetscInt cOff;
25066ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
25076ecaa68aSToby Isaac 
25086ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
2509628cbfb8SToby Isaac         if (numRowIndices != dof) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Miscounted dofs");
25106ecaa68aSToby Isaac         ierr = DMGetWorkArray(coarse,numRowIndices,PETSC_INT,&rowIndices);CHKERRQ(ierr);
25116ecaa68aSToby Isaac         ierr = DMGetWorkArray(coarse,numColIndices,PETSC_INT,&colIndices);CHKERRQ(ierr);
25126ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(cSec,p,&cOff);CHKERRQ(ierr);
25136ecaa68aSToby Isaac         ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
25146ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
25156ecaa68aSToby Isaac         if (numFields) {
25166ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25176ecaa68aSToby Isaac             PetscInt fDof;
2518f13f9184SToby Isaac 
25196ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(cSec,p,f,&fDof);CHKERRQ(ierr);
25206ecaa68aSToby Isaac             offsets[f + 1] = fDof;
25216ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
25226ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
25236ecaa68aSToby Isaac               ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
25246ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
25256ecaa68aSToby Isaac             }
25266ecaa68aSToby Isaac           }
25276ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25286ecaa68aSToby Isaac             offsets[f + 1]       += offsets[f];
25296ecaa68aSToby Isaac             offsetsCopy[f + 1]    = offsets[f + 1];
25306ecaa68aSToby Isaac             newOffsets[f + 1]    += newOffsets[f];
25316ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
25326ecaa68aSToby Isaac           }
25334acb8e1eSToby Isaac           DMPlexGetIndicesPointFields_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,NULL,-1,rowIndices);CHKERRQ(ierr);
25346ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25356ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25366ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
25374acb8e1eSToby Isaac             DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL,-1,colIndices);CHKERRQ(ierr);
25386ecaa68aSToby Isaac           }
25396ecaa68aSToby Isaac         }
25406ecaa68aSToby Isaac         else {
25414acb8e1eSToby Isaac           DMPlexGetIndicesPoint_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,NULL,rowIndices);CHKERRQ(ierr);
25426ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25436ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25446ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
25454acb8e1eSToby Isaac             DMPlexGetIndicesPoint_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL,colIndices);CHKERRQ(ierr);
25466ecaa68aSToby Isaac           }
25476ecaa68aSToby Isaac         }
25486ecaa68aSToby Isaac         if (numFields) {
2549f13f9184SToby Isaac           PetscInt count, a;
2550f13f9184SToby Isaac 
25516ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
25526ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
25536ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
25546ecaa68aSToby Isaac             ierr = MatGetValues(cMat,iSize,&rowIndices[offsets[f]],jSize,&colIndices[newOffsets[f]],&pMat[count]);CHKERRQ(ierr);
25556ecaa68aSToby Isaac             count += iSize * jSize;
255646bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
255746bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f+1];
25586ecaa68aSToby Isaac           }
25596ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25606ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25616ecaa68aSToby Isaac             PetscInt gOff;
25626ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
25634acb8e1eSToby Isaac             DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL,-1,pInd);CHKERRQ(ierr);
25646ecaa68aSToby Isaac           }
25656ecaa68aSToby Isaac         }
25666ecaa68aSToby Isaac         else {
25676ecaa68aSToby Isaac           PetscInt a;
25686ecaa68aSToby Isaac           ierr = MatGetValues(cMat,numRowIndices,rowIndices,numColIndices,colIndices,pMat);CHKERRQ(ierr);
25696ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25706ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25716ecaa68aSToby Isaac             PetscInt gOff;
25726ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
25734acb8e1eSToby Isaac             DMPlexGetIndicesPoint_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL,pInd);CHKERRQ(ierr);
25746ecaa68aSToby Isaac           }
25756ecaa68aSToby Isaac         }
25766ecaa68aSToby Isaac         ierr = DMRestoreWorkArray(coarse,numColIndices,PETSC_INT,&colIndices);CHKERRQ(ierr);
25776ecaa68aSToby Isaac         ierr = DMRestoreWorkArray(coarse,numRowIndices,PETSC_INT,&rowIndices);CHKERRQ(ierr);
25786ecaa68aSToby Isaac       }
25796ecaa68aSToby Isaac       else {
25806ecaa68aSToby Isaac         PetscInt gOff;
25816ecaa68aSToby Isaac 
25826ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
25836ecaa68aSToby Isaac         if (numFields) {
25846ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25856ecaa68aSToby Isaac             PetscInt fDof;
25866ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
25876ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
25886ecaa68aSToby Isaac           }
25896ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
259046bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
259146bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f+1];
25926ecaa68aSToby Isaac           }
25934acb8e1eSToby Isaac           DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1,pInd);CHKERRQ(ierr);
25946ecaa68aSToby Isaac         }
25956ecaa68aSToby Isaac         else {
25964acb8e1eSToby Isaac           DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,pInd);CHKERRQ(ierr);
25976ecaa68aSToby Isaac         }
25986ecaa68aSToby Isaac       }
25996ecaa68aSToby Isaac     }
2600e44e4e7fSToby Isaac     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
26016ecaa68aSToby Isaac   }
260246bdb399SToby Isaac   {
260346bdb399SToby Isaac     PetscSF  indicesSF, matricesSF;
260446bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
260546bdb399SToby Isaac 
260646bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
260746bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafMatricesSec);CHKERRQ(ierr);
260846bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootIndicesSec,&remoteOffsetsIndices,leafIndicesSec);CHKERRQ(ierr);
260946bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootMatricesSec,&remoteOffsetsMatrices,leafMatricesSec);CHKERRQ(ierr);
261046bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootIndicesSec,remoteOffsetsIndices,leafIndicesSec,&indicesSF);CHKERRQ(ierr);
261146bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootMatricesSec,remoteOffsetsMatrices,leafMatricesSec,&matricesSF);CHKERRQ(ierr);
2612e44e4e7fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
261346bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsIndices);CHKERRQ(ierr);
261446bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsMatrices);CHKERRQ(ierr);
261546bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numLeafIndices);CHKERRQ(ierr);
261646bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafMatricesSec,&numLeafMatrices);CHKERRQ(ierr);
261746bdb399SToby Isaac     ierr = PetscMalloc2(numLeafIndices,&leafIndices,numLeafMatrices,&leafMatrices);CHKERRQ(ierr);
261846bdb399SToby Isaac     ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2619267d4f3fSToby Isaac     ierr = PetscSFBcastBegin(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
262046bdb399SToby Isaac     ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2621267d4f3fSToby Isaac     ierr = PetscSFBcastEnd(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
262246bdb399SToby Isaac     ierr = PetscSFDestroy(&matricesSF);CHKERRQ(ierr);
262346bdb399SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
262446bdb399SToby Isaac     ierr = PetscFree2(rootIndices,rootMatrices);CHKERRQ(ierr);
262546bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
262646bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootMatricesSec);CHKERRQ(ierr);
262746bdb399SToby Isaac   }
262846bdb399SToby Isaac   /* count to preallocate */
262946bdb399SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
263046bdb399SToby Isaac   {
263146bdb399SToby Isaac     PetscInt    nGlobal;
263246bdb399SToby Isaac     PetscInt    *dnnz, *onnz;
2633b9a5774bSToby Isaac     PetscLayout rowMap, colMap;
2634b9a5774bSToby Isaac     PetscInt    rowStart, rowEnd, colStart, colEnd;
26351c58ffc4SToby Isaac     PetscInt    maxDof;
26361c58ffc4SToby Isaac     PetscInt    *rowIndices;
26371c58ffc4SToby Isaac     DM           refTree;
26381c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
26391c58ffc4SToby Isaac     PetscScalar  ***refPointFieldMats;
26401c58ffc4SToby Isaac     PetscSection refConSec, refAnSec;
26410eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,maxConDof,maxColumns,leafStart,leafEnd;
26421c58ffc4SToby Isaac     PetscScalar  *pointWork;
264346bdb399SToby Isaac 
264446bdb399SToby Isaac     ierr = PetscSectionGetConstrainedStorageSize(globalFine,&nGlobal);CHKERRQ(ierr);
264546bdb399SToby Isaac     ierr = PetscCalloc2(nGlobal,&dnnz,nGlobal,&onnz);CHKERRQ(ierr);
2646b9a5774bSToby Isaac     ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
2647b9a5774bSToby Isaac     ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
26481c58ffc4SToby Isaac     ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
2649b9a5774bSToby Isaac     ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
265046bdb399SToby Isaac     ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
26511c58ffc4SToby Isaac     ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr);
26520eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafIndicesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
26531c58ffc4SToby Isaac     ierr = DMGetWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
26540eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
265546bdb399SToby Isaac       PetscInt    gDof, gcDof, gOff;
265646bdb399SToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
265746bdb399SToby Isaac       PetscInt    matSize;
265821968bf8SToby Isaac       PetscInt    i;
265946bdb399SToby Isaac 
266046bdb399SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
266146bdb399SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
266246bdb399SToby Isaac       if ((gDof - gcDof) <= 0) {
266346bdb399SToby Isaac         continue;
266446bdb399SToby Isaac       }
266546bdb399SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
266646bdb399SToby Isaac       if (gOff < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"I though having global dofs meant a non-negative offset");
2667b9a5774bSToby 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");
266846bdb399SToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
266946bdb399SToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
267046bdb399SToby Isaac       numColIndices -= 2 * numFields;
26711c58ffc4SToby Isaac       if (numColIndices <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"global fine dof with no dofs to interpolate from");
267246bdb399SToby Isaac       pInd = &leafIndices[pIndOff];
267321968bf8SToby Isaac       offsets[0]        = 0;
267421968bf8SToby Isaac       offsetsCopy[0]    = 0;
267521968bf8SToby Isaac       newOffsets[0]     = 0;
267621968bf8SToby Isaac       newOffsetsCopy[0] = 0;
267746bdb399SToby Isaac       if (numFields) {
267821968bf8SToby Isaac         PetscInt f;
267946bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
268046bdb399SToby Isaac           PetscInt rowDof;
268146bdb399SToby Isaac 
268246bdb399SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
268321968bf8SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
268421968bf8SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
268521968bf8SToby Isaac           newOffsets[f + 1]     = pInd[numColIndices + numFields + f];
268621968bf8SToby Isaac           numD[f] = 0;
268721968bf8SToby Isaac           numO[f] = 0;
268846bdb399SToby Isaac         }
26894acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,rowIndices);CHKERRQ(ierr);
269046bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
269121968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
269221968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
269346bdb399SToby Isaac 
269446bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
269546bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
269646bdb399SToby Isaac 
269746bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
269821968bf8SToby Isaac               numD[f]++;
269946bdb399SToby Isaac             }
270046bdb399SToby Isaac             else if (gInd >= 0) { /* negative means non-entry */
270121968bf8SToby Isaac               numO[f]++;
270246bdb399SToby Isaac             }
270346bdb399SToby Isaac           }
270446bdb399SToby Isaac         }
270546bdb399SToby Isaac       }
270646bdb399SToby Isaac       else {
27074acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,rowIndices);CHKERRQ(ierr);
270821968bf8SToby Isaac         numD[0] = 0;
270921968bf8SToby Isaac         numO[0] = 0;
271046bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
271146bdb399SToby Isaac           PetscInt gInd = pInd[i];
271246bdb399SToby Isaac 
271346bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
271421968bf8SToby Isaac             numD[0]++;
271546bdb399SToby Isaac           }
271646bdb399SToby Isaac           else if (gInd >= 0) { /* negative means non-entry */
271721968bf8SToby Isaac             numO[0]++;
271846bdb399SToby Isaac           }
271946bdb399SToby Isaac         }
272046bdb399SToby Isaac       }
272146bdb399SToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
272246bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
272346bdb399SToby Isaac         PetscInt childId;
272446bdb399SToby Isaac 
272546bdb399SToby Isaac         childId = childIds[p-pStartF];
272621968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
272746bdb399SToby Isaac           if (numFields) {
2728b9a5774bSToby Isaac             PetscInt f;
2729b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
273021968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
273146bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
273221968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
273321968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
273446bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2735b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2736b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
273746bdb399SToby Isaac                 }
273846bdb399SToby Isaac                 else if (gIndCoarse >= 0) { /* remote */
2739b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2740b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
274146bdb399SToby Isaac                 }
274246bdb399SToby Isaac                 else { /* constrained */
274346bdb399SToby Isaac                   if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
274446bdb399SToby Isaac                 }
274546bdb399SToby Isaac               }
274646bdb399SToby Isaac             }
274746bdb399SToby Isaac           }
274846bdb399SToby Isaac           else {
2749b9a5774bSToby Isaac             PetscInt i;
2750b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
275146bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
275246bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
275346bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2754b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2755b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
275646bdb399SToby Isaac               }
275746bdb399SToby Isaac               else if (gIndCoarse >= 0) { /* remote */
2758b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2759b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
276046bdb399SToby Isaac               }
276146bdb399SToby Isaac               else { /* constrained */
276246bdb399SToby Isaac                 if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
276346bdb399SToby Isaac               }
276446bdb399SToby Isaac             }
276546bdb399SToby Isaac           }
276646bdb399SToby Isaac         }
276746bdb399SToby Isaac         else { /* interpolate from all */
276846bdb399SToby Isaac           if (numFields) {
2769b9a5774bSToby Isaac             PetscInt f;
2770b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
277121968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
277246bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
277321968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
277446bdb399SToby Isaac                 if (gIndFine >= 0) {
2775b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2776b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2777b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
277846bdb399SToby Isaac                 }
277946bdb399SToby Isaac               }
278046bdb399SToby Isaac             }
278146bdb399SToby Isaac           }
278246bdb399SToby Isaac           else {
2783b9a5774bSToby Isaac             PetscInt i;
2784b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
278546bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
278646bdb399SToby Isaac               if (gIndFine >= 0) {
2787b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2788b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2789b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
279046bdb399SToby Isaac               }
279146bdb399SToby Isaac             }
279246bdb399SToby Isaac           }
279346bdb399SToby Isaac         }
279446bdb399SToby Isaac       }
279546bdb399SToby Isaac       else { /* interpolate from all */
279646bdb399SToby Isaac         if (numFields) {
2797b9a5774bSToby Isaac           PetscInt f;
2798b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
279921968bf8SToby Isaac             PetscInt numRows = offsets[f+1] - offsets[f], row;
280046bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
280121968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
280246bdb399SToby Isaac               if (gIndFine >= 0) {
2803b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2804b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2805b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
280646bdb399SToby Isaac               }
280746bdb399SToby Isaac             }
280846bdb399SToby Isaac           }
280946bdb399SToby Isaac         }
281046bdb399SToby Isaac         else { /* every dof get a full row */
2811b9a5774bSToby Isaac           PetscInt i;
2812b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
281346bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
281446bdb399SToby Isaac             if (gIndFine >= 0) {
2815b9a5774bSToby Isaac               if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2816b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2817b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
281846bdb399SToby Isaac             }
281946bdb399SToby Isaac           }
282046bdb399SToby Isaac         }
282146bdb399SToby Isaac       }
282246bdb399SToby Isaac     }
282346bdb399SToby Isaac     ierr = MatXAIJSetPreallocation(mat,1,dnnz,onnz,NULL,NULL);CHKERRQ(ierr);
282446bdb399SToby Isaac     ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
282521968bf8SToby Isaac 
282621968bf8SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
282721968bf8SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
2828e44e4e7fSToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
2829e44e4e7fSToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
2830e44e4e7fSToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
28311c58ffc4SToby Isaac     ierr = PetscSectionGetMaxDof(refConSec,&maxConDof);CHKERRQ(ierr);
28327c0540e0SToby Isaac     ierr = PetscSectionGetMaxDof(leafIndicesSec,&maxColumns);CHKERRQ(ierr);
28337c0540e0SToby Isaac     ierr = PetscMalloc1(maxConDof*maxColumns,&pointWork);CHKERRQ(ierr);
28340eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2835e44e4e7fSToby Isaac       PetscInt    gDof, gcDof, gOff;
2836e44e4e7fSToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
2837e44e4e7fSToby Isaac       PetscInt    matSize;
2838e44e4e7fSToby Isaac       PetscInt    childId;
2839e44e4e7fSToby Isaac 
2840e44e4e7fSToby Isaac 
2841e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
2842e44e4e7fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
2843e44e4e7fSToby Isaac       if ((gDof - gcDof) <= 0) {
2844e44e4e7fSToby Isaac         continue;
2845e44e4e7fSToby Isaac       }
2846e44e4e7fSToby Isaac       childId = childIds[p-pStartF];
2847e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
2848e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
2849e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
2850e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2851e44e4e7fSToby Isaac       pInd = &leafIndices[pIndOff];
2852e44e4e7fSToby Isaac       offsets[0]        = 0;
2853e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2854e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2855e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2856e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2857e44e4e7fSToby Isaac       if (numFields) {
2858e44e4e7fSToby Isaac         PetscInt f;
2859e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2860e44e4e7fSToby Isaac           PetscInt rowDof;
2861e44e4e7fSToby Isaac 
2862e44e4e7fSToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
2863e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2864e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2865e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2866e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2867e44e4e7fSToby Isaac         }
28684acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,rowIndices);CHKERRQ(ierr);
2869e44e4e7fSToby Isaac       }
28701c58ffc4SToby Isaac       else {
28714acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,rowIndices);CHKERRQ(ierr);
28721c58ffc4SToby Isaac       }
2873e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
2874e44e4e7fSToby Isaac       if (!matSize) { /* incoming matrix is identity */
2875e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2876e44e4e7fSToby Isaac           if (numFields) {
2877e44e4e7fSToby Isaac             PetscInt f;
2878e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2879e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
2880e44e4e7fSToby Isaac               for (row = 0; row < numRows; row++) {
2881e44e4e7fSToby Isaac                 ierr = MatSetValue(mat,rowIndices[offsets[f]+row],pInd[newOffsets[f]+row],1.,INSERT_VALUES);CHKERRQ(ierr);
288221968bf8SToby Isaac               }
288321968bf8SToby Isaac             }
2884e44e4e7fSToby Isaac           }
2885e44e4e7fSToby Isaac           else {
2886e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
2887e44e4e7fSToby Isaac             for (row = 0; row < numRows; row++) {
2888e44e4e7fSToby Isaac               ierr = MatSetValue(mat,rowIndices[row],pInd[row],1.,INSERT_VALUES);CHKERRQ(ierr);
2889e44e4e7fSToby Isaac             }
2890e44e4e7fSToby Isaac           }
2891e44e4e7fSToby Isaac         }
2892e44e4e7fSToby Isaac         else { /* interpolate from all */
2893e44e4e7fSToby Isaac           if (numFields) {
2894e44e4e7fSToby Isaac             PetscInt f;
2895e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2896e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f];
2897e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
2898e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],refPointFieldMats[childId - pRefStart][f],INSERT_VALUES);CHKERRQ(ierr);
2899e44e4e7fSToby Isaac             }
2900e44e4e7fSToby Isaac           }
2901e44e4e7fSToby Isaac           else {
2902e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,refPointFieldMats[childId - pRefStart][0],INSERT_VALUES);CHKERRQ(ierr);
2903e44e4e7fSToby Isaac           }
2904e44e4e7fSToby Isaac         }
2905e44e4e7fSToby Isaac       }
2906e44e4e7fSToby Isaac       else { /* interpolate from all */
2907e44e4e7fSToby Isaac         PetscInt    pMatOff;
2908e44e4e7fSToby Isaac         PetscScalar *pMat;
2909e44e4e7fSToby Isaac 
2910e44e4e7fSToby Isaac         ierr = PetscSectionGetOffset(leafMatricesSec,p,&pMatOff);CHKERRQ(ierr);
2911e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2912e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2913e44e4e7fSToby Isaac           if (numFields) {
2914e44e4e7fSToby Isaac             PetscInt f, count;
2915e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2916e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2917e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2918e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2919e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2920e44e4e7fSToby Isaac 
2921e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],inMat,INSERT_VALUES);CHKERRQ(ierr);
2922e44e4e7fSToby Isaac               count += numCols * numInRows;
2923e44e4e7fSToby Isaac             }
2924e44e4e7fSToby Isaac           }
2925e44e4e7fSToby Isaac           else {
2926e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,pMat,INSERT_VALUES);CHKERRQ(ierr);
2927e44e4e7fSToby Isaac           }
2928e44e4e7fSToby Isaac         }
2929e44e4e7fSToby Isaac         else { /* multiply the incoming matrix by the child interpolation */
2930e44e4e7fSToby Isaac           if (numFields) {
2931e44e4e7fSToby Isaac             PetscInt f, count;
2932e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2933e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2934e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2935e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2936e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2937e44e4e7fSToby Isaac               PetscInt i, j, k;
2938e44e4e7fSToby Isaac               if (refPointFieldN[childId - pRefStart][f] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2939e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2940e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2941e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2942e44e4e7fSToby Isaac                   for (k = 0; k < numInRows; k++) {
2943e44e4e7fSToby Isaac                     val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2944e44e4e7fSToby Isaac                   }
2945e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2946e44e4e7fSToby Isaac                 }
2947e44e4e7fSToby Isaac               }
2948e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],pointWork,INSERT_VALUES);CHKERRQ(ierr);
2949e44e4e7fSToby Isaac               count += numCols * numInRows;
2950e44e4e7fSToby Isaac             }
2951e44e4e7fSToby Isaac           }
2952267d4f3fSToby Isaac           else { /* every dof gets a full row */
2953e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2954e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2955e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2956e44e4e7fSToby Isaac             PetscInt i, j, k;
2957e44e4e7fSToby Isaac             if (refPointFieldN[childId - pRefStart][0] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2958e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2959e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2960e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2961e44e4e7fSToby Isaac                 for (k = 0; k < numInRows; k++) {
2962e44e4e7fSToby Isaac                   val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2963e44e4e7fSToby Isaac                 }
2964e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2965e44e4e7fSToby Isaac               }
2966e44e4e7fSToby Isaac             }
2967e44e4e7fSToby Isaac             ierr = MatSetValues(mat,numRows,rowIndices,numCols,pInd,pointWork,INSERT_VALUES);CHKERRQ(ierr);
2968e44e4e7fSToby Isaac           }
2969e44e4e7fSToby Isaac         }
2970e44e4e7fSToby Isaac       }
2971e44e4e7fSToby Isaac     }
29721c58ffc4SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
29731c58ffc4SToby Isaac     ierr = DMRestoreWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
2974e44e4e7fSToby Isaac     ierr = PetscFree(pointWork);CHKERRQ(ierr);
2975e44e4e7fSToby Isaac   }
2976e44e4e7fSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2977e44e4e7fSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2978e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
2979e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafMatricesSec);CHKERRQ(ierr);
2980e44e4e7fSToby Isaac   ierr = PetscFree2(leafIndices,leafMatrices);CHKERRQ(ierr);
29814acb8e1eSToby Isaac   ierr = PetscFree2(perms,flips);CHKERRQ(ierr);
2982e44e4e7fSToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
29836ecaa68aSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
29846ecaa68aSToby Isaac   PetscFunctionReturn(0);
29856ecaa68aSToby Isaac }
2986154bca37SToby Isaac 
29878d2f55e7SToby Isaac /*
29888d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
29898d2f55e7SToby Isaac  *
29908d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
29918d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
29928d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
29938d2f55e7SToby Isaac  *       a_{i,j} = 0;
29948d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
29958d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
29968d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
29978d2f55e7SToby Isaac  */
29988d2f55e7SToby Isaac PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
29998d2f55e7SToby Isaac {
30008d2f55e7SToby Isaac   PetscDS        ds;
30018d2f55e7SToby Isaac   PetscSection   section, cSection;
30028d2f55e7SToby Isaac   DMLabel        canonical, depth;
30038d2f55e7SToby Isaac   Mat            cMat, mat;
30048d2f55e7SToby Isaac   PetscInt       *nnz;
30058d2f55e7SToby Isaac   PetscInt       f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
30068d2f55e7SToby Isaac   PetscInt       m, n;
30078d2f55e7SToby Isaac   PetscScalar    *pointScalar;
30088d2f55e7SToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
30098d2f55e7SToby Isaac   PetscErrorCode ierr;
30108d2f55e7SToby Isaac 
30118d2f55e7SToby Isaac   PetscFunctionBegin;
30128d2f55e7SToby Isaac   ierr = DMGetDefaultSection(refTree,&section);CHKERRQ(ierr);
30138d2f55e7SToby Isaac   ierr = DMGetDimension(refTree, &dim);CHKERRQ(ierr);
30148d2f55e7SToby Isaac   ierr = PetscMalloc6(dim,&v0,dim,&v0parent,dim,&vtmp,dim*dim,&J,dim*dim,&Jparent,dim*dim,&invJ);CHKERRQ(ierr);
30158d2f55e7SToby Isaac   ierr = PetscMalloc2(dim,&pointScalar,dim,&pointRef);CHKERRQ(ierr);
30168d2f55e7SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
30178d2f55e7SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
30188d2f55e7SToby Isaac   ierr = PetscSectionGetNumFields(section,&numSecFields);CHKERRQ(ierr);
30198d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"canonical",&canonical);CHKERRQ(ierr);
30208d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"depth",&depth);CHKERRQ(ierr);
30218d2f55e7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSection,&cMat);CHKERRQ(ierr);
30228d2f55e7SToby Isaac   ierr = DMPlexGetChart(refTree, &pStart, &pEnd);CHKERRQ(ierr);
30238d2f55e7SToby Isaac   ierr = DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd);CHKERRQ(ierr);
30248d2f55e7SToby Isaac   ierr = MatGetSize(cMat,&n,&m);CHKERRQ(ierr); /* the injector has transpose sizes from the constraint matrix */
30258d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
30268d2f55e7SToby Isaac   ierr = PetscCalloc1(m,&nnz);CHKERRQ(ierr);
30278d2f55e7SToby 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 */
30288d2f55e7SToby Isaac     const PetscInt *children;
30298d2f55e7SToby Isaac     PetscInt numChildren;
30308d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30318d2f55e7SToby Isaac 
30328d2f55e7SToby Isaac     if (canonical) {
30338d2f55e7SToby Isaac       PetscInt pCanonical;
30348d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
30358d2f55e7SToby Isaac       if (p != pCanonical) continue;
30368d2f55e7SToby Isaac     }
30378d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
30388d2f55e7SToby Isaac     if (!numChildren) continue;
30398d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30408d2f55e7SToby Isaac       PetscInt child = children[i];
30418d2f55e7SToby Isaac       PetscInt dof;
30428d2f55e7SToby Isaac 
30438d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
30448d2f55e7SToby Isaac       numChildDof += dof;
30458d2f55e7SToby Isaac     }
30468d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
30478d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30488d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
30498d2f55e7SToby Isaac       PetscInt selfOff;
30508d2f55e7SToby Isaac 
30518d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
30528d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
30538d2f55e7SToby Isaac           PetscInt child = children[i];
30548d2f55e7SToby Isaac           PetscInt dof;
30558d2f55e7SToby Isaac 
30568d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
30578d2f55e7SToby Isaac           numChildDof += dof;
30588d2f55e7SToby Isaac         }
30598d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
30608d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
30618d2f55e7SToby Isaac       }
30628d2f55e7SToby Isaac       else {
30638d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
30648d2f55e7SToby Isaac       }
30658d2f55e7SToby Isaac       for (i = 0; i < numSelfDof; i++) {
30668d2f55e7SToby Isaac         nnz[selfOff + i] = numChildDof;
30678d2f55e7SToby Isaac       }
30688d2f55e7SToby Isaac     }
30698d2f55e7SToby Isaac   }
30708d2f55e7SToby Isaac   ierr = MatCreateAIJ(PETSC_COMM_SELF,m,n,m,n,-1,nnz,-1,NULL,&mat);CHKERRQ(ierr);
30718d2f55e7SToby Isaac   ierr = PetscFree(nnz);CHKERRQ(ierr);
30728d2f55e7SToby Isaac   /* Setp 2: compute entries */
30738d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
30748d2f55e7SToby Isaac     const PetscInt *children;
30758d2f55e7SToby Isaac     PetscInt numChildren;
30768d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30778d2f55e7SToby Isaac 
30788d2f55e7SToby Isaac     /* same conditions about when entries occur */
30798d2f55e7SToby Isaac     if (canonical) {
30808d2f55e7SToby Isaac       PetscInt pCanonical;
30818d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
30828d2f55e7SToby Isaac       if (p != pCanonical) continue;
30838d2f55e7SToby Isaac     }
30848d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
30858d2f55e7SToby Isaac     if (!numChildren) continue;
30868d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30878d2f55e7SToby Isaac       PetscInt child = children[i];
30888d2f55e7SToby Isaac       PetscInt dof;
30898d2f55e7SToby Isaac 
30908d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
30918d2f55e7SToby Isaac       numChildDof += dof;
30928d2f55e7SToby Isaac     }
30938d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
30948d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30958d2f55e7SToby Isaac 
30968d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
30978d2f55e7SToby Isaac       PetscInt       selfOff, fComp, numSelfShapes, numChildShapes, parentCell;
30988d2f55e7SToby Isaac       PetscInt       cellShapeOff;
30998d2f55e7SToby Isaac       PetscObject    disc;
31008d2f55e7SToby Isaac       PetscDualSpace dsp;
31018d2f55e7SToby Isaac       PetscClassId   classId;
31028d2f55e7SToby Isaac       PetscScalar    *pointMat;
31033b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
31048d2f55e7SToby Isaac       PetscInt       pO = PETSC_MIN_INT;
31058d2f55e7SToby Isaac       const PetscInt *depthNumDof;
31068d2f55e7SToby Isaac 
31078d2f55e7SToby Isaac       if (numSecFields) {
31088d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
31098d2f55e7SToby Isaac           PetscInt child = children[i];
31108d2f55e7SToby Isaac           PetscInt dof;
31118d2f55e7SToby Isaac 
31128d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
31138d2f55e7SToby Isaac           numChildDof += dof;
31148d2f55e7SToby Isaac         }
31158d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
31168d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
31178d2f55e7SToby Isaac         ierr = PetscSectionGetFieldComponents(section,f,&fComp);CHKERRQ(ierr);
31188d2f55e7SToby Isaac       }
31198d2f55e7SToby Isaac       else {
31208d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
31218d2f55e7SToby Isaac         fComp = 1;
31228d2f55e7SToby Isaac       }
31238d2f55e7SToby Isaac       numSelfShapes  = numSelfDof  / fComp;
31248d2f55e7SToby Isaac       numChildShapes = numChildDof / fComp;
31258d2f55e7SToby Isaac 
31263b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
31278d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
31288d2f55e7SToby Isaac         parentCell = p;
31298d2f55e7SToby Isaac       }
31308d2f55e7SToby Isaac       else {
31318d2f55e7SToby Isaac         PetscInt *star = NULL;
31328d2f55e7SToby Isaac         PetscInt numStar;
31338d2f55e7SToby Isaac 
31348d2f55e7SToby Isaac         parentCell = -1;
31358d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31368d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
31378d2f55e7SToby Isaac           PetscInt c = star[2 * i];
31388d2f55e7SToby Isaac 
31398d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
31408d2f55e7SToby Isaac             parentCell = c;
31418d2f55e7SToby Isaac             break;
31428d2f55e7SToby Isaac           }
31438d2f55e7SToby Isaac         }
31448d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31458d2f55e7SToby Isaac       }
31468d2f55e7SToby Isaac       /* determine the offset of p's shape functions withing parentCell's shape functions */
3147c5356c36SToby Isaac       ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
3148c5356c36SToby Isaac       ierr = PetscObjectGetClassId(disc,&classId);CHKERRQ(ierr);
3149c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
3150c5356c36SToby Isaac         ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
3151c5356c36SToby Isaac       }
3152c5356c36SToby Isaac       else if (classId == PETSCFV_CLASSID) {
3153c5356c36SToby Isaac         ierr = PetscFVGetDualSpace((PetscFV)disc,&dsp);CHKERRQ(ierr);
3154c5356c36SToby Isaac       }
3155c5356c36SToby Isaac       else {
3156c5356c36SToby Isaac         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported discretization object");CHKERRQ(ierr);
3157c5356c36SToby Isaac       }
31588d2f55e7SToby Isaac       ierr = PetscDualSpaceGetNumDof(dsp,&depthNumDof);CHKERRQ(ierr);
31598d2f55e7SToby Isaac       {
31608d2f55e7SToby Isaac         PetscInt *closure = NULL;
31618d2f55e7SToby Isaac         PetscInt numClosure;
31628d2f55e7SToby Isaac 
31638d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
31648d2f55e7SToby Isaac         for (i = 0, cellShapeOff = 0; i < numClosure; i++) {
31658d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
31668d2f55e7SToby Isaac 
31678d2f55e7SToby Isaac           pO = closure[2 * i + 1];
31688d2f55e7SToby Isaac           if (point == p) break;
31698d2f55e7SToby Isaac           ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
31708d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
31718d2f55e7SToby Isaac         }
31728d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
31738d2f55e7SToby Isaac       }
31748d2f55e7SToby Isaac 
31758d2f55e7SToby Isaac       ierr = DMGetWorkArray(refTree, numSelfShapes * numChildShapes, PETSC_SCALAR,&pointMat);CHKERRQ(ierr);
31763b1c2a6aSToby Isaac       ierr = DMGetWorkArray(refTree, numSelfShapes + numChildShapes, PETSC_INT,&matRows);CHKERRQ(ierr);
31773b1c2a6aSToby Isaac       matCols = matRows + numSelfShapes;
31783b1c2a6aSToby Isaac       for (i = 0; i < numSelfShapes; i++) {
31793b1c2a6aSToby Isaac         matRows[i] = selfOff + i * fComp;
31803b1c2a6aSToby Isaac       }
31813b1c2a6aSToby Isaac       {
31823b1c2a6aSToby Isaac         PetscInt colOff = 0;
31833b1c2a6aSToby Isaac 
31843b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
31853b1c2a6aSToby Isaac           PetscInt child = children[i];
31863b1c2a6aSToby Isaac           PetscInt dof, off, j;
31873b1c2a6aSToby Isaac 
31883b1c2a6aSToby Isaac           if (numSecFields) {
3189c5356c36SToby Isaac             ierr = PetscSectionGetFieldDof(cSection,child,f,&dof);CHKERRQ(ierr);
3190c5356c36SToby Isaac             ierr = PetscSectionGetFieldOffset(cSection,child,f,&off);CHKERRQ(ierr);
31913b1c2a6aSToby Isaac           }
31923b1c2a6aSToby Isaac           else {
3193c5356c36SToby Isaac             ierr = PetscSectionGetDof(cSection,child,&dof);CHKERRQ(ierr);
3194c5356c36SToby Isaac             ierr = PetscSectionGetOffset(cSection,child,&off);CHKERRQ(ierr);
31953b1c2a6aSToby Isaac           }
31963b1c2a6aSToby Isaac 
31973b1c2a6aSToby Isaac           for (j = 0; j < dof / fComp; j++) {
31983b1c2a6aSToby Isaac             matCols[colOff++] = off + j * fComp;
31993b1c2a6aSToby Isaac           }
32003b1c2a6aSToby Isaac         }
32013b1c2a6aSToby Isaac       }
32028d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
32038d2f55e7SToby Isaac         PetscFE        fe = (PetscFE) disc;
32048d2f55e7SToby Isaac         PetscInt       fSize;
32058d2f55e7SToby Isaac 
32068d2f55e7SToby Isaac         ierr = PetscFEGetDualSpace(fe,&dsp);CHKERRQ(ierr);
32073b1c2a6aSToby Isaac         ierr = PetscDualSpaceGetDimension(dsp,&fSize);CHKERRQ(ierr);
32088d2f55e7SToby Isaac         for (i = 0; i < numSelfShapes; i++) { /* for every shape function */
32098d2f55e7SToby Isaac           PetscQuadrature q;
32108d2f55e7SToby Isaac           PetscInt        dim, numPoints, j, k;
32118d2f55e7SToby Isaac           const PetscReal *points;
32128d2f55e7SToby Isaac           const PetscReal *weights;
32138d2f55e7SToby Isaac           PetscInt        *closure = NULL;
32148d2f55e7SToby Isaac           PetscInt        numClosure;
32153b1c2a6aSToby Isaac           PetscInt        parentCellShapeDof = cellShapeOff + (pO < 0 ? (numSelfShapes - 1 - i) : i);
32168d2f55e7SToby Isaac           PetscReal       *Bparent;
32178d2f55e7SToby Isaac 
32183b1c2a6aSToby Isaac           ierr = PetscDualSpaceGetFunctional(dsp,parentCellShapeDof,&q);CHKERRQ(ierr);
32193b1c2a6aSToby Isaac           ierr = PetscQuadratureGetData(q,&dim,&numPoints,&points,&weights);CHKERRQ(ierr);
32203b1c2a6aSToby Isaac           ierr = PetscFEGetTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
32218d2f55e7SToby Isaac           for (k = 0; k < numChildShapes; k++) {
32228d2f55e7SToby Isaac             pointMat[numChildShapes * i + k] = 0.;
32238d2f55e7SToby Isaac           }
32243b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
32258d2f55e7SToby Isaac             PetscInt          childCell = -1;
32263b1c2a6aSToby Isaac             PetscReal         parentValAtPoint;
32278d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
32288d2f55e7SToby Isaac             const PetscScalar *point;
32298d2f55e7SToby Isaac             PetscReal         *Bchild;
32308d2f55e7SToby Isaac             PetscInt          childCellShapeOff, pointMatOff;
32318d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
32328d2f55e7SToby Isaac             PetscInt          d;
32338d2f55e7SToby Isaac 
32348d2f55e7SToby Isaac             for (d = 0; d < dim; d++) {
32358d2f55e7SToby Isaac               pointScalar[d] = points[dim * j + d];
32368d2f55e7SToby Isaac             }
32378d2f55e7SToby Isaac             point = pointScalar;
32388d2f55e7SToby Isaac #else
32398d2f55e7SToby Isaac             point = pointReal;
32408d2f55e7SToby Isaac #endif
32418d2f55e7SToby Isaac 
32423b1c2a6aSToby Isaac             parentValAtPoint = Bparent[(fSize * j + parentCellShapeDof) * fComp];
32433b1c2a6aSToby Isaac 
32443b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
32458d2f55e7SToby Isaac               PetscInt child = children[k];
32468d2f55e7SToby Isaac               PetscInt *star = NULL;
32478d2f55e7SToby Isaac               PetscInt numStar, s;
32488d2f55e7SToby Isaac 
32498d2f55e7SToby Isaac               ierr = DMPlexGetTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
32508d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
32518d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
32528d2f55e7SToby Isaac 
32538d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
32548d2f55e7SToby Isaac                 ierr = DMPlexLocatePoint_Internal(refTree,dim,point,c,&childCell);CHKERRQ(ierr);
32558d2f55e7SToby Isaac                 if (childCell >= 0) break;
32568d2f55e7SToby Isaac               }
32578d2f55e7SToby Isaac               ierr = DMPlexRestoreTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
32588d2f55e7SToby Isaac               if (childCell >= 0) break;
32598d2f55e7SToby Isaac             }
32608d2f55e7SToby Isaac             if (childCell < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not locate quadrature point");CHKERRQ(ierr);
32618d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
32628d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent);CHKERRQ(ierr);
32638d2f55e7SToby Isaac             CoordinatesRefToReal(dim, dim, v0parent, Jparent, pointReal, vtmp);
32648d2f55e7SToby Isaac             CoordinatesRealToRef(dim, dim, v0, invJ, vtmp, pointRef);
32658d2f55e7SToby Isaac 
32668d2f55e7SToby Isaac             ierr = PetscFEGetTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr);
32678d2f55e7SToby Isaac             ierr = DMPlexGetTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
32683b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3269c5356c36SToby Isaac               PetscInt child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
32708d2f55e7SToby Isaac               PetscInt l;
32718d2f55e7SToby Isaac 
32728d2f55e7SToby Isaac               ierr = DMLabelGetValue(depth,child,&childDepth);CHKERRQ(ierr);
32738d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
32748d2f55e7SToby Isaac               for (l = 0, childCellShapeOff = 0; l < numClosure; l++) {
32758d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
32768d2f55e7SToby Isaac                 PetscInt pointDepth;
32778d2f55e7SToby Isaac 
32788d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
32798d2f55e7SToby Isaac                 if (point == child) break;
32808d2f55e7SToby Isaac                 ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
32818d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
32828d2f55e7SToby Isaac               }
32838d2f55e7SToby Isaac               if (l == numClosure) {
32848d2f55e7SToby Isaac                 pointMatOff += childDof;
32858d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
32868d2f55e7SToby Isaac               }
32878d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
32883b1c2a6aSToby Isaac                 PetscInt    childCellDof    = childCellShapeOff + (childO ? (childDof - 1 - l) : l);
32893b1c2a6aSToby Isaac                 PetscReal   childValAtPoint = Bchild[childCellDof * fComp];
32908d2f55e7SToby Isaac 
32913b1c2a6aSToby Isaac                 pointMat[i * numChildShapes + pointMatOff + l] += weights[j] * parentValAtPoint * childValAtPoint;
32928d2f55e7SToby Isaac               }
32938d2f55e7SToby Isaac               pointMatOff += childDof;
32948d2f55e7SToby Isaac             }
32958d2f55e7SToby Isaac             ierr = DMPlexRestoreTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
32968d2f55e7SToby Isaac             ierr = PetscFERestoreTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr);
32978d2f55e7SToby Isaac           }
32988d2f55e7SToby Isaac           ierr = PetscFERestoreTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr);
32998d2f55e7SToby Isaac         }
33008d2f55e7SToby Isaac       }
3301c5356c36SToby Isaac       else { /* just the volume-weighted averages of the children */
33023b1c2a6aSToby Isaac         PetscInt  childShapeOff;
33033b1c2a6aSToby Isaac         PetscReal parentVol;
33043b1c2a6aSToby Isaac 
33053b1c2a6aSToby Isaac         ierr = DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL);CHKERRQ(ierr);
33063b1c2a6aSToby Isaac         for (i = 0, childShapeOff = 0; i < numChildren; i++) {
33073b1c2a6aSToby Isaac           PetscInt  child = children[i];
33083b1c2a6aSToby Isaac           PetscReal childVol;
33093b1c2a6aSToby Isaac 
33103b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
33113b1c2a6aSToby Isaac           ierr = DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL);CHKERRQ(ierr);
33123b1c2a6aSToby Isaac           pointMat[childShapeOff] = childVol / parentVol;
33133b1c2a6aSToby Isaac           childShapeOff++;
33143b1c2a6aSToby Isaac         }
33158d2f55e7SToby Isaac       }
33163b1c2a6aSToby Isaac       /* Insert pointMat into mat */
33173b1c2a6aSToby Isaac       for (i = 0; i < fComp; i++) {
33183b1c2a6aSToby Isaac         PetscInt j;
33193b1c2a6aSToby Isaac         ierr = MatSetValues(mat,numSelfShapes,matRows,numChildShapes,matCols,pointMat,INSERT_VALUES);CHKERRQ(ierr);
33203b1c2a6aSToby Isaac 
33213b1c2a6aSToby Isaac         for (j = 0; j < numSelfShapes; j++) {
33223b1c2a6aSToby Isaac           matRows[j]++;
33233b1c2a6aSToby Isaac         }
33243b1c2a6aSToby Isaac         for (j = 0; j < numChildShapes; j++) {
33253b1c2a6aSToby Isaac           matCols[j]++;
33263b1c2a6aSToby Isaac         }
33273b1c2a6aSToby Isaac       }
33283b1c2a6aSToby Isaac       ierr = DMRestoreWorkArray(refTree, numSelfShapes + numChildShapes, PETSC_INT,&matRows);CHKERRQ(ierr);
33298d2f55e7SToby Isaac       ierr = DMRestoreWorkArray(refTree, numSelfShapes * numChildShapes, PETSC_SCALAR,&pointMat);CHKERRQ(ierr);
33308d2f55e7SToby Isaac     }
33318d2f55e7SToby Isaac   }
33323b1c2a6aSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJ);CHKERRQ(ierr);
33338d2f55e7SToby Isaac   ierr = PetscFree2(pointScalar,pointRef);CHKERRQ(ierr);
33343b1c2a6aSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33353b1c2a6aSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33368d2f55e7SToby Isaac   *inj = mat;
33378d2f55e7SToby Isaac   PetscFunctionReturn(0);
33388d2f55e7SToby Isaac }
33398d2f55e7SToby Isaac 
3340f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3341f30e825dSToby Isaac {
3342f30e825dSToby Isaac   PetscDS        ds;
3343f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3344f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3345f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3346f30e825dSToby Isaac   PetscErrorCode ierr;
3347f30e825dSToby Isaac 
3348f30e825dSToby Isaac   PetscFunctionBegin;
3349f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
3350f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3351f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
3352f30e825dSToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
3353f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3354f30e825dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
3355f30e825dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
3356f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
3357f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof*maxDof,&cols);CHKERRQ(ierr);
3358f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3359f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3360f30e825dSToby Isaac 
3361f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3362f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3363c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3364f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3365f30e825dSToby Isaac 
3366f30e825dSToby Isaac     ierr = PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
3367f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3368f30e825dSToby Isaac       PetscInt cDof, cOff, numCols, r, fComp;
3369f30e825dSToby Isaac       PetscObject disc;
3370f30e825dSToby Isaac       PetscClassId id;
3371f30e825dSToby Isaac       PetscFE fe = NULL;
3372f30e825dSToby Isaac       PetscFV fv = NULL;
3373f30e825dSToby Isaac 
3374f30e825dSToby Isaac       ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
3375f30e825dSToby Isaac       ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
3376f30e825dSToby Isaac       if (id == PETSCFE_CLASSID) {
3377f30e825dSToby Isaac         fe = (PetscFE) disc;
3378f30e825dSToby Isaac         ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr);
3379f30e825dSToby Isaac       }
3380f30e825dSToby Isaac       else if (id == PETSCFV_CLASSID) {
3381f30e825dSToby Isaac         fv = (PetscFV) disc;
3382f30e825dSToby Isaac         ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr);
3383f30e825dSToby Isaac       }
3384f30e825dSToby Isaac       else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
3385f30e825dSToby Isaac 
3386f30e825dSToby Isaac       if (numFields > 1) {
3387f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3388f30e825dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
3389f30e825dSToby Isaac       }
3390f30e825dSToby Isaac       else {
3391f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3392f30e825dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
3393f30e825dSToby Isaac       }
3394f30e825dSToby Isaac 
3395f30e825dSToby Isaac       for (r = 0; r < cDof; r++) {
3396f30e825dSToby Isaac         rows[r] = cOff + r;
3397f30e825dSToby Isaac       }
3398f30e825dSToby Isaac       numCols = 0;
3399f30e825dSToby Isaac       {
3400f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3401f30e825dSToby Isaac 
3402f30e825dSToby Isaac         if (numFields > 1) {
3403f30e825dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,parent,f,&aDof);CHKERRQ(ierr);
3404f30e825dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,parent,f,&aOff);CHKERRQ(ierr);
3405f30e825dSToby Isaac         }
3406f30e825dSToby Isaac         else {
3407f30e825dSToby Isaac           ierr = PetscSectionGetDof(refSection,parent,&aDof);CHKERRQ(ierr);
3408f30e825dSToby Isaac           ierr = PetscSectionGetOffset(refSection,parent,&aOff);CHKERRQ(ierr);
3409f30e825dSToby Isaac         }
3410f30e825dSToby Isaac 
3411f30e825dSToby Isaac         for (j = 0; j < aDof; j++) {
3412f30e825dSToby Isaac           cols[numCols++] = aOff + j;
3413f30e825dSToby Isaac         }
3414f30e825dSToby Isaac       }
3415f30e825dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3416f30e825dSToby Isaac       /* transpose of constraint matrix */
3417f30e825dSToby Isaac       ierr = MatGetValues(inj,numCols,cols,cDof,rows,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3418f30e825dSToby Isaac     }
3419f30e825dSToby Isaac   }
3420f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
3421f30e825dSToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
3422f30e825dSToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
3423f30e825dSToby Isaac   PetscFunctionReturn(0);
3424f30e825dSToby Isaac }
3425f30e825dSToby Isaac 
3426f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3427f30e825dSToby Isaac {
3428f30e825dSToby Isaac   PetscDS        ds;
3429f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3430f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3431c6154584SToby Isaac   PetscSection   refConSec, refSection;
3432f30e825dSToby Isaac   PetscErrorCode ierr;
3433f30e825dSToby Isaac 
3434f30e825dSToby Isaac   PetscFunctionBegin;
3435f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3436f30e825dSToby Isaac   *childrenMats = NULL;
3437f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
3438c6154584SToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
3439f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3440f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
3441f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3442f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3443f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3444f30e825dSToby Isaac 
3445f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3446f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3447c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3448f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3449f30e825dSToby Isaac 
3450f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3451f30e825dSToby Isaac       PetscInt cDof;
3452f30e825dSToby Isaac 
3453f30e825dSToby Isaac       if (numFields > 1) {
3454f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3455f30e825dSToby Isaac       }
3456f30e825dSToby Isaac       else {
3457f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3458f30e825dSToby Isaac       }
3459f30e825dSToby Isaac 
3460f30e825dSToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
3461f30e825dSToby Isaac     }
3462f30e825dSToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
3463f30e825dSToby Isaac   }
3464f30e825dSToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
3465f30e825dSToby Isaac   PetscFunctionReturn(0);
3466f30e825dSToby Isaac }
3467f30e825dSToby Isaac 
3468ebf164c7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree,Mat *injRef)
3469154bca37SToby Isaac {
3470ebf164c7SToby Isaac   Mat            cMatRef;
34716148253fSToby Isaac   PetscObject    injRefObj;
34728d2f55e7SToby Isaac   PetscErrorCode ierr;
34738d2f55e7SToby Isaac 
3474154bca37SToby Isaac   PetscFunctionBegin;
3475ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,NULL,&cMatRef);CHKERRQ(ierr);
34766148253fSToby Isaac   ierr = PetscObjectQuery((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",&injRefObj);CHKERRQ(ierr);
3477ebf164c7SToby Isaac   *injRef = (Mat) injRefObj;
3478ebf164c7SToby Isaac   if (!*injRef) {
3479ebf164c7SToby Isaac     ierr = DMPlexComputeInjectorReferenceTree(refTree,injRef);CHKERRQ(ierr);
3480ebf164c7SToby Isaac     ierr = PetscObjectCompose((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",(PetscObject)*injRef);CHKERRQ(ierr);
3481ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
3482ebf164c7SToby Isaac     ierr = PetscObjectDereference((PetscObject)*injRef);CHKERRQ(ierr);
3483ebf164c7SToby Isaac   }
3484ebf164c7SToby Isaac   PetscFunctionReturn(0);
34856148253fSToby Isaac }
3486f30e825dSToby Isaac 
3487c921d74cSToby 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)
3488ebf164c7SToby Isaac {
3489c921d74cSToby Isaac   PetscInt       pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3490ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3491ebf164c7SToby Isaac   PetscSection   localCoarse, localFine, leafIndicesSec;
3492c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3493c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3494c921d74cSToby Isaac   const PetscInt *rootDegrees;
3495c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3496ebf164c7SToby Isaac   PetscSF        coarseToFineEmbedded;
3497ebf164c7SToby Isaac   PetscErrorCode ierr;
3498ebf164c7SToby Isaac 
3499ebf164c7SToby Isaac   PetscFunctionBegin;
3500ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
35018d2f55e7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
3502f30e825dSToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
35038d2f55e7SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3504f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
3505f30e825dSToby Isaac   ierr = PetscSectionSetChart(leafIndicesSec,pStartF, pEndF);CHKERRQ(ierr);
3506c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localFine,&maxDof);CHKERRQ(ierr);
35078d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
35087e96bdafSToby Isaac     PetscInt l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
35097e96bdafSToby Isaac     const PetscInt *leaves;
35108d2f55e7SToby Isaac 
35117e96bdafSToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
35127e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
35137e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35148d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
35158d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
35168d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
35178d2f55e7SToby Isaac         numPointsWithDofs++;
3518f30e825dSToby Isaac 
3519f30e825dSToby Isaac         ierr = PetscSectionGetDof(localFine,p,&dof);CHKERRQ(ierr);
3520f30e825dSToby Isaac         ierr = PetscSectionSetDof(leafIndicesSec,p,dof + 1);CHKERRQ(ierr);
35218d2f55e7SToby Isaac       }
35228d2f55e7SToby Isaac     }
35238d2f55e7SToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
3524f30e825dSToby Isaac     ierr = PetscSectionSetUp(leafIndicesSec);CHKERRQ(ierr);
3525f30e825dSToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numIndices);CHKERRQ(ierr);
3526c921d74cSToby Isaac     ierr = PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1),&leafInds);CHKERRQ(ierr);
3527c921d74cSToby Isaac     if (gatheredValues)  {ierr = PetscMalloc1(numIndices,&leafVals);CHKERRQ(ierr);}
35287e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
35297e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35308d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
35318d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
35328d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3533f30e825dSToby Isaac         PetscInt    off, gOff;
3534f30e825dSToby Isaac         PetscInt    *pInd;
3535c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3536f30e825dSToby Isaac 
35377e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3538f30e825dSToby Isaac 
3539f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3540f30e825dSToby Isaac 
3541c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3542c921d74cSToby Isaac         if (gatheredValues) {
3543c921d74cSToby Isaac           PetscInt i;
3544c921d74cSToby Isaac 
3545c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3546c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3547c921d74cSToby Isaac         }
3548f30e825dSToby Isaac         ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
3549f30e825dSToby Isaac 
3550f30e825dSToby Isaac         offsets[0] = 0;
3551f30e825dSToby Isaac         if (numFields) {
3552f30e825dSToby Isaac           PetscInt f;
3553f30e825dSToby Isaac 
3554f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3555f30e825dSToby Isaac             PetscInt fDof;
3556f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(localFine,p,f,&fDof);CHKERRQ(ierr);
3557f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3558f30e825dSToby Isaac           }
35594acb8e1eSToby Isaac           DMPlexGetIndicesPointFields_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1,pInd);CHKERRQ(ierr);
3560f30e825dSToby Isaac         }
3561f30e825dSToby Isaac         else {
35624acb8e1eSToby Isaac           DMPlexGetIndicesPoint_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,pInd);CHKERRQ(ierr);
3563f30e825dSToby Isaac         }
3564c921d74cSToby Isaac         if (gatheredValues) {ierr = VecGetValues(fineVec,dof,pInd,pVal);CHKERRQ(ierr);}
35658d2f55e7SToby Isaac       }
35668d2f55e7SToby Isaac     }
35678d2f55e7SToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
3568f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
35698d2f55e7SToby Isaac   }
3570f30e825dSToby Isaac 
3571f30e825dSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
3572f30e825dSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
3573f30e825dSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3574f30e825dSToby Isaac 
35756148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
35766148253fSToby Isaac     MPI_Datatype threeInt;
35776148253fSToby Isaac     PetscMPIInt  rank;
35786148253fSToby Isaac     PetscInt     (*parentNodeAndIdCoarse)[3];
35796148253fSToby Isaac     PetscInt     (*parentNodeAndIdFine)[3];
35806148253fSToby Isaac     PetscInt     p, nleaves, nleavesToParents;
35816148253fSToby Isaac     PetscSF      pointSF, sfToParents;
35826148253fSToby Isaac     const PetscInt *ilocal;
35836148253fSToby Isaac     const PetscSFNode *iremote;
35846148253fSToby Isaac     PetscSFNode  *iremoteToParents;
35856148253fSToby Isaac     PetscInt     *ilocalToParents;
35866148253fSToby Isaac 
35876148253fSToby Isaac     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)coarse),&rank);CHKERRQ(ierr);
35886148253fSToby Isaac     ierr = MPI_Type_contiguous(3,MPIU_INT,&threeInt);CHKERRQ(ierr);
35896148253fSToby Isaac     ierr = MPI_Type_commit(&threeInt);CHKERRQ(ierr);
35906148253fSToby Isaac     ierr = PetscMalloc2(pEndC-pStartC,&parentNodeAndIdCoarse,pEndF-pStartF,&parentNodeAndIdFine);CHKERRQ(ierr);
35916148253fSToby Isaac     ierr = DMGetPointSF(coarse,&pointSF);CHKERRQ(ierr);
35926148253fSToby Isaac     ierr = PetscSFGetGraph(pointSF,NULL,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
35936148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
35946148253fSToby Isaac       PetscInt parent, childId;
35956148253fSToby Isaac       ierr = DMPlexGetTreeParent(coarse,p,&parent,&childId);CHKERRQ(ierr);
35966148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
35976148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
35986148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
35996148253fSToby Isaac       if (nleaves > 0) {
36006148253fSToby Isaac         PetscInt leaf = -1;
36016148253fSToby Isaac 
36026148253fSToby Isaac         if (ilocal) {
36036148253fSToby Isaac           ierr  = PetscFindInt(parent,nleaves,ilocal,&leaf);CHKERRQ(ierr);
36046148253fSToby Isaac         }
36056148253fSToby Isaac         else {
36066148253fSToby Isaac           leaf = p - pStartC;
36076148253fSToby Isaac         }
36086148253fSToby Isaac         if (leaf >= 0) {
36096148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
36106148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
36116148253fSToby Isaac         }
36126148253fSToby Isaac       }
36136148253fSToby Isaac     }
36146148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
36156148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
36166148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
36176148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
36186148253fSToby Isaac     }
36196148253fSToby Isaac     ierr = PetscSFBcastBegin(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36206148253fSToby Isaac     ierr = PetscSFBcastEnd(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36216148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3622f30e825dSToby Isaac       PetscInt dof;
3623f30e825dSToby Isaac 
3624f30e825dSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&dof);CHKERRQ(ierr);
3625f30e825dSToby Isaac       if (dof) {
3626f30e825dSToby Isaac         PetscInt off;
3627f30e825dSToby Isaac 
3628f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3629c921d74cSToby Isaac         if (gatheredIndices) {
3630c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3631c921d74cSToby Isaac         } else if (gatheredValues) {
3632c921d74cSToby Isaac           leafVals[off] = (PetscScalar) PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3633c921d74cSToby Isaac         }
3634f30e825dSToby Isaac       }
36356148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36366148253fSToby Isaac         nleavesToParents++;
36376148253fSToby Isaac       }
36386148253fSToby Isaac     }
36396148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&ilocalToParents);CHKERRQ(ierr);
36406148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&iremoteToParents);CHKERRQ(ierr);
36416148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
36426148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36436148253fSToby Isaac         ilocalToParents[nleavesToParents] = p - pStartF;
36446148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p-pStartF][0];
36456148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p-pStartF][1];
36466148253fSToby Isaac         nleavesToParents++;
36476148253fSToby Isaac       }
36486148253fSToby Isaac     }
36496148253fSToby Isaac     ierr = PetscSFCreate(PetscObjectComm((PetscObject)coarse),&sfToParents);CHKERRQ(ierr);
36506148253fSToby Isaac     ierr = PetscSFSetGraph(sfToParents,pEndC-pStartC,nleavesToParents,ilocalToParents,PETSC_OWN_POINTER,iremoteToParents,PETSC_OWN_POINTER);CHKERRQ(ierr);
36516148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
36526148253fSToby Isaac 
36536148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
36546148253fSToby Isaac 
36556148253fSToby Isaac     ierr = PetscFree2(parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36566148253fSToby Isaac     ierr = MPI_Type_free(&threeInt);CHKERRQ(ierr);
36576148253fSToby Isaac   }
3658f30e825dSToby Isaac 
36596148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
36606148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
36616148253fSToby Isaac     PetscSF  sfDofsOnly;
36626148253fSToby Isaac 
36636148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
36646148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
36656148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
36666148253fSToby Isaac       if ((dof - cdof) > 0) {
36676148253fSToby Isaac         numPointsWithDofs++;
36686148253fSToby Isaac       }
36696148253fSToby Isaac     }
36706148253fSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
36716148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
36726148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
36736148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
36746148253fSToby Isaac       if ((dof - cdof) > 0) {
3675e03d9830SToby Isaac         pointsWithDofs[offset++] = p - pStartC;
36766148253fSToby Isaac       }
36776148253fSToby Isaac     }
36786148253fSToby Isaac     ierr = PetscSFCreateEmbeddedSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly);CHKERRQ(ierr);
36796148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3680f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
36816148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
36826148253fSToby Isaac   }
3683f30e825dSToby Isaac 
36846148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
3685f30e825dSToby Isaac   ierr = PetscSFComputeDegreeBegin(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3686f30e825dSToby Isaac   ierr = PetscSFComputeDegreeEnd(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3687f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&multiRootSec);CHKERRQ(ierr);
3688f30e825dSToby Isaac   ierr = PetscSectionSetChart(multiRootSec,pStartC,pEndC);CHKERRQ(ierr);
36898d2f55e7SToby Isaac   for (p = pStartC; p < pEndC; p++) {
3690f30e825dSToby Isaac     ierr = PetscSectionSetDof(multiRootSec,p,rootDegrees[p-pStartC]);CHKERRQ(ierr);
36918d2f55e7SToby Isaac   }
3692f30e825dSToby Isaac   ierr = PetscSectionSetUp(multiRootSec);CHKERRQ(ierr);
3693f30e825dSToby Isaac   ierr = PetscSectionGetStorageSize(multiRootSec,&numMulti);CHKERRQ(ierr);
36948d2f55e7SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
3695f30e825dSToby Isaac   { /* distribute the leaf section */
3696f30e825dSToby Isaac     PetscSF multi, multiInv, indicesSF;
3697f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
36988d2f55e7SToby Isaac 
3699f30e825dSToby Isaac     ierr = PetscSFGetMultiSF(coarseToFineEmbedded,&multi);CHKERRQ(ierr);
3700f30e825dSToby Isaac     ierr = PetscSFCreateInverseSF(multi,&multiInv);CHKERRQ(ierr);
3701f30e825dSToby Isaac     ierr = PetscSFDistributeSection(multiInv,leafIndicesSec,&remoteOffsets,rootIndicesSec);CHKERRQ(ierr);
3702f30e825dSToby Isaac     ierr = PetscSFCreateSectionSF(multiInv,leafIndicesSec,remoteOffsets,rootIndicesSec,&indicesSF);CHKERRQ(ierr);
3703f30e825dSToby Isaac     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
3704f30e825dSToby Isaac     ierr = PetscSFDestroy(&multiInv);CHKERRQ(ierr);
37058d2f55e7SToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
3706c921d74cSToby Isaac     if (gatheredIndices) {
3707c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootInds);CHKERRQ(ierr);
3708c921d74cSToby Isaac       ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr);
3709c921d74cSToby Isaac       ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr);
3710c921d74cSToby Isaac     }
3711c921d74cSToby Isaac     if (gatheredValues) {
3712c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootVals);CHKERRQ(ierr);
3713c921d74cSToby Isaac       ierr = PetscSFBcastBegin(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr);
3714c921d74cSToby Isaac       ierr = PetscSFBcastEnd(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr);
3715c921d74cSToby Isaac     }
37168d2f55e7SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
37178d2f55e7SToby Isaac   }
3718ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
3719c921d74cSToby Isaac   ierr = PetscFree(leafInds);CHKERRQ(ierr);
3720c921d74cSToby Isaac   ierr = PetscFree(leafVals);CHKERRQ(ierr);
3721f30e825dSToby Isaac   ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3722c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3723c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3724c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3725c921d74cSToby Isaac   if (gatheredValues)  *gatheredValues  = rootVals;
3726ebf164c7SToby Isaac   PetscFunctionReturn(0);
3727ebf164c7SToby Isaac }
3728ebf164c7SToby Isaac 
3729ebf164c7SToby Isaac PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3730ebf164c7SToby Isaac {
3731ebf164c7SToby Isaac   DM             refTree;
3732c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3733ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3734ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3735ebf164c7SToby Isaac   PetscSection   cSecRef;
3736c921d74cSToby Isaac   PetscInt       *rootIndices, *parentIndices, pRefStart, pRefEnd;
3737ebf164c7SToby Isaac   Mat            injRef;
3738c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3739ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3740ebf164c7SToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
3741ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3742ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3743ebf164c7SToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3744ebf164c7SToby Isaac   PetscErrorCode ierr;
3745ebf164c7SToby Isaac 
3746ebf164c7SToby Isaac   PetscFunctionBegin;
3747ebf164c7SToby Isaac 
3748ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
3749ebf164c7SToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
3750ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
3751ebf164c7SToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3752ebf164c7SToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
3753ebf164c7SToby Isaac 
3754ebf164c7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
3755ebf164c7SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
3756ebf164c7SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3757ebf164c7SToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
3758ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
3759ebf164c7SToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
3760ebf164c7SToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3761ebf164c7SToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
3762ebf164c7SToby Isaac   {
3763ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
3764ebf164c7SToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
3765ebf164c7SToby Isaac   }
3766ebf164c7SToby Isaac 
3767c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,childIds,NULL,numFields,offsets,&multiRootSec,&rootIndicesSec,&rootIndices,NULL);CHKERRQ(ierr);
37688d2f55e7SToby Isaac 
3769f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&parentIndices);CHKERRQ(ierr);
3770f30e825dSToby Isaac 
3771f30e825dSToby Isaac   /* count indices */
37728d2f55e7SToby Isaac   ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
3773c6154584SToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
3774c6154584SToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
37758d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
37768d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
3777f30e825dSToby Isaac   ierr = PetscCalloc2(rowEnd-rowStart,&nnzD,rowEnd-rowStart,&nnzO);CHKERRQ(ierr);
3778f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3779f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
37808d2f55e7SToby Isaac 
3781f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3782f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3783f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3784f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
37858d2f55e7SToby Isaac 
37868d2f55e7SToby Isaac     rowOffsets[0] = 0;
3787f30e825dSToby Isaac     offsetsCopy[0] = 0;
37888d2f55e7SToby Isaac     if (numFields) {
37898d2f55e7SToby Isaac       PetscInt f;
37908d2f55e7SToby Isaac 
3791f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3792f30e825dSToby Isaac         PetscInt fDof;
3793f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3794f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
37958d2f55e7SToby Isaac       }
37964acb8e1eSToby Isaac       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,parentIndices);CHKERRQ(ierr);
37978d2f55e7SToby Isaac     }
37988d2f55e7SToby Isaac     else {
37994acb8e1eSToby Isaac       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,parentIndices);CHKERRQ(ierr);
3800f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
38018d2f55e7SToby Isaac     }
3802f30e825dSToby Isaac 
3803f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3804f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3805f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3806f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3807f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3808f30e825dSToby Isaac       const PetscInt *childIndices;
3809f30e825dSToby Isaac 
3810f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3811f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3812f30e825dSToby Isaac       childId = rootIndices[offset++];
3813f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3814f30e825dSToby Isaac       numIndices--;
3815f30e825dSToby Isaac 
3816f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3817f30e825dSToby Isaac         PetscInt i;
3818f30e825dSToby Isaac 
3819f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3820f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3821f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3822f30e825dSToby Isaac           if (rowIndex < 0) continue;
3823f30e825dSToby Isaac           if (colIndex < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unconstrained fine and constrained coarse");
3824a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3825f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
3826f30e825dSToby Isaac           }
3827f30e825dSToby Isaac           else {
3828f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3829f30e825dSToby Isaac           }
3830f30e825dSToby Isaac         }
3831f30e825dSToby Isaac       }
3832f30e825dSToby Isaac       else {
3833f30e825dSToby Isaac         PetscInt parentId, f, lim;
3834f30e825dSToby Isaac 
3835f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3836f30e825dSToby Isaac 
3837f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3838f30e825dSToby Isaac         offsets[0] = 0;
38398d2f55e7SToby Isaac         if (numFields) {
38408d2f55e7SToby Isaac           PetscInt f;
3841f30e825dSToby Isaac 
38428d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3843f30e825dSToby Isaac             PetscInt fDof;
3844f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
3845f30e825dSToby Isaac 
3846f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
38478d2f55e7SToby Isaac           }
38488d2f55e7SToby Isaac         }
38498d2f55e7SToby Isaac         else {
3850f30e825dSToby Isaac           PetscInt cDof;
3851f30e825dSToby Isaac 
3852f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
3853f30e825dSToby Isaac           offsets[1] = cDof;
3854f30e825dSToby Isaac         }
3855f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3856f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3857f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3858f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3859f30e825dSToby Isaac 
3860f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3861f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3862f30e825dSToby Isaac 
3863f30e825dSToby Isaac             if (colIndex < 0) continue;
3864f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3865f30e825dSToby Isaac               numD++;
3866f30e825dSToby Isaac             }
3867f30e825dSToby Isaac             else {
3868f30e825dSToby Isaac               numO++;
3869f30e825dSToby Isaac             }
3870f30e825dSToby Isaac           }
3871f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3872f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3873f30e825dSToby Isaac 
3874f30e825dSToby Isaac             if (rowIndex < 0) continue;
3875f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3876f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
38778d2f55e7SToby Isaac           }
38788d2f55e7SToby Isaac         }
38798d2f55e7SToby Isaac       }
3880f30e825dSToby Isaac     }
3881f30e825dSToby Isaac   }
3882f30e825dSToby Isaac   /* preallocate */
3883f30e825dSToby Isaac   ierr = MatXAIJSetPreallocation(mat,1,nnzD,nnzO,NULL,NULL);CHKERRQ(ierr);
3884f30e825dSToby Isaac   ierr = PetscFree2(nnzD,nnzO);CHKERRQ(ierr);
3885f30e825dSToby Isaac   /* insert values */
3886f30e825dSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
3887f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3888f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3889f30e825dSToby Isaac 
3890f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3891f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3892f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3893f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
3894f30e825dSToby Isaac 
3895f30e825dSToby Isaac     rowOffsets[0] = 0;
3896f30e825dSToby Isaac     offsetsCopy[0] = 0;
38978d2f55e7SToby Isaac     if (numFields) {
38988d2f55e7SToby Isaac       PetscInt f;
3899f30e825dSToby Isaac 
39008d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3901f30e825dSToby Isaac         PetscInt fDof;
3902f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3903f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3904f30e825dSToby Isaac       }
39054acb8e1eSToby Isaac       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,parentIndices);CHKERRQ(ierr);
3906f30e825dSToby Isaac     }
3907f30e825dSToby Isaac     else {
39084acb8e1eSToby Isaac       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,parentIndices);CHKERRQ(ierr);
3909f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3910f30e825dSToby Isaac     }
3911f30e825dSToby Isaac 
3912f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3913f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3914f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3915f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3916f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3917f30e825dSToby Isaac       const PetscInt *childIndices;
3918f30e825dSToby Isaac 
3919f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3920f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3921f30e825dSToby Isaac       childId = rootIndices[offset++];
3922f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3923f30e825dSToby Isaac       numIndices--;
3924f30e825dSToby Isaac 
3925f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3926f30e825dSToby Isaac         PetscInt i;
3927f30e825dSToby Isaac 
3928f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3929f30e825dSToby Isaac           ierr = MatSetValue(mat,parentIndices[i],childIndices[i],1.,INSERT_VALUES);CHKERRQ(ierr);
39308d2f55e7SToby Isaac         }
39318d2f55e7SToby Isaac       }
39328d2f55e7SToby Isaac       else {
3933f30e825dSToby Isaac         PetscInt parentId, f, lim;
39348d2f55e7SToby Isaac 
3935f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3936f30e825dSToby Isaac 
3937f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3938f30e825dSToby Isaac         offsets[0] = 0;
39398d2f55e7SToby Isaac         if (numFields) {
3940f30e825dSToby Isaac           PetscInt f;
39418d2f55e7SToby Isaac 
3942f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3943f30e825dSToby Isaac             PetscInt fDof;
3944f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
3945f30e825dSToby Isaac 
3946f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
39478d2f55e7SToby Isaac           }
39488d2f55e7SToby Isaac         }
39498d2f55e7SToby Isaac         else {
3950f30e825dSToby Isaac           PetscInt cDof;
3951f30e825dSToby Isaac 
3952f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
3953f30e825dSToby Isaac           offsets[1] = cDof;
39548d2f55e7SToby Isaac         }
3955f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3956f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3957f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3958f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3959f30e825dSToby Isaac 
3960f30e825dSToby Isaac           ierr = MatSetValues(mat,rowOffsets[f+1]-rowOffsets[f],rowIndices,offsets[f+1]-offsets[f],colIndices,childMat,INSERT_VALUES);CHKERRQ(ierr);
39618d2f55e7SToby Isaac         }
39628d2f55e7SToby Isaac       }
39638d2f55e7SToby Isaac     }
39648d2f55e7SToby Isaac   }
3965ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
3966ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
3967ec92bd66SToby Isaac   ierr = PetscFree(parentIndices);CHKERRQ(ierr);
3968f30e825dSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
3969f30e825dSToby Isaac   ierr = PetscFree(rootIndices);CHKERRQ(ierr);
3970f30e825dSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
3971f30e825dSToby Isaac 
39728d2f55e7SToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
39738d2f55e7SToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
3974154bca37SToby Isaac   PetscFunctionReturn(0);
3975154bca37SToby Isaac }
397638fc2455SToby Isaac 
39770eb7e1eaSToby Isaac static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3978ebf164c7SToby Isaac {
39794833aeb0SToby Isaac   PetscDS           ds;
398062095d54SToby Isaac   PetscSF           coarseToFineEmbedded;
398162095d54SToby Isaac   PetscSection      globalCoarse, globalFine;
398262095d54SToby Isaac   PetscSection      localCoarse, localFine;
398362095d54SToby Isaac   PetscSection      aSec, cSec;
398462095d54SToby Isaac   PetscSection      rootValuesSec;
398562095d54SToby Isaac   PetscSection      leafValuesSec;
398662095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
398762095d54SToby Isaac   IS                aIS;
398862095d54SToby Isaac   const PetscInt    *anchors;
398962095d54SToby Isaac   Mat               cMat;
399062095d54SToby Isaac   PetscInt          numFields;
399189698031SToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd, cellEndInterior;
399262095d54SToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
399362095d54SToby Isaac   PetscInt          *maxChildIds;
399462095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
39950eb7e1eaSToby Isaac   PetscFV           fv = NULL;
39960eb7e1eaSToby Isaac   PetscInt          dim, numFVcomps = -1, fvField = -1;
39970eb7e1eaSToby Isaac   DM                cellDM = NULL, gradDM = NULL;
39980eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
39990eb7e1eaSToby Isaac   const PetscScalar *gradArray = NULL;
400062095d54SToby Isaac   PetscErrorCode    ierr;
400162095d54SToby Isaac 
4002ebf164c7SToby Isaac   PetscFunctionBegin;
4003708c7f19SToby Isaac   ierr = VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
400462095d54SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
40050eb7e1eaSToby Isaac   ierr = DMPlexGetHeightStratum(coarse,0,&cellStart,&cellEnd);CHKERRQ(ierr);
400689698031SToby Isaac   ierr = DMPlexGetHybridBounds(coarse,&cellEndInterior,NULL,NULL,NULL);CHKERRQ(ierr);
400789698031SToby Isaac   cellEnd = (cellEndInterior < 0) ? cellEnd : cellEndInterior;
400862095d54SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
400962095d54SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
40100eb7e1eaSToby Isaac   ierr = DMGetCoordinateDim(coarse,&dim);CHKERRQ(ierr);
401162095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
4012e4a60869SToby Isaac     PetscInt       nleaves, l;
4013e4a60869SToby Isaac     const PetscInt *leaves;
401462095d54SToby Isaac     PetscInt       dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
401562095d54SToby Isaac 
4016e4a60869SToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
4017e4a60869SToby Isaac 
4018e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
4019e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
4020e4a60869SToby Isaac 
402162095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
402262095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
402362095d54SToby Isaac       if ((dof - cdof) > 0) {
402462095d54SToby Isaac         numPointsWithDofs++;
402562095d54SToby Isaac       }
402662095d54SToby Isaac     }
402762095d54SToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
40284833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
4029e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
4030e4a60869SToby Isaac 
403162095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
403262095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
403362095d54SToby Isaac       if ((dof - cdof) > 0) {
4034e4a60869SToby Isaac         pointsWithDofs[offset++] = l;
403562095d54SToby Isaac       }
403662095d54SToby Isaac     }
403762095d54SToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
403862095d54SToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
403962095d54SToby Isaac   }
404062095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
404162095d54SToby Isaac   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
404262095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) {
404362095d54SToby Isaac     maxChildIds[p - pStartC] = -2;
404462095d54SToby Isaac   }
404562095d54SToby Isaac   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
404662095d54SToby Isaac   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
404762095d54SToby Isaac 
404862095d54SToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
404962095d54SToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
405062095d54SToby Isaac 
405162095d54SToby Isaac   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
405262095d54SToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
405362095d54SToby Isaac   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
405462095d54SToby Isaac 
405562095d54SToby Isaac   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
405662095d54SToby Isaac   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
405762095d54SToby Isaac 
405862095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
405962095d54SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootValuesSec);CHKERRQ(ierr);
406062095d54SToby Isaac   ierr = PetscSectionSetChart(rootValuesSec,pStartC,pEndC);CHKERRQ(ierr);
4061708c7f19SToby Isaac   ierr = PetscSectionGetNumFields(localCoarse,&numFields);CHKERRQ(ierr);
406262095d54SToby Isaac   {
406362095d54SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
406462095d54SToby Isaac     ierr = PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO);CHKERRQ(ierr);
406562095d54SToby Isaac   }
40660eb7e1eaSToby Isaac   if (grad) {
40670eb7e1eaSToby Isaac     PetscInt i;
40680eb7e1eaSToby Isaac 
40690eb7e1eaSToby Isaac     ierr = VecGetDM(cellGeom,&cellDM);CHKERRQ(ierr);
40700eb7e1eaSToby Isaac     ierr = VecGetArrayRead(cellGeom,&cellGeomArray);CHKERRQ(ierr);
40710eb7e1eaSToby Isaac     ierr = VecGetDM(grad,&gradDM);CHKERRQ(ierr);
40720eb7e1eaSToby Isaac     ierr = VecGetArrayRead(grad,&gradArray);CHKERRQ(ierr);
40730eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1,numFields); i++) {
40740eb7e1eaSToby Isaac       PetscObject  obj;
40750eb7e1eaSToby Isaac       PetscClassId id;
40760eb7e1eaSToby Isaac 
40770eb7e1eaSToby Isaac       ierr = DMGetField(coarse, i, &obj);CHKERRQ(ierr);
40780eb7e1eaSToby Isaac       ierr = PetscObjectGetClassId(obj,&id);CHKERRQ(ierr);
40790eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
40800eb7e1eaSToby Isaac         fv      = (PetscFV) obj;
40810eb7e1eaSToby Isaac         ierr    = PetscFVGetNumComponents(fv,&numFVcomps);CHKERRQ(ierr);
40820eb7e1eaSToby Isaac         fvField = i;
40830eb7e1eaSToby Isaac         break;
40840eb7e1eaSToby Isaac       }
40850eb7e1eaSToby Isaac     }
40860eb7e1eaSToby Isaac   }
408762095d54SToby Isaac 
408862095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
408962095d54SToby Isaac     PetscInt dof;
409062095d54SToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
409162095d54SToby Isaac     PetscInt numValues      = 0;
409262095d54SToby Isaac 
409362095d54SToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
409462095d54SToby Isaac     if (dof < 0) {
409562095d54SToby Isaac       dof = -(dof + 1);
409662095d54SToby Isaac     }
409762095d54SToby Isaac     offsets[0]    = 0;
409862095d54SToby Isaac     newOffsets[0] = 0;
409962095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
410062095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
410162095d54SToby Isaac 
41024833aeb0SToby Isaac       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
410362095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
410462095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
410562095d54SToby Isaac 
410662095d54SToby Isaac         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
410762095d54SToby Isaac         numValues += clDof;
410862095d54SToby Isaac       }
41094833aeb0SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
411062095d54SToby Isaac     }
411162095d54SToby Isaac     else if (maxChildId == -1) {
411262095d54SToby Isaac       ierr = PetscSectionGetDof(localCoarse,p,&numValues);CHKERRQ(ierr);
411362095d54SToby Isaac     }
411462095d54SToby Isaac     /* we will pack the column indices with the field offsets */
411578b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
41160eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
41170eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
41180eb7e1eaSToby Isaac     }
411962095d54SToby Isaac     ierr = PetscSectionSetDof(rootValuesSec,p,numValues);CHKERRQ(ierr);
412062095d54SToby Isaac   }
412162095d54SToby Isaac   ierr = PetscSectionSetUp(rootValuesSec);CHKERRQ(ierr);
412262095d54SToby Isaac   {
412362095d54SToby Isaac     PetscInt          numRootValues;
412462095d54SToby Isaac     const PetscScalar *coarseArray;
412562095d54SToby Isaac 
412662095d54SToby Isaac     ierr = PetscSectionGetStorageSize(rootValuesSec,&numRootValues);CHKERRQ(ierr);
412762095d54SToby Isaac     ierr = PetscMalloc1(numRootValues,&rootValues);CHKERRQ(ierr);
412862095d54SToby Isaac     ierr = VecGetArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr);
412962095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
413062095d54SToby Isaac       PetscInt    numValues;
413162095d54SToby Isaac       PetscInt    pValOff;
413262095d54SToby Isaac       PetscScalar *pVal;
413362095d54SToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
413462095d54SToby Isaac 
413562095d54SToby Isaac       ierr = PetscSectionGetDof(rootValuesSec,p,&numValues);CHKERRQ(ierr);
413662095d54SToby Isaac       if (!numValues) {
413762095d54SToby Isaac         continue;
413862095d54SToby Isaac       }
413962095d54SToby Isaac       ierr = PetscSectionGetOffset(rootValuesSec,p,&pValOff);CHKERRQ(ierr);
414062095d54SToby Isaac       pVal = &(rootValues[pValOff]);
414162095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
41420eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
41430eb7e1eaSToby Isaac         ierr = DMPlexVecGetClosure(coarse,NULL,vecCoarseLocal,p,&closureSize,&pVal);CHKERRQ(ierr);
41440eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
4145193eb951SToby Isaac           PetscFVCellGeom *cg;
41466dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
41470eb7e1eaSToby Isaac           PetscInt        i;
41480eb7e1eaSToby Isaac 
41490eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
41500eb7e1eaSToby Isaac 
4151193eb951SToby Isaac           ierr = DMPlexPointLocalRead(cellDM,p,cellGeomArray,(void *) &cg);CHKERRQ(ierr);
41520eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
41530eb7e1eaSToby Isaac           pVal += dim;
4154193eb951SToby Isaac           ierr = DMPlexPointGlobalRead(gradDM,p,gradArray,(void *) &gradVals);CHKERRQ(ierr);
41550eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
41560eb7e1eaSToby Isaac         }
415762095d54SToby Isaac       }
415878b7adb5SToby Isaac       else if (maxChildId == -1) {
415978b7adb5SToby Isaac         PetscInt lDof, lOff, i;
416078b7adb5SToby Isaac 
416178b7adb5SToby Isaac         ierr = PetscSectionGetDof(localCoarse,p,&lDof);CHKERRQ(ierr);
416278b7adb5SToby Isaac         ierr = PetscSectionGetOffset(localCoarse,p,&lOff);CHKERRQ(ierr);
416378b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
416478b7adb5SToby Isaac       }
416578b7adb5SToby Isaac     }
416662095d54SToby Isaac     ierr = VecRestoreArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr);
416762095d54SToby Isaac     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
416862095d54SToby Isaac   }
416962095d54SToby Isaac   {
417062095d54SToby Isaac     PetscSF  valuesSF;
417162095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
417262095d54SToby Isaac 
417362095d54SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafValuesSec);CHKERRQ(ierr);
417462095d54SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootValuesSec,&remoteOffsetsValues,leafValuesSec);CHKERRQ(ierr);
417562095d54SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootValuesSec,remoteOffsetsValues,leafValuesSec,&valuesSF);CHKERRQ(ierr);
417662095d54SToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
417762095d54SToby Isaac     ierr = PetscFree(remoteOffsetsValues);CHKERRQ(ierr);
417862095d54SToby Isaac     ierr = PetscSectionGetStorageSize(leafValuesSec,&numLeafValues);CHKERRQ(ierr);
417962095d54SToby Isaac     ierr = PetscMalloc1(numLeafValues,&leafValues);CHKERRQ(ierr);
418062095d54SToby Isaac     ierr = PetscSFBcastBegin(valuesSF,MPIU_SCALAR,rootValues,leafValues);CHKERRQ(ierr);
418162095d54SToby Isaac     ierr = PetscSFBcastEnd(valuesSF,MPIU_SCALAR,rootValues,leafValues);CHKERRQ(ierr);
418262095d54SToby Isaac     ierr = PetscSFDestroy(&valuesSF);CHKERRQ(ierr);
418362095d54SToby Isaac     ierr = PetscFree(rootValues);CHKERRQ(ierr);
418462095d54SToby Isaac     ierr = PetscSectionDestroy(&rootValuesSec);CHKERRQ(ierr);
418562095d54SToby Isaac   }
418662095d54SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
418762095d54SToby Isaac   {
418862095d54SToby Isaac     PetscInt    maxDof;
418962095d54SToby Isaac     PetscInt    *rowIndices;
419062095d54SToby Isaac     DM           refTree;
419162095d54SToby Isaac     PetscInt     **refPointFieldN;
419262095d54SToby Isaac     PetscScalar  ***refPointFieldMats;
419362095d54SToby Isaac     PetscSection refConSec, refAnSec;
41940eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,leafStart,leafEnd;
419562095d54SToby Isaac     PetscScalar  *pointWork;
419662095d54SToby Isaac 
419762095d54SToby Isaac     ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr);
419862095d54SToby Isaac     ierr = DMGetWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
419962095d54SToby Isaac     ierr = DMGetWorkArray(fine,maxDof,PETSC_SCALAR,&pointWork);CHKERRQ(ierr);
420062095d54SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
42014833aeb0SToby Isaac     ierr = DMGetDS(fine,&ds);CHKERRQ(ierr);
42024833aeb0SToby Isaac     ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
420362095d54SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
420462095d54SToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
420562095d54SToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
420662095d54SToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
42070eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafValuesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
42080eb7e1eaSToby Isaac     ierr = DMPlexGetHeightStratum(fine,0,&cellStart,&cellEnd);CHKERRQ(ierr);
420989698031SToby Isaac     ierr = DMPlexGetHybridBounds(fine,&cellEndInterior,NULL,NULL,NULL);CHKERRQ(ierr);
421089698031SToby Isaac     cellEnd = (cellEndInterior < 0) ? cellEnd : cellEndInterior;
42110eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
421262095d54SToby Isaac       PetscInt          gDof, gcDof, gOff, lDof;
421362095d54SToby Isaac       PetscInt          numValues, pValOff;
421462095d54SToby Isaac       PetscInt          childId;
421562095d54SToby Isaac       const PetscScalar *pVal;
42160eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
421762095d54SToby Isaac 
421862095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
421962095d54SToby Isaac       ierr = PetscSectionGetDof(localFine,p,&lDof);CHKERRQ(ierr);
422062095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
422162095d54SToby Isaac       if ((gDof - gcDof) <= 0) {
422262095d54SToby Isaac         continue;
422362095d54SToby Isaac       }
422462095d54SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
422562095d54SToby Isaac       ierr = PetscSectionGetDof(leafValuesSec,p,&numValues);CHKERRQ(ierr);
422662095d54SToby Isaac       if (!numValues) continue;
422762095d54SToby Isaac       ierr = PetscSectionGetOffset(leafValuesSec,p,&pValOff);CHKERRQ(ierr);
422862095d54SToby Isaac       pVal = &leafValues[pValOff];
422962095d54SToby Isaac       offsets[0]        = 0;
423062095d54SToby Isaac       offsetsCopy[0]    = 0;
423162095d54SToby Isaac       newOffsets[0]     = 0;
423262095d54SToby Isaac       newOffsetsCopy[0] = 0;
42334833aeb0SToby Isaac       childId           = cids[p - pStartF];
423462095d54SToby Isaac       if (numFields) {
423562095d54SToby Isaac         PetscInt f;
423662095d54SToby Isaac         for (f = 0; f < numFields; f++) {
423762095d54SToby Isaac           PetscInt rowDof;
423862095d54SToby Isaac 
423962095d54SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
424062095d54SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
424162095d54SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
424262095d54SToby Isaac           /* TODO: closure indices */
42439f4e70e1SToby Isaac           newOffsets[f + 1]     = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
424462095d54SToby Isaac         }
42454acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,rowIndices);CHKERRQ(ierr);
424662095d54SToby Isaac       }
424762095d54SToby Isaac       else {
42484833aeb0SToby Isaac         offsets[0]    = 0;
42494833aeb0SToby Isaac         offsets[1]    = lDof;
42504833aeb0SToby Isaac         newOffsets[0] = 0;
42514833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
42524acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,rowIndices);CHKERRQ(ierr);
425362095d54SToby Isaac       }
425462095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
42552f65e181SToby Isaac         ierr = VecSetValues(vecFine,numValues,rowIndices,pVal,INSERT_VALUES);CHKERRQ(ierr);
425662095d54SToby Isaac       } else {
425762095d54SToby Isaac         PetscInt f;
425862095d54SToby Isaac 
425978b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
426078b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
426178b7adb5SToby Isaac           fvGradData = &pVal[numValues];
426278b7adb5SToby Isaac         }
426362095d54SToby Isaac         for (f = 0; f < PetscMax(1,numFields); f++) {
426462095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
426562095d54SToby Isaac           PetscInt numRows = offsets[f+1] - offsets[f];
426662095d54SToby Isaac           PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
426762095d54SToby Isaac           const PetscScalar *cVal = &pVal[newOffsets[f]];
426862095d54SToby Isaac           PetscScalar *rVal = &pointWork[offsets[f]];
426962095d54SToby Isaac           PetscInt i, j;
427062095d54SToby Isaac 
4271708c7f19SToby Isaac #if 0
4272708c7f19SToby 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);
4273708c7f19SToby Isaac #endif
427462095d54SToby Isaac           for (i = 0; i < numRows; i++) {
427562095d54SToby Isaac             PetscScalar val = 0.;
427662095d54SToby Isaac             for (j = 0; j < numCols; j++) {
427762095d54SToby Isaac               val += childMat[i * numCols + j] * cVal[j];
427862095d54SToby Isaac             }
427962095d54SToby Isaac             rVal[i] = val;
428062095d54SToby Isaac           }
42810eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
42820eb7e1eaSToby Isaac             PetscReal   centroid[3];
42830eb7e1eaSToby Isaac             PetscScalar diff[3];
42840eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
42850eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
42860eb7e1eaSToby Isaac 
42870eb7e1eaSToby Isaac             ierr = DMPlexComputeCellGeometryFVM(fine,p,NULL,centroid,NULL);CHKERRQ(ierr);
42880eb7e1eaSToby Isaac             for (i = 0; i < dim; i++) {
42890eb7e1eaSToby Isaac               diff[i] = centroid[i] - parentCentroid[i];
42900eb7e1eaSToby Isaac             }
42910eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
42920eb7e1eaSToby Isaac               PetscScalar val = 0.;
42930eb7e1eaSToby Isaac 
429489698031SToby Isaac               for (j = 0; j < dim; j++) {
42950eb7e1eaSToby Isaac                 val += gradient[dim * i + j] * diff[j];
42960eb7e1eaSToby Isaac               }
42970eb7e1eaSToby Isaac               rVal[i] += val;
42980eb7e1eaSToby Isaac             }
42990eb7e1eaSToby Isaac           }
43002f65e181SToby Isaac           ierr = VecSetValues(vecFine,numRows,&rowIndices[offsets[f]],rVal,INSERT_VALUES);CHKERRQ(ierr);
430162095d54SToby Isaac         }
430262095d54SToby Isaac       }
430362095d54SToby Isaac     }
430462095d54SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
430562095d54SToby Isaac     ierr = DMRestoreWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
430662095d54SToby Isaac     ierr = DMRestoreWorkArray(fine,maxDof,PETSC_SCALAR,&pointWork);CHKERRQ(ierr);
430762095d54SToby Isaac   }
43084fe3dfefSToby Isaac   ierr = PetscFree(leafValues);CHKERRQ(ierr);
430962095d54SToby Isaac   ierr = PetscSectionDestroy(&leafValuesSec);CHKERRQ(ierr);
431062095d54SToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
431162095d54SToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
4312ebf164c7SToby Isaac   PetscFunctionReturn(0);
4313ebf164c7SToby Isaac }
4314ebf164c7SToby Isaac 
4315ebf164c7SToby Isaac static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4316ebf164c7SToby Isaac {
43174833aeb0SToby Isaac   PetscDS        ds;
4318c921d74cSToby Isaac   DM             refTree;
4319c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4320c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4321c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4322c921d74cSToby Isaac   PetscSection   cSecRef;
4323c921d74cSToby Isaac   PetscInt       *parentIndices, pRefStart, pRefEnd;
4324d3bc4906SToby Isaac   PetscScalar    *rootValues, *parentValues;
4325c921d74cSToby Isaac   Mat            injRef;
4326c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4327c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4328c921d74cSToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
4329c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4330c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4331c921d74cSToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4332c921d74cSToby Isaac   PetscErrorCode ierr;
4333c921d74cSToby Isaac 
4334ebf164c7SToby Isaac   PetscFunctionBegin;
4335c921d74cSToby Isaac 
4336c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
4337708c7f19SToby Isaac   ierr = VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
4338708c7f19SToby Isaac   ierr = VecSetOption(vecCoarse,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
4339c921d74cSToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
43404833aeb0SToby Isaac   ierr = DMGetDS(coarse,&ds);CHKERRQ(ierr);
43414833aeb0SToby Isaac   ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
4342c921d74cSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
4343c921d74cSToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
4344c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
4345c921d74cSToby Isaac 
4346c921d74cSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
4347c921d74cSToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
4348c921d74cSToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
4349c921d74cSToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
4350c921d74cSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
4351c921d74cSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
4352c921d74cSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
4353c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
4354c921d74cSToby Isaac   {
4355c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
4356c921d74cSToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
4357c921d74cSToby Isaac   }
4358c921d74cSToby Isaac 
4359c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,cids,vecFine,numFields,offsets,&multiRootSec,&rootIndicesSec,NULL,&rootValues);CHKERRQ(ierr);
4360c921d74cSToby Isaac 
4361d3bc4906SToby Isaac   ierr = PetscMalloc2(maxDof,&parentIndices,maxDof,&parentValues);CHKERRQ(ierr);
4362c921d74cSToby Isaac 
4363c921d74cSToby Isaac   /* count indices */
436462095d54SToby Isaac   ierr = VecGetLayout(vecFine,&colMap);CHKERRQ(ierr);
436562095d54SToby Isaac   ierr = VecGetLayout(vecCoarse,&rowMap);CHKERRQ(ierr);
4366c921d74cSToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
4367c921d74cSToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
4368c921d74cSToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
4369c921d74cSToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
4370c921d74cSToby Isaac   /* insert values */
4371c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4372c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4373c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
437478b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4375c921d74cSToby Isaac 
4376c921d74cSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
4377c921d74cSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
4378c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
43792f65e181SToby Isaac     ierr = PetscSectionGetDof(localCoarse,p,&dof);CHKERRQ(ierr);
4380c921d74cSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
4381c921d74cSToby Isaac 
4382c921d74cSToby Isaac     rowOffsets[0] = 0;
4383c921d74cSToby Isaac     offsetsCopy[0] = 0;
4384c921d74cSToby Isaac     if (numFields) {
4385c921d74cSToby Isaac       PetscInt f;
4386c921d74cSToby Isaac 
4387c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4388c921d74cSToby Isaac         PetscInt fDof;
4389c921d74cSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
4390c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4391c921d74cSToby Isaac       }
43924acb8e1eSToby Isaac       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,parentIndices);CHKERRQ(ierr);
4393c921d74cSToby Isaac     }
4394c921d74cSToby Isaac     else {
43954acb8e1eSToby Isaac       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,parentIndices);CHKERRQ(ierr);
4396c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4397c921d74cSToby Isaac     }
4398c921d74cSToby Isaac 
4399c921d74cSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
4400c921d74cSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
4401c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
44022f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4403c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4404c921d74cSToby Isaac       PetscInt numIndices, childId, offset;
4405c921d74cSToby Isaac       const PetscScalar *childValues;
4406c921d74cSToby Isaac 
4407c921d74cSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
4408c921d74cSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
4409c921d74cSToby Isaac       childId = (PetscInt) PetscRealPart(rootValues[offset++]);
4410c921d74cSToby Isaac       childValues = &rootValues[offset];
4411c921d74cSToby Isaac       numIndices--;
4412c921d74cSToby Isaac 
4413c921d74cSToby Isaac       if (childId == -2) { /* skip */
4414c921d74cSToby Isaac         continue;
4415c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
44162f65e181SToby Isaac         PetscInt m;
44172f65e181SToby Isaac 
441878b7adb5SToby Isaac         contribute = PETSC_TRUE;
44192f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4420beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4421d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4422d3bc4906SToby Isaac 
442378b7adb5SToby Isaac         contribute = PETSC_TRUE;
4424d3bc4906SToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
4425d3bc4906SToby Isaac 
4426d3bc4906SToby Isaac         lim = PetscMax(1,numFields);
4427d3bc4906SToby Isaac         offsets[0] = 0;
4428d3bc4906SToby Isaac         if (numFields) {
4429d3bc4906SToby Isaac           PetscInt f;
4430d3bc4906SToby Isaac 
4431d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4432d3bc4906SToby Isaac             PetscInt fDof;
4433d3bc4906SToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
4434d3bc4906SToby Isaac 
4435d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4436d3bc4906SToby Isaac           }
4437d3bc4906SToby Isaac         }
4438d3bc4906SToby Isaac         else {
4439d3bc4906SToby Isaac           PetscInt cDof;
4440d3bc4906SToby Isaac 
4441d3bc4906SToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
4442d3bc4906SToby Isaac           offsets[1] = cDof;
4443d3bc4906SToby Isaac         }
4444d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4445d3bc4906SToby Isaac           PetscScalar       *childMat   = &childrenMats[childId - pRefStart][f][0];
4446d3bc4906SToby Isaac           PetscInt          n           = offsets[f+1]-offsets[f];
4447*e328ff09SToby Isaac           PetscInt          m           = rowOffsets[f+1]-rowOffsets[f];
4448d3bc4906SToby Isaac           PetscInt          i, j;
4449d3bc4906SToby Isaac           const PetscScalar *colValues  = &childValues[offsets[f]];
4450d3bc4906SToby Isaac 
4451*e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4452d3bc4906SToby Isaac             PetscScalar val = 0.;
4453d3bc4906SToby Isaac             for (j = 0; j < n; j++) {
4454d3bc4906SToby Isaac               val += childMat[n * i + j] * colValues[j];
4455d3bc4906SToby Isaac             }
4456*e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4457d3bc4906SToby Isaac           }
4458d3bc4906SToby Isaac         }
4459c921d74cSToby Isaac       }
4460c921d74cSToby Isaac     }
446178b7adb5SToby Isaac     if (contribute) {ierr = VecSetValues(vecCoarse,dof,parentIndices,parentValues,INSERT_VALUES);CHKERRQ(ierr);}
4462c921d74cSToby Isaac   }
4463c921d74cSToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
4464c921d74cSToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
4465d3bc4906SToby Isaac   ierr = PetscFree2(parentIndices,parentValues);CHKERRQ(ierr);
4466c921d74cSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4467c921d74cSToby Isaac   ierr = PetscFree(rootValues);CHKERRQ(ierr);
4468c921d74cSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
4469ebf164c7SToby Isaac   PetscFunctionReturn(0);
4470ebf164c7SToby Isaac }
4471ebf164c7SToby Isaac 
4472ff1f73f7SToby Isaac /*@
4473ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4474ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4475ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4476ff1f73f7SToby Isaac 
4477ff1f73f7SToby Isaac   collective
4478ff1f73f7SToby Isaac 
4479ff1f73f7SToby Isaac   Input Parameters:
4480ff1f73f7SToby Isaac + dmIn        - The DMPlex mesh for the input vector
4481ff1f73f7SToby Isaac . vecIn       - The input vector
4482ff1f73f7SToby Isaac . sfRefine    - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4483ff1f73f7SToby Isaac                 the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4484ff1f73f7SToby Isaac . sfCoarsen   - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4485ff1f73f7SToby Isaac                 the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4486ff1f73f7SToby Isaac . cidsRefine  - The childIds of the points in dmOut.  These childIds relate back to the reference tree: childid[j] = k implies
4487ff1f73f7SToby Isaac                 that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4488ff1f73f7SToby Isaac                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in dmOut is exactly
4489ff1f73f7SToby Isaac                 equivalent to its root in dmIn, so no interpolation is necessary.  childid[j] = -2 indicates that this
4490ff1f73f7SToby Isaac                 point j in dmOut is not a leaf of sfRefine.
4491ff1f73f7SToby Isaac . cidsCoarsen - The childIds of the points in dmIn.  These childIds relate back to the reference tree: childid[j] = k implies
4492ff1f73f7SToby Isaac                 that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4493ff1f73f7SToby Isaac                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4494ff1f73f7SToby Isaac . useBCs      - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4495ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4496ff1f73f7SToby Isaac 
4497ff1f73f7SToby Isaac   Output Parameters:
4498ff1f73f7SToby Isaac . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transfered
4499ff1f73f7SToby Isaac                 projection of vecIn from dmIn to dmOut.  Note that any field discretized with a PetscFV finite volume
4500ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4501ff1f73f7SToby Isaac                 coarse points to fine points.
4502ff1f73f7SToby Isaac 
4503ff1f73f7SToby Isaac   Level: developer
4504ff1f73f7SToby Isaac 
4505ff1f73f7SToby Isaac .seealso(): DMPlexSetReferenceTree(), DMPlexGetReferenceTree(), PetscFVGetComputeGradients()
4506ff1f73f7SToby Isaac @*/
4507ff1f73f7SToby Isaac PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
450838fc2455SToby Isaac {
4509ebf164c7SToby Isaac   PetscErrorCode ierr;
4510ebf164c7SToby Isaac 
451138fc2455SToby Isaac   PetscFunctionBegin;
451278b7adb5SToby Isaac   ierr = VecSet(vecOut,0.0);CHKERRQ(ierr);
4513ff1f73f7SToby Isaac   if (sfRefine) {
4514fbfa57b9SToby Isaac     Vec vecInLocal;
45150eb7e1eaSToby Isaac     DM  dmGrad = NULL;
45160eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4517fbfa57b9SToby Isaac 
4518fbfa57b9SToby Isaac     ierr = DMGetLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
4519fbfa57b9SToby Isaac     ierr = VecSet(vecInLocal,0.0);CHKERRQ(ierr);
45200eb7e1eaSToby Isaac     {
45210eb7e1eaSToby Isaac       PetscInt  numFields, i;
45220eb7e1eaSToby Isaac 
45230eb7e1eaSToby Isaac       ierr = DMGetNumFields(dmIn, &numFields);CHKERRQ(ierr);
45240eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
45250eb7e1eaSToby Isaac         PetscObject  obj;
45260eb7e1eaSToby Isaac         PetscClassId classid;
45270eb7e1eaSToby Isaac 
45280eb7e1eaSToby Isaac         ierr = DMGetField(dmIn, i, &obj);CHKERRQ(ierr);
45290eb7e1eaSToby Isaac         ierr = PetscObjectGetClassId(obj, &classid);CHKERRQ(ierr);
45300eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
45310eb7e1eaSToby Isaac           ierr = DMPlexGetDataFVM(dmIn,(PetscFV)obj,&cellGeom,&faceGeom,&dmGrad);CHKERRQ(ierr);
45320eb7e1eaSToby Isaac           break;
45330eb7e1eaSToby Isaac         }
45340eb7e1eaSToby Isaac       }
45350eb7e1eaSToby Isaac     }
45360eb7e1eaSToby Isaac     if (useBCs) {
45370eb7e1eaSToby Isaac       ierr = DMPlexInsertBoundaryValues(dmIn,PETSC_TRUE,vecInLocal,time,faceGeom,cellGeom,NULL);CHKERRQ(ierr);
45380eb7e1eaSToby Isaac     }
4539fbfa57b9SToby Isaac     ierr = DMGlobalToLocalBegin(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
4540fbfa57b9SToby Isaac     ierr = DMGlobalToLocalEnd(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
45410eb7e1eaSToby Isaac     if (dmGrad) {
45420eb7e1eaSToby Isaac       ierr = DMGetGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
45430eb7e1eaSToby Isaac       ierr = DMPlexReconstructGradientsFVM(dmIn,vecInLocal,grad);CHKERRQ(ierr);
45440eb7e1eaSToby Isaac     }
4545ff1f73f7SToby Isaac     ierr = DMPlexTransferVecTree_Interpolate(dmIn,vecInLocal,dmOut,vecOut,sfRefine,cidsRefine,grad,cellGeom);CHKERRQ(ierr);
4546fbfa57b9SToby Isaac     ierr = DMRestoreLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
45470eb7e1eaSToby Isaac     if (dmGrad) {
45480eb7e1eaSToby Isaac       ierr = DMRestoreGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
45490eb7e1eaSToby Isaac     }
4550ebf164c7SToby Isaac   }
4551ff1f73f7SToby Isaac   if (sfCoarsen) {
4552ff1f73f7SToby Isaac     ierr = DMPlexTransferVecTree_Inject(dmIn,vecIn,dmOut,vecOut,sfCoarsen,cidsCoarsen);CHKERRQ(ierr);
4553ebf164c7SToby Isaac   }
45542f65e181SToby Isaac   ierr = VecAssemblyBegin(vecOut);CHKERRQ(ierr);
45552f65e181SToby Isaac   ierr = VecAssemblyEnd(vecOut);CHKERRQ(ierr);
455638fc2455SToby Isaac   PetscFunctionReturn(0);
455738fc2455SToby Isaac }
4558