xref: /petsc/src/dm/impls/plex/plextree.c (revision 1683a169f336407cb9d0d8662b3b43f2a09d25dc)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2af0996ceSBarry Smith #include <petsc/private/isimpl.h>
3af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
4d6a7ad0dSToby Isaac #include <petscsf.h>
50c37af3bSToby Isaac #include <petscds.h>
6d6a7ad0dSToby Isaac 
7d6a7ad0dSToby Isaac /** hierarchy routines */
8d6a7ad0dSToby Isaac 
9d6a7ad0dSToby Isaac /*@
10d6a7ad0dSToby Isaac   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
11d6a7ad0dSToby Isaac 
12d6a7ad0dSToby Isaac   Not collective
13d6a7ad0dSToby Isaac 
14d6a7ad0dSToby Isaac   Input Parameters:
15d6a7ad0dSToby Isaac + dm - The DMPlex object
16d6a7ad0dSToby Isaac - ref - The reference tree DMPlex object
17d6a7ad0dSToby Isaac 
180b7167a0SToby Isaac   Level: intermediate
19d6a7ad0dSToby Isaac 
20da43764aSToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexCreateDefaultReferenceTree()
21d6a7ad0dSToby Isaac @*/
22d6a7ad0dSToby Isaac PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
23d6a7ad0dSToby Isaac {
24d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
25d6a7ad0dSToby Isaac   PetscErrorCode  ierr;
26d6a7ad0dSToby Isaac 
27d6a7ad0dSToby Isaac   PetscFunctionBegin;
28d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2947a1df27SMatthew G. Knepley   if (ref) {PetscValidHeaderSpecific(ref, DM_CLASSID, 2);}
30d6a7ad0dSToby Isaac   ierr = PetscObjectReference((PetscObject)ref);CHKERRQ(ierr);
31d6a7ad0dSToby Isaac   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
32d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
33d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
34d6a7ad0dSToby Isaac }
35d6a7ad0dSToby Isaac 
36d6a7ad0dSToby Isaac /*@
37d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
38d6a7ad0dSToby Isaac 
39d6a7ad0dSToby Isaac   Not collective
40d6a7ad0dSToby Isaac 
41d6a7ad0dSToby Isaac   Input Parameters:
42d6a7ad0dSToby Isaac . dm - The DMPlex object
43d6a7ad0dSToby Isaac 
44d6a7ad0dSToby Isaac   Output Parameters
45d6a7ad0dSToby Isaac . ref - The reference tree DMPlex object
46d6a7ad0dSToby Isaac 
470b7167a0SToby Isaac   Level: intermediate
48d6a7ad0dSToby Isaac 
49da43764aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexCreateDefaultReferenceTree()
50d6a7ad0dSToby Isaac @*/
51d6a7ad0dSToby Isaac PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
52d6a7ad0dSToby Isaac {
53d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
54d6a7ad0dSToby Isaac 
55d6a7ad0dSToby Isaac   PetscFunctionBegin;
56d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
57d6a7ad0dSToby Isaac   PetscValidPointer(ref,2);
58d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
59d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
60d6a7ad0dSToby Isaac }
61d6a7ad0dSToby Isaac 
62dcbd3bf7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
63dcbd3bf7SToby Isaac {
64dcbd3bf7SToby Isaac   PetscInt       coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
65dcbd3bf7SToby Isaac   PetscErrorCode ierr;
66dcbd3bf7SToby Isaac 
67dcbd3bf7SToby Isaac   PetscFunctionBegin;
68dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
69dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
70dcbd3bf7SToby Isaac     if (childB) *childB = childA;
71dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
72dcbd3bf7SToby Isaac   }
73dcbd3bf7SToby Isaac   for (dim = 0; dim < 3; dim++) {
74dcbd3bf7SToby Isaac     ierr = DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd);CHKERRQ(ierr);
75dcbd3bf7SToby Isaac     if (parent >= dStart && parent <= dEnd) {
76dcbd3bf7SToby Isaac       break;
77dcbd3bf7SToby Isaac     }
78dcbd3bf7SToby Isaac   }
79dcbd3bf7SToby Isaac   if (dim > 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim);
80dcbd3bf7SToby Isaac   if (!dim) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
81dcbd3bf7SToby Isaac   if (childA < dStart || childA >= dEnd) {
82dcbd3bf7SToby Isaac     /* this is a lower-dimensional child: bootstrap */
83dcbd3bf7SToby Isaac     PetscInt size, i, sA = -1, sB, sOrientB, sConeSize;
84dcbd3bf7SToby Isaac     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
85dcbd3bf7SToby Isaac 
86dcbd3bf7SToby Isaac     ierr = DMPlexGetSupportSize(dm,childA,&size);CHKERRQ(ierr);
87dcbd3bf7SToby Isaac     ierr = DMPlexGetSupport(dm,childA,&supp);CHKERRQ(ierr);
88dcbd3bf7SToby Isaac 
89dcbd3bf7SToby Isaac     /* find a point sA in supp(childA) that has the same parent */
90dcbd3bf7SToby Isaac     for (i = 0; i < size; i++) {
91dcbd3bf7SToby Isaac       PetscInt sParent;
92dcbd3bf7SToby Isaac 
93dcbd3bf7SToby Isaac       sA   = supp[i];
94dcbd3bf7SToby Isaac       if (sA == parent) continue;
95dcbd3bf7SToby Isaac       ierr = DMPlexGetTreeParent(dm,sA,&sParent,NULL);CHKERRQ(ierr);
96dcbd3bf7SToby Isaac       if (sParent == parent) {
97dcbd3bf7SToby Isaac         break;
98dcbd3bf7SToby Isaac       }
99dcbd3bf7SToby Isaac     }
100dcbd3bf7SToby Isaac     if (i == size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
101dcbd3bf7SToby Isaac     /* find out which point sB is in an equivalent position to sA under
102dcbd3bf7SToby Isaac      * parentOrientB */
103dcbd3bf7SToby Isaac     ierr = DMPlexReferenceTreeGetChildSymmetry_Default(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB);CHKERRQ(ierr);
104dcbd3bf7SToby Isaac     ierr = DMPlexGetConeSize(dm,sA,&sConeSize);CHKERRQ(ierr);
105dcbd3bf7SToby Isaac     ierr = DMPlexGetCone(dm,sA,&coneA);CHKERRQ(ierr);
106dcbd3bf7SToby Isaac     ierr = DMPlexGetCone(dm,sB,&coneB);CHKERRQ(ierr);
107dcbd3bf7SToby Isaac     ierr = DMPlexGetConeOrientation(dm,sA,&oA);CHKERRQ(ierr);
108dcbd3bf7SToby Isaac     ierr = DMPlexGetConeOrientation(dm,sB,&oB);CHKERRQ(ierr);
109dcbd3bf7SToby Isaac     /* step through the cone of sA in natural order */
110dcbd3bf7SToby Isaac     for (i = 0; i < sConeSize; i++) {
111dcbd3bf7SToby Isaac       if (coneA[i] == childA) {
112dcbd3bf7SToby Isaac         /* if childA is at position i in coneA,
113dcbd3bf7SToby Isaac          * then we want the point that is at sOrientB*i in coneB */
114dcbd3bf7SToby Isaac         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
115dcbd3bf7SToby Isaac         if (childB) *childB = coneB[j];
116dcbd3bf7SToby Isaac         if (childOrientB) {
117dcbd3bf7SToby Isaac           PetscInt oBtrue;
118dcbd3bf7SToby Isaac 
119dcbd3bf7SToby Isaac           ierr          = DMPlexGetConeSize(dm,childA,&coneSize);CHKERRQ(ierr);
120dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
121dcbd3bf7SToby Isaac           if (coneSize != 0 && coneSize != 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
122dcbd3bf7SToby Isaac           /* we may have to flip an edge */
123dcbd3bf7SToby Isaac           oBtrue        = coneSize ? ((sOrientB >= 0) ? oB[j] : -(oB[j] + 2)) : 0;
124367003a6SStefano Zampini           ABswap        = DihedralSwap(coneSize,oA[i],oBtrue);
125dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
126dcbd3bf7SToby Isaac         }
127dcbd3bf7SToby Isaac         break;
128dcbd3bf7SToby Isaac       }
129dcbd3bf7SToby Isaac     }
130dcbd3bf7SToby Isaac     if (i == sConeSize) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
131dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
132dcbd3bf7SToby Isaac   }
133dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
134dcbd3bf7SToby Isaac   ierr   = DMPlexGetConeSize(dm,parent,&coneSize);CHKERRQ(ierr);
135dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
136dcbd3bf7SToby Isaac   if (dim == 2) {
137dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
138dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
139dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
140dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
141dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
142dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
143947b95d8SBarry Smith   } else {
144dcbd3bf7SToby Isaac     ABswapVert = ABswap;
145dcbd3bf7SToby Isaac   }
146dcbd3bf7SToby Isaac   if (childB) {
147dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
148dcbd3bf7SToby Isaac     PetscInt p, posA = -1, numChildren, i;
149dcbd3bf7SToby Isaac     const PetscInt *children;
150dcbd3bf7SToby Isaac 
151dcbd3bf7SToby Isaac     /* count which position the child is in */
152dcbd3bf7SToby Isaac     ierr = DMPlexGetTreeChildren(dm,parent,&numChildren,&children);CHKERRQ(ierr);
153dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
154dcbd3bf7SToby Isaac       p = children[i];
155dcbd3bf7SToby Isaac       if (p == childA) {
156dcbd3bf7SToby Isaac         posA = i;
157dcbd3bf7SToby Isaac         break;
158dcbd3bf7SToby Isaac       }
159dcbd3bf7SToby Isaac     }
160dcbd3bf7SToby Isaac     if (posA >= coneSize) {
161dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
162dcbd3bf7SToby Isaac        * is invariant */
163dcbd3bf7SToby Isaac       if (dim != 2 || posA != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Expected a middle triangle, got something else");
164dcbd3bf7SToby Isaac       *childB = childA;
165dcbd3bf7SToby Isaac     }
166dcbd3bf7SToby Isaac     else {
167dcbd3bf7SToby Isaac       /* figure out position B by applying ABswapVert */
168dcbd3bf7SToby Isaac       PetscInt posB;
169dcbd3bf7SToby Isaac 
170dcbd3bf7SToby Isaac       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
171dcbd3bf7SToby Isaac       if (childB) *childB = children[posB];
172dcbd3bf7SToby Isaac     }
173dcbd3bf7SToby Isaac   }
174dcbd3bf7SToby Isaac   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
175dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
176dcbd3bf7SToby Isaac }
177dcbd3bf7SToby Isaac 
178dcbd3bf7SToby Isaac /*@
179dcbd3bf7SToby Isaac   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
180dcbd3bf7SToby Isaac 
181dcbd3bf7SToby Isaac   Input Parameters:
182dcbd3bf7SToby Isaac + dm - the reference tree DMPlex object
183dcbd3bf7SToby Isaac . parent - the parent point
184dcbd3bf7SToby Isaac . parentOrientA - the reference orientation for describing the parent
185dcbd3bf7SToby Isaac . childOrientA - the reference orientation for describing the child
186dcbd3bf7SToby Isaac . childA - the reference childID for describing the child
187dcbd3bf7SToby Isaac - parentOrientB - the new orientation for describing the parent
188dcbd3bf7SToby Isaac 
189dcbd3bf7SToby Isaac   Output Parameters:
190dcbd3bf7SToby Isaac + childOrientB - if not NULL, set to the new oreintation for describing the child
191ff1f73f7SToby Isaac - childB - if not NULL, the new childID for describing the child
192dcbd3bf7SToby Isaac 
193dcbd3bf7SToby Isaac   Level: developer
194dcbd3bf7SToby Isaac 
195dcbd3bf7SToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexSetReferenceTree(), DMPlexSetTree()
196dcbd3bf7SToby Isaac @*/
197dcbd3bf7SToby Isaac PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
198dcbd3bf7SToby Isaac {
199dcbd3bf7SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
200dcbd3bf7SToby Isaac   PetscErrorCode ierr;
201dcbd3bf7SToby Isaac 
202dcbd3bf7SToby Isaac   PetscFunctionBegin;
203dcbd3bf7SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
204dcbd3bf7SToby Isaac   if (!mesh->getchildsymmetry) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlexReferenceTreeGetChildSymmetry not implemented");
205dcbd3bf7SToby Isaac   ierr = mesh->getchildsymmetry(dm,parent,parentOrientA,childOrientA,childA,parentOrientB,childOrientB,childB);CHKERRQ(ierr);
206dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
207dcbd3bf7SToby Isaac }
208dcbd3bf7SToby Isaac 
209776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM,PetscSection,PetscInt*,PetscInt*,PetscBool,PetscBool);
210f9f063d4SToby Isaac 
211f2c1aa1dSLisandro Dalcin PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
212f2c1aa1dSLisandro Dalcin {
213f2c1aa1dSLisandro Dalcin   PetscErrorCode ierr;
214f2c1aa1dSLisandro Dalcin 
215f2c1aa1dSLisandro Dalcin   PetscFunctionBegin;
216f2c1aa1dSLisandro Dalcin   ierr = DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
217f2c1aa1dSLisandro Dalcin   PetscFunctionReturn(0);
218f2c1aa1dSLisandro Dalcin }
219f2c1aa1dSLisandro Dalcin 
2200e2cc29aSToby Isaac PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
221da43764aSToby Isaac {
2220e2cc29aSToby Isaac   MPI_Comm       comm;
2230e2cc29aSToby Isaac   PetscInt       dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
224da43764aSToby Isaac   PetscInt      *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
225da43764aSToby Isaac   DMLabel        identity, identityRef;
22610f7e118SToby Isaac   PetscSection   unionSection, unionConeSection, parentSection;
227da43764aSToby Isaac   PetscScalar   *unionCoords;
228da43764aSToby Isaac   IS             perm;
229da43764aSToby Isaac   PetscErrorCode ierr;
230da43764aSToby Isaac 
231da43764aSToby Isaac   PetscFunctionBegin;
2320e2cc29aSToby Isaac   comm = PetscObjectComm((PetscObject)K);
2330e2cc29aSToby Isaac   ierr = DMGetDimension(K, &dim);CHKERRQ(ierr);
234da43764aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
2350e2cc29aSToby Isaac   ierr = DMGetLabel(K, labelName, &identity);CHKERRQ(ierr);
2360e2cc29aSToby Isaac   ierr = DMGetLabel(Kref, labelName, &identityRef);CHKERRQ(ierr);
237da43764aSToby Isaac   ierr = DMPlexGetChart(Kref, &pRefStart, &pRefEnd);CHKERRQ(ierr);
238da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionSection);CHKERRQ(ierr);
239da43764aSToby Isaac   ierr = PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart));CHKERRQ(ierr);
240da43764aSToby Isaac   /* count points that will go in the union */
241da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
242da43764aSToby Isaac     ierr = PetscSectionSetDof(unionSection, p - pStart, 1);CHKERRQ(ierr);
243da43764aSToby Isaac   }
244da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
245da43764aSToby Isaac     PetscInt q, qSize;
246da43764aSToby Isaac     ierr = DMLabelGetValue(identityRef, p, &q);CHKERRQ(ierr);
247da43764aSToby Isaac     ierr = DMLabelGetStratumSize(identityRef, q, &qSize);CHKERRQ(ierr);
248da43764aSToby Isaac     if (qSize > 1) {
249da43764aSToby Isaac       ierr = PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1);CHKERRQ(ierr);
250da43764aSToby Isaac     }
251da43764aSToby Isaac   }
252854ce69bSBarry Smith   ierr = PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart,&permvals);CHKERRQ(ierr);
253da43764aSToby Isaac   offset = 0;
254da43764aSToby Isaac   /* stratify points in the union by topological dimension */
255da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
256da43764aSToby Isaac     PetscInt cStart, cEnd, c;
257da43764aSToby Isaac 
258da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K, d, &cStart, &cEnd);CHKERRQ(ierr);
259da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
260da43764aSToby Isaac       permvals[offset++] = c;
261da43764aSToby Isaac     }
262da43764aSToby Isaac 
263da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd);CHKERRQ(ierr);
264da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
265da43764aSToby Isaac       permvals[offset++] = c + (pEnd - pStart);
266da43764aSToby Isaac     }
267da43764aSToby Isaac   }
268da43764aSToby Isaac   ierr = ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm);CHKERRQ(ierr);
269da43764aSToby Isaac   ierr = PetscSectionSetPermutation(unionSection,perm);CHKERRQ(ierr);
270da43764aSToby Isaac   ierr = PetscSectionSetUp(unionSection);CHKERRQ(ierr);
271da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionSection,&numUnionPoints);CHKERRQ(ierr);
272da43764aSToby Isaac   ierr = PetscMalloc2(numUnionPoints,&coneSizes,dim+1,&numDimPoints);CHKERRQ(ierr);
273da43764aSToby Isaac   /* count dimension points */
274da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
275da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
276da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K,d,&cStart,NULL);CHKERRQ(ierr);
277da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff);CHKERRQ(ierr);
278da43764aSToby Isaac     if (d < dim) {
279da43764aSToby Isaac       ierr = DMPlexGetHeightStratum(K,d+1,&cStart,NULL);CHKERRQ(ierr);
280da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff2);CHKERRQ(ierr);
281da43764aSToby Isaac     }
282da43764aSToby Isaac     else {
283da43764aSToby Isaac       cOff2 = numUnionPoints;
284da43764aSToby Isaac     }
285da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
286da43764aSToby Isaac   }
287da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionConeSection);CHKERRQ(ierr);
288da43764aSToby Isaac   ierr = PetscSectionSetChart(unionConeSection, 0, numUnionPoints);CHKERRQ(ierr);
289da43764aSToby Isaac   /* count the cones in the union */
290da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
291da43764aSToby Isaac     PetscInt dof, uOff;
292da43764aSToby Isaac 
293da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
294da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
295da43764aSToby Isaac     ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
296da43764aSToby Isaac     coneSizes[uOff] = dof;
297da43764aSToby Isaac   }
298da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
299da43764aSToby Isaac     PetscInt dof, uDof, uOff;
300da43764aSToby Isaac 
301da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
302da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
303da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
304da43764aSToby Isaac     if (uDof) {
305da43764aSToby Isaac       ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
306da43764aSToby Isaac       coneSizes[uOff] = dof;
307da43764aSToby Isaac     }
308da43764aSToby Isaac   }
309da43764aSToby Isaac   ierr = PetscSectionSetUp(unionConeSection);CHKERRQ(ierr);
310da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionConeSection,&numCones);CHKERRQ(ierr);
311da43764aSToby Isaac   ierr = PetscMalloc2(numCones,&unionCones,numCones,&unionOrientations);CHKERRQ(ierr);
312da43764aSToby Isaac   /* write the cones in the union */
313da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
314da43764aSToby Isaac     PetscInt dof, uOff, c, cOff;
315da43764aSToby Isaac     const PetscInt *cone, *orientation;
316da43764aSToby Isaac 
317da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
318da43764aSToby Isaac     ierr = DMPlexGetCone(K, p, &cone);CHKERRQ(ierr);
319da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(K, p, &orientation);CHKERRQ(ierr);
320da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
321da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
322da43764aSToby Isaac     for (c = 0; c < dof; c++) {
323da43764aSToby Isaac       PetscInt e, eOff;
324da43764aSToby Isaac       e                           = cone[c];
325da43764aSToby Isaac       ierr                        = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
326da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
327da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
328da43764aSToby Isaac     }
329da43764aSToby Isaac   }
330da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
331da43764aSToby Isaac     PetscInt dof, uDof, uOff, c, cOff;
332da43764aSToby Isaac     const PetscInt *cone, *orientation;
333da43764aSToby Isaac 
334da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
335da43764aSToby Isaac     ierr = DMPlexGetCone(Kref, p, &cone);CHKERRQ(ierr);
336da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(Kref, p, &orientation);CHKERRQ(ierr);
337da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
338da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
339da43764aSToby Isaac     if (uDof) {
340da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
341da43764aSToby Isaac       for (c = 0; c < dof; c++) {
342da43764aSToby Isaac         PetscInt e, eOff, eDof;
343da43764aSToby Isaac 
344da43764aSToby Isaac         e    = cone[c];
345da43764aSToby Isaac         ierr = PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart),&eDof);CHKERRQ(ierr);
346da43764aSToby Isaac         if (eDof) {
347da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff);CHKERRQ(ierr);
348da43764aSToby Isaac         }
349da43764aSToby Isaac         else {
350da43764aSToby Isaac           ierr = DMLabelGetValue(identityRef, e, &e);CHKERRQ(ierr);
351da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
352da43764aSToby Isaac         }
353da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
354da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
355da43764aSToby Isaac       }
356da43764aSToby Isaac     }
357da43764aSToby Isaac   }
358da43764aSToby Isaac   /* get the coordinates */
359da43764aSToby Isaac   {
360da43764aSToby Isaac     PetscInt     vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
361da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
362da43764aSToby Isaac     Vec          KcoordsVec, KrefCoordsVec;
363da43764aSToby Isaac     PetscScalar *Kcoords;
364da43764aSToby Isaac 
365367003a6SStefano Zampini     ierr = DMGetCoordinateSection(K, &KcoordsSec);CHKERRQ(ierr);
366367003a6SStefano Zampini     ierr = DMGetCoordinatesLocal(K, &KcoordsVec);CHKERRQ(ierr);
367367003a6SStefano Zampini     ierr = DMGetCoordinateSection(Kref, &KrefCoordsSec);CHKERRQ(ierr);
368367003a6SStefano Zampini     ierr = DMGetCoordinatesLocal(Kref, &KrefCoordsVec);CHKERRQ(ierr);
369da43764aSToby Isaac 
370da43764aSToby Isaac     numVerts = numDimPoints[0];
371da43764aSToby Isaac     ierr     = PetscMalloc1(numVerts * dim,&unionCoords);CHKERRQ(ierr);
372da43764aSToby Isaac     ierr     = DMPlexGetDepthStratum(K,0,&vStart,&vEnd);CHKERRQ(ierr);
373da43764aSToby Isaac 
374da43764aSToby Isaac     offset = 0;
375da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
376da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pStart,&vOff);CHKERRQ(ierr);
377da43764aSToby Isaac       ierr = VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords);CHKERRQ(ierr);
378da43764aSToby Isaac       for (d = 0; d < dim; d++) {
379da43764aSToby Isaac         unionCoords[offset * dim + d] = Kcoords[d];
380da43764aSToby Isaac       }
381da43764aSToby Isaac       offset++;
382da43764aSToby Isaac     }
383da43764aSToby Isaac     ierr = DMPlexGetDepthStratum(Kref,0,&vRefStart,&vRefEnd);CHKERRQ(ierr);
384da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
385da43764aSToby Isaac       ierr = PetscSectionGetDof(unionSection,v - pRefStart + (pEnd - pStart),&vDof);CHKERRQ(ierr);
386da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pRefStart + (pEnd - pStart),&vOff);CHKERRQ(ierr);
387da43764aSToby Isaac       ierr = VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords);CHKERRQ(ierr);
388da43764aSToby Isaac       if (vDof) {
389da43764aSToby Isaac         for (d = 0; d < dim; d++) {
390da43764aSToby Isaac           unionCoords[offset * dim + d] = Kcoords[d];
391da43764aSToby Isaac         }
392da43764aSToby Isaac         offset++;
393da43764aSToby Isaac       }
394da43764aSToby Isaac     }
395da43764aSToby Isaac   }
396da43764aSToby Isaac   ierr = DMCreate(comm,ref);CHKERRQ(ierr);
397da43764aSToby Isaac   ierr = DMSetType(*ref,DMPLEX);CHKERRQ(ierr);
39828f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ref,dim);CHKERRQ(ierr);
399da43764aSToby Isaac   ierr = DMPlexCreateFromDAG(*ref,dim,numDimPoints,coneSizes,unionCones,unionOrientations,unionCoords);CHKERRQ(ierr);
40010f7e118SToby Isaac   /* set the tree */
40110f7e118SToby Isaac   ierr = PetscSectionCreate(comm,&parentSection);CHKERRQ(ierr);
40210f7e118SToby Isaac   ierr = PetscSectionSetChart(parentSection,0,numUnionPoints);CHKERRQ(ierr);
40310f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
40410f7e118SToby Isaac     PetscInt uDof, uOff;
40510f7e118SToby Isaac 
40610f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
40710f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
40810f7e118SToby Isaac     if (uDof) {
409367003a6SStefano Zampini       ierr = PetscSectionSetDof(parentSection,uOff,1);CHKERRQ(ierr);
41010f7e118SToby Isaac     }
41110f7e118SToby Isaac   }
41210f7e118SToby Isaac   ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
41310f7e118SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&parentSize);CHKERRQ(ierr);
41410f7e118SToby Isaac   ierr = PetscMalloc2(parentSize,&parents,parentSize,&childIDs);CHKERRQ(ierr);
41510f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
41610f7e118SToby Isaac     PetscInt uDof, uOff;
41710f7e118SToby Isaac 
41810f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
41910f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
42010f7e118SToby Isaac     if (uDof) {
42110f7e118SToby Isaac       PetscInt pOff, parent, parentU;
422367003a6SStefano Zampini       ierr = PetscSectionGetOffset(parentSection,uOff,&pOff);CHKERRQ(ierr);
423367003a6SStefano Zampini       ierr = DMLabelGetValue(identityRef,p,&parent);CHKERRQ(ierr);
42410f7e118SToby Isaac       ierr = PetscSectionGetOffset(unionSection, parent - pStart,&parentU);CHKERRQ(ierr);
42510f7e118SToby Isaac       parents[pOff] = parentU;
42610f7e118SToby Isaac       childIDs[pOff] = uOff;
42710f7e118SToby Isaac     }
42810f7e118SToby Isaac   }
429f2c1aa1dSLisandro Dalcin   ierr = DMPlexCreateReferenceTree_SetTree(*ref,parentSection,parents,childIDs);CHKERRQ(ierr);
43010f7e118SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
43110f7e118SToby Isaac   ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
43210f7e118SToby Isaac 
433da43764aSToby Isaac   /* clean up */
434da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionSection);CHKERRQ(ierr);
435da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionConeSection);CHKERRQ(ierr);
436da43764aSToby Isaac   ierr = ISDestroy(&perm);CHKERRQ(ierr);
437da43764aSToby Isaac   ierr = PetscFree(unionCoords);CHKERRQ(ierr);
438da43764aSToby Isaac   ierr = PetscFree2(unionCones,unionOrientations);CHKERRQ(ierr);
439da43764aSToby Isaac   ierr = PetscFree2(coneSizes,numDimPoints);CHKERRQ(ierr);
4400e2cc29aSToby Isaac   PetscFunctionReturn(0);
4410e2cc29aSToby Isaac }
4420e2cc29aSToby Isaac 
4430e2cc29aSToby Isaac /*@
4440e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4450e2cc29aSToby Isaac 
4460e2cc29aSToby Isaac   Collective on comm
4470e2cc29aSToby Isaac 
4480e2cc29aSToby Isaac   Input Parameters:
4490e2cc29aSToby Isaac + comm    - the MPI communicator
4500e2cc29aSToby Isaac . dim     - the spatial dimension
4510e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4520e2cc29aSToby Isaac 
4530e2cc29aSToby Isaac   Output Parameters:
4540e2cc29aSToby Isaac . ref     - the reference tree DMPlex object
4550e2cc29aSToby Isaac 
4560e2cc29aSToby Isaac   Level: intermediate
4570e2cc29aSToby Isaac 
4580e2cc29aSToby Isaac .keywords: reference cell
4590e2cc29aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree()
4600e2cc29aSToby Isaac @*/
4610e2cc29aSToby Isaac PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
4620e2cc29aSToby Isaac {
4630e2cc29aSToby Isaac   DM_Plex       *mesh;
4640e2cc29aSToby Isaac   DM             K, Kref;
4650e2cc29aSToby Isaac   PetscInt       p, pStart, pEnd;
4660e2cc29aSToby Isaac   DMLabel        identity;
4670e2cc29aSToby Isaac   PetscErrorCode ierr;
4680e2cc29aSToby Isaac 
4690e2cc29aSToby Isaac   PetscFunctionBegin;
4700e2cc29aSToby Isaac #if 1
4710e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4720e2cc29aSToby Isaac #endif
4730e2cc29aSToby Isaac   /* create a reference element */
4740e2cc29aSToby Isaac   ierr = DMPlexCreateReferenceCell(comm, dim, simplex, &K);CHKERRQ(ierr);
4750e2cc29aSToby Isaac   ierr = DMCreateLabel(K, "identity");CHKERRQ(ierr);
4760e2cc29aSToby Isaac   ierr = DMGetLabel(K, "identity", &identity);CHKERRQ(ierr);
4770e2cc29aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
4780e2cc29aSToby Isaac   for (p = pStart; p < pEnd; p++) {
4790e2cc29aSToby Isaac     ierr = DMLabelSetValue(identity, p, p);CHKERRQ(ierr);
4800e2cc29aSToby Isaac   }
4810e2cc29aSToby Isaac   /* refine it */
4820e2cc29aSToby Isaac   ierr = DMRefine(K,comm,&Kref);CHKERRQ(ierr);
4830e2cc29aSToby Isaac 
4840e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4850e2cc29aSToby Isaac    * points that appear in both */
4860e2cc29aSToby Isaac   ierr = DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref);CHKERRQ(ierr);
4870e2cc29aSToby Isaac   mesh = (DM_Plex *) (*ref)->data;
4880e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
489da43764aSToby Isaac   ierr = DMDestroy(&K);CHKERRQ(ierr);
490da43764aSToby Isaac   ierr = DMDestroy(&Kref);CHKERRQ(ierr);
491da43764aSToby Isaac   PetscFunctionReturn(0);
492da43764aSToby Isaac }
493da43764aSToby Isaac 
494878b19aaSToby Isaac static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
495878b19aaSToby Isaac {
496878b19aaSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
497878b19aaSToby Isaac   PetscSection   childSec, pSec;
498878b19aaSToby Isaac   PetscInt       p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
499878b19aaSToby Isaac   PetscInt       *offsets, *children, pStart, pEnd;
500878b19aaSToby Isaac   PetscErrorCode ierr;
501878b19aaSToby Isaac 
502878b19aaSToby Isaac   PetscFunctionBegin;
503878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
504878b19aaSToby Isaac   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
505878b19aaSToby Isaac   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
506878b19aaSToby Isaac   pSec = mesh->parentSection;
507878b19aaSToby Isaac   if (!pSec) PetscFunctionReturn(0);
508878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(pSec,&pSize);CHKERRQ(ierr);
509878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
510878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
511878b19aaSToby Isaac 
512878b19aaSToby Isaac     parMax = PetscMax(parMax,par+1);
513878b19aaSToby Isaac     parMin = PetscMin(parMin,par);
514878b19aaSToby Isaac   }
515878b19aaSToby Isaac   if (parMin > parMax) {
516878b19aaSToby Isaac     parMin = -1;
517878b19aaSToby Isaac     parMax = -1;
518878b19aaSToby Isaac   }
519878b19aaSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)pSec),&childSec);CHKERRQ(ierr);
520878b19aaSToby Isaac   ierr = PetscSectionSetChart(childSec,parMin,parMax);CHKERRQ(ierr);
521878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
522878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
523878b19aaSToby Isaac 
524878b19aaSToby Isaac     ierr = PetscSectionAddDof(childSec,par,1);CHKERRQ(ierr);
525878b19aaSToby Isaac   }
526878b19aaSToby Isaac   ierr = PetscSectionSetUp(childSec);CHKERRQ(ierr);
527878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(childSec,&cSize);CHKERRQ(ierr);
528878b19aaSToby Isaac   ierr = PetscMalloc1(cSize,&children);CHKERRQ(ierr);
529878b19aaSToby Isaac   ierr = PetscCalloc1(parMax-parMin,&offsets);CHKERRQ(ierr);
530878b19aaSToby Isaac   ierr = PetscSectionGetChart(pSec,&pStart,&pEnd);CHKERRQ(ierr);
531878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
532878b19aaSToby Isaac     PetscInt dof, off, i;
533878b19aaSToby Isaac 
534878b19aaSToby Isaac     ierr = PetscSectionGetDof(pSec,p,&dof);CHKERRQ(ierr);
535878b19aaSToby Isaac     ierr = PetscSectionGetOffset(pSec,p,&off);CHKERRQ(ierr);
536878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
537878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
538878b19aaSToby Isaac 
539878b19aaSToby Isaac       ierr = PetscSectionGetOffset(childSec,par,&cOff);CHKERRQ(ierr);
540878b19aaSToby Isaac       children[cOff + offsets[par-parMin]++] = p;
541878b19aaSToby Isaac     }
542878b19aaSToby Isaac   }
543878b19aaSToby Isaac   mesh->childSection = childSec;
544878b19aaSToby Isaac   mesh->children = children;
545878b19aaSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
546878b19aaSToby Isaac   PetscFunctionReturn(0);
547878b19aaSToby Isaac }
548878b19aaSToby Isaac 
5496dd5a8c8SToby Isaac static PetscErrorCode AnchorsFlatten (PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
5506dd5a8c8SToby Isaac {
5516dd5a8c8SToby Isaac   PetscInt       pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5526dd5a8c8SToby Isaac   const PetscInt *vals;
5536dd5a8c8SToby Isaac   PetscSection   secNew;
5546dd5a8c8SToby Isaac   PetscBool      anyNew, globalAnyNew;
5556dd5a8c8SToby Isaac   PetscBool      compress;
5566dd5a8c8SToby Isaac   PetscErrorCode ierr;
5576dd5a8c8SToby Isaac 
5586dd5a8c8SToby Isaac   PetscFunctionBegin;
5596dd5a8c8SToby Isaac   ierr = PetscSectionGetChart(section,&pStart,&pEnd);CHKERRQ(ierr);
5606dd5a8c8SToby Isaac   ierr = ISGetLocalSize(is,&size);CHKERRQ(ierr);
5616dd5a8c8SToby Isaac   ierr = ISGetIndices(is,&vals);CHKERRQ(ierr);
5626dd5a8c8SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secNew);CHKERRQ(ierr);
5636dd5a8c8SToby Isaac   ierr = PetscSectionSetChart(secNew,pStart,pEnd);CHKERRQ(ierr);
5646dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5656dd5a8c8SToby Isaac     PetscInt dof;
5666dd5a8c8SToby Isaac 
5676dd5a8c8SToby Isaac     p = vals[i];
5686dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5696dd5a8c8SToby Isaac     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5706dd5a8c8SToby Isaac     if (dof) break;
5716dd5a8c8SToby Isaac   }
5726dd5a8c8SToby Isaac   if (i == size) {
5736dd5a8c8SToby Isaac     ierr     = PetscSectionSetUp(secNew);CHKERRQ(ierr);
5746dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5756dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5766dd5a8c8SToby Isaac     sizeNew  = 0;
5776dd5a8c8SToby Isaac   }
5786dd5a8c8SToby Isaac   else {
5796dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5806dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5816dd5a8c8SToby Isaac       PetscInt dof, off;
5826dd5a8c8SToby Isaac 
5836dd5a8c8SToby Isaac       ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5846dd5a8c8SToby Isaac       ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
5856dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5866dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5876dd5a8c8SToby Isaac 
5886dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5896dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
5906dd5a8c8SToby Isaac         }
5916dd5a8c8SToby Isaac         if (qDof) {
5926dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, qDof);CHKERRQ(ierr);
5936dd5a8c8SToby Isaac         }
5946dd5a8c8SToby Isaac         else {
5956dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, 1);CHKERRQ(ierr);
5966dd5a8c8SToby Isaac         }
5976dd5a8c8SToby Isaac       }
5986dd5a8c8SToby Isaac     }
5996dd5a8c8SToby Isaac     ierr = PetscSectionSetUp(secNew);CHKERRQ(ierr);
6006dd5a8c8SToby Isaac     ierr = PetscSectionGetStorageSize(secNew,&sizeNew);CHKERRQ(ierr);
6016dd5a8c8SToby Isaac     ierr = PetscMalloc1(sizeNew,&valsNew);CHKERRQ(ierr);
6026dd5a8c8SToby Isaac     compress = PETSC_FALSE;
6036dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
6046dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
6056dd5a8c8SToby Isaac 
6066dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
6076dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
6086dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(secNew, p, &dofNew);CHKERRQ(ierr);
6096dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(secNew, p, &offNew);CHKERRQ(ierr);
6106dd5a8c8SToby Isaac       count = 0;
6116dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
6126dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
6136dd5a8c8SToby Isaac 
6146dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
6156dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
6166dd5a8c8SToby Isaac           ierr = PetscSectionGetOffset(section, q, &qOff);CHKERRQ(ierr);
6176dd5a8c8SToby Isaac         }
6186dd5a8c8SToby Isaac         if (qDof) {
6196dd5a8c8SToby Isaac           PetscInt oldCount = count;
6206dd5a8c8SToby Isaac 
6216dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
6226dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
6236dd5a8c8SToby Isaac 
6246dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
6256dd5a8c8SToby Isaac               if (valsNew[offNew + k] == r) {
6266dd5a8c8SToby Isaac                 break;
6276dd5a8c8SToby Isaac               }
6286dd5a8c8SToby Isaac             }
6296dd5a8c8SToby Isaac             if (k == oldCount) {
6306dd5a8c8SToby Isaac               valsNew[offNew + count++] = r;
6316dd5a8c8SToby Isaac             }
6326dd5a8c8SToby Isaac           }
6336dd5a8c8SToby Isaac         }
6346dd5a8c8SToby Isaac         else {
6356dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
6366dd5a8c8SToby Isaac 
6376dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
6386dd5a8c8SToby Isaac             if (valsNew[offNew + k] == q) {
6396dd5a8c8SToby Isaac               break;
6406dd5a8c8SToby Isaac             }
6416dd5a8c8SToby Isaac           }
6426dd5a8c8SToby Isaac           if (k == oldCount) {
6436dd5a8c8SToby Isaac             valsNew[offNew + count++] = q;
6446dd5a8c8SToby Isaac           }
6456dd5a8c8SToby Isaac         }
6466dd5a8c8SToby Isaac       }
6476dd5a8c8SToby Isaac       if (count < dofNew) {
6486dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secNew, p, count);CHKERRQ(ierr);
6496dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6506dd5a8c8SToby Isaac       }
6516dd5a8c8SToby Isaac     }
6526dd5a8c8SToby Isaac   }
6536dd5a8c8SToby Isaac   ierr = ISRestoreIndices(is,&vals);CHKERRQ(ierr);
654b2566f29SBarry Smith   ierr = MPIU_Allreduce(&anyNew,&globalAnyNew,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
6556dd5a8c8SToby Isaac   if (!globalAnyNew) {
6566dd5a8c8SToby Isaac     ierr = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6576dd5a8c8SToby Isaac     *sectionNew = NULL;
6586dd5a8c8SToby Isaac     *isNew = NULL;
6596dd5a8c8SToby Isaac   }
6606dd5a8c8SToby Isaac   else {
6616dd5a8c8SToby Isaac     PetscBool globalCompress;
6626dd5a8c8SToby Isaac 
663b2566f29SBarry Smith     ierr = MPIU_Allreduce(&compress,&globalCompress,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
6646dd5a8c8SToby Isaac     if (compress) {
6656dd5a8c8SToby Isaac       PetscSection secComp;
6666dd5a8c8SToby Isaac       PetscInt *valsComp = NULL;
6676dd5a8c8SToby Isaac 
6686dd5a8c8SToby Isaac       ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secComp);CHKERRQ(ierr);
6696dd5a8c8SToby Isaac       ierr = PetscSectionSetChart(secComp,pStart,pEnd);CHKERRQ(ierr);
6706dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6716dd5a8c8SToby Isaac         PetscInt dof;
6726dd5a8c8SToby Isaac 
6736dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6746dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secComp, p, dof);CHKERRQ(ierr);
6756dd5a8c8SToby Isaac       }
6766dd5a8c8SToby Isaac       ierr = PetscSectionSetUp(secComp);CHKERRQ(ierr);
6776dd5a8c8SToby Isaac       ierr = PetscSectionGetStorageSize(secComp,&sizeNew);CHKERRQ(ierr);
6786dd5a8c8SToby Isaac       ierr = PetscMalloc1(sizeNew,&valsComp);CHKERRQ(ierr);
6796dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6806dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6816dd5a8c8SToby Isaac 
6826dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6836dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secNew, p, &off);CHKERRQ(ierr);
6846dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secComp, p, &offNew);CHKERRQ(ierr);
6856dd5a8c8SToby Isaac         for (j = 0; j < dof; j++) {
6866dd5a8c8SToby Isaac           valsComp[offNew + j] = valsNew[off + j];
6876dd5a8c8SToby Isaac         }
6886dd5a8c8SToby Isaac       }
6896dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6906dd5a8c8SToby Isaac       secNew  = secComp;
6916dd5a8c8SToby Isaac       ierr    = PetscFree(valsNew);CHKERRQ(ierr);
6926dd5a8c8SToby Isaac       valsNew = valsComp;
6936dd5a8c8SToby Isaac     }
6946dd5a8c8SToby Isaac     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is),sizeNew,valsNew,PETSC_OWN_POINTER,isNew);CHKERRQ(ierr);
6956dd5a8c8SToby Isaac   }
6966dd5a8c8SToby Isaac   PetscFunctionReturn(0);
6976dd5a8c8SToby Isaac }
6986dd5a8c8SToby Isaac 
699f7c74593SToby Isaac static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
70066af876cSToby Isaac {
70166af876cSToby Isaac   PetscInt       p, pStart, pEnd, *anchors, size;
70266af876cSToby Isaac   PetscInt       aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
70366af876cSToby Isaac   PetscSection   aSec;
704f9f063d4SToby Isaac   DMLabel        canonLabel;
70566af876cSToby Isaac   IS             aIS;
70666af876cSToby Isaac   PetscErrorCode ierr;
70766af876cSToby Isaac 
70866af876cSToby Isaac   PetscFunctionBegin;
70966af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
71066af876cSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
711c58f1c22SToby Isaac   ierr = DMGetLabel(dm,"canonical",&canonLabel);CHKERRQ(ierr);
71266af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
71366af876cSToby Isaac     PetscInt parent;
71466af876cSToby Isaac 
715f9f063d4SToby Isaac     if (canonLabel) {
716f9f063d4SToby Isaac       PetscInt canon;
717f9f063d4SToby Isaac 
718f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
719f9f063d4SToby Isaac       if (p != canon) continue;
720f9f063d4SToby Isaac     }
72166af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
72266af876cSToby Isaac     if (parent != p) {
72366af876cSToby Isaac       aMin = PetscMin(aMin,p);
72466af876cSToby Isaac       aMax = PetscMax(aMax,p+1);
72566af876cSToby Isaac     }
72666af876cSToby Isaac   }
72766af876cSToby Isaac   if (aMin > aMax) {
72866af876cSToby Isaac     aMin = -1;
72966af876cSToby Isaac     aMax = -1;
73066af876cSToby Isaac   }
731e228b242SToby Isaac   ierr = PetscSectionCreate(PETSC_COMM_SELF,&aSec);CHKERRQ(ierr);
73266af876cSToby Isaac   ierr = PetscSectionSetChart(aSec,aMin,aMax);CHKERRQ(ierr);
73366af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
73466af876cSToby Isaac     PetscInt parent, ancestor = p;
73566af876cSToby Isaac 
736f9f063d4SToby Isaac     if (canonLabel) {
737f9f063d4SToby Isaac       PetscInt canon;
738f9f063d4SToby Isaac 
739f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
740f9f063d4SToby Isaac       if (p != canon) continue;
741f9f063d4SToby Isaac     }
74266af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
74366af876cSToby Isaac     while (parent != ancestor) {
74466af876cSToby Isaac       ancestor = parent;
74566af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
74666af876cSToby Isaac     }
74766af876cSToby Isaac     if (ancestor != p) {
74866af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
74966af876cSToby Isaac 
75066af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
75166af876cSToby Isaac       ierr = PetscSectionSetDof(aSec,p,closureSize);CHKERRQ(ierr);
75266af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
75366af876cSToby Isaac     }
75466af876cSToby Isaac   }
75566af876cSToby Isaac   ierr = PetscSectionSetUp(aSec);CHKERRQ(ierr);
75666af876cSToby Isaac   ierr = PetscSectionGetStorageSize(aSec,&size);CHKERRQ(ierr);
75766af876cSToby Isaac   ierr = PetscMalloc1(size,&anchors);CHKERRQ(ierr);
75866af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
75966af876cSToby Isaac     PetscInt parent, ancestor = p;
76066af876cSToby Isaac 
761f9f063d4SToby Isaac     if (canonLabel) {
762f9f063d4SToby Isaac       PetscInt canon;
763f9f063d4SToby Isaac 
764f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
765f9f063d4SToby Isaac       if (p != canon) continue;
766f9f063d4SToby Isaac     }
76766af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
76866af876cSToby Isaac     while (parent != ancestor) {
76966af876cSToby Isaac       ancestor = parent;
77066af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
77166af876cSToby Isaac     }
77266af876cSToby Isaac     if (ancestor != p) {
77366af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
77466af876cSToby Isaac 
77566af876cSToby Isaac       ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
77666af876cSToby Isaac 
77766af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
77866af876cSToby Isaac       for (j = 0; j < closureSize; j++) {
77966af876cSToby Isaac         anchors[aOff + j] = closure[2*j];
78066af876cSToby Isaac       }
78166af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
78266af876cSToby Isaac     }
78366af876cSToby Isaac   }
784e228b242SToby Isaac   ierr = ISCreateGeneral(PETSC_COMM_SELF,size,anchors,PETSC_OWN_POINTER,&aIS);CHKERRQ(ierr);
7856dd5a8c8SToby Isaac   {
7866dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7876dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7886dd5a8c8SToby Isaac 
7896dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aSec);CHKERRQ(ierr);
7906dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aIS);CHKERRQ(ierr);
7916dd5a8c8SToby Isaac     while (aSecNew) {
7926dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
7936dd5a8c8SToby Isaac       ierr    = ISDestroy(&aIS);CHKERRQ(ierr);
7946dd5a8c8SToby Isaac       aSec    = aSecNew;
7956dd5a8c8SToby Isaac       aIS     = aISNew;
7966dd5a8c8SToby Isaac       aSecNew = NULL;
7976dd5a8c8SToby Isaac       aISNew  = NULL;
7986dd5a8c8SToby Isaac       ierr    = AnchorsFlatten(aSec,aIS,&aSecNew,&aISNew);CHKERRQ(ierr);
7996dd5a8c8SToby Isaac     }
8006dd5a8c8SToby Isaac   }
801a17985deSToby Isaac   ierr = DMPlexSetAnchors(dm,aSec,aIS);CHKERRQ(ierr);
80266af876cSToby Isaac   ierr = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
80366af876cSToby Isaac   ierr = ISDestroy(&aIS);CHKERRQ(ierr);
80466af876cSToby Isaac   PetscFunctionReturn(0);
80566af876cSToby Isaac }
80666af876cSToby Isaac 
8076461c1adSToby Isaac static PetscErrorCode DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt *dof,PetscInt *numTrueSupp)
8086461c1adSToby Isaac {
8096461c1adSToby Isaac   PetscErrorCode ierr;
8106461c1adSToby Isaac 
8116461c1adSToby Isaac   PetscFunctionBegin;
8126461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
8136461c1adSToby Isaac     PetscInt i, alldof;
8146461c1adSToby Isaac     const PetscInt *supp;
8156461c1adSToby Isaac     PetscInt count = 0;
8166461c1adSToby Isaac 
8176461c1adSToby Isaac     ierr = DMPlexGetSupportSize(dm,p,&alldof);CHKERRQ(ierr);
8186461c1adSToby Isaac     ierr = DMPlexGetSupport(dm,p,&supp);CHKERRQ(ierr);
8196461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
8206461c1adSToby Isaac       PetscInt q = supp[i], numCones, j;
8216461c1adSToby Isaac       const PetscInt *cone;
8226461c1adSToby Isaac 
8236461c1adSToby Isaac       ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
8246461c1adSToby Isaac       ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
8256461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
8266461c1adSToby Isaac         if (cone[j] == p) break;
8276461c1adSToby Isaac       }
8286461c1adSToby Isaac       if (j < numCones) count++;
8296461c1adSToby Isaac     }
8306461c1adSToby Isaac     numTrueSupp[p] = count;
8316461c1adSToby Isaac   }
8326461c1adSToby Isaac   *dof = numTrueSupp[p];
8336461c1adSToby Isaac   PetscFunctionReturn(0);
8346461c1adSToby Isaac }
8356461c1adSToby Isaac 
836776742edSToby Isaac static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
837776742edSToby Isaac {
838776742edSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
839776742edSToby Isaac   PetscSection newSupportSection;
840776742edSToby Isaac   PetscInt newSize, *newSupports, pStart, pEnd, p, d, depth;
8416461c1adSToby Isaac   PetscInt *numTrueSupp;
842776742edSToby Isaac   PetscInt *offsets;
843776742edSToby Isaac   PetscErrorCode ierr;
844776742edSToby Isaac 
845776742edSToby Isaac   PetscFunctionBegin;
846776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
847776742edSToby Isaac   /* symmetrize the hierarchy */
848776742edSToby Isaac   ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr);
849e228b242SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)),&newSupportSection);CHKERRQ(ierr);
850776742edSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
851776742edSToby Isaac   ierr = PetscSectionSetChart(newSupportSection,pStart,pEnd);CHKERRQ(ierr);
852776742edSToby Isaac   ierr = PetscCalloc1(pEnd,&offsets);CHKERRQ(ierr);
8536461c1adSToby Isaac   ierr = PetscMalloc1(pEnd,&numTrueSupp);CHKERRQ(ierr);
8546461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8556461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
856776742edSToby Isaac    * parent(q) */
857776742edSToby Isaac   for (d = 0; d <= depth; d++) {
858776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
859776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
860776742edSToby Isaac       PetscInt dof, q, qdof, parent;
861776742edSToby Isaac 
8626461c1adSToby Isaac       ierr = DMPlexGetTrueSupportSize(dm,p,&dof,numTrueSupp);CHKERRQ(ierr);
863776742edSToby Isaac       ierr = PetscSectionAddDof(newSupportSection, p, dof);CHKERRQ(ierr);
864776742edSToby Isaac       q    = p;
865776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
866776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
867776742edSToby Isaac         q = parent;
868776742edSToby Isaac 
8696461c1adSToby Isaac         ierr = DMPlexGetTrueSupportSize(dm,q,&qdof,numTrueSupp);CHKERRQ(ierr);
870776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,p,qdof);CHKERRQ(ierr);
871776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,q,dof);CHKERRQ(ierr);
872776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
873776742edSToby Isaac       }
874776742edSToby Isaac     }
875776742edSToby Isaac   }
876776742edSToby Isaac   ierr = PetscSectionSetUp(newSupportSection);CHKERRQ(ierr);
877776742edSToby Isaac   ierr = PetscSectionGetStorageSize(newSupportSection,&newSize);CHKERRQ(ierr);
878776742edSToby Isaac   ierr = PetscMalloc1(newSize,&newSupports);CHKERRQ(ierr);
879776742edSToby Isaac   for (d = 0; d <= depth; d++) {
880776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
881776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
882776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
883776742edSToby Isaac 
884776742edSToby Isaac       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
885776742edSToby Isaac       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
886776742edSToby Isaac       ierr = PetscSectionGetDof(newSupportSection, p, &newDof);CHKERRQ(ierr);
887776742edSToby Isaac       ierr = PetscSectionGetOffset(newSupportSection, p, &newOff);CHKERRQ(ierr);
888776742edSToby Isaac       for (i = 0; i < dof; i++) {
8896461c1adSToby Isaac         PetscInt numCones, j;
8906461c1adSToby Isaac         const PetscInt *cone;
8916461c1adSToby Isaac         PetscInt q = mesh->supports[off + i];
8926461c1adSToby Isaac 
8936461c1adSToby Isaac         ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
8946461c1adSToby Isaac         ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
8956461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8966461c1adSToby Isaac           if (cone[j] == p) break;
8976461c1adSToby Isaac         }
8986461c1adSToby Isaac         if (j < numCones) newSupports[newOff+offsets[p]++] = q;
899776742edSToby Isaac       }
900776742edSToby Isaac       mesh->maxSupportSize = PetscMax(mesh->maxSupportSize,newDof);
901776742edSToby Isaac 
902776742edSToby Isaac       q    = p;
903776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
904776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
905776742edSToby Isaac         q = parent;
906776742edSToby Isaac         ierr = PetscSectionGetDof(mesh->supportSection, q, &qdof);CHKERRQ(ierr);
907776742edSToby Isaac         ierr = PetscSectionGetOffset(mesh->supportSection, q, &qoff);CHKERRQ(ierr);
908776742edSToby Isaac         ierr = PetscSectionGetOffset(newSupportSection, q, &newqOff);CHKERRQ(ierr);
909776742edSToby Isaac         for (i = 0; i < qdof; i++) {
9106461c1adSToby Isaac           PetscInt numCones, j;
9116461c1adSToby Isaac           const PetscInt *cone;
9126461c1adSToby Isaac           PetscInt r = mesh->supports[qoff + i];
9136461c1adSToby Isaac 
9146461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9156461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9166461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9176461c1adSToby Isaac             if (cone[j] == q) break;
9186461c1adSToby Isaac           }
9196461c1adSToby Isaac           if (j < numCones) newSupports[newOff+offsets[p]++] = r;
920776742edSToby Isaac         }
921776742edSToby Isaac         for (i = 0; i < dof; i++) {
9226461c1adSToby Isaac           PetscInt numCones, j;
9236461c1adSToby Isaac           const PetscInt *cone;
9246461c1adSToby Isaac           PetscInt r = mesh->supports[off + i];
9256461c1adSToby Isaac 
9266461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9276461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9286461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9296461c1adSToby Isaac             if (cone[j] == p) break;
9306461c1adSToby Isaac           }
9316461c1adSToby Isaac           if (j < numCones) newSupports[newqOff+offsets[q]++] = r;
932776742edSToby Isaac         }
933776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
934776742edSToby Isaac       }
935776742edSToby Isaac     }
936776742edSToby Isaac   }
937776742edSToby Isaac   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
938776742edSToby Isaac   mesh->supportSection = newSupportSection;
939776742edSToby Isaac   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
940776742edSToby Isaac   mesh->supports = newSupports;
941776742edSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
9426461c1adSToby Isaac   ierr = PetscFree(numTrueSupp);CHKERRQ(ierr);
943776742edSToby Isaac 
944776742edSToby Isaac   PetscFunctionReturn(0);
945776742edSToby Isaac }
946776742edSToby Isaac 
947f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM,PetscSection,PetscSection,Mat);
948f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM,PetscSection,PetscSection,Mat);
949f7c74593SToby Isaac 
950776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
951f9f063d4SToby Isaac {
952f9f063d4SToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
953f9f063d4SToby Isaac   DM             refTree;
954f9f063d4SToby Isaac   PetscInt       size;
955f9f063d4SToby Isaac   PetscErrorCode ierr;
956f9f063d4SToby Isaac 
957f9f063d4SToby Isaac   PetscFunctionBegin;
958f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
959f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
960f9f063d4SToby Isaac   ierr = PetscObjectReference((PetscObject)parentSection);CHKERRQ(ierr);
961f9f063d4SToby Isaac   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
962f9f063d4SToby Isaac   mesh->parentSection = parentSection;
963f9f063d4SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&size);CHKERRQ(ierr);
964f9f063d4SToby Isaac   if (parents != mesh->parents) {
965f9f063d4SToby Isaac     ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
966f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->parents);CHKERRQ(ierr);
967f9f063d4SToby Isaac     ierr = PetscMemcpy(mesh->parents, parents, size * sizeof(*parents));CHKERRQ(ierr);
968f9f063d4SToby Isaac   }
969f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
970f9f063d4SToby Isaac     ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
971f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->childIDs);CHKERRQ(ierr);
972f9f063d4SToby Isaac     ierr = PetscMemcpy(mesh->childIDs, childIDs, size * sizeof(*childIDs));CHKERRQ(ierr);
973f9f063d4SToby Isaac   }
974f9f063d4SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
975f9f063d4SToby Isaac   if (refTree) {
976f9f063d4SToby Isaac     DMLabel canonLabel;
977f9f063d4SToby Isaac 
978c58f1c22SToby Isaac     ierr = DMGetLabel(refTree,"canonical",&canonLabel);CHKERRQ(ierr);
979f9f063d4SToby Isaac     if (canonLabel) {
980f9f063d4SToby Isaac       PetscInt i;
981f9f063d4SToby Isaac 
982f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
983f9f063d4SToby Isaac         PetscInt canon;
984f9f063d4SToby Isaac         ierr = DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon);CHKERRQ(ierr);
985f9f063d4SToby Isaac         if (canon >= 0) {
986f9f063d4SToby Isaac           mesh->childIDs[i] = canon;
987f9f063d4SToby Isaac         }
988f9f063d4SToby Isaac       }
989f9f063d4SToby Isaac     }
990f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
991f7c74593SToby Isaac   }
992f7c74593SToby Isaac   else {
993f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
994f9f063d4SToby Isaac   }
995f9f063d4SToby Isaac   ierr = DMPlexTreeSymmetrize(dm);CHKERRQ(ierr);
996f9f063d4SToby Isaac   if (computeCanonical) {
997f9f063d4SToby Isaac     PetscInt d, dim;
998f9f063d4SToby Isaac 
999f9f063d4SToby Isaac     /* add the canonical label */
100028f4b327SMatthew G. Knepley     ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
1001c58f1c22SToby Isaac     ierr = DMCreateLabel(dm,"canonical");CHKERRQ(ierr);
1002f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
1003f9f063d4SToby Isaac       PetscInt p, dStart, dEnd, canon = -1, cNumChildren;
1004f9f063d4SToby Isaac       const PetscInt *cChildren;
1005f9f063d4SToby Isaac 
1006f9f063d4SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
1007f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1008f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&cNumChildren,&cChildren);CHKERRQ(ierr);
1009f9f063d4SToby Isaac         if (cNumChildren) {
1010f9f063d4SToby Isaac           canon = p;
1011f9f063d4SToby Isaac           break;
1012f9f063d4SToby Isaac         }
1013f9f063d4SToby Isaac       }
1014f9f063d4SToby Isaac       if (canon == -1) continue;
1015f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1016f9f063d4SToby Isaac         PetscInt numChildren, i;
1017f9f063d4SToby Isaac         const PetscInt *children;
1018f9f063d4SToby Isaac 
1019f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&numChildren,&children);CHKERRQ(ierr);
1020f9f063d4SToby Isaac         if (numChildren) {
1021f9f063d4SToby 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);
1022c58f1c22SToby Isaac           ierr = DMSetLabelValue(dm,"canonical",p,canon);CHKERRQ(ierr);
1023f9f063d4SToby Isaac           for (i = 0; i < numChildren; i++) {
1024c58f1c22SToby Isaac             ierr = DMSetLabelValue(dm,"canonical",children[i],cChildren[i]);CHKERRQ(ierr);
1025f9f063d4SToby Isaac           }
1026f9f063d4SToby Isaac         }
1027f9f063d4SToby Isaac       }
1028f9f063d4SToby Isaac     }
1029f9f063d4SToby Isaac   }
1030776742edSToby Isaac   if (exchangeSupports) {
1031776742edSToby Isaac     ierr = DMPlexTreeExchangeSupports(dm);CHKERRQ(ierr);
1032776742edSToby Isaac   }
1033f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
1034f7c74593SToby Isaac   /* reset anchors */
1035f7c74593SToby Isaac   ierr = DMPlexSetAnchors(dm,NULL,NULL);CHKERRQ(ierr);
1036f9f063d4SToby Isaac   PetscFunctionReturn(0);
1037f9f063d4SToby Isaac }
1038f9f063d4SToby Isaac 
10390b7167a0SToby Isaac /*@
10400b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
10410b7167a0SToby Isaac   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
10420b7167a0SToby Isaac   tree root.
10430b7167a0SToby Isaac 
10440b7167a0SToby Isaac   Collective on dm
10450b7167a0SToby Isaac 
10460b7167a0SToby Isaac   Input Parameters:
10470b7167a0SToby Isaac + dm - the DMPlex object
10480b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
10490b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
10500b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
10510b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
10520b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
10530b7167a0SToby Isaac 
10540b7167a0SToby Isaac   Level: intermediate
10550b7167a0SToby Isaac 
1056a17985deSToby Isaac .seealso: DMPlexGetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
10570b7167a0SToby Isaac @*/
1058b2f41788SToby Isaac PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
10590b7167a0SToby Isaac {
10600b7167a0SToby Isaac   PetscErrorCode ierr;
10610b7167a0SToby Isaac 
10620b7167a0SToby Isaac   PetscFunctionBegin;
1063776742edSToby Isaac   ierr = DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
10640b7167a0SToby Isaac   PetscFunctionReturn(0);
10650b7167a0SToby Isaac }
10660b7167a0SToby Isaac 
1067b2f41788SToby Isaac /*@
1068b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1069b2f41788SToby Isaac   Collective on dm
1070b2f41788SToby Isaac 
1071b2f41788SToby Isaac   Input Parameters:
1072b2f41788SToby Isaac . dm - the DMPlex object
1073b2f41788SToby Isaac 
1074b2f41788SToby Isaac   Output Parameters:
1075b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1076b2f41788SToby Isaac                   offset indexes the parent and childID list
1077b2f41788SToby Isaac . parents - a list of the point parents
1078b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1079b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1080b2f41788SToby Isaac . childSection - the inverse of the parent section
1081b2f41788SToby Isaac - children - a list of the point children
1082b2f41788SToby Isaac 
1083b2f41788SToby Isaac   Level: intermediate
1084b2f41788SToby Isaac 
1085a17985deSToby Isaac .seealso: DMPlexSetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
1086b2f41788SToby Isaac @*/
1087b2f41788SToby Isaac PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1088b2f41788SToby Isaac {
1089b2f41788SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
1090b2f41788SToby Isaac 
1091b2f41788SToby Isaac   PetscFunctionBegin;
1092b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1093b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1094b2f41788SToby Isaac   if (parents)       *parents       = mesh->parents;
1095b2f41788SToby Isaac   if (childIDs)      *childIDs      = mesh->childIDs;
1096b2f41788SToby Isaac   if (childSection)  *childSection  = mesh->childSection;
1097b2f41788SToby Isaac   if (children)      *children      = mesh->children;
1098b2f41788SToby Isaac   PetscFunctionReturn(0);
1099b2f41788SToby Isaac }
1100b2f41788SToby Isaac 
1101d961a43aSToby Isaac /*@
1102eaf898f9SPatrick Sanan   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)
1103d961a43aSToby Isaac 
1104d961a43aSToby Isaac   Input Parameters:
1105d961a43aSToby Isaac + dm - the DMPlex object
1106d961a43aSToby Isaac - point - the query point
1107d961a43aSToby Isaac 
1108d961a43aSToby Isaac   Output Parameters:
1109d961a43aSToby Isaac + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1110d961a43aSToby Isaac - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point
1111d961a43aSToby Isaac             does not have a parent
1112d961a43aSToby Isaac 
1113d961a43aSToby Isaac   Level: intermediate
1114d961a43aSToby Isaac 
1115d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeChildren()
1116d961a43aSToby Isaac @*/
1117d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1118d961a43aSToby Isaac {
1119d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1120d961a43aSToby Isaac   PetscSection   pSec;
1121d961a43aSToby Isaac   PetscErrorCode ierr;
1122d961a43aSToby Isaac 
1123d961a43aSToby Isaac   PetscFunctionBegin;
1124d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1125d961a43aSToby Isaac   pSec = mesh->parentSection;
1126d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1127d961a43aSToby Isaac     PetscInt dof;
1128d961a43aSToby Isaac 
1129d961a43aSToby Isaac     ierr = PetscSectionGetDof (pSec, point, &dof);CHKERRQ(ierr);
1130d961a43aSToby Isaac     if (dof) {
1131d961a43aSToby Isaac       PetscInt off;
1132d961a43aSToby Isaac 
1133d961a43aSToby Isaac       ierr = PetscSectionGetOffset (pSec, point, &off);CHKERRQ(ierr);
1134d961a43aSToby Isaac       if (parent)  *parent = mesh->parents[off];
1135d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
1136d961a43aSToby Isaac       PetscFunctionReturn(0);
1137d961a43aSToby Isaac     }
1138d961a43aSToby Isaac   }
1139d961a43aSToby Isaac   if (parent) {
1140d961a43aSToby Isaac     *parent = point;
1141d961a43aSToby Isaac   }
1142d961a43aSToby Isaac   if (childID) {
1143d961a43aSToby Isaac     *childID = 0;
1144d961a43aSToby Isaac   }
1145d961a43aSToby Isaac   PetscFunctionReturn(0);
1146d961a43aSToby Isaac }
1147d961a43aSToby Isaac 
1148d961a43aSToby Isaac /*@C
1149eaf898f9SPatrick Sanan   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)
1150d961a43aSToby Isaac 
1151d961a43aSToby Isaac   Input Parameters:
1152d961a43aSToby Isaac + dm - the DMPlex object
1153d961a43aSToby Isaac - point - the query point
1154d961a43aSToby Isaac 
1155d961a43aSToby Isaac   Output Parameters:
1156d961a43aSToby Isaac + numChildren - if not NULL, set to the number of children
1157d961a43aSToby Isaac - children - if not NULL, set to a list children, or set to NULL if the point has no children
1158d961a43aSToby Isaac 
1159d961a43aSToby Isaac   Level: intermediate
1160d961a43aSToby Isaac 
1161d961a43aSToby Isaac   Fortran Notes:
1162d961a43aSToby Isaac   Since it returns an array, this routine is only available in Fortran 90, and you must
1163d961a43aSToby Isaac   include petsc.h90 in your code.
1164d961a43aSToby Isaac 
1165d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeParent()
1166d961a43aSToby Isaac @*/
1167d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1168d961a43aSToby Isaac {
1169d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1170d961a43aSToby Isaac   PetscSection   childSec;
1171d961a43aSToby Isaac   PetscInt       dof = 0;
1172d961a43aSToby Isaac   PetscErrorCode ierr;
1173d961a43aSToby Isaac 
1174d961a43aSToby Isaac   PetscFunctionBegin;
1175d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1176d961a43aSToby Isaac   childSec = mesh->childSection;
1177d961a43aSToby Isaac   if (childSec && point >= childSec->pStart && point < childSec->pEnd) {
1178d961a43aSToby Isaac     ierr = PetscSectionGetDof (childSec, point, &dof);CHKERRQ(ierr);
1179d961a43aSToby Isaac   }
1180d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1181d961a43aSToby Isaac   if (children) {
1182d961a43aSToby Isaac     if (dof) {
1183d961a43aSToby Isaac       PetscInt off;
1184d961a43aSToby Isaac 
1185d961a43aSToby Isaac       ierr = PetscSectionGetOffset (childSec, point, &off);CHKERRQ(ierr);
1186d961a43aSToby Isaac       *children = &mesh->children[off];
1187d961a43aSToby Isaac     }
1188d961a43aSToby Isaac     else {
1189d961a43aSToby Isaac       *children = NULL;
1190d961a43aSToby Isaac     }
1191d961a43aSToby Isaac   }
1192d961a43aSToby Isaac   PetscFunctionReturn(0);
1193d961a43aSToby Isaac }
11940c37af3bSToby Isaac 
119552a3aeb4SToby Isaac static PetscErrorCode EvaluateBasis(PetscSpace space, PetscInt nBasis, PetscInt nFunctionals, PetscInt nComps, PetscInt nPoints, const PetscInt *pointsPerFn, const PetscReal *points, const PetscReal *weights, PetscReal *work, Mat basisAtPoints)
1196b3a4bf2aSToby Isaac {
119752a3aeb4SToby Isaac   PetscInt       f, b, p, c, offset, qPoints;
1198b3a4bf2aSToby Isaac   PetscErrorCode ierr;
1199b3a4bf2aSToby Isaac 
1200b3a4bf2aSToby Isaac   PetscFunctionBegin;
1201b3a4bf2aSToby Isaac   ierr = PetscSpaceEvaluate(space,nPoints,points,work,NULL,NULL);CHKERRQ(ierr);
120252a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
120352a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
120452a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1205b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1206b3a4bf2aSToby Isaac 
120752a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
120852a3aeb4SToby Isaac         for (c = 0; c < nComps; c++) {
120952a3aeb4SToby Isaac           val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
1210b3a4bf2aSToby Isaac         }
121152a3aeb4SToby Isaac       }
121252a3aeb4SToby Isaac       ierr = MatSetValue(basisAtPoints,b,f,val,INSERT_VALUES);CHKERRQ(ierr);
1213b3a4bf2aSToby Isaac     }
1214b3a4bf2aSToby Isaac     offset += qPoints;
1215b3a4bf2aSToby Isaac   }
1216b3a4bf2aSToby Isaac   ierr = MatAssemblyBegin(basisAtPoints,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1217b3a4bf2aSToby Isaac   ierr = MatAssemblyEnd(basisAtPoints,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1218b3a4bf2aSToby Isaac   PetscFunctionReturn(0);
1219b3a4bf2aSToby Isaac }
1220b3a4bf2aSToby Isaac 
1221f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
12220c37af3bSToby Isaac {
12230c37af3bSToby Isaac   PetscDS        ds;
12240c37af3bSToby Isaac   PetscInt       spdim;
12250c37af3bSToby Isaac   PetscInt       numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
12260c37af3bSToby Isaac   const PetscInt *anchors;
1227f7c74593SToby Isaac   PetscSection   aSec;
12280c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
12290c37af3bSToby Isaac   IS             aIS;
12300c37af3bSToby Isaac   PetscErrorCode ierr;
12310c37af3bSToby Isaac 
12320c37af3bSToby Isaac   PetscFunctionBegin;
12330c37af3bSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
12340c37af3bSToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
12350c37af3bSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
12360c37af3bSToby Isaac   ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
1237a17985deSToby Isaac   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
12380c37af3bSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
12390c37af3bSToby Isaac   ierr = PetscSectionGetChart(cSec,&conStart,&conEnd);CHKERRQ(ierr);
124028f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&spdim);CHKERRQ(ierr);
12410c37af3bSToby Isaac   ierr = PetscMalloc6(spdim,&v0,spdim,&v0parent,spdim,&vtmp,spdim*spdim,&J,spdim*spdim,&Jparent,spdim*spdim,&invJparent);CHKERRQ(ierr);
12420c37af3bSToby Isaac 
12430c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
12440dd1b1feSToby Isaac     PetscObject       disc;
12450dd1b1feSToby Isaac     PetscClassId      id;
1246b3a4bf2aSToby Isaac     PetscSpace        bspace;
1247b3a4bf2aSToby Isaac     PetscDualSpace    dspace;
12489c3cf19fSMatthew G. Knepley     PetscInt          i, j, k, nPoints, Nc, offset;
124952a3aeb4SToby Isaac     PetscInt          fSize, maxDof;
1250b3a4bf2aSToby Isaac     PetscReal         *weights, *pointsRef, *pointsReal, *work;
1251*1683a169SBarry Smith     PetscScalar       *scwork;
1252*1683a169SBarry Smith     const PetscScalar *X;
12532c44ad04SToby Isaac     PetscInt          *sizes, *workIndRow, *workIndCol;
12540c37af3bSToby Isaac     Mat               Amat, Bmat, Xmat;
12552c44ad04SToby Isaac     const PetscInt    *numDof  = NULL;
1256085f0adfSToby Isaac     const PetscInt    ***perms = NULL;
1257085f0adfSToby Isaac     const PetscScalar ***flips = NULL;
12580c37af3bSToby Isaac 
12590dd1b1feSToby Isaac     ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
12600dd1b1feSToby Isaac     ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
12610dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1262b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE) disc;
1263b3a4bf2aSToby Isaac 
1264b3a4bf2aSToby Isaac       ierr = PetscFEGetBasisSpace(fe,&bspace);CHKERRQ(ierr);
1265b3a4bf2aSToby Isaac       ierr = PetscFEGetDualSpace(fe,&dspace);CHKERRQ(ierr);
1266b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetDimension(dspace,&fSize);CHKERRQ(ierr);
126752a3aeb4SToby Isaac       ierr = PetscFEGetNumComponents(fe,&Nc);CHKERRQ(ierr);
12680dd1b1feSToby Isaac     }
12690dd1b1feSToby Isaac     else if (id == PETSCFV_CLASSID) {
1270b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV) disc;
1271b3a4bf2aSToby Isaac 
127252a3aeb4SToby Isaac       ierr = PetscFVGetNumComponents(fv,&Nc);CHKERRQ(ierr);
1273b3a4bf2aSToby Isaac       ierr = PetscSpaceCreate(PetscObjectComm((PetscObject)fv),&bspace);CHKERRQ(ierr);
1274b3a4bf2aSToby Isaac       ierr = PetscSpaceSetType(bspace,PETSCSPACEPOLYNOMIAL);CHKERRQ(ierr);
1275d39dd5f5SToby Isaac       ierr = PetscSpaceSetDegree(bspace,0,PETSC_DETERMINE);CHKERRQ(ierr);
127652a3aeb4SToby Isaac       ierr = PetscSpaceSetNumComponents(bspace,Nc);CHKERRQ(ierr);
1277157782e2SToby Isaac       ierr = PetscSpaceSetNumVariables(bspace,spdim);CHKERRQ(ierr);
1278b3a4bf2aSToby Isaac       ierr = PetscSpaceSetUp(bspace);CHKERRQ(ierr);
1279b3a4bf2aSToby Isaac       ierr = PetscFVGetDualSpace(fv,&dspace);CHKERRQ(ierr);
1280b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetDimension(dspace,&fSize);CHKERRQ(ierr);
12810dd1b1feSToby Isaac     }
12820dd1b1feSToby Isaac     else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
12832c44ad04SToby Isaac     ierr = PetscDualSpaceGetNumDof(dspace,&numDof);CHKERRQ(ierr);
12842c44ad04SToby Isaac     for (i = 0, maxDof = 0; i <= spdim; i++) {maxDof = PetscMax(maxDof,numDof[i]);}
1285085f0adfSToby Isaac     ierr = PetscDualSpaceGetSymmetries(dspace,&perms,&flips);CHKERRQ(ierr);
12860dd1b1feSToby Isaac 
12870c37af3bSToby Isaac     ierr = MatCreate(PETSC_COMM_SELF,&Amat);CHKERRQ(ierr);
12880c37af3bSToby Isaac     ierr = MatSetSizes(Amat,fSize,fSize,fSize,fSize);CHKERRQ(ierr);
12890c37af3bSToby Isaac     ierr = MatSetType(Amat,MATSEQDENSE);CHKERRQ(ierr);
12900c37af3bSToby Isaac     ierr = MatSetUp(Amat);CHKERRQ(ierr);
12910c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Bmat);CHKERRQ(ierr);
12920c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Xmat);CHKERRQ(ierr);
12930c37af3bSToby Isaac     nPoints = 0;
12940c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
129552a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
12960c37af3bSToby Isaac       PetscQuadrature quad;
12970c37af3bSToby Isaac 
1298b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetFunctional(dspace,i,&quad);CHKERRQ(ierr);
129952a3aeb4SToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,&thisNc,&qPoints,NULL,NULL);CHKERRQ(ierr);
130052a3aeb4SToby Isaac       if (thisNc != Nc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %D does not much basis dim %D\n",thisNc,Nc);
13010c37af3bSToby Isaac       nPoints += qPoints;
13020c37af3bSToby Isaac     }
130352a3aeb4SToby Isaac     ierr = PetscMalloc7(fSize,&sizes,nPoints*Nc,&weights,spdim*nPoints,&pointsRef,spdim*nPoints,&pointsReal,nPoints*fSize*Nc,&work,maxDof,&workIndRow,maxDof,&workIndCol);CHKERRQ(ierr);
13042c44ad04SToby Isaac     ierr = PetscMalloc1(maxDof * maxDof,&scwork);CHKERRQ(ierr);
13050c37af3bSToby Isaac     offset = 0;
13060c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
13070c37af3bSToby Isaac       PetscInt        qPoints;
13080c37af3bSToby Isaac       const PetscReal    *p, *w;
13090c37af3bSToby Isaac       PetscQuadrature quad;
13100c37af3bSToby Isaac 
1311b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetFunctional(dspace,i,&quad);CHKERRQ(ierr);
131252a3aeb4SToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,NULL,&qPoints,&p,&w);CHKERRQ(ierr);
131352a3aeb4SToby Isaac       ierr = PetscMemcpy(weights+Nc*offset,w,Nc*qPoints*sizeof(*w));CHKERRQ(ierr);
13140c37af3bSToby Isaac       ierr = PetscMemcpy(pointsRef+spdim*offset,p,spdim*qPoints*sizeof(*p));CHKERRQ(ierr);
1315b3a4bf2aSToby Isaac       sizes[i] = qPoints;
13160c37af3bSToby Isaac       offset  += qPoints;
13170c37af3bSToby Isaac     }
131852a3aeb4SToby Isaac     ierr = EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsRef,weights,work,Amat);CHKERRQ(ierr);
13190c37af3bSToby Isaac     ierr = MatLUFactor(Amat,NULL,NULL,NULL);CHKERRQ(ierr);
13200c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
13210c37af3bSToby Isaac       PetscInt        parent;
13220c37af3bSToby Isaac       PetscInt        closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
13230c37af3bSToby Isaac       PetscInt        *childOffsets, *parentOffsets;
13240c37af3bSToby Isaac 
13250c37af3bSToby Isaac       ierr = DMPlexGetTreeParent(dm,c,&parent,NULL);CHKERRQ(ierr);
13260c37af3bSToby Isaac       if (parent == c) continue;
13270c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13280c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13290c37af3bSToby Isaac         PetscInt p = closure[2*i];
13300c37af3bSToby Isaac         PetscInt conDof;
13310c37af3bSToby Isaac 
13320c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1333085f0adfSToby Isaac         if (numFields) {
13340c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
13350c37af3bSToby Isaac         }
13360c37af3bSToby Isaac         else {
13370c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
13380c37af3bSToby Isaac         }
13390c37af3bSToby Isaac         if (conDof) break;
13400c37af3bSToby Isaac       }
13410c37af3bSToby Isaac       if (i == closureSize) {
13420c37af3bSToby Isaac         ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13430c37af3bSToby Isaac         continue;
13440c37af3bSToby Isaac       }
13450c37af3bSToby Isaac 
134673a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
134773a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent);CHKERRQ(ierr);
13480c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1349c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
1350c330f8ffSToby Isaac 
1351c330f8ffSToby Isaac         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i*spdim],vtmp);
1352c330f8ffSToby Isaac         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i*spdim]);
13530c37af3bSToby Isaac       }
135452a3aeb4SToby Isaac       ierr = EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsReal,weights,work,Bmat);CHKERRQ(ierr);
13550c37af3bSToby Isaac       ierr = MatMatSolve(Amat,Bmat,Xmat);CHKERRQ(ierr);
1356*1683a169SBarry Smith       ierr = MatDenseGetArrayRead(Xmat,&X);CHKERRQ(ierr);
13570c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
13580c37af3bSToby Isaac       ierr = PetscMalloc2(closureSize+1,&childOffsets,closureSizeP+1,&parentOffsets);CHKERRQ(ierr);
13590c37af3bSToby Isaac       childOffsets[0] = 0;
13600c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13610c37af3bSToby Isaac         PetscInt p = closure[2*i];
13620c37af3bSToby Isaac         PetscInt dof;
13630c37af3bSToby Isaac 
1364085f0adfSToby Isaac         if (numFields) {
13650c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
13660c37af3bSToby Isaac         }
13670c37af3bSToby Isaac         else {
13680c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
13690c37af3bSToby Isaac         }
137052a3aeb4SToby Isaac         childOffsets[i+1]=childOffsets[i]+dof;
13710c37af3bSToby Isaac       }
13720c37af3bSToby Isaac       parentOffsets[0] = 0;
13730c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
13740c37af3bSToby Isaac         PetscInt p = closureP[2*i];
13750c37af3bSToby Isaac         PetscInt dof;
13760c37af3bSToby Isaac 
1377085f0adfSToby Isaac         if (numFields) {
13780c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
13790c37af3bSToby Isaac         }
13800c37af3bSToby Isaac         else {
13810c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
13820c37af3bSToby Isaac         }
138352a3aeb4SToby Isaac         parentOffsets[i+1]=parentOffsets[i]+dof;
13840c37af3bSToby Isaac       }
13850c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13862c44ad04SToby Isaac         PetscInt conDof, conOff, aDof, aOff, nWork;
13870c37af3bSToby Isaac         PetscInt p = closure[2*i];
13880c37af3bSToby Isaac         PetscInt o = closure[2*i+1];
1389085f0adfSToby Isaac         const PetscInt    *perm;
1390085f0adfSToby Isaac         const PetscScalar *flip;
13910c37af3bSToby Isaac 
13920c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1393085f0adfSToby Isaac         if (numFields) {
13940c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
13950c37af3bSToby Isaac           ierr = PetscSectionGetFieldOffset(cSec,p,f,&conOff);CHKERRQ(ierr);
13960c37af3bSToby Isaac         }
13970c37af3bSToby Isaac         else {
13980c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
13990c37af3bSToby Isaac           ierr = PetscSectionGetOffset(cSec,p,&conOff);CHKERRQ(ierr);
14000c37af3bSToby Isaac         }
14010c37af3bSToby Isaac         if (!conDof) continue;
1402085f0adfSToby Isaac         perm  = (perms && perms[i]) ? perms[i][o] : NULL;
1403085f0adfSToby Isaac         flip  = (flips && flips[i]) ? flips[i][o] : NULL;
14040c37af3bSToby Isaac         ierr  = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
14050c37af3bSToby Isaac         ierr  = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
14062c44ad04SToby Isaac         nWork = childOffsets[i+1]-childOffsets[i];
14070c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
14080c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
14090c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
14100c37af3bSToby Isaac 
1411085f0adfSToby Isaac           if (numFields) {
14120c37af3bSToby Isaac             ierr = PetscSectionGetFieldDof(section,a,f,&aSecDof);CHKERRQ(ierr);
14130c37af3bSToby Isaac             ierr = PetscSectionGetFieldOffset(section,a,f,&aSecOff);CHKERRQ(ierr);
14140c37af3bSToby Isaac           }
14150c37af3bSToby Isaac           else {
14160c37af3bSToby Isaac             ierr = PetscSectionGetDof(section,a,&aSecDof);CHKERRQ(ierr);
14170c37af3bSToby Isaac             ierr = PetscSectionGetOffset(section,a,&aSecOff);CHKERRQ(ierr);
14180c37af3bSToby Isaac           }
14190c37af3bSToby Isaac           if (!aSecDof) continue;
14200c37af3bSToby Isaac 
14210c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
14220c37af3bSToby Isaac             PetscInt q = closureP[2*j];
14230c37af3bSToby Isaac             PetscInt oq = closureP[2*j+1];
14242c44ad04SToby Isaac 
14252c44ad04SToby Isaac             if (q == a) {
142652a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1427085f0adfSToby Isaac               const PetscInt    *permP;
1428085f0adfSToby Isaac               const PetscScalar *flipP;
1429085f0adfSToby Isaac 
1430085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1431085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
14322c44ad04SToby Isaac               nWorkP = parentOffsets[j+1]-parentOffsets[j];
14332c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
1434*1683a169SBarry Smith                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
14352c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
14362c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
14372c44ad04SToby Isaac                 for (s = 0; s < nWorkP; s++) {
14382c44ad04SToby Isaac                   scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
14392c44ad04SToby Isaac                 }
14402c44ad04SToby Isaac               }
144152a3aeb4SToby Isaac               for (r = 0; r < nWork; r++)  {workIndRow[perm  ? perm[r]  : r] = conOff  + r;}
144252a3aeb4SToby Isaac               for (s = 0; s < nWorkP; s++) {workIndCol[permP ? permP[s] : s] = aSecOff + s;}
14432c44ad04SToby Isaac               if (flip) {
14442c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14452c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14462c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flip[r];
14472c44ad04SToby Isaac                   }
14482c44ad04SToby Isaac                 }
14492c44ad04SToby Isaac               }
14502c44ad04SToby Isaac               if (flipP) {
14512c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14522c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14532c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flipP[s];
14542c44ad04SToby Isaac                   }
14552c44ad04SToby Isaac                 }
14562c44ad04SToby Isaac               }
14572c44ad04SToby Isaac               ierr = MatSetValues(cMat,nWork,workIndRow,nWorkP,workIndCol,scwork,INSERT_VALUES);CHKERRQ(ierr);
14582c44ad04SToby Isaac               break;
14590c37af3bSToby Isaac             }
14600c37af3bSToby Isaac           }
14610c37af3bSToby Isaac         }
14620c37af3bSToby Isaac       }
1463*1683a169SBarry Smith       ierr = MatDenseRestoreArrayRead(Xmat,&X);CHKERRQ(ierr);
14640c37af3bSToby Isaac       ierr = PetscFree2(childOffsets,parentOffsets);CHKERRQ(ierr);
14650c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
14660c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
14670c37af3bSToby Isaac     }
14680c37af3bSToby Isaac     ierr = MatDestroy(&Amat);CHKERRQ(ierr);
14690c37af3bSToby Isaac     ierr = MatDestroy(&Bmat);CHKERRQ(ierr);
14700c37af3bSToby Isaac     ierr = MatDestroy(&Xmat);CHKERRQ(ierr);
14712c44ad04SToby Isaac     ierr = PetscFree(scwork);CHKERRQ(ierr);
14722c44ad04SToby Isaac     ierr = PetscFree7(sizes,weights,pointsRef,pointsReal,work,workIndRow,workIndCol);CHKERRQ(ierr);
1473b3a4bf2aSToby Isaac     if (id == PETSCFV_CLASSID) {
1474b3a4bf2aSToby Isaac       ierr = PetscSpaceDestroy(&bspace);CHKERRQ(ierr);
1475b3a4bf2aSToby Isaac     }
14760c37af3bSToby Isaac   }
14770c37af3bSToby Isaac   ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14780c37af3bSToby Isaac   ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14790c37af3bSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJparent);CHKERRQ(ierr);
14800c37af3bSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
14810c37af3bSToby Isaac 
14820c37af3bSToby Isaac   PetscFunctionReturn(0);
14830c37af3bSToby Isaac }
148495a0b26dSToby Isaac 
148521968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
148695a0b26dSToby Isaac {
1487f7c74593SToby Isaac   Mat               refCmat;
148821968bf8SToby Isaac   PetscDS           ds;
1489085f0adfSToby Isaac   PetscInt          numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
149021968bf8SToby Isaac   PetscScalar       ***refPointFieldMats;
149121968bf8SToby Isaac   PetscSection      refConSec, refAnSec, refSection;
149221968bf8SToby Isaac   IS                refAnIS;
149321968bf8SToby Isaac   const PetscInt    *refAnchors;
1494085f0adfSToby Isaac   const PetscInt    **perms;
1495085f0adfSToby Isaac   const PetscScalar **flips;
149695a0b26dSToby Isaac   PetscErrorCode    ierr;
149795a0b26dSToby Isaac 
149895a0b26dSToby Isaac   PetscFunctionBegin;
149921968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
150095a0b26dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1501085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
1502f7c74593SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
1503a17985deSToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
150495a0b26dSToby Isaac   ierr = ISGetIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
1505e87a4003SBarry Smith   ierr = DMGetSection(refTree,&refSection);CHKERRQ(ierr);
150695a0b26dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
150795a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
150895a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldN);CHKERRQ(ierr);
150995a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
151095a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
151195a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
151295a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof*maxAnDof,&cols);CHKERRQ(ierr);
151395a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
151495a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
151595a0b26dSToby Isaac 
151695a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
151795a0b26dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
151895a0b26dSToby Isaac     if (!pDof || parent == p) continue;
151995a0b26dSToby Isaac 
1520085f0adfSToby Isaac     ierr = PetscMalloc1(maxFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
1521085f0adfSToby Isaac     ierr = PetscCalloc1(maxFields,&refPointFieldN[p-pRefStart]);CHKERRQ(ierr);
152295a0b26dSToby Isaac     ierr = DMPlexGetTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1523085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1524085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
152595a0b26dSToby Isaac 
1526085f0adfSToby Isaac       if (f < numFields) {
152795a0b26dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
152895a0b26dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
1529085f0adfSToby Isaac         ierr = PetscSectionGetFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1530085f0adfSToby Isaac       } else {
153195a0b26dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
153295a0b26dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
1533085f0adfSToby Isaac         ierr = PetscSectionGetPointSyms(refSection,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
153495a0b26dSToby Isaac       }
153595a0b26dSToby Isaac 
153695a0b26dSToby Isaac       for (r = 0; r < cDof; r++) {
153795a0b26dSToby Isaac         rows[r] = cOff + r;
153895a0b26dSToby Isaac       }
153995a0b26dSToby Isaac       numCols = 0;
154095a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
154195a0b26dSToby Isaac         PetscInt          q = closure[2*i];
154295a0b26dSToby Isaac         PetscInt          aDof, aOff, j;
1543085f0adfSToby Isaac         const PetscInt    *perm = perms ? perms[i] : NULL;
154495a0b26dSToby Isaac 
1545085f0adfSToby Isaac         if (numFields) {
154695a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
154795a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
154895a0b26dSToby Isaac         }
154995a0b26dSToby Isaac         else {
155095a0b26dSToby Isaac           ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
155195a0b26dSToby Isaac           ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
155295a0b26dSToby Isaac         }
155395a0b26dSToby Isaac 
155495a0b26dSToby Isaac         for (j = 0; j < aDof; j++) {
1555085f0adfSToby Isaac           cols[numCols++] = aOff + (perm ? perm[j] : j);
155695a0b26dSToby Isaac         }
155795a0b26dSToby Isaac       }
155895a0b26dSToby Isaac       refPointFieldN[p-pRefStart][f] = numCols;
155995a0b26dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
156095a0b26dSToby Isaac       ierr = MatGetValues(refCmat,cDof,rows,numCols,cols,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
1561085f0adfSToby Isaac       if (flips) {
1562085f0adfSToby Isaac         PetscInt colOff = 0;
1563085f0adfSToby Isaac 
1564085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1565085f0adfSToby Isaac           PetscInt          q = closure[2*i];
1566085f0adfSToby Isaac           PetscInt          aDof, aOff, j;
1567085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1568085f0adfSToby Isaac 
1569085f0adfSToby Isaac           if (numFields) {
1570085f0adfSToby Isaac             ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
1571085f0adfSToby Isaac             ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
1572085f0adfSToby Isaac           }
1573085f0adfSToby Isaac           else {
1574085f0adfSToby Isaac             ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
1575085f0adfSToby Isaac             ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
1576085f0adfSToby Isaac           }
1577085f0adfSToby Isaac           if (flip) {
1578085f0adfSToby Isaac             PetscInt k;
1579085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1580085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1581085f0adfSToby Isaac                 refPointFieldMats[p-pRefStart][f][k * numCols + colOff + j] *= flip[j];
1582085f0adfSToby Isaac               }
1583085f0adfSToby Isaac             }
1584085f0adfSToby Isaac           }
1585085f0adfSToby Isaac           colOff += aDof;
1586085f0adfSToby Isaac         }
1587085f0adfSToby Isaac       }
1588085f0adfSToby Isaac       if (numFields) {
1589085f0adfSToby Isaac         ierr = PetscSectionRestoreFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1590085f0adfSToby Isaac       } else {
1591085f0adfSToby Isaac         ierr = PetscSectionRestorePointSyms(refSection,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1592085f0adfSToby Isaac       }
159395a0b26dSToby Isaac     }
159495a0b26dSToby Isaac     ierr = DMPlexRestoreTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
159595a0b26dSToby Isaac   }
159621968bf8SToby Isaac   *childrenMats = refPointFieldMats;
159721968bf8SToby Isaac   *childrenN = refPointFieldN;
159821968bf8SToby Isaac   ierr = ISRestoreIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
159921968bf8SToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
160021968bf8SToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
160121968bf8SToby Isaac   PetscFunctionReturn(0);
160221968bf8SToby Isaac }
160321968bf8SToby Isaac 
160421968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
160521968bf8SToby Isaac {
160621968bf8SToby Isaac   PetscDS        ds;
160721968bf8SToby Isaac   PetscInt       **refPointFieldN;
160821968bf8SToby Isaac   PetscScalar    ***refPointFieldMats;
1609085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
161021968bf8SToby Isaac   PetscSection   refConSec;
161121968bf8SToby Isaac   PetscErrorCode ierr;
161221968bf8SToby Isaac 
161321968bf8SToby Isaac   PetscFunctionBegin;
161421968bf8SToby Isaac   refPointFieldN = *childrenN;
161521968bf8SToby Isaac   *childrenN = NULL;
161621968bf8SToby Isaac   refPointFieldMats = *childrenMats;
161721968bf8SToby Isaac   *childrenMats = NULL;
161821968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
161921968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1620367003a6SStefano Zampini   maxFields = PetscMax(1,numFields);
162121968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
1622e44e4e7fSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
162321968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
162421968bf8SToby Isaac     PetscInt parent, pDof;
162521968bf8SToby Isaac 
162621968bf8SToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
162721968bf8SToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
162821968bf8SToby Isaac     if (!pDof || parent == p) continue;
162921968bf8SToby Isaac 
1630085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
163121968bf8SToby Isaac       PetscInt cDof;
163221968bf8SToby Isaac 
1633085f0adfSToby Isaac       if (numFields) {
163421968bf8SToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
163521968bf8SToby Isaac       }
163621968bf8SToby Isaac       else {
163721968bf8SToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
163821968bf8SToby Isaac       }
163921968bf8SToby Isaac 
164021968bf8SToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
164121968bf8SToby Isaac     }
164221968bf8SToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
164321968bf8SToby Isaac     ierr = PetscFree(refPointFieldN[p - pRefStart]);CHKERRQ(ierr);
164421968bf8SToby Isaac   }
164521968bf8SToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
164621968bf8SToby Isaac   ierr = PetscFree(refPointFieldN);CHKERRQ(ierr);
164721968bf8SToby Isaac   PetscFunctionReturn(0);
164821968bf8SToby Isaac }
164921968bf8SToby Isaac 
165021968bf8SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
165121968bf8SToby Isaac {
165221968bf8SToby Isaac   DM             refTree;
165321968bf8SToby Isaac   PetscDS        ds;
165421968bf8SToby Isaac   Mat            refCmat;
1655085f0adfSToby Isaac   PetscInt       numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
165621968bf8SToby Isaac   PetscScalar ***refPointFieldMats, *pointWork;
165721968bf8SToby Isaac   PetscSection   refConSec, refAnSec, anSec;
165821968bf8SToby Isaac   IS             refAnIS, anIS;
165921968bf8SToby Isaac   const PetscInt *anchors;
166021968bf8SToby Isaac   PetscErrorCode ierr;
166121968bf8SToby Isaac 
166221968bf8SToby Isaac   PetscFunctionBegin;
166321968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
166421968bf8SToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
166521968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1666085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
166721968bf8SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
1668e5e52638SMatthew G. Knepley   ierr = DMCopyDisc(dm,refTree);CHKERRQ(ierr);
166921968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
167021968bf8SToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
167121968bf8SToby Isaac   ierr = DMPlexGetAnchors(dm,&anSec,&anIS);CHKERRQ(ierr);
167221968bf8SToby Isaac   ierr = ISGetIndices(anIS,&anchors);CHKERRQ(ierr);
167321968bf8SToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
167421968bf8SToby Isaac   ierr = PetscSectionGetChart(conSec,&conStart,&conEnd);CHKERRQ(ierr);
167521968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
167621968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
167721968bf8SToby Isaac   ierr = PetscMalloc1(maxDof*maxDof*maxAnDof,&pointWork);CHKERRQ(ierr);
167821968bf8SToby Isaac 
167921968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
168021968bf8SToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
168195a0b26dSToby Isaac 
168295a0b26dSToby Isaac   /* step 2: compute the preorder */
168395a0b26dSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
168495a0b26dSToby Isaac   ierr = PetscMalloc2(pEnd-pStart,&perm,pEnd-pStart,&iperm);CHKERRQ(ierr);
168595a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
168695a0b26dSToby Isaac     perm[p - pStart] = p;
168795a0b26dSToby Isaac     iperm[p - pStart] = p-pStart;
168895a0b26dSToby Isaac   }
168995a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
169095a0b26dSToby Isaac     PetscInt point = perm[p];
169195a0b26dSToby Isaac     PetscInt parent;
169295a0b26dSToby Isaac 
169395a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
169495a0b26dSToby Isaac     if (parent == point) {
169595a0b26dSToby Isaac       p++;
169695a0b26dSToby Isaac     }
169795a0b26dSToby Isaac     else {
169895a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
169995a0b26dSToby Isaac 
170095a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
170195a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
170295a0b26dSToby Isaac         PetscInt q = closure[2*i];
170395a0b26dSToby Isaac         if (iperm[q-pStart] > iperm[point-pStart]) {
170495a0b26dSToby Isaac           /* swap */
170595a0b26dSToby Isaac           perm[p]               = q;
170695a0b26dSToby Isaac           perm[iperm[q-pStart]] = point;
170795a0b26dSToby Isaac           iperm[point-pStart]   = iperm[q-pStart];
170895a0b26dSToby Isaac           iperm[q-pStart]       = p;
170995a0b26dSToby Isaac           break;
171095a0b26dSToby Isaac         }
171195a0b26dSToby Isaac       }
171295a0b26dSToby Isaac       size = closureSize;
171395a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
171495a0b26dSToby Isaac       if (i == size) {
171595a0b26dSToby Isaac         p++;
171695a0b26dSToby Isaac       }
171795a0b26dSToby Isaac     }
171895a0b26dSToby Isaac   }
171995a0b26dSToby Isaac 
172095a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
172195a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
172295a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
172395a0b26dSToby Isaac    * values outside of the Mat first.
172495a0b26dSToby Isaac    */
172595a0b26dSToby Isaac   {
172695a0b26dSToby Isaac     PetscInt nRows, row, nnz;
172795a0b26dSToby Isaac     PetscBool done;
172895a0b26dSToby Isaac     const PetscInt *ia, *ja;
172995a0b26dSToby Isaac     PetscScalar *vals;
173095a0b26dSToby Isaac 
173195a0b26dSToby Isaac     ierr = MatGetRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
173295a0b26dSToby Isaac     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not get RowIJ of constraint matrix");
173395a0b26dSToby Isaac     nnz  = ia[nRows];
173495a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
173595a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
173695a0b26dSToby Isaac     ierr = PetscMalloc1(nnz,&vals);CHKERRQ(ierr);
173795a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
173895a0b26dSToby Isaac       PetscInt        parent, childid, closureSize, *closure = NULL;
173995a0b26dSToby Isaac       PetscInt        point = perm[p], pointDof;
174095a0b26dSToby Isaac 
174195a0b26dSToby Isaac       ierr = DMPlexGetTreeParent(dm,point,&parent,&childid);CHKERRQ(ierr);
174295a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
174395a0b26dSToby Isaac       ierr = PetscSectionGetDof(conSec,point,&pointDof);CHKERRQ(ierr);
174495a0b26dSToby Isaac       if (!pointDof) continue;
174595a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1746085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1747085f0adfSToby Isaac         PetscInt cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
174895a0b26dSToby Isaac         PetscScalar *pointMat;
1749085f0adfSToby Isaac         const PetscInt    **perms;
1750085f0adfSToby Isaac         const PetscScalar **flips;
175195a0b26dSToby Isaac 
1752085f0adfSToby Isaac         if (numFields) {
175395a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(conSec,point,f,&cDof);CHKERRQ(ierr);
175495a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(conSec,point,f,&cOff);CHKERRQ(ierr);
175595a0b26dSToby Isaac         }
175695a0b26dSToby Isaac         else {
175795a0b26dSToby Isaac           ierr = PetscSectionGetDof(conSec,point,&cDof);CHKERRQ(ierr);
175895a0b26dSToby Isaac           ierr = PetscSectionGetOffset(conSec,point,&cOff);CHKERRQ(ierr);
175995a0b26dSToby Isaac         }
176095a0b26dSToby Isaac         if (!cDof) continue;
1761085f0adfSToby Isaac         if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);}
1762085f0adfSToby Isaac         else           {ierr = PetscSectionGetPointSyms(section,closureSize,closure,&perms,&flips);CHKERRQ(ierr);}
176395a0b26dSToby Isaac 
176495a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
176595a0b26dSToby Isaac #if defined(PETSC_USE_DEBUG)
176695a0b26dSToby Isaac         for (r = 0; r < cDof; r++) {
176795a0b26dSToby Isaac           if (cDof > 1 && r) {
176821968bf8SToby 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]));
176995a0b26dSToby Isaac           }
177095a0b26dSToby Isaac         }
177195a0b26dSToby Isaac #endif
177295a0b26dSToby Isaac         /* zero rows */
177395a0b26dSToby Isaac         for (i = ia[cOff] ; i< ia[cOff+cDof];i++) {
177495a0b26dSToby Isaac           vals[i] = 0.;
177595a0b26dSToby Isaac         }
177695a0b26dSToby Isaac         matOffset = ia[cOff];
177795a0b26dSToby Isaac         numFillCols = ia[cOff+1] - matOffset;
177895a0b26dSToby Isaac         pointMat = refPointFieldMats[childid-pRefStart][f];
177995a0b26dSToby Isaac         numCols = refPointFieldN[childid-pRefStart][f];
178095a0b26dSToby Isaac         offset = 0;
178195a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
178295a0b26dSToby Isaac           PetscInt q = closure[2*i];
178395a0b26dSToby Isaac           PetscInt aDof, aOff, j, k, qConDof, qConOff;
1784085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1785085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
178695a0b26dSToby Isaac 
178795a0b26dSToby Isaac           qConDof = qConOff = 0;
1788085f0adfSToby Isaac           if (numFields) {
178995a0b26dSToby Isaac             ierr = PetscSectionGetFieldDof(section,q,f,&aDof);CHKERRQ(ierr);
179095a0b26dSToby Isaac             ierr = PetscSectionGetFieldOffset(section,q,f,&aOff);CHKERRQ(ierr);
179195a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
179295a0b26dSToby Isaac               ierr = PetscSectionGetFieldDof(conSec,q,f,&qConDof);CHKERRQ(ierr);
179395a0b26dSToby Isaac               ierr = PetscSectionGetFieldOffset(conSec,q,f,&qConOff);CHKERRQ(ierr);
179495a0b26dSToby Isaac             }
179595a0b26dSToby Isaac           }
179695a0b26dSToby Isaac           else {
179795a0b26dSToby Isaac             ierr = PetscSectionGetDof(section,q,&aDof);CHKERRQ(ierr);
179895a0b26dSToby Isaac             ierr = PetscSectionGetOffset(section,q,&aOff);CHKERRQ(ierr);
179995a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
180095a0b26dSToby Isaac               ierr = PetscSectionGetDof(conSec,q,&qConDof);CHKERRQ(ierr);
180195a0b26dSToby Isaac               ierr = PetscSectionGetOffset(conSec,q,&qConOff);CHKERRQ(ierr);
180295a0b26dSToby Isaac             }
180395a0b26dSToby Isaac           }
180495a0b26dSToby Isaac           if (!aDof) continue;
180595a0b26dSToby Isaac           if (qConDof) {
180695a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
180795a0b26dSToby Isaac              * be filled, thanks to preordering */
180895a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
180995a0b26dSToby Isaac             PetscInt aMatOffset = ia[qConOff];
181095a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
181195a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
181295a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
181395a0b26dSToby Isaac                 PetscScalar inVal = 0;
181495a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1815085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
181695a0b26dSToby Isaac 
1817085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
181895a0b26dSToby Isaac                 }
181995a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
182095a0b26dSToby Isaac               }
182195a0b26dSToby Isaac             }
182295a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
182395a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
182495a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
182595a0b26dSToby Isaac               for (;k < numFillCols; k++) {
182695a0b26dSToby Isaac                 if (ja[matOffset + k] == col) {
182795a0b26dSToby Isaac                   break;
182895a0b26dSToby Isaac                 }
182995a0b26dSToby Isaac               }
183095a0b26dSToby Isaac               if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, col);
183195a0b26dSToby Isaac               for (r = 0; r < cDof; r++) {
183295a0b26dSToby Isaac                 vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
183395a0b26dSToby Isaac               }
183495a0b26dSToby Isaac             }
183595a0b26dSToby Isaac           }
183695a0b26dSToby Isaac           else {
183795a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
183895a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
183995a0b26dSToby Isaac               if (ja[matOffset + k] == aOff) {
184095a0b26dSToby Isaac                 break;
184195a0b26dSToby Isaac               }
184295a0b26dSToby Isaac             }
184395a0b26dSToby Isaac             if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, aOff);
184495a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1845085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1846085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1847085f0adfSToby Isaac 
1848085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
184995a0b26dSToby Isaac               }
185095a0b26dSToby Isaac             }
185195a0b26dSToby Isaac           }
185295a0b26dSToby Isaac           offset += aDof;
185395a0b26dSToby Isaac         }
1854085f0adfSToby Isaac         if (numFields) {
1855085f0adfSToby Isaac           ierr = PetscSectionRestoreFieldPointSyms(section,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1856085f0adfSToby Isaac         } else {
1857085f0adfSToby Isaac           ierr = PetscSectionRestorePointSyms(section,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1858085f0adfSToby Isaac         }
185995a0b26dSToby Isaac       }
186095a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
186195a0b26dSToby Isaac     }
186295a0b26dSToby Isaac     for (row = 0; row < nRows; row++) {
186395a0b26dSToby Isaac       ierr = MatSetValues(cMat,1,&row,ia[row+1]-ia[row],&ja[ia[row]],&vals[ia[row]],INSERT_VALUES);CHKERRQ(ierr);
186495a0b26dSToby Isaac     }
186595a0b26dSToby Isaac     ierr = MatRestoreRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
186695a0b26dSToby Isaac     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not restore RowIJ of constraint matrix");
186795a0b26dSToby Isaac     ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
186895a0b26dSToby Isaac     ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
186995a0b26dSToby Isaac     ierr = PetscFree(vals);CHKERRQ(ierr);
187095a0b26dSToby Isaac   }
187195a0b26dSToby Isaac 
187295a0b26dSToby Isaac   /* clean up */
187395a0b26dSToby Isaac   ierr = ISRestoreIndices(anIS,&anchors);CHKERRQ(ierr);
187495a0b26dSToby Isaac   ierr = PetscFree2(perm,iperm);CHKERRQ(ierr);
187595a0b26dSToby Isaac   ierr = PetscFree(pointWork);CHKERRQ(ierr);
187621968bf8SToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
187795a0b26dSToby Isaac   PetscFunctionReturn(0);
187895a0b26dSToby Isaac }
187995a0b26dSToby Isaac 
18806f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
18816f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
18826f5f1567SToby Isaac PetscErrorCode DMPlexTreeRefineCell (DM dm, PetscInt cell, DM *ncdm)
18836f5f1567SToby Isaac {
18846f5f1567SToby Isaac   DM K;
1885420f55faSMatthew G. Knepley   PetscMPIInt rank;
18866f5f1567SToby Isaac   PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
18876f5f1567SToby Isaac   PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations;
18886f5f1567SToby Isaac   PetscInt *Kembedding;
18896f5f1567SToby Isaac   PetscInt *cellClosure=NULL, nc;
18906f5f1567SToby Isaac   PetscScalar *newVertexCoords;
18916f5f1567SToby Isaac   PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
18926f5f1567SToby Isaac   PetscSection parentSection;
18936f5f1567SToby Isaac   PetscErrorCode ierr;
18946f5f1567SToby Isaac 
18956f5f1567SToby Isaac   PetscFunctionBegin;
18966f5f1567SToby Isaac   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRQ(ierr);
189728f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
18986f5f1567SToby Isaac   ierr = DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm);CHKERRQ(ierr);
189928f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ncdm,dim);CHKERRQ(ierr);
19006f5f1567SToby Isaac 
19016f5f1567SToby Isaac   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
19026f5f1567SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&parentSection);CHKERRQ(ierr);
19036f5f1567SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&K);CHKERRQ(ierr);
19046f5f1567SToby Isaac   if (!rank) {
19056f5f1567SToby Isaac     /* compute the new charts */
19066f5f1567SToby Isaac     ierr = PetscMalloc5(dim+1,&pNewCount,dim+1,&pNewStart,dim+1,&pNewEnd,dim+1,&pOldStart,dim+1,&pOldEnd);CHKERRQ(ierr);
19076f5f1567SToby Isaac     offset = 0;
19086f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19096f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
19106f5f1567SToby Isaac 
19116f5f1567SToby Isaac       pNewStart[d] = offset;
19126f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(dm,d,&pOldStart[d],&pOldEnd[d]);CHKERRQ(ierr);
19136f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
19146f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
19156f5f1567SToby Isaac       /* adding the new points */
19166f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
19176f5f1567SToby Isaac       if (!d) {
19186f5f1567SToby Isaac         /* removing the cell */
19196f5f1567SToby Isaac         pNewCount[d]--;
19206f5f1567SToby Isaac       }
19216f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19226f5f1567SToby Isaac         PetscInt parent;
19236f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&parent,NULL);CHKERRQ(ierr);
19246f5f1567SToby Isaac         if (parent == k) {
19256f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
19266f5f1567SToby Isaac           pNewCount[d]--;
19276f5f1567SToby Isaac         }
19286f5f1567SToby Isaac       }
19296f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
19306f5f1567SToby Isaac       offset = pNewEnd[d];
19316f5f1567SToby Isaac 
19326f5f1567SToby Isaac     }
19336f5f1567SToby 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]);
19346f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
19356f5f1567SToby Isaac     ierr = DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
19366f5f1567SToby Isaac 
19376f5f1567SToby Isaac     ierr = PetscMalloc1(pNewEnd[dim],&newConeSizes);CHKERRQ(ierr);
19386f5f1567SToby Isaac     {
19396f5f1567SToby Isaac       PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
19406f5f1567SToby Isaac 
19416f5f1567SToby Isaac       ierr = DMPlexGetChart(K,&kStart,&kEnd);CHKERRQ(ierr);
19426f5f1567SToby Isaac       ierr = PetscMalloc4(kEnd-kStart,&Kembedding,kEnd-kStart,&perm,kEnd-kStart,&iperm,kEnd-kStart,&preOrient);CHKERRQ(ierr);
19436f5f1567SToby Isaac 
19446f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19456f5f1567SToby Isaac         perm[k - kStart] = k;
19466f5f1567SToby Isaac         iperm [k - kStart] = k - kStart;
19476f5f1567SToby Isaac         preOrient[k - kStart] = 0;
19486f5f1567SToby Isaac       }
19496f5f1567SToby Isaac 
19506f5f1567SToby Isaac       ierr = DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
19516f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
19526f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2*j+1];
19536f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2*j+1];
19546f5f1567SToby Isaac         PetscInt p, q;
19556f5f1567SToby Isaac 
19566f5f1567SToby Isaac         p = closureK[2*j];
19576f5f1567SToby Isaac         q = cellClosure[2*j];
19586f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
19596f5f1567SToby Isaac           if (q >= pOldStart[d] && q < pOldEnd[d]) {
19606f5f1567SToby Isaac             Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
19616f5f1567SToby Isaac           }
19626f5f1567SToby Isaac         }
19636f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
19646f5f1567SToby Isaac           PetscInt numChildren, i;
19656f5f1567SToby Isaac           const PetscInt *children;
19666f5f1567SToby Isaac 
19676f5f1567SToby Isaac           ierr = DMPlexGetTreeChildren(K,p,&numChildren,&children);CHKERRQ(ierr);
19686f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
19696f5f1567SToby Isaac             PetscInt kPerm, oPerm;
19706f5f1567SToby Isaac 
19716f5f1567SToby Isaac             k    = children[i];
19726f5f1567SToby Isaac             ierr = DMPlexReferenceTreeGetChildSymmetry(K,p,parentOrientA,0,k,parentOrientB,&oPerm,&kPerm);CHKERRQ(ierr);
19736f5f1567SToby Isaac             /* perm = what refTree position I'm in */
19746f5f1567SToby Isaac             perm[kPerm-kStart]      = k;
19756f5f1567SToby Isaac             /* iperm = who is at this position */
19766f5f1567SToby Isaac             iperm[k-kStart]         = kPerm-kStart;
19776f5f1567SToby Isaac             preOrient[kPerm-kStart] = oPerm;
19786f5f1567SToby Isaac           }
19796f5f1567SToby Isaac         }
19806f5f1567SToby Isaac       }
19816f5f1567SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
19826f5f1567SToby Isaac     }
19836f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,0,pNewEnd[dim]);CHKERRQ(ierr);
19846f5f1567SToby Isaac     offset = 0;
19856f5f1567SToby Isaac     numNewCones = 0;
19866f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19876f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
19886f5f1567SToby Isaac       PetscInt p;
19896f5f1567SToby Isaac       PetscInt size;
19906f5f1567SToby Isaac 
19916f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19926f5f1567SToby Isaac         /* skip cell 0 */
19936f5f1567SToby Isaac         if (p == cell) continue;
19946f5f1567SToby Isaac         /* old cones to new cones */
19956f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
19966f5f1567SToby Isaac         newConeSizes[offset++] = size;
19976f5f1567SToby Isaac         numNewCones += size;
19986f5f1567SToby Isaac       }
19996f5f1567SToby Isaac 
20006f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
20016f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20026f5f1567SToby Isaac         PetscInt kParent;
20036f5f1567SToby Isaac 
20046f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
20056f5f1567SToby Isaac         if (kParent != k) {
20066f5f1567SToby Isaac           Kembedding[k] = offset;
20076f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
20086f5f1567SToby Isaac           newConeSizes[offset++] = size;
20096f5f1567SToby Isaac           numNewCones += size;
20106f5f1567SToby Isaac           if (kParent != 0) {
20116f5f1567SToby Isaac             ierr = PetscSectionSetDof(parentSection,Kembedding[k],1);CHKERRQ(ierr);
20126f5f1567SToby Isaac           }
20136f5f1567SToby Isaac         }
20146f5f1567SToby Isaac       }
20156f5f1567SToby Isaac     }
20166f5f1567SToby Isaac 
20176f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
20186f5f1567SToby Isaac     ierr = PetscSectionGetStorageSize(parentSection,&numPointsWithParents);CHKERRQ(ierr);
20196f5f1567SToby Isaac     ierr = PetscMalloc2(numNewCones,&newCones,numNewCones,&newOrientations);CHKERRQ(ierr);
20206f5f1567SToby Isaac     ierr = PetscMalloc2(numPointsWithParents,&parents,numPointsWithParents,&childIDs);CHKERRQ(ierr);
20216f5f1567SToby Isaac 
20226f5f1567SToby Isaac     /* fill new cones */
20236f5f1567SToby Isaac     offset = 0;
20246f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20256f5f1567SToby Isaac       PetscInt kStart, kEnd, k, l;
20266f5f1567SToby Isaac       PetscInt p;
20276f5f1567SToby Isaac       PetscInt size;
20286f5f1567SToby Isaac       const PetscInt *cone, *orientation;
20296f5f1567SToby Isaac 
20306f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
20316f5f1567SToby Isaac         /* skip cell 0 */
20326f5f1567SToby Isaac         if (p == cell) continue;
20336f5f1567SToby Isaac         /* old cones to new cones */
20346f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
20356f5f1567SToby Isaac         ierr = DMPlexGetCone(dm,p,&cone);CHKERRQ(ierr);
20366f5f1567SToby Isaac         ierr = DMPlexGetConeOrientation(dm,p,&orientation);CHKERRQ(ierr);
20376f5f1567SToby Isaac         for (l = 0; l < size; l++) {
20386f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
20396f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
20406f5f1567SToby Isaac         }
20416f5f1567SToby Isaac       }
20426f5f1567SToby Isaac 
20436f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
20446f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20456f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
20466f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
20476f5f1567SToby Isaac 
20486f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
20496f5f1567SToby Isaac         if (kParent != k) {
20506f5f1567SToby Isaac           /* embed new cones */
20516f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
20526f5f1567SToby Isaac           ierr = DMPlexGetCone(K,kPerm,&cone);CHKERRQ(ierr);
20536f5f1567SToby Isaac           ierr = DMPlexGetConeOrientation(K,kPerm,&orientation);CHKERRQ(ierr);
20546f5f1567SToby Isaac           for (l = 0; l < size; l++) {
20556f5f1567SToby Isaac             PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size -(preO + 1) - l) % size);
20566f5f1567SToby Isaac             PetscInt newO, lSize, oTrue;
20576f5f1567SToby Isaac 
20586f5f1567SToby Isaac             q                         = iperm[cone[m]];
20596f5f1567SToby Isaac             newCones[offset]          = Kembedding[q];
20606f5f1567SToby Isaac             ierr                      = DMPlexGetConeSize(K,q,&lSize);CHKERRQ(ierr);
20616f5f1567SToby Isaac             oTrue                     = orientation[m];
20626f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
20636f5f1567SToby Isaac             newO                      = DihedralCompose(lSize,oTrue,preOrient[q]);
20646f5f1567SToby Isaac             newOrientations[offset++] = newO;
20656f5f1567SToby Isaac           }
20666f5f1567SToby Isaac           if (kParent != 0) {
20676f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
20686f5f1567SToby Isaac             ierr              = PetscSectionGetOffset(parentSection,Kembedding[k],&pOffset);CHKERRQ(ierr);
20696f5f1567SToby Isaac             parents[pOffset]  = newPoint;
20706f5f1567SToby Isaac             childIDs[pOffset] = k;
20716f5f1567SToby Isaac           }
20726f5f1567SToby Isaac         }
20736f5f1567SToby Isaac       }
20746f5f1567SToby Isaac     }
20756f5f1567SToby Isaac 
20766f5f1567SToby Isaac     ierr = PetscMalloc1(dim*(pNewEnd[dim]-pNewStart[dim]),&newVertexCoords);CHKERRQ(ierr);
20776f5f1567SToby Isaac 
20786f5f1567SToby Isaac     /* fill coordinates */
20796f5f1567SToby Isaac     offset = 0;
20806f5f1567SToby Isaac     {
2081d90620a3SMatthew G. Knepley       PetscInt kStart, kEnd, l;
20826f5f1567SToby Isaac       PetscSection vSection;
20836f5f1567SToby Isaac       PetscInt v;
20846f5f1567SToby Isaac       Vec coords;
20856f5f1567SToby Isaac       PetscScalar *coordvals;
20866f5f1567SToby Isaac       PetscInt dof, off;
2087c111c6b7SMatthew G. Knepley       PetscReal v0[3], J[9], detJ;
20886f5f1567SToby Isaac 
20896f5f1567SToby Isaac #if defined(PETSC_USE_DEBUG)
2090d90620a3SMatthew G. Knepley       {
2091d90620a3SMatthew G. Knepley         PetscInt k;
20926f5f1567SToby Isaac         ierr = DMPlexGetHeightStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
20936f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
209473a7f2aaSMatthew G. Knepley           ierr = DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
20956f5f1567SToby Isaac           if (detJ <= 0.) SETERRQ1 (PETSC_COMM_SELF,PETSC_ERR_PLIB,"reference tree cell %d has bad determinant",k);
20966f5f1567SToby Isaac         }
2097d90620a3SMatthew G. Knepley       }
20986f5f1567SToby Isaac #endif
209973a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
21006f5f1567SToby Isaac       ierr = DMGetCoordinateSection(dm,&vSection);CHKERRQ(ierr);
21016f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr);
21026f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
21036f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
21046f5f1567SToby Isaac 
21056f5f1567SToby Isaac         ierr = PetscSectionGetDof(vSection,v,&dof);CHKERRQ(ierr);
21066f5f1567SToby Isaac         ierr = PetscSectionGetOffset(vSection,v,&off);CHKERRQ(ierr);
21076f5f1567SToby Isaac         for (l = 0; l < dof; l++) {
21086f5f1567SToby Isaac           newVertexCoords[offset++] = coordvals[off + l];
21096f5f1567SToby Isaac         }
21106f5f1567SToby Isaac       }
21116f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21126f5f1567SToby Isaac 
21136f5f1567SToby Isaac       ierr = DMGetCoordinateSection(K,&vSection);CHKERRQ(ierr);
21146f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(K,&coords);CHKERRQ(ierr);
21156f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
21166f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
21176f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
21189bc368c7SMatthew G. Knepley         PetscReal coord[3], newCoord[3];
21196f5f1567SToby Isaac         PetscInt  vPerm = perm[v];
21206f5f1567SToby Isaac         PetscInt  kParent;
2121c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
21226f5f1567SToby Isaac 
21236f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,v,&kParent,NULL);CHKERRQ(ierr);
21246f5f1567SToby Isaac         if (kParent != v) {
21256f5f1567SToby Isaac           /* this is a new vertex */
21266f5f1567SToby Isaac           ierr = PetscSectionGetOffset(vSection,vPerm,&off);CHKERRQ(ierr);
21279bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off+l]);
2128367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
21299bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset+l] = newCoord[l];
21306f5f1567SToby Isaac           offset += dim;
21316f5f1567SToby Isaac         }
21326f5f1567SToby Isaac       }
21336f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21346f5f1567SToby Isaac     }
21356f5f1567SToby Isaac 
21366f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
21376f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
21386f5f1567SToby Isaac       PetscInt tmp;
21396f5f1567SToby Isaac 
21406f5f1567SToby Isaac       tmp = pNewCount[d];
21416f5f1567SToby Isaac       pNewCount[d] = pNewCount[dim - d];
21426f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
21436f5f1567SToby Isaac     }
21446f5f1567SToby Isaac 
21456f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,pNewCount,newConeSizes,newCones,newOrientations,newVertexCoords);CHKERRQ(ierr);
21466f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
21476f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,parents,childIDs);CHKERRQ(ierr);
21486f5f1567SToby Isaac 
21496f5f1567SToby Isaac     /* clean up */
21506f5f1567SToby Isaac     ierr = DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
21516f5f1567SToby Isaac     ierr = PetscFree5(pNewCount,pNewStart,pNewEnd,pOldStart,pOldEnd);CHKERRQ(ierr);
21526f5f1567SToby Isaac     ierr = PetscFree(newConeSizes);CHKERRQ(ierr);
21536f5f1567SToby Isaac     ierr = PetscFree2(newCones,newOrientations);CHKERRQ(ierr);
21546f5f1567SToby Isaac     ierr = PetscFree(newVertexCoords);CHKERRQ(ierr);
21556f5f1567SToby Isaac     ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
21566f5f1567SToby Isaac     ierr = PetscFree4(Kembedding,perm,iperm,preOrient);CHKERRQ(ierr);
21576f5f1567SToby Isaac   }
21586f5f1567SToby Isaac   else {
21596f5f1567SToby Isaac     PetscInt    p, counts[4];
21606f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
21616f5f1567SToby Isaac     Vec         coordVec;
21626f5f1567SToby Isaac     PetscScalar *coords;
21636f5f1567SToby Isaac 
21646f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
21656f5f1567SToby Isaac       PetscInt dStart, dEnd;
21666f5f1567SToby Isaac 
21676f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
21686f5f1567SToby Isaac       counts[d] = dEnd - dStart;
21696f5f1567SToby Isaac     }
21706f5f1567SToby Isaac     ierr = PetscMalloc1(pEnd-pStart,&coneSizes);CHKERRQ(ierr);
21716f5f1567SToby Isaac     for (p = pStart; p < pEnd; p++) {
21726f5f1567SToby Isaac       ierr = DMPlexGetConeSize(dm,p,&coneSizes[p-pStart]);CHKERRQ(ierr);
21736f5f1567SToby Isaac     }
21746f5f1567SToby Isaac     ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
21756f5f1567SToby Isaac     ierr = DMPlexGetConeOrientations(dm, &orientations);CHKERRQ(ierr);
21766f5f1567SToby Isaac     ierr = DMGetCoordinatesLocal(dm,&coordVec);CHKERRQ(ierr);
21776f5f1567SToby Isaac     ierr = VecGetArray(coordVec,&coords);CHKERRQ(ierr);
21786f5f1567SToby Isaac 
21796f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,pStart,pEnd);CHKERRQ(ierr);
21806f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
21816f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,counts,coneSizes,cones,orientations,NULL);CHKERRQ(ierr);
21826f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
21836f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,NULL,NULL);CHKERRQ(ierr);
21846f5f1567SToby Isaac     ierr = VecRestoreArray(coordVec,&coords);CHKERRQ(ierr);
21856f5f1567SToby Isaac   }
21866f5f1567SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
21876f5f1567SToby Isaac 
21886f5f1567SToby Isaac   PetscFunctionReturn(0);
21896f5f1567SToby Isaac }
21906ecaa68aSToby Isaac 
21916ecaa68aSToby Isaac PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
21926ecaa68aSToby Isaac {
21936ecaa68aSToby Isaac   PetscSF           coarseToFineEmbedded;
21946ecaa68aSToby Isaac   PetscSection      globalCoarse, globalFine;
21956ecaa68aSToby Isaac   PetscSection      localCoarse, localFine;
21966ecaa68aSToby Isaac   PetscSection      aSec, cSec;
21976ecaa68aSToby Isaac   PetscSection      rootIndicesSec, rootMatricesSec;
219846bdb399SToby Isaac   PetscSection      leafIndicesSec, leafMatricesSec;
219946bdb399SToby Isaac   PetscInt          *rootIndices, *leafIndices;
220046bdb399SToby Isaac   PetscScalar       *rootMatrices, *leafMatrices;
22016ecaa68aSToby Isaac   IS                aIS;
22026ecaa68aSToby Isaac   const PetscInt    *anchors;
22036ecaa68aSToby Isaac   Mat               cMat;
22044acb8e1eSToby Isaac   PetscInt          numFields, maxFields;
22056ecaa68aSToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p;
22066ecaa68aSToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
22071c58ffc4SToby Isaac   PetscInt          *maxChildIds;
2208e44e4e7fSToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
22094acb8e1eSToby Isaac   const PetscInt    ***perms;
22104acb8e1eSToby Isaac   const PetscScalar ***flips;
22116ecaa68aSToby Isaac   PetscErrorCode    ierr;
22126ecaa68aSToby Isaac 
22136ecaa68aSToby Isaac   PetscFunctionBegin;
22146ecaa68aSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
22156ecaa68aSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
2216e87a4003SBarry Smith   ierr = DMGetGlobalSection(fine,&globalFine);CHKERRQ(ierr);
22176ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
221889698031SToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
221989698031SToby Isaac     const PetscInt *leaves;
22206ecaa68aSToby Isaac 
222189698031SToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
222289698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
222389698031SToby Isaac       p = leaves ? leaves[l] : l;
22246ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22256ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22266ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
22276ecaa68aSToby Isaac         numPointsWithDofs++;
22286ecaa68aSToby Isaac       }
22296ecaa68aSToby Isaac     }
22306ecaa68aSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
22317cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
223289698031SToby Isaac       p = leaves ? leaves[l] : l;
22336ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22346ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22356ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
223689698031SToby Isaac         pointsWithDofs[offset++] = l;
22376ecaa68aSToby Isaac       }
22386ecaa68aSToby Isaac     }
22396ecaa68aSToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
2240ec92bd66SToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
22416ecaa68aSToby Isaac   }
22426ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
22436ecaa68aSToby Isaac   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
22446ecaa68aSToby Isaac   for (p = pStartC; p < pEndC; p++) {
22458d2f55e7SToby Isaac     maxChildIds[p - pStartC] = -2;
22466ecaa68aSToby Isaac   }
22476ecaa68aSToby Isaac   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
22486ecaa68aSToby Isaac   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
224946bdb399SToby Isaac 
2250e87a4003SBarry Smith   ierr = DMGetSection(coarse,&localCoarse);CHKERRQ(ierr);
2251e87a4003SBarry Smith   ierr = DMGetGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
225246bdb399SToby Isaac 
22536ecaa68aSToby Isaac   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
22546ecaa68aSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
22556ecaa68aSToby Isaac   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
225646bdb399SToby Isaac 
22576ecaa68aSToby Isaac   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
22586ecaa68aSToby Isaac   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
225946bdb399SToby Isaac 
226046bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
22616ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
22626ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootMatricesSec);CHKERRQ(ierr);
22636ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootIndicesSec,pStartC,pEndC);CHKERRQ(ierr);
22646ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootMatricesSec,pStartC,pEndC);CHKERRQ(ierr);
2265708c7f19SToby Isaac   ierr = PetscSectionGetNumFields(localCoarse,&numFields);CHKERRQ(ierr);
2266713c1c5dSToby Isaac   maxFields = PetscMax(1,numFields);
2267713c1c5dSToby 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);
2268f489ac74SBarry Smith   ierr = PetscMalloc2(maxFields+1,(PetscInt****)&perms,maxFields+1,(PetscScalar****)&flips);CHKERRQ(ierr);
2269713c1c5dSToby Isaac   ierr = PetscMemzero((void *) perms, (maxFields+1) * sizeof(const PetscInt **));CHKERRQ(ierr);
2270713c1c5dSToby Isaac   ierr = PetscMemzero((void *) flips, (maxFields+1) * sizeof(const PetscScalar **));CHKERRQ(ierr);
227146bdb399SToby Isaac 
227246bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
22738d2f55e7SToby Isaac     PetscInt dof, matSize   = 0;
22746ecaa68aSToby Isaac     PetscInt aDof           = 0;
22756ecaa68aSToby Isaac     PetscInt cDof           = 0;
22766ecaa68aSToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
22776ecaa68aSToby Isaac     PetscInt numRowIndices  = 0;
22786ecaa68aSToby Isaac     PetscInt numColIndices  = 0;
2279f13f9184SToby Isaac     PetscInt f;
22806ecaa68aSToby Isaac 
22816ecaa68aSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
22821cfc5b76SToby Isaac     if (dof < 0) {
22831cfc5b76SToby Isaac       dof = -(dof + 1);
22841cfc5b76SToby Isaac     }
22856ecaa68aSToby Isaac     if (p >= aStart && p < aEnd) {
22866ecaa68aSToby Isaac       ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
22876ecaa68aSToby Isaac     }
22886ecaa68aSToby Isaac     if (p >= cStart && p < cEnd) {
22896ecaa68aSToby Isaac       ierr = PetscSectionGetDof(cSec,p,&cDof);CHKERRQ(ierr);
22906ecaa68aSToby Isaac     }
2291f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2292f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
22936ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2294f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
22956ecaa68aSToby Isaac 
22966ecaa68aSToby Isaac       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
229746bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
22986ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
22996ecaa68aSToby Isaac 
23006ecaa68aSToby Isaac         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
23016ecaa68aSToby Isaac         numRowIndices += clDof;
23026ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23036ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,c,f,&clDof);CHKERRQ(ierr);
23046ecaa68aSToby Isaac           offsets[f + 1] += clDof;
23056ecaa68aSToby Isaac         }
23066ecaa68aSToby Isaac       }
23076ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
23086ecaa68aSToby Isaac         offsets[f + 1]   += offsets[f];
23096ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
23106ecaa68aSToby Isaac       }
231146bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
23124acb8e1eSToby Isaac       ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,NULL,NULL,NULL,&numColIndices,NULL,NULL,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
23136ecaa68aSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
23146ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
23156ecaa68aSToby Isaac         numColIndices = numRowIndices;
23166ecaa68aSToby Isaac         matSize = 0;
23176ecaa68aSToby Isaac       }
231846bdb399SToby Isaac       else if (numFields) { /* we send one submat for each field: sum their sizes */
23196ecaa68aSToby Isaac         matSize = 0;
23206ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23216ecaa68aSToby Isaac           PetscInt numRow, numCol;
23226ecaa68aSToby Isaac 
23236ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2324f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
23256ecaa68aSToby Isaac           matSize += numRow * numCol;
23266ecaa68aSToby Isaac         }
23276ecaa68aSToby Isaac       }
23286ecaa68aSToby Isaac       else {
23296ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
23306ecaa68aSToby Isaac       }
2331f13f9184SToby Isaac     } else if (maxChildId == -1) {
23328d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2333f13f9184SToby Isaac         PetscInt aOff, a;
23346ecaa68aSToby Isaac 
23356ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
23366ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23376ecaa68aSToby Isaac           PetscInt fDof;
23386ecaa68aSToby Isaac 
23396ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
234021968bf8SToby Isaac           offsets[f+1] = fDof;
23416ecaa68aSToby Isaac         }
23426ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
23436ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
23446ecaa68aSToby Isaac 
23456ecaa68aSToby Isaac           ierr = PetscSectionGetDof(localCoarse,anchor,&aLocalDof);CHKERRQ(ierr);
23466ecaa68aSToby Isaac           numColIndices += aLocalDof;
23476ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23486ecaa68aSToby Isaac             PetscInt fDof;
23496ecaa68aSToby Isaac 
23506ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
235121968bf8SToby Isaac             newOffsets[f+1] += fDof;
23526ecaa68aSToby Isaac           }
23536ecaa68aSToby Isaac         }
23546ecaa68aSToby Isaac         if (numFields) {
23556ecaa68aSToby Isaac           matSize = 0;
23566ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
235721968bf8SToby Isaac             matSize += offsets[f+1] * newOffsets[f+1];
23586ecaa68aSToby Isaac           }
23596ecaa68aSToby Isaac         }
23606ecaa68aSToby Isaac         else {
23616ecaa68aSToby Isaac           matSize = numColIndices * dof;
23626ecaa68aSToby Isaac         }
23636ecaa68aSToby Isaac       }
23646ecaa68aSToby Isaac       else { /* no children, and no constraints on dofs: just get the global indices */
23656ecaa68aSToby Isaac         numColIndices = dof;
23666ecaa68aSToby Isaac         matSize       = 0;
23676ecaa68aSToby Isaac       }
23688d2f55e7SToby Isaac     }
236946bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
23706ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootIndicesSec,p,numColIndices ? numColIndices+2*numFields : 0);CHKERRQ(ierr);
23716ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootMatricesSec,p,matSize);CHKERRQ(ierr);
23726ecaa68aSToby Isaac   }
23736ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootIndicesSec);CHKERRQ(ierr);
23746ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootMatricesSec);CHKERRQ(ierr);
23756ecaa68aSToby Isaac   {
23766ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
23776ecaa68aSToby Isaac 
23786ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
23796ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootMatricesSec,&numRootMatrices);CHKERRQ(ierr);
23806ecaa68aSToby Isaac     ierr = PetscMalloc2(numRootIndices,&rootIndices,numRootMatrices,&rootMatrices);CHKERRQ(ierr);
23816ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
23826ecaa68aSToby Isaac       PetscInt    numRowIndices, numColIndices, matSize, dof;
2383f13f9184SToby Isaac       PetscInt    pIndOff, pMatOff, f;
23846ecaa68aSToby Isaac       PetscInt    *pInd;
23856ecaa68aSToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
23866ecaa68aSToby Isaac       PetscScalar *pMat = NULL;
23876ecaa68aSToby Isaac 
23886ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,p,&numColIndices);CHKERRQ(ierr);
23896ecaa68aSToby Isaac       if (!numColIndices) {
23906ecaa68aSToby Isaac         continue;
23916ecaa68aSToby Isaac       }
2392f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2393f13f9184SToby Isaac         offsets[f]        = 0;
2394f13f9184SToby Isaac         newOffsets[f]     = 0;
2395f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2396f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2397f13f9184SToby Isaac       }
23986ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
23996ecaa68aSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,p,&pIndOff);CHKERRQ(ierr);
24006ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
24016ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootMatricesSec,p,&matSize);CHKERRQ(ierr);
24026ecaa68aSToby Isaac       if (matSize) {
24036ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(rootMatricesSec,p,&pMatOff);CHKERRQ(ierr);
24046ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
24056ecaa68aSToby Isaac       }
24066ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
24071cfc5b76SToby Isaac       if (dof < 0) {
24081cfc5b76SToby Isaac         dof = -(dof + 1);
24091cfc5b76SToby Isaac       }
24106ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
24116ecaa68aSToby Isaac         PetscInt i, j;
24126ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
24136ecaa68aSToby Isaac 
24146ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
24156ecaa68aSToby Isaac           PetscInt numIndices, *indices;
24166ecaa68aSToby Isaac           ierr = DMPlexGetClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
24176ecaa68aSToby Isaac           if (numIndices != numColIndices) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"mismatching constraint indices calculations");
24186ecaa68aSToby Isaac           for (i = 0; i < numColIndices; i++) {
24196ecaa68aSToby Isaac             pInd[i] = indices[i];
24206ecaa68aSToby Isaac           }
24216ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
242246bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i+1];
242346bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i+1];
24246ecaa68aSToby Isaac           }
242546bdb399SToby Isaac           ierr = DMPlexRestoreClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
24266ecaa68aSToby Isaac         }
24276ecaa68aSToby Isaac         else {
24286ecaa68aSToby Isaac           PetscInt closureSize, *closure = NULL, cl;
24296ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
24306ecaa68aSToby Isaac           PetscInt numPoints,*points;
24316ecaa68aSToby Isaac 
243269291d52SBarry Smith           ierr = DMGetWorkArray(coarse,numRowIndices * numRowIndices,MPIU_SCALAR,&pMatIn);CHKERRQ(ierr);
24336ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
24346ecaa68aSToby Isaac             for (j = 0; j < numRowIndices; j++) {
24356ecaa68aSToby Isaac               pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
24366ecaa68aSToby Isaac             }
24376ecaa68aSToby Isaac           }
24386ecaa68aSToby Isaac           ierr = DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
24394acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24404acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionGetFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24414acb8e1eSToby Isaac             else           {ierr = PetscSectionGetPointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24424acb8e1eSToby Isaac           }
24436ecaa68aSToby Isaac           if (numFields) {
24446ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
24456ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
24466ecaa68aSToby Isaac 
24476ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
24486ecaa68aSToby Isaac                 PetscInt fDof;
24496ecaa68aSToby Isaac 
24506ecaa68aSToby Isaac                 ierr = PetscSectionGetFieldDof(localCoarse,c,f,&fDof);CHKERRQ(ierr);
24516ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
24526ecaa68aSToby Isaac               }
24536ecaa68aSToby Isaac             }
24546ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
24556ecaa68aSToby Isaac               offsets[f + 1]   += offsets[f];
24566ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
24576ecaa68aSToby Isaac             }
24586ecaa68aSToby Isaac           }
24594acb8e1eSToby Isaac           /* TODO : flips here ? */
24606ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
24614acb8e1eSToby Isaac           ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,perms,pMatIn,&numPoints,NULL,&points,&pMatModified,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
24624acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24634acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24644acb8e1eSToby Isaac             else           {ierr = PetscSectionRestorePointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24654acb8e1eSToby Isaac           }
24664acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24674acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionGetFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
24684acb8e1eSToby Isaac             else           {ierr = PetscSectionGetPointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
24694acb8e1eSToby Isaac           }
24706ecaa68aSToby Isaac           if (!numFields) {
24716ecaa68aSToby Isaac             for (i = 0; i < numRowIndices * numColIndices; i++) {
24726ecaa68aSToby Isaac               pMat[i] = pMatModified[i];
24736ecaa68aSToby Isaac             }
24746ecaa68aSToby Isaac           }
24756ecaa68aSToby Isaac           else {
2476f13f9184SToby Isaac             PetscInt i, j, count;
24776ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
24786ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f+1]; i++) {
24796ecaa68aSToby Isaac                 for (j = newOffsets[f]; j < newOffsets[f+1]; j++, count++) {
24806ecaa68aSToby Isaac                   pMat[count] = pMatModified[i * numColIndices + j];
24816ecaa68aSToby Isaac                 }
24826ecaa68aSToby Isaac               }
24836ecaa68aSToby Isaac             }
24846ecaa68aSToby Isaac           }
248569291d52SBarry Smith           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatModified);CHKERRQ(ierr);
24866ecaa68aSToby Isaac           ierr = DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
248769291d52SBarry Smith           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatIn);CHKERRQ(ierr);
24886ecaa68aSToby Isaac           if (numFields) {
248946bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
249046bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f+1];
249146bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f+1];
24926ecaa68aSToby Isaac             }
24934acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
24944acb8e1eSToby Isaac               PetscInt globalOff, c = points[2*cl];
24956ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
249605586334SMatthew G. Knepley               DMPlexGetIndicesPointFields_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd);
24976ecaa68aSToby Isaac             }
24986ecaa68aSToby Isaac           } else {
24994acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
25004acb8e1eSToby Isaac               PetscInt c = points[2*cl], globalOff;
25014acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
25024acb8e1eSToby Isaac 
25036ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
250405586334SMatthew G. Knepley               DMPlexGetIndicesPoint_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd);
25056ecaa68aSToby Isaac             }
25066ecaa68aSToby Isaac           }
25074acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
25084acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
25094acb8e1eSToby Isaac             else           {ierr = PetscSectionRestorePointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
25104acb8e1eSToby Isaac           }
251169291d52SBarry Smith           ierr = DMRestoreWorkArray(coarse,numPoints,MPIU_SCALAR,&points);CHKERRQ(ierr);
25126ecaa68aSToby Isaac         }
25136ecaa68aSToby Isaac       }
25146ecaa68aSToby Isaac       else if (matSize) {
25156ecaa68aSToby Isaac         PetscInt cOff;
25166ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
25176ecaa68aSToby Isaac 
25186ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
2519628cbfb8SToby Isaac         if (numRowIndices != dof) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Miscounted dofs");
252069291d52SBarry Smith         ierr = DMGetWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices);CHKERRQ(ierr);
252169291d52SBarry Smith         ierr = DMGetWorkArray(coarse,numColIndices,MPIU_INT,&colIndices);CHKERRQ(ierr);
25226ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(cSec,p,&cOff);CHKERRQ(ierr);
25236ecaa68aSToby Isaac         ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
25246ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
25256ecaa68aSToby Isaac         if (numFields) {
25266ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25276ecaa68aSToby Isaac             PetscInt fDof;
2528f13f9184SToby Isaac 
25296ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(cSec,p,f,&fDof);CHKERRQ(ierr);
25306ecaa68aSToby Isaac             offsets[f + 1] = fDof;
25316ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
25326ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
25336ecaa68aSToby Isaac               ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
25346ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
25356ecaa68aSToby Isaac             }
25366ecaa68aSToby Isaac           }
25376ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25386ecaa68aSToby Isaac             offsets[f + 1]       += offsets[f];
25396ecaa68aSToby Isaac             offsetsCopy[f + 1]    = offsets[f + 1];
25406ecaa68aSToby Isaac             newOffsets[f + 1]    += newOffsets[f];
25416ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
25426ecaa68aSToby Isaac           }
254305586334SMatthew G. Knepley           ierr = DMPlexGetIndicesPointFields_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,NULL,-1, NULL,rowIndices);CHKERRQ(ierr);
25446ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25456ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25466ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
254705586334SMatthew G. Knepley             ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL,-1, NULL,colIndices);CHKERRQ(ierr);
25486ecaa68aSToby Isaac           }
25496ecaa68aSToby Isaac         }
25506ecaa68aSToby Isaac         else {
255105586334SMatthew G. Knepley           ierr = DMPlexGetIndicesPoint_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,NULL, NULL,rowIndices);CHKERRQ(ierr);
25526ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25536ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25546ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
255505586334SMatthew G. Knepley             ierr = DMPlexGetIndicesPoint_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL, NULL,colIndices);CHKERRQ(ierr);
25566ecaa68aSToby Isaac           }
25576ecaa68aSToby Isaac         }
25586ecaa68aSToby Isaac         if (numFields) {
2559f13f9184SToby Isaac           PetscInt count, a;
2560f13f9184SToby Isaac 
25616ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
25626ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
25636ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
25646ecaa68aSToby Isaac             ierr = MatGetValues(cMat,iSize,&rowIndices[offsets[f]],jSize,&colIndices[newOffsets[f]],&pMat[count]);CHKERRQ(ierr);
25656ecaa68aSToby Isaac             count += iSize * jSize;
256646bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
256746bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f+1];
25686ecaa68aSToby Isaac           }
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);
257305586334SMatthew G. Knepley             ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL,-1, NULL,pInd);CHKERRQ(ierr);
25746ecaa68aSToby Isaac           }
25756ecaa68aSToby Isaac         }
25766ecaa68aSToby Isaac         else {
25776ecaa68aSToby Isaac           PetscInt a;
25786ecaa68aSToby Isaac           ierr = MatGetValues(cMat,numRowIndices,rowIndices,numColIndices,colIndices,pMat);CHKERRQ(ierr);
25796ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25806ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25816ecaa68aSToby Isaac             PetscInt gOff;
25826ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
258305586334SMatthew G. Knepley             ierr = DMPlexGetIndicesPoint_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL, NULL,pInd);CHKERRQ(ierr);
25846ecaa68aSToby Isaac           }
25856ecaa68aSToby Isaac         }
258669291d52SBarry Smith         ierr = DMRestoreWorkArray(coarse,numColIndices,MPIU_INT,&colIndices);CHKERRQ(ierr);
258769291d52SBarry Smith         ierr = DMRestoreWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices);CHKERRQ(ierr);
25886ecaa68aSToby Isaac       }
25896ecaa68aSToby Isaac       else {
25906ecaa68aSToby Isaac         PetscInt gOff;
25916ecaa68aSToby Isaac 
25926ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
25936ecaa68aSToby Isaac         if (numFields) {
25946ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25956ecaa68aSToby Isaac             PetscInt fDof;
25966ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
25976ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
25986ecaa68aSToby Isaac           }
25996ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
260046bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
260146bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f+1];
26026ecaa68aSToby Isaac           }
260305586334SMatthew G. Knepley           ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1, NULL,pInd);CHKERRQ(ierr);
2604367003a6SStefano Zampini         } else {
260505586334SMatthew G. Knepley           ierr = DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL, NULL,pInd);CHKERRQ(ierr);
26066ecaa68aSToby Isaac         }
26076ecaa68aSToby Isaac       }
26086ecaa68aSToby Isaac     }
2609e44e4e7fSToby Isaac     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
26106ecaa68aSToby Isaac   }
261146bdb399SToby Isaac   {
261246bdb399SToby Isaac     PetscSF  indicesSF, matricesSF;
261346bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
261446bdb399SToby Isaac 
261546bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
261646bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafMatricesSec);CHKERRQ(ierr);
261746bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootIndicesSec,&remoteOffsetsIndices,leafIndicesSec);CHKERRQ(ierr);
261846bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootMatricesSec,&remoteOffsetsMatrices,leafMatricesSec);CHKERRQ(ierr);
261946bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootIndicesSec,remoteOffsetsIndices,leafIndicesSec,&indicesSF);CHKERRQ(ierr);
262046bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootMatricesSec,remoteOffsetsMatrices,leafMatricesSec,&matricesSF);CHKERRQ(ierr);
2621e44e4e7fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
262246bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsIndices);CHKERRQ(ierr);
262346bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsMatrices);CHKERRQ(ierr);
262446bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numLeafIndices);CHKERRQ(ierr);
262546bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafMatricesSec,&numLeafMatrices);CHKERRQ(ierr);
262646bdb399SToby Isaac     ierr = PetscMalloc2(numLeafIndices,&leafIndices,numLeafMatrices,&leafMatrices);CHKERRQ(ierr);
262746bdb399SToby Isaac     ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2628267d4f3fSToby Isaac     ierr = PetscSFBcastBegin(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
262946bdb399SToby Isaac     ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2630267d4f3fSToby Isaac     ierr = PetscSFBcastEnd(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
263146bdb399SToby Isaac     ierr = PetscSFDestroy(&matricesSF);CHKERRQ(ierr);
263246bdb399SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
263346bdb399SToby Isaac     ierr = PetscFree2(rootIndices,rootMatrices);CHKERRQ(ierr);
263446bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
263546bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootMatricesSec);CHKERRQ(ierr);
263646bdb399SToby Isaac   }
263746bdb399SToby Isaac   /* count to preallocate */
2638e87a4003SBarry Smith   ierr = DMGetSection(fine,&localFine);CHKERRQ(ierr);
263946bdb399SToby Isaac   {
264046bdb399SToby Isaac     PetscInt    nGlobal;
264146bdb399SToby Isaac     PetscInt    *dnnz, *onnz;
2642b9a5774bSToby Isaac     PetscLayout rowMap, colMap;
2643b9a5774bSToby Isaac     PetscInt    rowStart, rowEnd, colStart, colEnd;
26441c58ffc4SToby Isaac     PetscInt    maxDof;
26451c58ffc4SToby Isaac     PetscInt    *rowIndices;
26461c58ffc4SToby Isaac     DM           refTree;
26471c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
26481c58ffc4SToby Isaac     PetscScalar  ***refPointFieldMats;
26491c58ffc4SToby Isaac     PetscSection refConSec, refAnSec;
26500eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,maxConDof,maxColumns,leafStart,leafEnd;
26511c58ffc4SToby Isaac     PetscScalar  *pointWork;
265246bdb399SToby Isaac 
265346bdb399SToby Isaac     ierr = PetscSectionGetConstrainedStorageSize(globalFine,&nGlobal);CHKERRQ(ierr);
265446bdb399SToby Isaac     ierr = PetscCalloc2(nGlobal,&dnnz,nGlobal,&onnz);CHKERRQ(ierr);
2655b9a5774bSToby Isaac     ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
2656b9a5774bSToby Isaac     ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
26571c58ffc4SToby Isaac     ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
2658b9a5774bSToby Isaac     ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
265946bdb399SToby Isaac     ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
26601c58ffc4SToby Isaac     ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr);
26610eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafIndicesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
266269291d52SBarry Smith     ierr = DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
26630eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
266446bdb399SToby Isaac       PetscInt    gDof, gcDof, gOff;
266546bdb399SToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
266646bdb399SToby Isaac       PetscInt    matSize;
266721968bf8SToby Isaac       PetscInt    i;
266846bdb399SToby Isaac 
266946bdb399SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
267046bdb399SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
267146bdb399SToby Isaac       if ((gDof - gcDof) <= 0) {
267246bdb399SToby Isaac         continue;
267346bdb399SToby Isaac       }
267446bdb399SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
267546bdb399SToby Isaac       if (gOff < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"I though having global dofs meant a non-negative offset");
2676b9a5774bSToby 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");
267746bdb399SToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
267846bdb399SToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
267946bdb399SToby Isaac       numColIndices -= 2 * numFields;
26801c58ffc4SToby Isaac       if (numColIndices <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"global fine dof with no dofs to interpolate from");
268146bdb399SToby Isaac       pInd = &leafIndices[pIndOff];
268221968bf8SToby Isaac       offsets[0]        = 0;
268321968bf8SToby Isaac       offsetsCopy[0]    = 0;
268421968bf8SToby Isaac       newOffsets[0]     = 0;
268521968bf8SToby Isaac       newOffsetsCopy[0] = 0;
268646bdb399SToby Isaac       if (numFields) {
268721968bf8SToby Isaac         PetscInt f;
268846bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
268946bdb399SToby Isaac           PetscInt rowDof;
269046bdb399SToby Isaac 
269146bdb399SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
269221968bf8SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
269321968bf8SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
269421968bf8SToby Isaac           newOffsets[f + 1]     = pInd[numColIndices + numFields + f];
269521968bf8SToby Isaac           numD[f] = 0;
269621968bf8SToby Isaac           numO[f] = 0;
269746bdb399SToby Isaac         }
269805586334SMatthew G. Knepley         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,rowIndices);CHKERRQ(ierr);
269946bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
270021968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
270121968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
270246bdb399SToby Isaac 
270346bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
270446bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
270546bdb399SToby Isaac 
270646bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
270721968bf8SToby Isaac               numD[f]++;
270846bdb399SToby Isaac             }
270946bdb399SToby Isaac             else if (gInd >= 0) { /* negative means non-entry */
271021968bf8SToby Isaac               numO[f]++;
271146bdb399SToby Isaac             }
271246bdb399SToby Isaac           }
271346bdb399SToby Isaac         }
271446bdb399SToby Isaac       }
271546bdb399SToby Isaac       else {
271605586334SMatthew G. Knepley         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,rowIndices);CHKERRQ(ierr);
271721968bf8SToby Isaac         numD[0] = 0;
271821968bf8SToby Isaac         numO[0] = 0;
271946bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
272046bdb399SToby Isaac           PetscInt gInd = pInd[i];
272146bdb399SToby Isaac 
272246bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
272321968bf8SToby Isaac             numD[0]++;
272446bdb399SToby Isaac           }
272546bdb399SToby Isaac           else if (gInd >= 0) { /* negative means non-entry */
272621968bf8SToby Isaac             numO[0]++;
272746bdb399SToby Isaac           }
272846bdb399SToby Isaac         }
272946bdb399SToby Isaac       }
273046bdb399SToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
273146bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
273246bdb399SToby Isaac         PetscInt childId;
273346bdb399SToby Isaac 
273446bdb399SToby Isaac         childId = childIds[p-pStartF];
273521968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
273646bdb399SToby Isaac           if (numFields) {
2737b9a5774bSToby Isaac             PetscInt f;
2738b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
273921968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
274046bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
274121968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
274221968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
274346bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2744b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2745b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
274646bdb399SToby Isaac                 }
274746bdb399SToby Isaac                 else if (gIndCoarse >= 0) { /* remote */
2748b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2749b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
275046bdb399SToby Isaac                 }
275146bdb399SToby Isaac                 else { /* constrained */
275246bdb399SToby Isaac                   if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
275346bdb399SToby Isaac                 }
275446bdb399SToby Isaac               }
275546bdb399SToby Isaac             }
275646bdb399SToby Isaac           }
275746bdb399SToby Isaac           else {
2758b9a5774bSToby Isaac             PetscInt i;
2759b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
276046bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
276146bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
276246bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2763b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2764b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
276546bdb399SToby Isaac               }
276646bdb399SToby Isaac               else if (gIndCoarse >= 0) { /* remote */
2767b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2768b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
276946bdb399SToby Isaac               }
277046bdb399SToby Isaac               else { /* constrained */
277146bdb399SToby Isaac                 if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
277246bdb399SToby Isaac               }
277346bdb399SToby Isaac             }
277446bdb399SToby Isaac           }
277546bdb399SToby Isaac         }
277646bdb399SToby Isaac         else { /* interpolate from all */
277746bdb399SToby Isaac           if (numFields) {
2778b9a5774bSToby Isaac             PetscInt f;
2779b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
278021968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
278146bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
278221968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
278346bdb399SToby Isaac                 if (gIndFine >= 0) {
2784b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2785b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2786b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
278746bdb399SToby Isaac                 }
278846bdb399SToby Isaac               }
278946bdb399SToby Isaac             }
279046bdb399SToby Isaac           }
279146bdb399SToby Isaac           else {
2792b9a5774bSToby Isaac             PetscInt i;
2793b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
279446bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
279546bdb399SToby Isaac               if (gIndFine >= 0) {
2796b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2797b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2798b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
279946bdb399SToby Isaac               }
280046bdb399SToby Isaac             }
280146bdb399SToby Isaac           }
280246bdb399SToby Isaac         }
280346bdb399SToby Isaac       }
280446bdb399SToby Isaac       else { /* interpolate from all */
280546bdb399SToby Isaac         if (numFields) {
2806b9a5774bSToby Isaac           PetscInt f;
2807b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
280821968bf8SToby Isaac             PetscInt numRows = offsets[f+1] - offsets[f], row;
280946bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
281021968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
281146bdb399SToby Isaac               if (gIndFine >= 0) {
2812b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2813b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2814b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
281546bdb399SToby Isaac               }
281646bdb399SToby Isaac             }
281746bdb399SToby Isaac           }
281846bdb399SToby Isaac         }
281946bdb399SToby Isaac         else { /* every dof get a full row */
2820b9a5774bSToby Isaac           PetscInt i;
2821b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
282246bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
282346bdb399SToby Isaac             if (gIndFine >= 0) {
2824b9a5774bSToby Isaac               if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2825b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2826b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
282746bdb399SToby Isaac             }
282846bdb399SToby Isaac           }
282946bdb399SToby Isaac         }
283046bdb399SToby Isaac       }
283146bdb399SToby Isaac     }
283246bdb399SToby Isaac     ierr = MatXAIJSetPreallocation(mat,1,dnnz,onnz,NULL,NULL);CHKERRQ(ierr);
283346bdb399SToby Isaac     ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
283421968bf8SToby Isaac 
283521968bf8SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
283621968bf8SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
2837e44e4e7fSToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
2838e44e4e7fSToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
2839e44e4e7fSToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
28401c58ffc4SToby Isaac     ierr = PetscSectionGetMaxDof(refConSec,&maxConDof);CHKERRQ(ierr);
28417c0540e0SToby Isaac     ierr = PetscSectionGetMaxDof(leafIndicesSec,&maxColumns);CHKERRQ(ierr);
28427c0540e0SToby Isaac     ierr = PetscMalloc1(maxConDof*maxColumns,&pointWork);CHKERRQ(ierr);
28430eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2844e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2845e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2846e44e4e7fSToby Isaac       PetscInt matSize;
2847e44e4e7fSToby Isaac       PetscInt childId;
2848e44e4e7fSToby Isaac 
2849e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
2850e44e4e7fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
2851e44e4e7fSToby Isaac       if ((gDof - gcDof) <= 0) {
2852e44e4e7fSToby Isaac         continue;
2853e44e4e7fSToby Isaac       }
2854e44e4e7fSToby Isaac       childId = childIds[p-pStartF];
2855e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
2856e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
2857e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
2858e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2859e44e4e7fSToby Isaac       pInd = &leafIndices[pIndOff];
2860e44e4e7fSToby Isaac       offsets[0]        = 0;
2861e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2862e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2863e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2864e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2865e44e4e7fSToby Isaac       if (numFields) {
2866e44e4e7fSToby Isaac         PetscInt f;
2867e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2868e44e4e7fSToby Isaac           PetscInt rowDof;
2869e44e4e7fSToby Isaac 
2870e44e4e7fSToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
2871e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2872e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2873e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2874e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2875e44e4e7fSToby Isaac         }
287605586334SMatthew G. Knepley         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,rowIndices);CHKERRQ(ierr);
2877e44e4e7fSToby Isaac       }
28781c58ffc4SToby Isaac       else {
287905586334SMatthew G. Knepley         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,rowIndices);CHKERRQ(ierr);
28801c58ffc4SToby Isaac       }
2881e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
2882e44e4e7fSToby Isaac       if (!matSize) { /* incoming matrix is identity */
2883e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2884e44e4e7fSToby Isaac           if (numFields) {
2885e44e4e7fSToby Isaac             PetscInt f;
2886e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2887e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
2888e44e4e7fSToby Isaac               for (row = 0; row < numRows; row++) {
2889e44e4e7fSToby Isaac                 ierr = MatSetValue(mat,rowIndices[offsets[f]+row],pInd[newOffsets[f]+row],1.,INSERT_VALUES);CHKERRQ(ierr);
289021968bf8SToby Isaac               }
289121968bf8SToby Isaac             }
2892e44e4e7fSToby Isaac           }
2893e44e4e7fSToby Isaac           else {
2894e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
2895e44e4e7fSToby Isaac             for (row = 0; row < numRows; row++) {
2896e44e4e7fSToby Isaac               ierr = MatSetValue(mat,rowIndices[row],pInd[row],1.,INSERT_VALUES);CHKERRQ(ierr);
2897e44e4e7fSToby Isaac             }
2898e44e4e7fSToby Isaac           }
2899e44e4e7fSToby Isaac         }
2900e44e4e7fSToby Isaac         else { /* interpolate from all */
2901e44e4e7fSToby Isaac           if (numFields) {
2902e44e4e7fSToby Isaac             PetscInt f;
2903e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2904e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f];
2905e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
2906e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],refPointFieldMats[childId - pRefStart][f],INSERT_VALUES);CHKERRQ(ierr);
2907e44e4e7fSToby Isaac             }
2908e44e4e7fSToby Isaac           }
2909e44e4e7fSToby Isaac           else {
2910e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,refPointFieldMats[childId - pRefStart][0],INSERT_VALUES);CHKERRQ(ierr);
2911e44e4e7fSToby Isaac           }
2912e44e4e7fSToby Isaac         }
2913e44e4e7fSToby Isaac       }
2914e44e4e7fSToby Isaac       else { /* interpolate from all */
2915e44e4e7fSToby Isaac         PetscInt    pMatOff;
2916e44e4e7fSToby Isaac         PetscScalar *pMat;
2917e44e4e7fSToby Isaac 
2918e44e4e7fSToby Isaac         ierr = PetscSectionGetOffset(leafMatricesSec,p,&pMatOff);CHKERRQ(ierr);
2919e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2920e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2921e44e4e7fSToby Isaac           if (numFields) {
2922e44e4e7fSToby Isaac             PetscInt f, count;
2923e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2924e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2925e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2926e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2927e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2928e44e4e7fSToby Isaac 
2929e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],inMat,INSERT_VALUES);CHKERRQ(ierr);
2930e44e4e7fSToby Isaac               count += numCols * numInRows;
2931e44e4e7fSToby Isaac             }
2932e44e4e7fSToby Isaac           }
2933e44e4e7fSToby Isaac           else {
2934e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,pMat,INSERT_VALUES);CHKERRQ(ierr);
2935e44e4e7fSToby Isaac           }
2936e44e4e7fSToby Isaac         }
2937e44e4e7fSToby Isaac         else { /* multiply the incoming matrix by the child interpolation */
2938e44e4e7fSToby Isaac           if (numFields) {
2939e44e4e7fSToby Isaac             PetscInt f, count;
2940e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2941e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2942e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2943e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2944e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2945e44e4e7fSToby Isaac               PetscInt i, j, k;
2946e44e4e7fSToby Isaac               if (refPointFieldN[childId - pRefStart][f] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2947e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2948e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2949e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2950e44e4e7fSToby Isaac                   for (k = 0; k < numInRows; k++) {
2951e44e4e7fSToby Isaac                     val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2952e44e4e7fSToby Isaac                   }
2953e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2954e44e4e7fSToby Isaac                 }
2955e44e4e7fSToby Isaac               }
2956e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],pointWork,INSERT_VALUES);CHKERRQ(ierr);
2957e44e4e7fSToby Isaac               count += numCols * numInRows;
2958e44e4e7fSToby Isaac             }
2959e44e4e7fSToby Isaac           }
2960267d4f3fSToby Isaac           else { /* every dof gets a full row */
2961e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2962e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2963e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2964e44e4e7fSToby Isaac             PetscInt i, j, k;
2965e44e4e7fSToby Isaac             if (refPointFieldN[childId - pRefStart][0] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2966e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2967e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2968e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2969e44e4e7fSToby Isaac                 for (k = 0; k < numInRows; k++) {
2970e44e4e7fSToby Isaac                   val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2971e44e4e7fSToby Isaac                 }
2972e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2973e44e4e7fSToby Isaac               }
2974e44e4e7fSToby Isaac             }
2975e44e4e7fSToby Isaac             ierr = MatSetValues(mat,numRows,rowIndices,numCols,pInd,pointWork,INSERT_VALUES);CHKERRQ(ierr);
2976e44e4e7fSToby Isaac           }
2977e44e4e7fSToby Isaac         }
2978e44e4e7fSToby Isaac       }
2979e44e4e7fSToby Isaac     }
29801c58ffc4SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
298169291d52SBarry Smith     ierr = DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
2982e44e4e7fSToby Isaac     ierr = PetscFree(pointWork);CHKERRQ(ierr);
2983e44e4e7fSToby Isaac   }
2984e44e4e7fSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2985e44e4e7fSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2986e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
2987e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafMatricesSec);CHKERRQ(ierr);
2988e44e4e7fSToby Isaac   ierr = PetscFree2(leafIndices,leafMatrices);CHKERRQ(ierr);
29892cd485c2SBarry Smith   ierr = PetscFree2(*(PetscInt****)&perms,*(PetscScalar****)&flips);CHKERRQ(ierr);
2990e44e4e7fSToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
29916ecaa68aSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
29926ecaa68aSToby Isaac   PetscFunctionReturn(0);
29936ecaa68aSToby Isaac }
2994154bca37SToby Isaac 
29958d2f55e7SToby Isaac /*
29968d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
29978d2f55e7SToby Isaac  *
29988d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
29998d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
30008d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
30018d2f55e7SToby Isaac  *       a_{i,j} = 0;
30028d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
30038d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
30048d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
30058d2f55e7SToby Isaac  */
30068d2f55e7SToby Isaac PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
30078d2f55e7SToby Isaac {
30088d2f55e7SToby Isaac   PetscDS        ds;
30098d2f55e7SToby Isaac   PetscSection   section, cSection;
30108d2f55e7SToby Isaac   DMLabel        canonical, depth;
30118d2f55e7SToby Isaac   Mat            cMat, mat;
30128d2f55e7SToby Isaac   PetscInt       *nnz;
30138d2f55e7SToby Isaac   PetscInt       f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
30148d2f55e7SToby Isaac   PetscInt       m, n;
30158d2f55e7SToby Isaac   PetscScalar    *pointScalar;
30168d2f55e7SToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
30178d2f55e7SToby Isaac   PetscErrorCode ierr;
30188d2f55e7SToby Isaac 
30198d2f55e7SToby Isaac   PetscFunctionBegin;
3020e87a4003SBarry Smith   ierr = DMGetSection(refTree,&section);CHKERRQ(ierr);
30218d2f55e7SToby Isaac   ierr = DMGetDimension(refTree, &dim);CHKERRQ(ierr);
30228d2f55e7SToby Isaac   ierr = PetscMalloc6(dim,&v0,dim,&v0parent,dim,&vtmp,dim*dim,&J,dim*dim,&Jparent,dim*dim,&invJ);CHKERRQ(ierr);
30238d2f55e7SToby Isaac   ierr = PetscMalloc2(dim,&pointScalar,dim,&pointRef);CHKERRQ(ierr);
30248d2f55e7SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
30258d2f55e7SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
30268d2f55e7SToby Isaac   ierr = PetscSectionGetNumFields(section,&numSecFields);CHKERRQ(ierr);
30278d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"canonical",&canonical);CHKERRQ(ierr);
30288d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"depth",&depth);CHKERRQ(ierr);
30298d2f55e7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSection,&cMat);CHKERRQ(ierr);
30308d2f55e7SToby Isaac   ierr = DMPlexGetChart(refTree, &pStart, &pEnd);CHKERRQ(ierr);
30318d2f55e7SToby Isaac   ierr = DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd);CHKERRQ(ierr);
30328d2f55e7SToby Isaac   ierr = MatGetSize(cMat,&n,&m);CHKERRQ(ierr); /* the injector has transpose sizes from the constraint matrix */
30338d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
30348d2f55e7SToby Isaac   ierr = PetscCalloc1(m,&nnz);CHKERRQ(ierr);
30358d2f55e7SToby 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 */
30368d2f55e7SToby Isaac     const PetscInt *children;
30378d2f55e7SToby Isaac     PetscInt numChildren;
30388d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30398d2f55e7SToby Isaac 
30408d2f55e7SToby Isaac     if (canonical) {
30418d2f55e7SToby Isaac       PetscInt pCanonical;
30428d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
30438d2f55e7SToby Isaac       if (p != pCanonical) continue;
30448d2f55e7SToby Isaac     }
30458d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
30468d2f55e7SToby Isaac     if (!numChildren) continue;
30478d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30488d2f55e7SToby Isaac       PetscInt child = children[i];
30498d2f55e7SToby Isaac       PetscInt dof;
30508d2f55e7SToby Isaac 
30518d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
30528d2f55e7SToby Isaac       numChildDof += dof;
30538d2f55e7SToby Isaac     }
30548d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
30558d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30568d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
30578d2f55e7SToby Isaac       PetscInt selfOff;
30588d2f55e7SToby Isaac 
30598d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
30608d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
30618d2f55e7SToby Isaac           PetscInt child = children[i];
30628d2f55e7SToby Isaac           PetscInt dof;
30638d2f55e7SToby Isaac 
30648d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
30658d2f55e7SToby Isaac           numChildDof += dof;
30668d2f55e7SToby Isaac         }
30678d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
30688d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
30698d2f55e7SToby Isaac       }
30708d2f55e7SToby Isaac       else {
30718d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
30728d2f55e7SToby Isaac       }
30738d2f55e7SToby Isaac       for (i = 0; i < numSelfDof; i++) {
30748d2f55e7SToby Isaac         nnz[selfOff + i] = numChildDof;
30758d2f55e7SToby Isaac       }
30768d2f55e7SToby Isaac     }
30778d2f55e7SToby Isaac   }
30788d2f55e7SToby Isaac   ierr = MatCreateAIJ(PETSC_COMM_SELF,m,n,m,n,-1,nnz,-1,NULL,&mat);CHKERRQ(ierr);
30798d2f55e7SToby Isaac   ierr = PetscFree(nnz);CHKERRQ(ierr);
30808d2f55e7SToby Isaac   /* Setp 2: compute entries */
30818d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
30828d2f55e7SToby Isaac     const PetscInt *children;
30838d2f55e7SToby Isaac     PetscInt numChildren;
30848d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30858d2f55e7SToby Isaac 
30868d2f55e7SToby Isaac     /* same conditions about when entries occur */
30878d2f55e7SToby Isaac     if (canonical) {
30888d2f55e7SToby Isaac       PetscInt pCanonical;
30898d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
30908d2f55e7SToby Isaac       if (p != pCanonical) continue;
30918d2f55e7SToby Isaac     }
30928d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
30938d2f55e7SToby Isaac     if (!numChildren) continue;
30948d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30958d2f55e7SToby Isaac       PetscInt child = children[i];
30968d2f55e7SToby Isaac       PetscInt dof;
30978d2f55e7SToby Isaac 
30988d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
30998d2f55e7SToby Isaac       numChildDof += dof;
31008d2f55e7SToby Isaac     }
31018d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
31028d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
31038d2f55e7SToby Isaac 
31048d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
310559fc6756SToby Isaac       PetscInt       pI = -1, cI = -1;
310652a3aeb4SToby Isaac       PetscInt       selfOff, Nc, parentCell;
31078d2f55e7SToby Isaac       PetscInt       cellShapeOff;
31088d2f55e7SToby Isaac       PetscObject    disc;
31098d2f55e7SToby Isaac       PetscDualSpace dsp;
31108d2f55e7SToby Isaac       PetscClassId   classId;
31118d2f55e7SToby Isaac       PetscScalar    *pointMat;
31123b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
31138d2f55e7SToby Isaac       PetscInt       pO = PETSC_MIN_INT;
31148d2f55e7SToby Isaac       const PetscInt *depthNumDof;
31158d2f55e7SToby Isaac 
31168d2f55e7SToby Isaac       if (numSecFields) {
31178d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
31188d2f55e7SToby Isaac           PetscInt child = children[i];
31198d2f55e7SToby Isaac           PetscInt dof;
31208d2f55e7SToby Isaac 
31218d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
31228d2f55e7SToby Isaac           numChildDof += dof;
31238d2f55e7SToby Isaac         }
31248d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
31258d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
31268d2f55e7SToby Isaac       }
31278d2f55e7SToby Isaac       else {
31288d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
31298d2f55e7SToby Isaac       }
31308d2f55e7SToby Isaac 
31313b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
31328d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
31338d2f55e7SToby Isaac         parentCell = p;
31348d2f55e7SToby Isaac       }
31358d2f55e7SToby Isaac       else {
31368d2f55e7SToby Isaac         PetscInt *star = NULL;
31378d2f55e7SToby Isaac         PetscInt numStar;
31388d2f55e7SToby Isaac 
31398d2f55e7SToby Isaac         parentCell = -1;
31408d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31418d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
31428d2f55e7SToby Isaac           PetscInt c = star[2 * i];
31438d2f55e7SToby Isaac 
31448d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
31458d2f55e7SToby Isaac             parentCell = c;
31468d2f55e7SToby Isaac             break;
31478d2f55e7SToby Isaac           }
31488d2f55e7SToby Isaac         }
31498d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31508d2f55e7SToby Isaac       }
31518d2f55e7SToby Isaac       /* determine the offset of p's shape functions withing parentCell's shape functions */
3152c5356c36SToby Isaac       ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
3153c5356c36SToby Isaac       ierr = PetscObjectGetClassId(disc,&classId);CHKERRQ(ierr);
3154c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
3155c5356c36SToby Isaac         ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
3156c5356c36SToby Isaac       }
3157c5356c36SToby Isaac       else if (classId == PETSCFV_CLASSID) {
3158c5356c36SToby Isaac         ierr = PetscFVGetDualSpace((PetscFV)disc,&dsp);CHKERRQ(ierr);
3159c5356c36SToby Isaac       }
3160c5356c36SToby Isaac       else {
31619b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported discretization object");
3162c5356c36SToby Isaac       }
31638d2f55e7SToby Isaac       ierr = PetscDualSpaceGetNumDof(dsp,&depthNumDof);CHKERRQ(ierr);
316452a3aeb4SToby Isaac       ierr = PetscDualSpaceGetNumComponents(dsp,&Nc);CHKERRQ(ierr);
31658d2f55e7SToby Isaac       {
31668d2f55e7SToby Isaac         PetscInt *closure = NULL;
31678d2f55e7SToby Isaac         PetscInt numClosure;
31688d2f55e7SToby Isaac 
31698d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
317059fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
31718d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
31728d2f55e7SToby Isaac 
31738d2f55e7SToby Isaac           pO = closure[2 * i + 1];
317459fc6756SToby Isaac           if (point == p) {
317559fc6756SToby Isaac             pI = i;
317659fc6756SToby Isaac             break;
317759fc6756SToby Isaac           }
31788d2f55e7SToby Isaac           ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
31798d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
31808d2f55e7SToby Isaac         }
31818d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
31828d2f55e7SToby Isaac       }
31838d2f55e7SToby Isaac 
318469291d52SBarry Smith       ierr = DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat);CHKERRQ(ierr);
318569291d52SBarry Smith       ierr = DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows);CHKERRQ(ierr);
318652a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
318752a3aeb4SToby Isaac       for (i = 0; i < numSelfDof; i++) {
318852a3aeb4SToby Isaac         matRows[i] = selfOff + i;
31893b1c2a6aSToby Isaac       }
319052a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
31913b1c2a6aSToby Isaac       {
31923b1c2a6aSToby Isaac         PetscInt colOff = 0;
31933b1c2a6aSToby Isaac 
31943b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
31953b1c2a6aSToby Isaac           PetscInt child = children[i];
31963b1c2a6aSToby Isaac           PetscInt dof, off, j;
31973b1c2a6aSToby Isaac 
31983b1c2a6aSToby Isaac           if (numSecFields) {
3199c5356c36SToby Isaac             ierr = PetscSectionGetFieldDof(cSection,child,f,&dof);CHKERRQ(ierr);
3200c5356c36SToby Isaac             ierr = PetscSectionGetFieldOffset(cSection,child,f,&off);CHKERRQ(ierr);
32013b1c2a6aSToby Isaac           }
32023b1c2a6aSToby Isaac           else {
3203c5356c36SToby Isaac             ierr = PetscSectionGetDof(cSection,child,&dof);CHKERRQ(ierr);
3204c5356c36SToby Isaac             ierr = PetscSectionGetOffset(cSection,child,&off);CHKERRQ(ierr);
32053b1c2a6aSToby Isaac           }
32063b1c2a6aSToby Isaac 
320752a3aeb4SToby Isaac           for (j = 0; j < dof; j++) {
320852a3aeb4SToby Isaac             matCols[colOff++] = off + j;
32093b1c2a6aSToby Isaac           }
32103b1c2a6aSToby Isaac         }
32113b1c2a6aSToby Isaac       }
32128d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
32138d2f55e7SToby Isaac         PetscFE        fe = (PetscFE) disc;
32148d2f55e7SToby Isaac         PetscInt       fSize;
321559fc6756SToby Isaac         const PetscInt ***perms;
321659fc6756SToby Isaac         const PetscScalar ***flips;
321759fc6756SToby Isaac         const PetscInt *pperms;
321859fc6756SToby Isaac 
32198d2f55e7SToby Isaac 
32208d2f55e7SToby Isaac         ierr = PetscFEGetDualSpace(fe,&dsp);CHKERRQ(ierr);
32213b1c2a6aSToby Isaac         ierr = PetscDualSpaceGetDimension(dsp,&fSize);CHKERRQ(ierr);
322259fc6756SToby Isaac         ierr = PetscDualSpaceGetSymmetries(dsp, &perms, &flips);CHKERRQ(ierr);
322359fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
322452a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
32258d2f55e7SToby Isaac           PetscQuadrature q;
322652a3aeb4SToby Isaac           PetscInt        dim, thisNc, numPoints, j, k;
32278d2f55e7SToby Isaac           const PetscReal *points;
32288d2f55e7SToby Isaac           const PetscReal *weights;
32298d2f55e7SToby Isaac           PetscInt        *closure = NULL;
32308d2f55e7SToby Isaac           PetscInt        numClosure;
323159fc6756SToby Isaac           PetscInt        iCell = pperms ? pperms[i] : i;
323259fc6756SToby Isaac           PetscInt        parentCellShapeDof = cellShapeOff + iCell;
32338d2f55e7SToby Isaac           PetscReal       *Bparent;
32348d2f55e7SToby Isaac 
32353b1c2a6aSToby Isaac           ierr = PetscDualSpaceGetFunctional(dsp,parentCellShapeDof,&q);CHKERRQ(ierr);
323652a3aeb4SToby Isaac           ierr = PetscQuadratureGetData(q,&dim,&thisNc,&numPoints,&points,&weights);CHKERRQ(ierr);
323752a3aeb4SToby Isaac           if (thisNc != Nc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %D does not much basis dim %D\n",thisNc,Nc);
32383b1c2a6aSToby Isaac           ierr = PetscFEGetTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
32393b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
32408d2f55e7SToby Isaac             PetscInt          childCell = -1;
324152a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3242c330f8ffSToby Isaac             const PetscReal   xi0[3] = {-1.,-1.,-1.};
32438d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
32448d2f55e7SToby Isaac             const PetscScalar *point;
32458d2f55e7SToby Isaac             PetscReal         *Bchild;
32468d2f55e7SToby Isaac             PetscInt          childCellShapeOff, pointMatOff;
32478d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
32488d2f55e7SToby Isaac             PetscInt          d;
32498d2f55e7SToby Isaac 
32508d2f55e7SToby Isaac             for (d = 0; d < dim; d++) {
32518d2f55e7SToby Isaac               pointScalar[d] = points[dim * j + d];
32528d2f55e7SToby Isaac             }
32538d2f55e7SToby Isaac             point = pointScalar;
32548d2f55e7SToby Isaac #else
32558d2f55e7SToby Isaac             point = pointReal;
32568d2f55e7SToby Isaac #endif
32578d2f55e7SToby Isaac 
325852a3aeb4SToby Isaac             parentValAtPoint = &Bparent[(fSize * j + parentCellShapeDof) * Nc];
32593b1c2a6aSToby Isaac 
32603b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
32618d2f55e7SToby Isaac               PetscInt child = children[k];
32628d2f55e7SToby Isaac               PetscInt *star = NULL;
32638d2f55e7SToby Isaac               PetscInt numStar, s;
32648d2f55e7SToby Isaac 
32658d2f55e7SToby Isaac               ierr = DMPlexGetTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
32668d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
32678d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
32688d2f55e7SToby Isaac 
32698d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
32708d2f55e7SToby Isaac                 ierr = DMPlexLocatePoint_Internal(refTree,dim,point,c,&childCell);CHKERRQ(ierr);
32718d2f55e7SToby Isaac                 if (childCell >= 0) break;
32728d2f55e7SToby Isaac               }
32738d2f55e7SToby Isaac               ierr = DMPlexRestoreTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
32748d2f55e7SToby Isaac               if (childCell >= 0) break;
32758d2f55e7SToby Isaac             }
327613903a91SSatish Balay             if (childCell < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not locate quadrature point");
32778d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
32788d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent);CHKERRQ(ierr);
3279c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3280c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
32818d2f55e7SToby Isaac 
32828d2f55e7SToby Isaac             ierr = PetscFEGetTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr);
32838d2f55e7SToby Isaac             ierr = DMPlexGetTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
32843b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3285c5356c36SToby Isaac               PetscInt child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
32868d2f55e7SToby Isaac               PetscInt l;
328759fc6756SToby Isaac               const PetscInt *cperms;
32888d2f55e7SToby Isaac 
32898d2f55e7SToby Isaac               ierr = DMLabelGetValue(depth,child,&childDepth);CHKERRQ(ierr);
32908d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
329159fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
32928d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
32938d2f55e7SToby Isaac                 PetscInt pointDepth;
32948d2f55e7SToby Isaac 
32958d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
329659fc6756SToby Isaac                 if (point == child) {
329759fc6756SToby Isaac                   cI = l;
329859fc6756SToby Isaac                   break;
329959fc6756SToby Isaac                 }
33008d2f55e7SToby Isaac                 ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
33018d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
33028d2f55e7SToby Isaac               }
33038d2f55e7SToby Isaac               if (l == numClosure) {
33048d2f55e7SToby Isaac                 pointMatOff += childDof;
33058d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
33068d2f55e7SToby Isaac               }
330759fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
33088d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
330959fc6756SToby Isaac                 PetscInt    lCell = cperms ? cperms[l] : l;
331059fc6756SToby Isaac                 PetscInt    childCellDof = childCellShapeOff + lCell;
331152a3aeb4SToby Isaac                 PetscReal   *childValAtPoint;
331252a3aeb4SToby Isaac                 PetscReal   val = 0.;
33138d2f55e7SToby Isaac 
331452a3aeb4SToby Isaac                 childValAtPoint = &Bchild[childCellDof * Nc];
331552a3aeb4SToby Isaac                 for (m = 0; m < Nc; m++) {
331652a3aeb4SToby Isaac                   val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
331752a3aeb4SToby Isaac                 }
331852a3aeb4SToby Isaac 
331952a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
33208d2f55e7SToby Isaac               }
33218d2f55e7SToby Isaac               pointMatOff += childDof;
33228d2f55e7SToby Isaac             }
33238d2f55e7SToby Isaac             ierr = DMPlexRestoreTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
33248d2f55e7SToby Isaac             ierr = PetscFERestoreTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr);
33258d2f55e7SToby Isaac           }
33268d2f55e7SToby Isaac           ierr = PetscFERestoreTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr);
33278d2f55e7SToby Isaac         }
33288d2f55e7SToby Isaac       }
3329c5356c36SToby Isaac       else { /* just the volume-weighted averages of the children */
33303b1c2a6aSToby Isaac         PetscReal parentVol;
3331bfaa5bdcSToby Isaac         PetscInt  childCell;
33323b1c2a6aSToby Isaac 
33333b1c2a6aSToby Isaac         ierr = DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL);CHKERRQ(ierr);
3334bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
333552a3aeb4SToby Isaac           PetscInt  child = children[i], j;
33363b1c2a6aSToby Isaac           PetscReal childVol;
33373b1c2a6aSToby Isaac 
33383b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
33393b1c2a6aSToby Isaac           ierr = DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL);CHKERRQ(ierr);
334052a3aeb4SToby Isaac           for (j = 0; j < Nc; j++) {
3341bfaa5bdcSToby Isaac             pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
334252a3aeb4SToby Isaac           }
3343bfaa5bdcSToby Isaac           childCell++;
33443b1c2a6aSToby Isaac         }
33458d2f55e7SToby Isaac       }
33463b1c2a6aSToby Isaac       /* Insert pointMat into mat */
334752a3aeb4SToby Isaac       ierr = MatSetValues(mat,numSelfDof,matRows,numChildDof,matCols,pointMat,INSERT_VALUES);CHKERRQ(ierr);
334869291d52SBarry Smith       ierr = DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows);CHKERRQ(ierr);
334969291d52SBarry Smith       ierr = DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat);CHKERRQ(ierr);
33508d2f55e7SToby Isaac     }
33518d2f55e7SToby Isaac   }
33523b1c2a6aSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJ);CHKERRQ(ierr);
33538d2f55e7SToby Isaac   ierr = PetscFree2(pointScalar,pointRef);CHKERRQ(ierr);
33543b1c2a6aSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33553b1c2a6aSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33568d2f55e7SToby Isaac   *inj = mat;
33578d2f55e7SToby Isaac   PetscFunctionReturn(0);
33588d2f55e7SToby Isaac }
33598d2f55e7SToby Isaac 
3360f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3361f30e825dSToby Isaac {
3362f30e825dSToby Isaac   PetscDS        ds;
3363f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3364f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3365f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3366f30e825dSToby Isaac   PetscErrorCode ierr;
3367f30e825dSToby Isaac 
3368f30e825dSToby Isaac   PetscFunctionBegin;
3369f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
3370f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3371f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
3372e87a4003SBarry Smith   ierr = DMGetSection(refTree,&refSection);CHKERRQ(ierr);
3373f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3374f30e825dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
3375f30e825dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
3376f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
3377f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof*maxDof,&cols);CHKERRQ(ierr);
3378f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3379f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3380f30e825dSToby Isaac 
3381f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3382f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3383c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3384f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3385f30e825dSToby Isaac 
3386f30e825dSToby Isaac     ierr = PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
3387f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
338852a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3389f30e825dSToby Isaac 
3390f30e825dSToby Isaac       if (numFields > 1) {
3391f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3392f30e825dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
3393f30e825dSToby Isaac       }
3394f30e825dSToby Isaac       else {
3395f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3396f30e825dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
3397f30e825dSToby Isaac       }
3398f30e825dSToby Isaac 
3399f30e825dSToby Isaac       for (r = 0; r < cDof; r++) {
3400f30e825dSToby Isaac         rows[r] = cOff + r;
3401f30e825dSToby Isaac       }
3402f30e825dSToby Isaac       numCols = 0;
3403f30e825dSToby Isaac       {
3404f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3405f30e825dSToby Isaac 
3406f30e825dSToby Isaac         if (numFields > 1) {
3407f30e825dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,parent,f,&aDof);CHKERRQ(ierr);
3408f30e825dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,parent,f,&aOff);CHKERRQ(ierr);
3409f30e825dSToby Isaac         }
3410f30e825dSToby Isaac         else {
3411f30e825dSToby Isaac           ierr = PetscSectionGetDof(refSection,parent,&aDof);CHKERRQ(ierr);
3412f30e825dSToby Isaac           ierr = PetscSectionGetOffset(refSection,parent,&aOff);CHKERRQ(ierr);
3413f30e825dSToby Isaac         }
3414f30e825dSToby Isaac 
3415f30e825dSToby Isaac         for (j = 0; j < aDof; j++) {
3416f30e825dSToby Isaac           cols[numCols++] = aOff + j;
3417f30e825dSToby Isaac         }
3418f30e825dSToby Isaac       }
3419f30e825dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3420f30e825dSToby Isaac       /* transpose of constraint matrix */
3421f30e825dSToby Isaac       ierr = MatGetValues(inj,numCols,cols,cDof,rows,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3422f30e825dSToby Isaac     }
3423f30e825dSToby Isaac   }
3424f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
3425f30e825dSToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
3426f30e825dSToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
3427f30e825dSToby Isaac   PetscFunctionReturn(0);
3428f30e825dSToby Isaac }
3429f30e825dSToby Isaac 
3430f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3431f30e825dSToby Isaac {
3432f30e825dSToby Isaac   PetscDS        ds;
3433f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3434f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3435c6154584SToby Isaac   PetscSection   refConSec, refSection;
3436f30e825dSToby Isaac   PetscErrorCode ierr;
3437f30e825dSToby Isaac 
3438f30e825dSToby Isaac   PetscFunctionBegin;
3439f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3440f30e825dSToby Isaac   *childrenMats = NULL;
3441f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
3442e87a4003SBarry Smith   ierr = DMGetSection(refTree,&refSection);CHKERRQ(ierr);
3443f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3444f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
3445f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3446f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3447f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3448f30e825dSToby Isaac 
3449f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3450f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3451c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3452f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3453f30e825dSToby Isaac 
3454f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3455f30e825dSToby Isaac       PetscInt cDof;
3456f30e825dSToby Isaac 
3457f30e825dSToby Isaac       if (numFields > 1) {
3458f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3459f30e825dSToby Isaac       }
3460f30e825dSToby Isaac       else {
3461f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3462f30e825dSToby Isaac       }
3463f30e825dSToby Isaac 
3464f30e825dSToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
3465f30e825dSToby Isaac     }
3466f30e825dSToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
3467f30e825dSToby Isaac   }
3468f30e825dSToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
3469f30e825dSToby Isaac   PetscFunctionReturn(0);
3470f30e825dSToby Isaac }
3471f30e825dSToby Isaac 
3472ebf164c7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree,Mat *injRef)
3473154bca37SToby Isaac {
3474ebf164c7SToby Isaac   Mat            cMatRef;
34756148253fSToby Isaac   PetscObject    injRefObj;
34768d2f55e7SToby Isaac   PetscErrorCode ierr;
34778d2f55e7SToby Isaac 
3478154bca37SToby Isaac   PetscFunctionBegin;
3479ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,NULL,&cMatRef);CHKERRQ(ierr);
34806148253fSToby Isaac   ierr = PetscObjectQuery((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",&injRefObj);CHKERRQ(ierr);
3481ebf164c7SToby Isaac   *injRef = (Mat) injRefObj;
3482ebf164c7SToby Isaac   if (!*injRef) {
3483ebf164c7SToby Isaac     ierr = DMPlexComputeInjectorReferenceTree(refTree,injRef);CHKERRQ(ierr);
3484ebf164c7SToby Isaac     ierr = PetscObjectCompose((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",(PetscObject)*injRef);CHKERRQ(ierr);
3485ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
3486ebf164c7SToby Isaac     ierr = PetscObjectDereference((PetscObject)*injRef);CHKERRQ(ierr);
3487ebf164c7SToby Isaac   }
3488ebf164c7SToby Isaac   PetscFunctionReturn(0);
34896148253fSToby Isaac }
3490f30e825dSToby Isaac 
3491c921d74cSToby 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)
3492ebf164c7SToby Isaac {
3493c921d74cSToby Isaac   PetscInt       pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3494ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3495ebf164c7SToby Isaac   PetscSection   localCoarse, localFine, leafIndicesSec;
3496c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3497c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3498c921d74cSToby Isaac   const PetscInt *rootDegrees;
3499c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3500ebf164c7SToby Isaac   PetscSF        coarseToFineEmbedded;
3501ebf164c7SToby Isaac   PetscErrorCode ierr;
3502ebf164c7SToby Isaac 
3503ebf164c7SToby Isaac   PetscFunctionBegin;
3504ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
35058d2f55e7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
3506e87a4003SBarry Smith   ierr = DMGetSection(fine,&localFine);CHKERRQ(ierr);
3507e87a4003SBarry Smith   ierr = DMGetGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3508f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
3509f30e825dSToby Isaac   ierr = PetscSectionSetChart(leafIndicesSec,pStartF, pEndF);CHKERRQ(ierr);
3510c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localFine,&maxDof);CHKERRQ(ierr);
35118d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
35127e96bdafSToby Isaac     PetscInt l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
35137e96bdafSToby Isaac     const PetscInt *leaves;
35148d2f55e7SToby Isaac 
35157e96bdafSToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
35167e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
35177e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35188d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
35198d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
35208d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
35218d2f55e7SToby Isaac         numPointsWithDofs++;
3522f30e825dSToby Isaac 
3523f30e825dSToby Isaac         ierr = PetscSectionGetDof(localFine,p,&dof);CHKERRQ(ierr);
3524f30e825dSToby Isaac         ierr = PetscSectionSetDof(leafIndicesSec,p,dof + 1);CHKERRQ(ierr);
35258d2f55e7SToby Isaac       }
35268d2f55e7SToby Isaac     }
35278d2f55e7SToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
3528f30e825dSToby Isaac     ierr = PetscSectionSetUp(leafIndicesSec);CHKERRQ(ierr);
3529f30e825dSToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numIndices);CHKERRQ(ierr);
3530c921d74cSToby Isaac     ierr = PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1),&leafInds);CHKERRQ(ierr);
3531c921d74cSToby Isaac     if (gatheredValues)  {ierr = PetscMalloc1(numIndices,&leafVals);CHKERRQ(ierr);}
35327e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
35337e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35348d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
35358d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
35368d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3537f30e825dSToby Isaac         PetscInt    off, gOff;
3538f30e825dSToby Isaac         PetscInt    *pInd;
3539c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3540f30e825dSToby Isaac 
35417e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3542f30e825dSToby Isaac 
3543f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3544f30e825dSToby Isaac 
3545c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3546c921d74cSToby Isaac         if (gatheredValues) {
3547c921d74cSToby Isaac           PetscInt i;
3548c921d74cSToby Isaac 
3549c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3550c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3551c921d74cSToby Isaac         }
3552f30e825dSToby Isaac         ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
3553f30e825dSToby Isaac 
3554f30e825dSToby Isaac         offsets[0] = 0;
3555f30e825dSToby Isaac         if (numFields) {
3556f30e825dSToby Isaac           PetscInt f;
3557f30e825dSToby Isaac 
3558f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3559f30e825dSToby Isaac             PetscInt fDof;
3560f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(localFine,p,f,&fDof);CHKERRQ(ierr);
3561f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3562f30e825dSToby Isaac           }
356305586334SMatthew G. Knepley           ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1, NULL,pInd);CHKERRQ(ierr);
3564367003a6SStefano Zampini         } else {
356505586334SMatthew G. Knepley           ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL, NULL,pInd);CHKERRQ(ierr);
3566f30e825dSToby Isaac         }
3567c921d74cSToby Isaac         if (gatheredValues) {ierr = VecGetValues(fineVec,dof,pInd,pVal);CHKERRQ(ierr);}
35688d2f55e7SToby Isaac       }
35698d2f55e7SToby Isaac     }
35708d2f55e7SToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
3571f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
35728d2f55e7SToby Isaac   }
3573f30e825dSToby Isaac 
3574f30e825dSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
3575e87a4003SBarry Smith   ierr = DMGetSection(coarse,&localCoarse);CHKERRQ(ierr);
3576e87a4003SBarry Smith   ierr = DMGetGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3577f30e825dSToby Isaac 
35786148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
35796148253fSToby Isaac     MPI_Datatype threeInt;
35806148253fSToby Isaac     PetscMPIInt  rank;
35816148253fSToby Isaac     PetscInt     (*parentNodeAndIdCoarse)[3];
35826148253fSToby Isaac     PetscInt     (*parentNodeAndIdFine)[3];
35836148253fSToby Isaac     PetscInt     p, nleaves, nleavesToParents;
35846148253fSToby Isaac     PetscSF      pointSF, sfToParents;
35856148253fSToby Isaac     const PetscInt *ilocal;
35866148253fSToby Isaac     const PetscSFNode *iremote;
35876148253fSToby Isaac     PetscSFNode  *iremoteToParents;
35886148253fSToby Isaac     PetscInt     *ilocalToParents;
35896148253fSToby Isaac 
35906148253fSToby Isaac     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)coarse),&rank);CHKERRQ(ierr);
35916148253fSToby Isaac     ierr = MPI_Type_contiguous(3,MPIU_INT,&threeInt);CHKERRQ(ierr);
35926148253fSToby Isaac     ierr = MPI_Type_commit(&threeInt);CHKERRQ(ierr);
35936148253fSToby Isaac     ierr = PetscMalloc2(pEndC-pStartC,&parentNodeAndIdCoarse,pEndF-pStartF,&parentNodeAndIdFine);CHKERRQ(ierr);
35946148253fSToby Isaac     ierr = DMGetPointSF(coarse,&pointSF);CHKERRQ(ierr);
35956148253fSToby Isaac     ierr = PetscSFGetGraph(pointSF,NULL,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
35966148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
35976148253fSToby Isaac       PetscInt parent, childId;
35986148253fSToby Isaac       ierr = DMPlexGetTreeParent(coarse,p,&parent,&childId);CHKERRQ(ierr);
35996148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
36006148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
36016148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
36026148253fSToby Isaac       if (nleaves > 0) {
36036148253fSToby Isaac         PetscInt leaf = -1;
36046148253fSToby Isaac 
36056148253fSToby Isaac         if (ilocal) {
36066148253fSToby Isaac           ierr  = PetscFindInt(parent,nleaves,ilocal,&leaf);CHKERRQ(ierr);
36076148253fSToby Isaac         }
36086148253fSToby Isaac         else {
36096148253fSToby Isaac           leaf = p - pStartC;
36106148253fSToby Isaac         }
36116148253fSToby Isaac         if (leaf >= 0) {
36126148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
36136148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
36146148253fSToby Isaac         }
36156148253fSToby Isaac       }
36166148253fSToby Isaac     }
36176148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
36186148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
36196148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
36206148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
36216148253fSToby Isaac     }
36226148253fSToby Isaac     ierr = PetscSFBcastBegin(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36236148253fSToby Isaac     ierr = PetscSFBcastEnd(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36246148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3625f30e825dSToby Isaac       PetscInt dof;
3626f30e825dSToby Isaac 
3627f30e825dSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&dof);CHKERRQ(ierr);
3628f30e825dSToby Isaac       if (dof) {
3629f30e825dSToby Isaac         PetscInt off;
3630f30e825dSToby Isaac 
3631f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3632c921d74cSToby Isaac         if (gatheredIndices) {
3633c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3634c921d74cSToby Isaac         } else if (gatheredValues) {
3635c921d74cSToby Isaac           leafVals[off] = (PetscScalar) PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3636c921d74cSToby Isaac         }
3637f30e825dSToby Isaac       }
36386148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36396148253fSToby Isaac         nleavesToParents++;
36406148253fSToby Isaac       }
36416148253fSToby Isaac     }
36426148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&ilocalToParents);CHKERRQ(ierr);
36436148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&iremoteToParents);CHKERRQ(ierr);
36446148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
36456148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36466148253fSToby Isaac         ilocalToParents[nleavesToParents] = p - pStartF;
36476148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p-pStartF][0];
36486148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p-pStartF][1];
36496148253fSToby Isaac         nleavesToParents++;
36506148253fSToby Isaac       }
36516148253fSToby Isaac     }
36526148253fSToby Isaac     ierr = PetscSFCreate(PetscObjectComm((PetscObject)coarse),&sfToParents);CHKERRQ(ierr);
36536148253fSToby Isaac     ierr = PetscSFSetGraph(sfToParents,pEndC-pStartC,nleavesToParents,ilocalToParents,PETSC_OWN_POINTER,iremoteToParents,PETSC_OWN_POINTER);CHKERRQ(ierr);
36546148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
36556148253fSToby Isaac 
36566148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
36576148253fSToby Isaac 
36586148253fSToby Isaac     ierr = PetscFree2(parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36596148253fSToby Isaac     ierr = MPI_Type_free(&threeInt);CHKERRQ(ierr);
36606148253fSToby Isaac   }
3661f30e825dSToby Isaac 
36626148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
36636148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
36646148253fSToby Isaac     PetscSF  sfDofsOnly;
36656148253fSToby Isaac 
36666148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
36676148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
36686148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
36696148253fSToby Isaac       if ((dof - cdof) > 0) {
36706148253fSToby Isaac         numPointsWithDofs++;
36716148253fSToby Isaac       }
36726148253fSToby Isaac     }
36736148253fSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
36746148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
36756148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
36766148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
36776148253fSToby Isaac       if ((dof - cdof) > 0) {
3678e03d9830SToby Isaac         pointsWithDofs[offset++] = p - pStartC;
36796148253fSToby Isaac       }
36806148253fSToby Isaac     }
36816148253fSToby Isaac     ierr = PetscSFCreateEmbeddedSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly);CHKERRQ(ierr);
36826148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3683f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
36846148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
36856148253fSToby Isaac   }
3686f30e825dSToby Isaac 
36876148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
3688f30e825dSToby Isaac   ierr = PetscSFComputeDegreeBegin(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3689f30e825dSToby Isaac   ierr = PetscSFComputeDegreeEnd(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3690f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&multiRootSec);CHKERRQ(ierr);
3691f30e825dSToby Isaac   ierr = PetscSectionSetChart(multiRootSec,pStartC,pEndC);CHKERRQ(ierr);
36928d2f55e7SToby Isaac   for (p = pStartC; p < pEndC; p++) {
3693f30e825dSToby Isaac     ierr = PetscSectionSetDof(multiRootSec,p,rootDegrees[p-pStartC]);CHKERRQ(ierr);
36948d2f55e7SToby Isaac   }
3695f30e825dSToby Isaac   ierr = PetscSectionSetUp(multiRootSec);CHKERRQ(ierr);
3696f30e825dSToby Isaac   ierr = PetscSectionGetStorageSize(multiRootSec,&numMulti);CHKERRQ(ierr);
36978d2f55e7SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
3698f30e825dSToby Isaac   { /* distribute the leaf section */
3699f30e825dSToby Isaac     PetscSF multi, multiInv, indicesSF;
3700f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
37018d2f55e7SToby Isaac 
3702f30e825dSToby Isaac     ierr = PetscSFGetMultiSF(coarseToFineEmbedded,&multi);CHKERRQ(ierr);
3703f30e825dSToby Isaac     ierr = PetscSFCreateInverseSF(multi,&multiInv);CHKERRQ(ierr);
3704f30e825dSToby Isaac     ierr = PetscSFDistributeSection(multiInv,leafIndicesSec,&remoteOffsets,rootIndicesSec);CHKERRQ(ierr);
3705f30e825dSToby Isaac     ierr = PetscSFCreateSectionSF(multiInv,leafIndicesSec,remoteOffsets,rootIndicesSec,&indicesSF);CHKERRQ(ierr);
3706f30e825dSToby Isaac     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
3707f30e825dSToby Isaac     ierr = PetscSFDestroy(&multiInv);CHKERRQ(ierr);
37088d2f55e7SToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
3709c921d74cSToby Isaac     if (gatheredIndices) {
3710c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootInds);CHKERRQ(ierr);
3711c921d74cSToby Isaac       ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr);
3712c921d74cSToby Isaac       ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr);
3713c921d74cSToby Isaac     }
3714c921d74cSToby Isaac     if (gatheredValues) {
3715c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootVals);CHKERRQ(ierr);
3716c921d74cSToby Isaac       ierr = PetscSFBcastBegin(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr);
3717c921d74cSToby Isaac       ierr = PetscSFBcastEnd(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr);
3718c921d74cSToby Isaac     }
37198d2f55e7SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
37208d2f55e7SToby Isaac   }
3721ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
3722c921d74cSToby Isaac   ierr = PetscFree(leafInds);CHKERRQ(ierr);
3723c921d74cSToby Isaac   ierr = PetscFree(leafVals);CHKERRQ(ierr);
3724f30e825dSToby Isaac   ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3725c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3726c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3727c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3728c921d74cSToby Isaac   if (gatheredValues)  *gatheredValues  = rootVals;
3729ebf164c7SToby Isaac   PetscFunctionReturn(0);
3730ebf164c7SToby Isaac }
3731ebf164c7SToby Isaac 
3732ebf164c7SToby Isaac PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3733ebf164c7SToby Isaac {
3734ebf164c7SToby Isaac   DM             refTree;
3735c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3736ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3737ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3738ebf164c7SToby Isaac   PetscSection   cSecRef;
3739c921d74cSToby Isaac   PetscInt       *rootIndices, *parentIndices, pRefStart, pRefEnd;
3740ebf164c7SToby Isaac   Mat            injRef;
3741c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3742ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3743ebf164c7SToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
3744ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3745ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3746ebf164c7SToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3747ebf164c7SToby Isaac   PetscErrorCode ierr;
3748ebf164c7SToby Isaac 
3749ebf164c7SToby Isaac   PetscFunctionBegin;
3750ebf164c7SToby Isaac 
3751ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
3752ebf164c7SToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
3753ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
3754ebf164c7SToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3755ebf164c7SToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
3756ebf164c7SToby Isaac 
3757ebf164c7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
3758e87a4003SBarry Smith   ierr = DMGetSection(fine,&localFine);CHKERRQ(ierr);
3759e87a4003SBarry Smith   ierr = DMGetGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3760ebf164c7SToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
3761ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
3762e87a4003SBarry Smith   ierr = DMGetSection(coarse,&localCoarse);CHKERRQ(ierr);
3763e87a4003SBarry Smith   ierr = DMGetGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3764ebf164c7SToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
3765ebf164c7SToby Isaac   {
3766ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
3767ebf164c7SToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
3768ebf164c7SToby Isaac   }
3769ebf164c7SToby Isaac 
3770c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,childIds,NULL,numFields,offsets,&multiRootSec,&rootIndicesSec,&rootIndices,NULL);CHKERRQ(ierr);
37718d2f55e7SToby Isaac 
3772f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&parentIndices);CHKERRQ(ierr);
3773f30e825dSToby Isaac 
3774f30e825dSToby Isaac   /* count indices */
37758d2f55e7SToby Isaac   ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
3776c6154584SToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
3777c6154584SToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
37788d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
37798d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
3780f30e825dSToby Isaac   ierr = PetscCalloc2(rowEnd-rowStart,&nnzD,rowEnd-rowStart,&nnzO);CHKERRQ(ierr);
3781f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3782f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
37838d2f55e7SToby Isaac 
3784f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3785f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3786f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3787f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
37888d2f55e7SToby Isaac 
37898d2f55e7SToby Isaac     rowOffsets[0] = 0;
3790f30e825dSToby Isaac     offsetsCopy[0] = 0;
37918d2f55e7SToby Isaac     if (numFields) {
37928d2f55e7SToby Isaac       PetscInt f;
37938d2f55e7SToby Isaac 
3794f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3795f30e825dSToby Isaac         PetscInt fDof;
3796f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3797f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
37988d2f55e7SToby Isaac       }
379905586334SMatthew G. Knepley       ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,parentIndices);CHKERRQ(ierr);
3800367003a6SStefano Zampini     } else {
380105586334SMatthew G. Knepley       ierr = DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,parentIndices);CHKERRQ(ierr);
3802f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
38038d2f55e7SToby Isaac     }
3804f30e825dSToby Isaac 
3805f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3806f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3807f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3808f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3809f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3810f30e825dSToby Isaac       const PetscInt *childIndices;
3811f30e825dSToby Isaac 
3812f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3813f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3814f30e825dSToby Isaac       childId = rootIndices[offset++];
3815f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3816f30e825dSToby Isaac       numIndices--;
3817f30e825dSToby Isaac 
3818f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3819f30e825dSToby Isaac         PetscInt i;
3820f30e825dSToby Isaac 
3821f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3822f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3823f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3824f30e825dSToby Isaac           if (rowIndex < 0) continue;
3825f30e825dSToby Isaac           if (colIndex < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unconstrained fine and constrained coarse");
3826a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3827f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
3828f30e825dSToby Isaac           }
3829f30e825dSToby Isaac           else {
3830f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3831f30e825dSToby Isaac           }
3832f30e825dSToby Isaac         }
3833f30e825dSToby Isaac       }
3834f30e825dSToby Isaac       else {
3835f30e825dSToby Isaac         PetscInt parentId, f, lim;
3836f30e825dSToby Isaac 
3837f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3838f30e825dSToby Isaac 
3839f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3840f30e825dSToby Isaac         offsets[0] = 0;
38418d2f55e7SToby Isaac         if (numFields) {
38428d2f55e7SToby Isaac           PetscInt f;
3843f30e825dSToby Isaac 
38448d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3845f30e825dSToby Isaac             PetscInt fDof;
3846f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
3847f30e825dSToby Isaac 
3848f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
38498d2f55e7SToby Isaac           }
38508d2f55e7SToby Isaac         }
38518d2f55e7SToby Isaac         else {
3852f30e825dSToby Isaac           PetscInt cDof;
3853f30e825dSToby Isaac 
3854f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
3855f30e825dSToby Isaac           offsets[1] = cDof;
3856f30e825dSToby Isaac         }
3857f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3858f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3859f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3860f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3861f30e825dSToby Isaac 
3862f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3863f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3864f30e825dSToby Isaac 
3865f30e825dSToby Isaac             if (colIndex < 0) continue;
3866f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3867f30e825dSToby Isaac               numD++;
3868f30e825dSToby Isaac             }
3869f30e825dSToby Isaac             else {
3870f30e825dSToby Isaac               numO++;
3871f30e825dSToby Isaac             }
3872f30e825dSToby Isaac           }
3873f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3874f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3875f30e825dSToby Isaac 
3876f30e825dSToby Isaac             if (rowIndex < 0) continue;
3877f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3878f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
38798d2f55e7SToby Isaac           }
38808d2f55e7SToby Isaac         }
38818d2f55e7SToby Isaac       }
3882f30e825dSToby Isaac     }
3883f30e825dSToby Isaac   }
3884f30e825dSToby Isaac   /* preallocate */
3885f30e825dSToby Isaac   ierr = MatXAIJSetPreallocation(mat,1,nnzD,nnzO,NULL,NULL);CHKERRQ(ierr);
3886f30e825dSToby Isaac   ierr = PetscFree2(nnzD,nnzO);CHKERRQ(ierr);
3887f30e825dSToby Isaac   /* insert values */
3888f30e825dSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
3889f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3890f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3891f30e825dSToby Isaac 
3892f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3893f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3894f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3895f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
3896f30e825dSToby Isaac 
3897f30e825dSToby Isaac     rowOffsets[0] = 0;
3898f30e825dSToby Isaac     offsetsCopy[0] = 0;
38998d2f55e7SToby Isaac     if (numFields) {
39008d2f55e7SToby Isaac       PetscInt f;
3901f30e825dSToby Isaac 
39028d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3903f30e825dSToby Isaac         PetscInt fDof;
3904f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3905f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3906f30e825dSToby Isaac       }
390705586334SMatthew G. Knepley       ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,parentIndices);CHKERRQ(ierr);
3908367003a6SStefano Zampini     } else {
390905586334SMatthew G. Knepley       ierr = DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,parentIndices);CHKERRQ(ierr);
3910f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3911f30e825dSToby Isaac     }
3912f30e825dSToby Isaac 
3913f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3914f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3915f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3916f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3917f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3918f30e825dSToby Isaac       const PetscInt *childIndices;
3919f30e825dSToby Isaac 
3920f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3921f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3922f30e825dSToby Isaac       childId = rootIndices[offset++];
3923f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3924f30e825dSToby Isaac       numIndices--;
3925f30e825dSToby Isaac 
3926f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3927f30e825dSToby Isaac         PetscInt i;
3928f30e825dSToby Isaac 
3929f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3930f30e825dSToby Isaac           ierr = MatSetValue(mat,parentIndices[i],childIndices[i],1.,INSERT_VALUES);CHKERRQ(ierr);
39318d2f55e7SToby Isaac         }
39328d2f55e7SToby Isaac       }
39338d2f55e7SToby Isaac       else {
3934f30e825dSToby Isaac         PetscInt parentId, f, lim;
39358d2f55e7SToby Isaac 
3936f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3937f30e825dSToby Isaac 
3938f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3939f30e825dSToby Isaac         offsets[0] = 0;
39408d2f55e7SToby Isaac         if (numFields) {
3941f30e825dSToby Isaac           PetscInt f;
39428d2f55e7SToby Isaac 
3943f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3944f30e825dSToby Isaac             PetscInt fDof;
3945f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
3946f30e825dSToby Isaac 
3947f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
39488d2f55e7SToby Isaac           }
39498d2f55e7SToby Isaac         }
39508d2f55e7SToby Isaac         else {
3951f30e825dSToby Isaac           PetscInt cDof;
3952f30e825dSToby Isaac 
3953f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
3954f30e825dSToby Isaac           offsets[1] = cDof;
39558d2f55e7SToby Isaac         }
3956f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3957f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3958f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3959f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3960f30e825dSToby Isaac 
3961f30e825dSToby Isaac           ierr = MatSetValues(mat,rowOffsets[f+1]-rowOffsets[f],rowIndices,offsets[f+1]-offsets[f],colIndices,childMat,INSERT_VALUES);CHKERRQ(ierr);
39628d2f55e7SToby Isaac         }
39638d2f55e7SToby Isaac       }
39648d2f55e7SToby Isaac     }
39658d2f55e7SToby Isaac   }
3966ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
3967ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
3968ec92bd66SToby Isaac   ierr = PetscFree(parentIndices);CHKERRQ(ierr);
3969f30e825dSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
3970f30e825dSToby Isaac   ierr = PetscFree(rootIndices);CHKERRQ(ierr);
3971f30e825dSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
3972f30e825dSToby Isaac 
39738d2f55e7SToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
39748d2f55e7SToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
3975154bca37SToby Isaac   PetscFunctionReturn(0);
3976154bca37SToby Isaac }
397738fc2455SToby Isaac 
39780eb7e1eaSToby Isaac static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3979ebf164c7SToby Isaac {
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);
4009e87a4003SBarry Smith   ierr = DMGetGlobalSection(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 
4048e87a4003SBarry Smith   ierr = DMGetSection(coarse,&localCoarse);CHKERRQ(ierr);
4049e87a4003SBarry Smith   ierr = DMGetGlobalSection(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 
407744a7f3ddSMatthew G. Knepley       ierr = DMGetField(coarse, i, NULL, &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   }
4186e87a4003SBarry Smith   ierr = DMGetSection(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 
4197cfc9abc1SToby Isaac     ierr = PetscSectionGetMaxDof(localFine,&maxDof);CHKERRQ(ierr);
419869291d52SBarry Smith     ierr = DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
419969291d52SBarry Smith     ierr = DMGetWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork);CHKERRQ(ierr);
420062095d54SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
4201e5e52638SMatthew G. Knepley     ierr = DMCopyDisc(fine,refTree);CHKERRQ(ierr);
420262095d54SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
420362095d54SToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
420462095d54SToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
420562095d54SToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
42060eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafValuesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
42070eb7e1eaSToby Isaac     ierr = DMPlexGetHeightStratum(fine,0,&cellStart,&cellEnd);CHKERRQ(ierr);
420889698031SToby Isaac     ierr = DMPlexGetHybridBounds(fine,&cellEndInterior,NULL,NULL,NULL);CHKERRQ(ierr);
420989698031SToby Isaac     cellEnd = (cellEndInterior < 0) ? cellEnd : cellEndInterior;
42100eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
421162095d54SToby Isaac       PetscInt          gDof, gcDof, gOff, lDof;
421262095d54SToby Isaac       PetscInt          numValues, pValOff;
421362095d54SToby Isaac       PetscInt          childId;
421462095d54SToby Isaac       const PetscScalar *pVal;
42150eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
421662095d54SToby Isaac 
421762095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
421862095d54SToby Isaac       ierr = PetscSectionGetDof(localFine,p,&lDof);CHKERRQ(ierr);
421962095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
422062095d54SToby Isaac       if ((gDof - gcDof) <= 0) {
422162095d54SToby Isaac         continue;
422262095d54SToby Isaac       }
422362095d54SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
422462095d54SToby Isaac       ierr = PetscSectionGetDof(leafValuesSec,p,&numValues);CHKERRQ(ierr);
422562095d54SToby Isaac       if (!numValues) continue;
422662095d54SToby Isaac       ierr = PetscSectionGetOffset(leafValuesSec,p,&pValOff);CHKERRQ(ierr);
422762095d54SToby Isaac       pVal = &leafValues[pValOff];
422862095d54SToby Isaac       offsets[0]        = 0;
422962095d54SToby Isaac       offsetsCopy[0]    = 0;
423062095d54SToby Isaac       newOffsets[0]     = 0;
423162095d54SToby Isaac       newOffsetsCopy[0] = 0;
42324833aeb0SToby Isaac       childId           = cids[p - pStartF];
423362095d54SToby Isaac       if (numFields) {
423462095d54SToby Isaac         PetscInt f;
423562095d54SToby Isaac         for (f = 0; f < numFields; f++) {
423662095d54SToby Isaac           PetscInt rowDof;
423762095d54SToby Isaac 
423862095d54SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
423962095d54SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
424062095d54SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
424162095d54SToby Isaac           /* TODO: closure indices */
42429f4e70e1SToby Isaac           newOffsets[f + 1]     = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
424362095d54SToby Isaac         }
424405586334SMatthew G. Knepley         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,NULL,rowIndices);CHKERRQ(ierr);
424562095d54SToby Isaac       }
424662095d54SToby Isaac       else {
42474833aeb0SToby Isaac         offsets[0]    = 0;
42484833aeb0SToby Isaac         offsets[1]    = lDof;
42494833aeb0SToby Isaac         newOffsets[0] = 0;
42504833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
425105586334SMatthew G. Knepley         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,NULL,rowIndices);CHKERRQ(ierr);
425262095d54SToby Isaac       }
425362095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
42542f65e181SToby Isaac         ierr = VecSetValues(vecFine,numValues,rowIndices,pVal,INSERT_VALUES);CHKERRQ(ierr);
425562095d54SToby Isaac       } else {
425662095d54SToby Isaac         PetscInt f;
425762095d54SToby Isaac 
425878b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
425978b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
426078b7adb5SToby Isaac           fvGradData = &pVal[numValues];
426178b7adb5SToby Isaac         }
426262095d54SToby Isaac         for (f = 0; f < PetscMax(1,numFields); f++) {
426362095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
426462095d54SToby Isaac           PetscInt numRows = offsets[f+1] - offsets[f];
426562095d54SToby Isaac           PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
426662095d54SToby Isaac           const PetscScalar *cVal = &pVal[newOffsets[f]];
426762095d54SToby Isaac           PetscScalar *rVal = &pointWork[offsets[f]];
426862095d54SToby Isaac           PetscInt i, j;
426962095d54SToby Isaac 
4270708c7f19SToby Isaac #if 0
4271cfc9abc1SToby Isaac           ierr = PetscInfo5(coarse,"childId %D, numRows %D, numCols %D, refPointFieldN %D maxDof %D\n",childId,numRows,numCols,refPointFieldN[childId - pRefStart][f], maxDof);CHKERRQ(ierr);
4272708c7f19SToby Isaac #endif
427362095d54SToby Isaac           for (i = 0; i < numRows; i++) {
427462095d54SToby Isaac             PetscScalar val = 0.;
427562095d54SToby Isaac             for (j = 0; j < numCols; j++) {
427662095d54SToby Isaac               val += childMat[i * numCols + j] * cVal[j];
427762095d54SToby Isaac             }
427862095d54SToby Isaac             rVal[i] = val;
427962095d54SToby Isaac           }
42800eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
42810eb7e1eaSToby Isaac             PetscReal   centroid[3];
42820eb7e1eaSToby Isaac             PetscScalar diff[3];
42830eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
42840eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
42850eb7e1eaSToby Isaac 
42860eb7e1eaSToby Isaac             ierr = DMPlexComputeCellGeometryFVM(fine,p,NULL,centroid,NULL);CHKERRQ(ierr);
42870eb7e1eaSToby Isaac             for (i = 0; i < dim; i++) {
42880eb7e1eaSToby Isaac               diff[i] = centroid[i] - parentCentroid[i];
42890eb7e1eaSToby Isaac             }
42900eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
42910eb7e1eaSToby Isaac               PetscScalar val = 0.;
42920eb7e1eaSToby Isaac 
429389698031SToby Isaac               for (j = 0; j < dim; j++) {
42940eb7e1eaSToby Isaac                 val += gradient[dim * i + j] * diff[j];
42950eb7e1eaSToby Isaac               }
42960eb7e1eaSToby Isaac               rVal[i] += val;
42970eb7e1eaSToby Isaac             }
42980eb7e1eaSToby Isaac           }
42992f65e181SToby Isaac           ierr = VecSetValues(vecFine,numRows,&rowIndices[offsets[f]],rVal,INSERT_VALUES);CHKERRQ(ierr);
430062095d54SToby Isaac         }
430162095d54SToby Isaac       }
430262095d54SToby Isaac     }
430362095d54SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
430469291d52SBarry Smith     ierr = DMRestoreWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork);CHKERRQ(ierr);
4305cfc9abc1SToby Isaac     ierr = DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
430662095d54SToby Isaac   }
43074fe3dfefSToby Isaac   ierr = PetscFree(leafValues);CHKERRQ(ierr);
430862095d54SToby Isaac   ierr = PetscSectionDestroy(&leafValuesSec);CHKERRQ(ierr);
430962095d54SToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
431062095d54SToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
4311ebf164c7SToby Isaac   PetscFunctionReturn(0);
4312ebf164c7SToby Isaac }
4313ebf164c7SToby Isaac 
4314ebf164c7SToby Isaac static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4315ebf164c7SToby Isaac {
4316c921d74cSToby Isaac   DM             refTree;
4317c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4318c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4319c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4320c921d74cSToby Isaac   PetscSection   cSecRef;
4321c921d74cSToby Isaac   PetscInt       *parentIndices, pRefStart, pRefEnd;
4322d3bc4906SToby Isaac   PetscScalar    *rootValues, *parentValues;
4323c921d74cSToby Isaac   Mat            injRef;
4324c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4325c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4326c921d74cSToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
4327c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4328c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4329c921d74cSToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4330c921d74cSToby Isaac   PetscErrorCode ierr;
4331c921d74cSToby Isaac 
4332ebf164c7SToby Isaac   PetscFunctionBegin;
4333c921d74cSToby Isaac 
4334c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
4335708c7f19SToby Isaac   ierr = VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
4336708c7f19SToby Isaac   ierr = VecSetOption(vecCoarse,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
4337c921d74cSToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
4338e5e52638SMatthew G. Knepley   ierr = DMCopyDisc(coarse,refTree);CHKERRQ(ierr);
4339c921d74cSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
4340c921d74cSToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
4341c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
4342c921d74cSToby Isaac 
4343c921d74cSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
4344e87a4003SBarry Smith   ierr = DMGetSection(fine,&localFine);CHKERRQ(ierr);
4345e87a4003SBarry Smith   ierr = DMGetGlobalSection(fine,&globalFine);CHKERRQ(ierr);
4346c921d74cSToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
4347c921d74cSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
4348e87a4003SBarry Smith   ierr = DMGetSection(coarse,&localCoarse);CHKERRQ(ierr);
4349e87a4003SBarry Smith   ierr = DMGetGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
4350c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
4351c921d74cSToby Isaac   {
4352c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
4353c921d74cSToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
4354c921d74cSToby Isaac   }
4355c921d74cSToby Isaac 
4356c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,cids,vecFine,numFields,offsets,&multiRootSec,&rootIndicesSec,NULL,&rootValues);CHKERRQ(ierr);
4357c921d74cSToby Isaac 
4358d3bc4906SToby Isaac   ierr = PetscMalloc2(maxDof,&parentIndices,maxDof,&parentValues);CHKERRQ(ierr);
4359c921d74cSToby Isaac 
4360c921d74cSToby Isaac   /* count indices */
436162095d54SToby Isaac   ierr = VecGetLayout(vecFine,&colMap);CHKERRQ(ierr);
436262095d54SToby Isaac   ierr = VecGetLayout(vecCoarse,&rowMap);CHKERRQ(ierr);
4363c921d74cSToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
4364c921d74cSToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
4365c921d74cSToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
4366c921d74cSToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
4367c921d74cSToby Isaac   /* insert values */
4368c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4369c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4370c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
437178b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4372c921d74cSToby Isaac 
4373c921d74cSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
4374c921d74cSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
4375c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
43762f65e181SToby Isaac     ierr = PetscSectionGetDof(localCoarse,p,&dof);CHKERRQ(ierr);
4377c921d74cSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
4378c921d74cSToby Isaac 
4379c921d74cSToby Isaac     rowOffsets[0] = 0;
4380c921d74cSToby Isaac     offsetsCopy[0] = 0;
4381c921d74cSToby Isaac     if (numFields) {
4382c921d74cSToby Isaac       PetscInt f;
4383c921d74cSToby Isaac 
4384c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4385c921d74cSToby Isaac         PetscInt fDof;
4386c921d74cSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
4387c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4388c921d74cSToby Isaac       }
438905586334SMatthew G. Knepley       ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,NULL,parentIndices);CHKERRQ(ierr);
4390367003a6SStefano Zampini     } else {
439105586334SMatthew G. Knepley       ierr = DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,NULL,parentIndices);CHKERRQ(ierr);
4392c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4393c921d74cSToby Isaac     }
4394c921d74cSToby Isaac 
4395c921d74cSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
4396c921d74cSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
4397c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
43982f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4399c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4400c921d74cSToby Isaac       PetscInt numIndices, childId, offset;
4401c921d74cSToby Isaac       const PetscScalar *childValues;
4402c921d74cSToby Isaac 
4403c921d74cSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
4404c921d74cSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
4405c921d74cSToby Isaac       childId = (PetscInt) PetscRealPart(rootValues[offset++]);
4406c921d74cSToby Isaac       childValues = &rootValues[offset];
4407c921d74cSToby Isaac       numIndices--;
4408c921d74cSToby Isaac 
4409c921d74cSToby Isaac       if (childId == -2) { /* skip */
4410c921d74cSToby Isaac         continue;
4411c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
44122f65e181SToby Isaac         PetscInt m;
44132f65e181SToby Isaac 
441478b7adb5SToby Isaac         contribute = PETSC_TRUE;
44152f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4416beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4417d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4418d3bc4906SToby Isaac 
441978b7adb5SToby Isaac         contribute = PETSC_TRUE;
4420d3bc4906SToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
4421d3bc4906SToby Isaac 
4422d3bc4906SToby Isaac         lim = PetscMax(1,numFields);
4423d3bc4906SToby Isaac         offsets[0] = 0;
4424d3bc4906SToby Isaac         if (numFields) {
4425d3bc4906SToby Isaac           PetscInt f;
4426d3bc4906SToby Isaac 
4427d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4428d3bc4906SToby Isaac             PetscInt fDof;
4429d3bc4906SToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
4430d3bc4906SToby Isaac 
4431d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4432d3bc4906SToby Isaac           }
4433d3bc4906SToby Isaac         }
4434d3bc4906SToby Isaac         else {
4435d3bc4906SToby Isaac           PetscInt cDof;
4436d3bc4906SToby Isaac 
4437d3bc4906SToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
4438d3bc4906SToby Isaac           offsets[1] = cDof;
4439d3bc4906SToby Isaac         }
4440d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4441d3bc4906SToby Isaac           PetscScalar       *childMat   = &childrenMats[childId - pRefStart][f][0];
4442d3bc4906SToby Isaac           PetscInt          n           = offsets[f+1]-offsets[f];
4443e328ff09SToby Isaac           PetscInt          m           = rowOffsets[f+1]-rowOffsets[f];
4444d3bc4906SToby Isaac           PetscInt          i, j;
4445d3bc4906SToby Isaac           const PetscScalar *colValues  = &childValues[offsets[f]];
4446d3bc4906SToby Isaac 
4447e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4448d3bc4906SToby Isaac             PetscScalar val = 0.;
4449d3bc4906SToby Isaac             for (j = 0; j < n; j++) {
4450d3bc4906SToby Isaac               val += childMat[n * i + j] * colValues[j];
4451d3bc4906SToby Isaac             }
4452e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4453d3bc4906SToby Isaac           }
4454d3bc4906SToby Isaac         }
4455c921d74cSToby Isaac       }
4456c921d74cSToby Isaac     }
445778b7adb5SToby Isaac     if (contribute) {ierr = VecSetValues(vecCoarse,dof,parentIndices,parentValues,INSERT_VALUES);CHKERRQ(ierr);}
4458c921d74cSToby Isaac   }
4459c921d74cSToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
4460c921d74cSToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
4461d3bc4906SToby Isaac   ierr = PetscFree2(parentIndices,parentValues);CHKERRQ(ierr);
4462c921d74cSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4463c921d74cSToby Isaac   ierr = PetscFree(rootValues);CHKERRQ(ierr);
4464c921d74cSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
4465ebf164c7SToby Isaac   PetscFunctionReturn(0);
4466ebf164c7SToby Isaac }
4467ebf164c7SToby Isaac 
4468ff1f73f7SToby Isaac /*@
4469ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4470ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4471ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4472ff1f73f7SToby Isaac 
4473ff1f73f7SToby Isaac   collective
4474ff1f73f7SToby Isaac 
4475ff1f73f7SToby Isaac   Input Parameters:
4476ff1f73f7SToby Isaac + dmIn        - The DMPlex mesh for the input vector
4477ff1f73f7SToby Isaac . vecIn       - The input vector
4478ff1f73f7SToby Isaac . sfRefine    - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4479ff1f73f7SToby Isaac                 the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4480ff1f73f7SToby Isaac . sfCoarsen   - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4481ff1f73f7SToby Isaac                 the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4482ff1f73f7SToby Isaac . cidsRefine  - The childIds of the points in dmOut.  These childIds relate back to the reference tree: childid[j] = k implies
4483ff1f73f7SToby Isaac                 that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4484ff1f73f7SToby Isaac                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in dmOut is exactly
4485ff1f73f7SToby Isaac                 equivalent to its root in dmIn, so no interpolation is necessary.  childid[j] = -2 indicates that this
4486ff1f73f7SToby Isaac                 point j in dmOut is not a leaf of sfRefine.
4487ff1f73f7SToby Isaac . cidsCoarsen - The childIds of the points in dmIn.  These childIds relate back to the reference tree: childid[j] = k implies
4488ff1f73f7SToby Isaac                 that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4489ff1f73f7SToby Isaac                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4490ff1f73f7SToby Isaac . useBCs      - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4491ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4492ff1f73f7SToby Isaac 
4493ff1f73f7SToby Isaac   Output Parameters:
4494ff1f73f7SToby Isaac . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transfered
4495ff1f73f7SToby Isaac                 projection of vecIn from dmIn to dmOut.  Note that any field discretized with a PetscFV finite volume
4496ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4497ff1f73f7SToby Isaac                 coarse points to fine points.
4498ff1f73f7SToby Isaac 
4499ff1f73f7SToby Isaac   Level: developer
4500ff1f73f7SToby Isaac 
4501ff1f73f7SToby Isaac .seealso(): DMPlexSetReferenceTree(), DMPlexGetReferenceTree(), PetscFVGetComputeGradients()
4502ff1f73f7SToby Isaac @*/
4503ff1f73f7SToby Isaac PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
450438fc2455SToby Isaac {
4505ebf164c7SToby Isaac   PetscErrorCode ierr;
4506ebf164c7SToby Isaac 
450738fc2455SToby Isaac   PetscFunctionBegin;
450878b7adb5SToby Isaac   ierr = VecSet(vecOut,0.0);CHKERRQ(ierr);
4509ff1f73f7SToby Isaac   if (sfRefine) {
4510fbfa57b9SToby Isaac     Vec vecInLocal;
45110eb7e1eaSToby Isaac     DM  dmGrad = NULL;
45120eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4513fbfa57b9SToby Isaac 
4514fbfa57b9SToby Isaac     ierr = DMGetLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
4515fbfa57b9SToby Isaac     ierr = VecSet(vecInLocal,0.0);CHKERRQ(ierr);
45160eb7e1eaSToby Isaac     {
45170eb7e1eaSToby Isaac       PetscInt  numFields, i;
45180eb7e1eaSToby Isaac 
45190eb7e1eaSToby Isaac       ierr = DMGetNumFields(dmIn, &numFields);CHKERRQ(ierr);
45200eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
45210eb7e1eaSToby Isaac         PetscObject  obj;
45220eb7e1eaSToby Isaac         PetscClassId classid;
45230eb7e1eaSToby Isaac 
452444a7f3ddSMatthew G. Knepley         ierr = DMGetField(dmIn, i, NULL, &obj);CHKERRQ(ierr);
45250eb7e1eaSToby Isaac         ierr = PetscObjectGetClassId(obj, &classid);CHKERRQ(ierr);
45260eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
45270eb7e1eaSToby Isaac           ierr = DMPlexGetDataFVM(dmIn,(PetscFV)obj,&cellGeom,&faceGeom,&dmGrad);CHKERRQ(ierr);
45280eb7e1eaSToby Isaac           break;
45290eb7e1eaSToby Isaac         }
45300eb7e1eaSToby Isaac       }
45310eb7e1eaSToby Isaac     }
45320eb7e1eaSToby Isaac     if (useBCs) {
45330eb7e1eaSToby Isaac       ierr = DMPlexInsertBoundaryValues(dmIn,PETSC_TRUE,vecInLocal,time,faceGeom,cellGeom,NULL);CHKERRQ(ierr);
45340eb7e1eaSToby Isaac     }
4535fbfa57b9SToby Isaac     ierr = DMGlobalToLocalBegin(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
4536fbfa57b9SToby Isaac     ierr = DMGlobalToLocalEnd(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
45370eb7e1eaSToby Isaac     if (dmGrad) {
45380eb7e1eaSToby Isaac       ierr = DMGetGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
45390eb7e1eaSToby Isaac       ierr = DMPlexReconstructGradientsFVM(dmIn,vecInLocal,grad);CHKERRQ(ierr);
45400eb7e1eaSToby Isaac     }
4541ff1f73f7SToby Isaac     ierr = DMPlexTransferVecTree_Interpolate(dmIn,vecInLocal,dmOut,vecOut,sfRefine,cidsRefine,grad,cellGeom);CHKERRQ(ierr);
4542fbfa57b9SToby Isaac     ierr = DMRestoreLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
45430eb7e1eaSToby Isaac     if (dmGrad) {
45440eb7e1eaSToby Isaac       ierr = DMRestoreGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
45450eb7e1eaSToby Isaac     }
4546ebf164c7SToby Isaac   }
4547ff1f73f7SToby Isaac   if (sfCoarsen) {
4548ff1f73f7SToby Isaac     ierr = DMPlexTransferVecTree_Inject(dmIn,vecIn,dmOut,vecOut,sfCoarsen,cidsCoarsen);CHKERRQ(ierr);
4549ebf164c7SToby Isaac   }
45502f65e181SToby Isaac   ierr = VecAssemblyBegin(vecOut);CHKERRQ(ierr);
45512f65e181SToby Isaac   ierr = VecAssemblyEnd(vecOut);CHKERRQ(ierr);
455238fc2455SToby Isaac   PetscFunctionReturn(0);
455338fc2455SToby Isaac }
4554