xref: /petsc/src/dm/impls/plex/plextree.c (revision 2c71b3e237ead271e4f3aa1505f92bf476e3413d)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2af0996ceSBarry Smith #include <petsc/private/isimpl.h>
3af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
4d6a7ad0dSToby Isaac #include <petscsf.h>
50c37af3bSToby Isaac #include <petscds.h>
6d6a7ad0dSToby Isaac 
70e3d61c9SBarry Smith /* hierarchy routines */
8d6a7ad0dSToby Isaac 
9d6a7ad0dSToby Isaac /*@
10d6a7ad0dSToby Isaac   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
11d6a7ad0dSToby Isaac 
12d6a7ad0dSToby Isaac   Not collective
13d6a7ad0dSToby Isaac 
14d6a7ad0dSToby Isaac   Input Parameters:
15d6a7ad0dSToby Isaac + dm - The DMPlex object
16d6a7ad0dSToby Isaac - ref - The reference tree DMPlex object
17d6a7ad0dSToby Isaac 
180b7167a0SToby Isaac   Level: intermediate
19d6a7ad0dSToby Isaac 
20da43764aSToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexCreateDefaultReferenceTree()
21d6a7ad0dSToby Isaac @*/
22d6a7ad0dSToby Isaac PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
23d6a7ad0dSToby Isaac {
24d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
25d6a7ad0dSToby Isaac   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 
447a7aea1fSJed Brown   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   }
79*2c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dim > 2,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim);
80*2c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!dim,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     }
100*2c71b3e2SJacob Faibussowitsch     PetscCheckFalse(i == size,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) {
117b5a892a1SMatthew G. Knepley           DMPolytopeType ct;
118dcbd3bf7SToby Isaac           PetscInt       oBtrue;
119dcbd3bf7SToby Isaac 
120dcbd3bf7SToby Isaac           ierr          = DMPlexGetConeSize(dm,childA,&coneSize);CHKERRQ(ierr);
121dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
122*2c71b3e2SJacob Faibussowitsch           PetscCheckFalse(coneSize != 0 && coneSize != 2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
123b5a892a1SMatthew G. Knepley           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
124dcbd3bf7SToby Isaac           /* we may have to flip an edge */
125b5a892a1SMatthew G. Knepley           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientation(ct, -1, oB[j]);
126b5a892a1SMatthew G. Knepley           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
127b5a892a1SMatthew G. Knepley           ABswap        = DihedralSwap(coneSize,DMPolytopeConvertNewOrientation_Internal(ct, oA[i]),oBtrue);
128dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
129dcbd3bf7SToby Isaac         }
130dcbd3bf7SToby Isaac         break;
131dcbd3bf7SToby Isaac       }
132dcbd3bf7SToby Isaac     }
133*2c71b3e2SJacob Faibussowitsch     PetscCheckFalse(i == sConeSize,PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
134dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
135dcbd3bf7SToby Isaac   }
136dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
137dcbd3bf7SToby Isaac   ierr   = DMPlexGetConeSize(dm,parent,&coneSize);CHKERRQ(ierr);
138dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
139dcbd3bf7SToby Isaac   if (dim == 2) {
140dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
141dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
142dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
143dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
144dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
145dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
146947b95d8SBarry Smith   } else {
147dcbd3bf7SToby Isaac     ABswapVert = ABswap;
148dcbd3bf7SToby Isaac   }
149dcbd3bf7SToby Isaac   if (childB) {
150dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
151dcbd3bf7SToby Isaac     PetscInt p, posA = -1, numChildren, i;
152dcbd3bf7SToby Isaac     const PetscInt *children;
153dcbd3bf7SToby Isaac 
154dcbd3bf7SToby Isaac     /* count which position the child is in */
155dcbd3bf7SToby Isaac     ierr = DMPlexGetTreeChildren(dm,parent,&numChildren,&children);CHKERRQ(ierr);
156dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
157dcbd3bf7SToby Isaac       p = children[i];
158dcbd3bf7SToby Isaac       if (p == childA) {
159dcbd3bf7SToby Isaac         posA = i;
160dcbd3bf7SToby Isaac         break;
161dcbd3bf7SToby Isaac       }
162dcbd3bf7SToby Isaac     }
163dcbd3bf7SToby Isaac     if (posA >= coneSize) {
164dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
165dcbd3bf7SToby Isaac        * is invariant */
166*2c71b3e2SJacob Faibussowitsch       PetscCheckFalse(dim != 2 || posA != 3,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Expected a middle triangle, got something else");
167dcbd3bf7SToby Isaac       *childB = childA;
168dcbd3bf7SToby Isaac     }
169dcbd3bf7SToby Isaac     else {
170dcbd3bf7SToby Isaac       /* figure out position B by applying ABswapVert */
171dcbd3bf7SToby Isaac       PetscInt posB;
172dcbd3bf7SToby Isaac 
173dcbd3bf7SToby Isaac       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
174dcbd3bf7SToby Isaac       if (childB) *childB = children[posB];
175dcbd3bf7SToby Isaac     }
176dcbd3bf7SToby Isaac   }
177dcbd3bf7SToby Isaac   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
178dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
179dcbd3bf7SToby Isaac }
180dcbd3bf7SToby Isaac 
181dcbd3bf7SToby Isaac /*@
182dcbd3bf7SToby Isaac   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
183dcbd3bf7SToby Isaac 
184dcbd3bf7SToby Isaac   Input Parameters:
185dcbd3bf7SToby Isaac + dm - the reference tree DMPlex object
186dcbd3bf7SToby Isaac . parent - the parent point
187dcbd3bf7SToby Isaac . parentOrientA - the reference orientation for describing the parent
188dcbd3bf7SToby Isaac . childOrientA - the reference orientation for describing the child
189dcbd3bf7SToby Isaac . childA - the reference childID for describing the child
190dcbd3bf7SToby Isaac - parentOrientB - the new orientation for describing the parent
191dcbd3bf7SToby Isaac 
192dcbd3bf7SToby Isaac   Output Parameters:
193dcbd3bf7SToby Isaac + childOrientB - if not NULL, set to the new oreintation for describing the child
194ff1f73f7SToby Isaac - childB - if not NULL, the new childID for describing the child
195dcbd3bf7SToby Isaac 
196dcbd3bf7SToby Isaac   Level: developer
197dcbd3bf7SToby Isaac 
198dcbd3bf7SToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexSetReferenceTree(), DMPlexSetTree()
199dcbd3bf7SToby Isaac @*/
200dcbd3bf7SToby Isaac PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
201dcbd3bf7SToby Isaac {
202dcbd3bf7SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
203dcbd3bf7SToby Isaac   PetscErrorCode ierr;
204dcbd3bf7SToby Isaac 
205dcbd3bf7SToby Isaac   PetscFunctionBegin;
206dcbd3bf7SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
207*2c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!mesh->getchildsymmetry,PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlexReferenceTreeGetChildSymmetry not implemented");
208dcbd3bf7SToby Isaac   ierr = mesh->getchildsymmetry(dm,parent,parentOrientA,childOrientA,childA,parentOrientB,childOrientB,childB);CHKERRQ(ierr);
209dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
210dcbd3bf7SToby Isaac }
211dcbd3bf7SToby Isaac 
212776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM,PetscSection,PetscInt*,PetscInt*,PetscBool,PetscBool);
213f9f063d4SToby Isaac 
214f2c1aa1dSLisandro Dalcin PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
215f2c1aa1dSLisandro Dalcin {
216f2c1aa1dSLisandro Dalcin   PetscErrorCode ierr;
217f2c1aa1dSLisandro Dalcin 
218f2c1aa1dSLisandro Dalcin   PetscFunctionBegin;
219f2c1aa1dSLisandro Dalcin   ierr = DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
220f2c1aa1dSLisandro Dalcin   PetscFunctionReturn(0);
221f2c1aa1dSLisandro Dalcin }
222f2c1aa1dSLisandro Dalcin 
2230e2cc29aSToby Isaac PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
224da43764aSToby Isaac {
2250e2cc29aSToby Isaac   MPI_Comm       comm;
2260e2cc29aSToby Isaac   PetscInt       dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
227da43764aSToby Isaac   PetscInt      *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
228da43764aSToby Isaac   DMLabel        identity, identityRef;
22910f7e118SToby Isaac   PetscSection   unionSection, unionConeSection, parentSection;
230da43764aSToby Isaac   PetscScalar   *unionCoords;
231da43764aSToby Isaac   IS             perm;
232da43764aSToby Isaac   PetscErrorCode ierr;
233da43764aSToby Isaac 
234da43764aSToby Isaac   PetscFunctionBegin;
2350e2cc29aSToby Isaac   comm = PetscObjectComm((PetscObject)K);
2360e2cc29aSToby Isaac   ierr = DMGetDimension(K, &dim);CHKERRQ(ierr);
237da43764aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
2380e2cc29aSToby Isaac   ierr = DMGetLabel(K, labelName, &identity);CHKERRQ(ierr);
2390e2cc29aSToby Isaac   ierr = DMGetLabel(Kref, labelName, &identityRef);CHKERRQ(ierr);
240da43764aSToby Isaac   ierr = DMPlexGetChart(Kref, &pRefStart, &pRefEnd);CHKERRQ(ierr);
241da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionSection);CHKERRQ(ierr);
242da43764aSToby Isaac   ierr = PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart));CHKERRQ(ierr);
243da43764aSToby Isaac   /* count points that will go in the union */
244da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
245da43764aSToby Isaac     ierr = PetscSectionSetDof(unionSection, p - pStart, 1);CHKERRQ(ierr);
246da43764aSToby Isaac   }
247da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
248da43764aSToby Isaac     PetscInt q, qSize;
249da43764aSToby Isaac     ierr = DMLabelGetValue(identityRef, p, &q);CHKERRQ(ierr);
250da43764aSToby Isaac     ierr = DMLabelGetStratumSize(identityRef, q, &qSize);CHKERRQ(ierr);
251da43764aSToby Isaac     if (qSize > 1) {
252da43764aSToby Isaac       ierr = PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1);CHKERRQ(ierr);
253da43764aSToby Isaac     }
254da43764aSToby Isaac   }
255854ce69bSBarry Smith   ierr = PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart,&permvals);CHKERRQ(ierr);
256da43764aSToby Isaac   offset = 0;
257da43764aSToby Isaac   /* stratify points in the union by topological dimension */
258da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
259da43764aSToby Isaac     PetscInt cStart, cEnd, c;
260da43764aSToby Isaac 
261da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K, d, &cStart, &cEnd);CHKERRQ(ierr);
262da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
263da43764aSToby Isaac       permvals[offset++] = c;
264da43764aSToby Isaac     }
265da43764aSToby Isaac 
266da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd);CHKERRQ(ierr);
267da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
268da43764aSToby Isaac       permvals[offset++] = c + (pEnd - pStart);
269da43764aSToby Isaac     }
270da43764aSToby Isaac   }
271da43764aSToby Isaac   ierr = ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm);CHKERRQ(ierr);
272da43764aSToby Isaac   ierr = PetscSectionSetPermutation(unionSection,perm);CHKERRQ(ierr);
273da43764aSToby Isaac   ierr = PetscSectionSetUp(unionSection);CHKERRQ(ierr);
274da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionSection,&numUnionPoints);CHKERRQ(ierr);
275da43764aSToby Isaac   ierr = PetscMalloc2(numUnionPoints,&coneSizes,dim+1,&numDimPoints);CHKERRQ(ierr);
276da43764aSToby Isaac   /* count dimension points */
277da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
278da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
279da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K,d,&cStart,NULL);CHKERRQ(ierr);
280da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff);CHKERRQ(ierr);
281da43764aSToby Isaac     if (d < dim) {
282da43764aSToby Isaac       ierr = DMPlexGetHeightStratum(K,d+1,&cStart,NULL);CHKERRQ(ierr);
283da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff2);CHKERRQ(ierr);
284da43764aSToby Isaac     }
285da43764aSToby Isaac     else {
286da43764aSToby Isaac       cOff2 = numUnionPoints;
287da43764aSToby Isaac     }
288da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
289da43764aSToby Isaac   }
290da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionConeSection);CHKERRQ(ierr);
291da43764aSToby Isaac   ierr = PetscSectionSetChart(unionConeSection, 0, numUnionPoints);CHKERRQ(ierr);
292da43764aSToby Isaac   /* count the cones in the union */
293da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
294da43764aSToby Isaac     PetscInt dof, uOff;
295da43764aSToby Isaac 
296da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
297da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
298da43764aSToby Isaac     ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
299da43764aSToby Isaac     coneSizes[uOff] = dof;
300da43764aSToby Isaac   }
301da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
302da43764aSToby Isaac     PetscInt dof, uDof, uOff;
303da43764aSToby Isaac 
304da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
305da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
306da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
307da43764aSToby Isaac     if (uDof) {
308da43764aSToby Isaac       ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
309da43764aSToby Isaac       coneSizes[uOff] = dof;
310da43764aSToby Isaac     }
311da43764aSToby Isaac   }
312da43764aSToby Isaac   ierr = PetscSectionSetUp(unionConeSection);CHKERRQ(ierr);
313da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionConeSection,&numCones);CHKERRQ(ierr);
314da43764aSToby Isaac   ierr = PetscMalloc2(numCones,&unionCones,numCones,&unionOrientations);CHKERRQ(ierr);
315da43764aSToby Isaac   /* write the cones in the union */
316da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
317da43764aSToby Isaac     PetscInt dof, uOff, c, cOff;
318da43764aSToby Isaac     const PetscInt *cone, *orientation;
319da43764aSToby Isaac 
320da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
321da43764aSToby Isaac     ierr = DMPlexGetCone(K, p, &cone);CHKERRQ(ierr);
322da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(K, p, &orientation);CHKERRQ(ierr);
323da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
324da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
325da43764aSToby Isaac     for (c = 0; c < dof; c++) {
326da43764aSToby Isaac       PetscInt e, eOff;
327da43764aSToby Isaac       e                           = cone[c];
328da43764aSToby Isaac       ierr                        = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
329da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
330da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
331da43764aSToby Isaac     }
332da43764aSToby Isaac   }
333da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
334da43764aSToby Isaac     PetscInt dof, uDof, uOff, c, cOff;
335da43764aSToby Isaac     const PetscInt *cone, *orientation;
336da43764aSToby Isaac 
337da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
338da43764aSToby Isaac     ierr = DMPlexGetCone(Kref, p, &cone);CHKERRQ(ierr);
339da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(Kref, p, &orientation);CHKERRQ(ierr);
340da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
341da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
342da43764aSToby Isaac     if (uDof) {
343da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
344da43764aSToby Isaac       for (c = 0; c < dof; c++) {
345da43764aSToby Isaac         PetscInt e, eOff, eDof;
346da43764aSToby Isaac 
347da43764aSToby Isaac         e    = cone[c];
348da43764aSToby Isaac         ierr = PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart),&eDof);CHKERRQ(ierr);
349da43764aSToby Isaac         if (eDof) {
350da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff);CHKERRQ(ierr);
351da43764aSToby Isaac         }
352da43764aSToby Isaac         else {
353da43764aSToby Isaac           ierr = DMLabelGetValue(identityRef, e, &e);CHKERRQ(ierr);
354da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
355da43764aSToby Isaac         }
356da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
357da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
358da43764aSToby Isaac       }
359da43764aSToby Isaac     }
360da43764aSToby Isaac   }
361da43764aSToby Isaac   /* get the coordinates */
362da43764aSToby Isaac   {
363da43764aSToby Isaac     PetscInt     vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
364da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
365da43764aSToby Isaac     Vec          KcoordsVec, KrefCoordsVec;
366da43764aSToby Isaac     PetscScalar *Kcoords;
367da43764aSToby Isaac 
368367003a6SStefano Zampini     ierr = DMGetCoordinateSection(K, &KcoordsSec);CHKERRQ(ierr);
369367003a6SStefano Zampini     ierr = DMGetCoordinatesLocal(K, &KcoordsVec);CHKERRQ(ierr);
370367003a6SStefano Zampini     ierr = DMGetCoordinateSection(Kref, &KrefCoordsSec);CHKERRQ(ierr);
371367003a6SStefano Zampini     ierr = DMGetCoordinatesLocal(Kref, &KrefCoordsVec);CHKERRQ(ierr);
372da43764aSToby Isaac 
373da43764aSToby Isaac     numVerts = numDimPoints[0];
374da43764aSToby Isaac     ierr     = PetscMalloc1(numVerts * dim,&unionCoords);CHKERRQ(ierr);
375da43764aSToby Isaac     ierr     = DMPlexGetDepthStratum(K,0,&vStart,&vEnd);CHKERRQ(ierr);
376da43764aSToby Isaac 
377da43764aSToby Isaac     offset = 0;
378da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
379da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pStart,&vOff);CHKERRQ(ierr);
380da43764aSToby Isaac       ierr = VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords);CHKERRQ(ierr);
381da43764aSToby Isaac       for (d = 0; d < dim; d++) {
382da43764aSToby Isaac         unionCoords[offset * dim + d] = Kcoords[d];
383da43764aSToby Isaac       }
384da43764aSToby Isaac       offset++;
385da43764aSToby Isaac     }
386da43764aSToby Isaac     ierr = DMPlexGetDepthStratum(Kref,0,&vRefStart,&vRefEnd);CHKERRQ(ierr);
387da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
388da43764aSToby Isaac       ierr = PetscSectionGetDof(unionSection,v - pRefStart + (pEnd - pStart),&vDof);CHKERRQ(ierr);
389da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pRefStart + (pEnd - pStart),&vOff);CHKERRQ(ierr);
390da43764aSToby Isaac       ierr = VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords);CHKERRQ(ierr);
391da43764aSToby Isaac       if (vDof) {
392da43764aSToby Isaac         for (d = 0; d < dim; d++) {
393da43764aSToby Isaac           unionCoords[offset * dim + d] = Kcoords[d];
394da43764aSToby Isaac         }
395da43764aSToby Isaac         offset++;
396da43764aSToby Isaac       }
397da43764aSToby Isaac     }
398da43764aSToby Isaac   }
399da43764aSToby Isaac   ierr = DMCreate(comm,ref);CHKERRQ(ierr);
400da43764aSToby Isaac   ierr = DMSetType(*ref,DMPLEX);CHKERRQ(ierr);
40128f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ref,dim);CHKERRQ(ierr);
402da43764aSToby Isaac   ierr = DMPlexCreateFromDAG(*ref,dim,numDimPoints,coneSizes,unionCones,unionOrientations,unionCoords);CHKERRQ(ierr);
40310f7e118SToby Isaac   /* set the tree */
40410f7e118SToby Isaac   ierr = PetscSectionCreate(comm,&parentSection);CHKERRQ(ierr);
40510f7e118SToby Isaac   ierr = PetscSectionSetChart(parentSection,0,numUnionPoints);CHKERRQ(ierr);
40610f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
40710f7e118SToby Isaac     PetscInt uDof, uOff;
40810f7e118SToby Isaac 
40910f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
41010f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
41110f7e118SToby Isaac     if (uDof) {
412367003a6SStefano Zampini       ierr = PetscSectionSetDof(parentSection,uOff,1);CHKERRQ(ierr);
41310f7e118SToby Isaac     }
41410f7e118SToby Isaac   }
41510f7e118SToby Isaac   ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
41610f7e118SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&parentSize);CHKERRQ(ierr);
41710f7e118SToby Isaac   ierr = PetscMalloc2(parentSize,&parents,parentSize,&childIDs);CHKERRQ(ierr);
41810f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
41910f7e118SToby Isaac     PetscInt uDof, uOff;
42010f7e118SToby Isaac 
42110f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
42210f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
42310f7e118SToby Isaac     if (uDof) {
42410f7e118SToby Isaac       PetscInt pOff, parent, parentU;
425367003a6SStefano Zampini       ierr = PetscSectionGetOffset(parentSection,uOff,&pOff);CHKERRQ(ierr);
426367003a6SStefano Zampini       ierr = DMLabelGetValue(identityRef,p,&parent);CHKERRQ(ierr);
42710f7e118SToby Isaac       ierr = PetscSectionGetOffset(unionSection, parent - pStart,&parentU);CHKERRQ(ierr);
42810f7e118SToby Isaac       parents[pOff] = parentU;
42910f7e118SToby Isaac       childIDs[pOff] = uOff;
43010f7e118SToby Isaac     }
43110f7e118SToby Isaac   }
432f2c1aa1dSLisandro Dalcin   ierr = DMPlexCreateReferenceTree_SetTree(*ref,parentSection,parents,childIDs);CHKERRQ(ierr);
43310f7e118SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
43410f7e118SToby Isaac   ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
43510f7e118SToby Isaac 
436da43764aSToby Isaac   /* clean up */
437da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionSection);CHKERRQ(ierr);
438da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionConeSection);CHKERRQ(ierr);
439da43764aSToby Isaac   ierr = ISDestroy(&perm);CHKERRQ(ierr);
440da43764aSToby Isaac   ierr = PetscFree(unionCoords);CHKERRQ(ierr);
441da43764aSToby Isaac   ierr = PetscFree2(unionCones,unionOrientations);CHKERRQ(ierr);
442da43764aSToby Isaac   ierr = PetscFree2(coneSizes,numDimPoints);CHKERRQ(ierr);
4430e2cc29aSToby Isaac   PetscFunctionReturn(0);
4440e2cc29aSToby Isaac }
4450e2cc29aSToby Isaac 
4460e2cc29aSToby Isaac /*@
4470e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4480e2cc29aSToby Isaac 
449d083f849SBarry Smith   Collective
4500e2cc29aSToby Isaac 
4510e2cc29aSToby Isaac   Input Parameters:
4520e2cc29aSToby Isaac + comm    - the MPI communicator
4530e2cc29aSToby Isaac . dim     - the spatial dimension
4540e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4550e2cc29aSToby Isaac 
4560e2cc29aSToby Isaac   Output Parameters:
4570e2cc29aSToby Isaac . ref     - the reference tree DMPlex object
4580e2cc29aSToby Isaac 
4590e2cc29aSToby Isaac   Level: intermediate
4600e2cc29aSToby Isaac 
4610e2cc29aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree()
4620e2cc29aSToby Isaac @*/
4630e2cc29aSToby Isaac PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
4640e2cc29aSToby Isaac {
4650e2cc29aSToby Isaac   DM_Plex       *mesh;
4660e2cc29aSToby Isaac   DM             K, Kref;
4670e2cc29aSToby Isaac   PetscInt       p, pStart, pEnd;
4680e2cc29aSToby Isaac   DMLabel        identity;
4690e2cc29aSToby Isaac   PetscErrorCode ierr;
4700e2cc29aSToby Isaac 
4710e2cc29aSToby Isaac   PetscFunctionBegin;
4720e2cc29aSToby Isaac #if 1
4730e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4740e2cc29aSToby Isaac #endif
4750e2cc29aSToby Isaac   /* create a reference element */
4769318fe57SMatthew G. Knepley   ierr = DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K);CHKERRQ(ierr);
4770e2cc29aSToby Isaac   ierr = DMCreateLabel(K, "identity");CHKERRQ(ierr);
4780e2cc29aSToby Isaac   ierr = DMGetLabel(K, "identity", &identity);CHKERRQ(ierr);
4790e2cc29aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
4800e2cc29aSToby Isaac   for (p = pStart; p < pEnd; p++) {
4810e2cc29aSToby Isaac     ierr = DMLabelSetValue(identity, p, p);CHKERRQ(ierr);
4820e2cc29aSToby Isaac   }
4830e2cc29aSToby Isaac   /* refine it */
4840e2cc29aSToby Isaac   ierr = DMRefine(K,comm,&Kref);CHKERRQ(ierr);
4850e2cc29aSToby Isaac 
4860e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4870e2cc29aSToby Isaac    * points that appear in both */
4880e2cc29aSToby Isaac   ierr = DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref);CHKERRQ(ierr);
4890e2cc29aSToby Isaac   mesh = (DM_Plex *) (*ref)->data;
4900e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
491da43764aSToby Isaac   ierr = DMDestroy(&K);CHKERRQ(ierr);
492da43764aSToby Isaac   ierr = DMDestroy(&Kref);CHKERRQ(ierr);
493da43764aSToby Isaac   PetscFunctionReturn(0);
494da43764aSToby Isaac }
495da43764aSToby Isaac 
496878b19aaSToby Isaac static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
497878b19aaSToby Isaac {
498878b19aaSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
499878b19aaSToby Isaac   PetscSection   childSec, pSec;
500878b19aaSToby Isaac   PetscInt       p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
501878b19aaSToby Isaac   PetscInt       *offsets, *children, pStart, pEnd;
502878b19aaSToby Isaac   PetscErrorCode ierr;
503878b19aaSToby Isaac 
504878b19aaSToby Isaac   PetscFunctionBegin;
505878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
506878b19aaSToby Isaac   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
507878b19aaSToby Isaac   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
508878b19aaSToby Isaac   pSec = mesh->parentSection;
509878b19aaSToby Isaac   if (!pSec) PetscFunctionReturn(0);
510878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(pSec,&pSize);CHKERRQ(ierr);
511878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
512878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
513878b19aaSToby Isaac 
514878b19aaSToby Isaac     parMax = PetscMax(parMax,par+1);
515878b19aaSToby Isaac     parMin = PetscMin(parMin,par);
516878b19aaSToby Isaac   }
517878b19aaSToby Isaac   if (parMin > parMax) {
518878b19aaSToby Isaac     parMin = -1;
519878b19aaSToby Isaac     parMax = -1;
520878b19aaSToby Isaac   }
521878b19aaSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)pSec),&childSec);CHKERRQ(ierr);
522878b19aaSToby Isaac   ierr = PetscSectionSetChart(childSec,parMin,parMax);CHKERRQ(ierr);
523878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
524878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
525878b19aaSToby Isaac 
526878b19aaSToby Isaac     ierr = PetscSectionAddDof(childSec,par,1);CHKERRQ(ierr);
527878b19aaSToby Isaac   }
528878b19aaSToby Isaac   ierr = PetscSectionSetUp(childSec);CHKERRQ(ierr);
529878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(childSec,&cSize);CHKERRQ(ierr);
530878b19aaSToby Isaac   ierr = PetscMalloc1(cSize,&children);CHKERRQ(ierr);
531878b19aaSToby Isaac   ierr = PetscCalloc1(parMax-parMin,&offsets);CHKERRQ(ierr);
532878b19aaSToby Isaac   ierr = PetscSectionGetChart(pSec,&pStart,&pEnd);CHKERRQ(ierr);
533878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
534878b19aaSToby Isaac     PetscInt dof, off, i;
535878b19aaSToby Isaac 
536878b19aaSToby Isaac     ierr = PetscSectionGetDof(pSec,p,&dof);CHKERRQ(ierr);
537878b19aaSToby Isaac     ierr = PetscSectionGetOffset(pSec,p,&off);CHKERRQ(ierr);
538878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
539878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
540878b19aaSToby Isaac 
541878b19aaSToby Isaac       ierr = PetscSectionGetOffset(childSec,par,&cOff);CHKERRQ(ierr);
542878b19aaSToby Isaac       children[cOff + offsets[par-parMin]++] = p;
543878b19aaSToby Isaac     }
544878b19aaSToby Isaac   }
545878b19aaSToby Isaac   mesh->childSection = childSec;
546878b19aaSToby Isaac   mesh->children = children;
547878b19aaSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
548878b19aaSToby Isaac   PetscFunctionReturn(0);
549878b19aaSToby Isaac }
550878b19aaSToby Isaac 
5516dd5a8c8SToby Isaac static PetscErrorCode AnchorsFlatten (PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
5526dd5a8c8SToby Isaac {
5536dd5a8c8SToby Isaac   PetscInt       pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5546dd5a8c8SToby Isaac   const PetscInt *vals;
5556dd5a8c8SToby Isaac   PetscSection   secNew;
5566dd5a8c8SToby Isaac   PetscBool      anyNew, globalAnyNew;
5576dd5a8c8SToby Isaac   PetscBool      compress;
5586dd5a8c8SToby Isaac   PetscErrorCode ierr;
5596dd5a8c8SToby Isaac 
5606dd5a8c8SToby Isaac   PetscFunctionBegin;
5616dd5a8c8SToby Isaac   ierr = PetscSectionGetChart(section,&pStart,&pEnd);CHKERRQ(ierr);
5626dd5a8c8SToby Isaac   ierr = ISGetLocalSize(is,&size);CHKERRQ(ierr);
5636dd5a8c8SToby Isaac   ierr = ISGetIndices(is,&vals);CHKERRQ(ierr);
5646dd5a8c8SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secNew);CHKERRQ(ierr);
5656dd5a8c8SToby Isaac   ierr = PetscSectionSetChart(secNew,pStart,pEnd);CHKERRQ(ierr);
5666dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5676dd5a8c8SToby Isaac     PetscInt dof;
5686dd5a8c8SToby Isaac 
5696dd5a8c8SToby Isaac     p = vals[i];
5706dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5716dd5a8c8SToby Isaac     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5726dd5a8c8SToby Isaac     if (dof) break;
5736dd5a8c8SToby Isaac   }
5746dd5a8c8SToby Isaac   if (i == size) {
5756dd5a8c8SToby Isaac     ierr     = PetscSectionSetUp(secNew);CHKERRQ(ierr);
5766dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5776dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5786dd5a8c8SToby Isaac     sizeNew  = 0;
5796dd5a8c8SToby Isaac   }
5806dd5a8c8SToby Isaac   else {
5816dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5826dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5836dd5a8c8SToby Isaac       PetscInt dof, off;
5846dd5a8c8SToby Isaac 
5856dd5a8c8SToby Isaac       ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5866dd5a8c8SToby Isaac       ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
5876dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5886dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5896dd5a8c8SToby Isaac 
5906dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5916dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
5926dd5a8c8SToby Isaac         }
5936dd5a8c8SToby Isaac         if (qDof) {
5946dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, qDof);CHKERRQ(ierr);
5956dd5a8c8SToby Isaac         }
5966dd5a8c8SToby Isaac         else {
5976dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, 1);CHKERRQ(ierr);
5986dd5a8c8SToby Isaac         }
5996dd5a8c8SToby Isaac       }
6006dd5a8c8SToby Isaac     }
6016dd5a8c8SToby Isaac     ierr = PetscSectionSetUp(secNew);CHKERRQ(ierr);
6026dd5a8c8SToby Isaac     ierr = PetscSectionGetStorageSize(secNew,&sizeNew);CHKERRQ(ierr);
6036dd5a8c8SToby Isaac     ierr = PetscMalloc1(sizeNew,&valsNew);CHKERRQ(ierr);
6046dd5a8c8SToby Isaac     compress = PETSC_FALSE;
6056dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
6066dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
6076dd5a8c8SToby Isaac 
6086dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
6096dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
6106dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(secNew, p, &dofNew);CHKERRQ(ierr);
6116dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(secNew, p, &offNew);CHKERRQ(ierr);
6126dd5a8c8SToby Isaac       count = 0;
6136dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
6146dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
6156dd5a8c8SToby Isaac 
6166dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
6176dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
6186dd5a8c8SToby Isaac           ierr = PetscSectionGetOffset(section, q, &qOff);CHKERRQ(ierr);
6196dd5a8c8SToby Isaac         }
6206dd5a8c8SToby Isaac         if (qDof) {
6216dd5a8c8SToby Isaac           PetscInt oldCount = count;
6226dd5a8c8SToby Isaac 
6236dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
6246dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
6256dd5a8c8SToby Isaac 
6266dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
6276dd5a8c8SToby Isaac               if (valsNew[offNew + k] == r) {
6286dd5a8c8SToby Isaac                 break;
6296dd5a8c8SToby Isaac               }
6306dd5a8c8SToby Isaac             }
6316dd5a8c8SToby Isaac             if (k == oldCount) {
6326dd5a8c8SToby Isaac               valsNew[offNew + count++] = r;
6336dd5a8c8SToby Isaac             }
6346dd5a8c8SToby Isaac           }
6356dd5a8c8SToby Isaac         }
6366dd5a8c8SToby Isaac         else {
6376dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
6386dd5a8c8SToby Isaac 
6396dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
6406dd5a8c8SToby Isaac             if (valsNew[offNew + k] == q) {
6416dd5a8c8SToby Isaac               break;
6426dd5a8c8SToby Isaac             }
6436dd5a8c8SToby Isaac           }
6446dd5a8c8SToby Isaac           if (k == oldCount) {
6456dd5a8c8SToby Isaac             valsNew[offNew + count++] = q;
6466dd5a8c8SToby Isaac           }
6476dd5a8c8SToby Isaac         }
6486dd5a8c8SToby Isaac       }
6496dd5a8c8SToby Isaac       if (count < dofNew) {
6506dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secNew, p, count);CHKERRQ(ierr);
6516dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6526dd5a8c8SToby Isaac       }
6536dd5a8c8SToby Isaac     }
6546dd5a8c8SToby Isaac   }
6556dd5a8c8SToby Isaac   ierr = ISRestoreIndices(is,&vals);CHKERRQ(ierr);
656820f2d46SBarry Smith   ierr = MPIU_Allreduce(&anyNew,&globalAnyNew,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRMPI(ierr);
6576dd5a8c8SToby Isaac   if (!globalAnyNew) {
6586dd5a8c8SToby Isaac     ierr = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6596dd5a8c8SToby Isaac     *sectionNew = NULL;
6606dd5a8c8SToby Isaac     *isNew = NULL;
6616dd5a8c8SToby Isaac   }
6626dd5a8c8SToby Isaac   else {
6636dd5a8c8SToby Isaac     PetscBool globalCompress;
6646dd5a8c8SToby Isaac 
665820f2d46SBarry Smith     ierr = MPIU_Allreduce(&compress,&globalCompress,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRMPI(ierr);
6666dd5a8c8SToby Isaac     if (compress) {
6676dd5a8c8SToby Isaac       PetscSection secComp;
6686dd5a8c8SToby Isaac       PetscInt *valsComp = NULL;
6696dd5a8c8SToby Isaac 
6706dd5a8c8SToby Isaac       ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secComp);CHKERRQ(ierr);
6716dd5a8c8SToby Isaac       ierr = PetscSectionSetChart(secComp,pStart,pEnd);CHKERRQ(ierr);
6726dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6736dd5a8c8SToby Isaac         PetscInt dof;
6746dd5a8c8SToby Isaac 
6756dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6766dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secComp, p, dof);CHKERRQ(ierr);
6776dd5a8c8SToby Isaac       }
6786dd5a8c8SToby Isaac       ierr = PetscSectionSetUp(secComp);CHKERRQ(ierr);
6796dd5a8c8SToby Isaac       ierr = PetscSectionGetStorageSize(secComp,&sizeNew);CHKERRQ(ierr);
6806dd5a8c8SToby Isaac       ierr = PetscMalloc1(sizeNew,&valsComp);CHKERRQ(ierr);
6816dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6826dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6836dd5a8c8SToby Isaac 
6846dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6856dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secNew, p, &off);CHKERRQ(ierr);
6866dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secComp, p, &offNew);CHKERRQ(ierr);
6876dd5a8c8SToby Isaac         for (j = 0; j < dof; j++) {
6886dd5a8c8SToby Isaac           valsComp[offNew + j] = valsNew[off + j];
6896dd5a8c8SToby Isaac         }
6906dd5a8c8SToby Isaac       }
6916dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6926dd5a8c8SToby Isaac       secNew  = secComp;
6936dd5a8c8SToby Isaac       ierr    = PetscFree(valsNew);CHKERRQ(ierr);
6946dd5a8c8SToby Isaac       valsNew = valsComp;
6956dd5a8c8SToby Isaac     }
6966dd5a8c8SToby Isaac     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is),sizeNew,valsNew,PETSC_OWN_POINTER,isNew);CHKERRQ(ierr);
6976dd5a8c8SToby Isaac   }
6986dd5a8c8SToby Isaac   PetscFunctionReturn(0);
6996dd5a8c8SToby Isaac }
7006dd5a8c8SToby Isaac 
701f7c74593SToby Isaac static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
70266af876cSToby Isaac {
70366af876cSToby Isaac   PetscInt       p, pStart, pEnd, *anchors, size;
70466af876cSToby Isaac   PetscInt       aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
70566af876cSToby Isaac   PetscSection   aSec;
706f9f063d4SToby Isaac   DMLabel        canonLabel;
70766af876cSToby Isaac   IS             aIS;
70866af876cSToby Isaac   PetscErrorCode ierr;
70966af876cSToby Isaac 
71066af876cSToby Isaac   PetscFunctionBegin;
71166af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
71266af876cSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
713c58f1c22SToby Isaac   ierr = DMGetLabel(dm,"canonical",&canonLabel);CHKERRQ(ierr);
71466af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
71566af876cSToby Isaac     PetscInt parent;
71666af876cSToby Isaac 
717f9f063d4SToby Isaac     if (canonLabel) {
718f9f063d4SToby Isaac       PetscInt canon;
719f9f063d4SToby Isaac 
720f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
721f9f063d4SToby Isaac       if (p != canon) continue;
722f9f063d4SToby Isaac     }
72366af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
72466af876cSToby Isaac     if (parent != p) {
72566af876cSToby Isaac       aMin = PetscMin(aMin,p);
72666af876cSToby Isaac       aMax = PetscMax(aMax,p+1);
72766af876cSToby Isaac     }
72866af876cSToby Isaac   }
72966af876cSToby Isaac   if (aMin > aMax) {
73066af876cSToby Isaac     aMin = -1;
73166af876cSToby Isaac     aMax = -1;
73266af876cSToby Isaac   }
733e228b242SToby Isaac   ierr = PetscSectionCreate(PETSC_COMM_SELF,&aSec);CHKERRQ(ierr);
73466af876cSToby Isaac   ierr = PetscSectionSetChart(aSec,aMin,aMax);CHKERRQ(ierr);
73566af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
73666af876cSToby Isaac     PetscInt parent, ancestor = p;
73766af876cSToby Isaac 
738f9f063d4SToby Isaac     if (canonLabel) {
739f9f063d4SToby Isaac       PetscInt canon;
740f9f063d4SToby Isaac 
741f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
742f9f063d4SToby Isaac       if (p != canon) continue;
743f9f063d4SToby Isaac     }
74466af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
74566af876cSToby Isaac     while (parent != ancestor) {
74666af876cSToby Isaac       ancestor = parent;
74766af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
74866af876cSToby Isaac     }
74966af876cSToby Isaac     if (ancestor != p) {
75066af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
75166af876cSToby Isaac 
75266af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
75366af876cSToby Isaac       ierr = PetscSectionSetDof(aSec,p,closureSize);CHKERRQ(ierr);
75466af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
75566af876cSToby Isaac     }
75666af876cSToby Isaac   }
75766af876cSToby Isaac   ierr = PetscSectionSetUp(aSec);CHKERRQ(ierr);
75866af876cSToby Isaac   ierr = PetscSectionGetStorageSize(aSec,&size);CHKERRQ(ierr);
75966af876cSToby Isaac   ierr = PetscMalloc1(size,&anchors);CHKERRQ(ierr);
76066af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
76166af876cSToby Isaac     PetscInt parent, ancestor = p;
76266af876cSToby Isaac 
763f9f063d4SToby Isaac     if (canonLabel) {
764f9f063d4SToby Isaac       PetscInt canon;
765f9f063d4SToby Isaac 
766f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
767f9f063d4SToby Isaac       if (p != canon) continue;
768f9f063d4SToby Isaac     }
76966af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
77066af876cSToby Isaac     while (parent != ancestor) {
77166af876cSToby Isaac       ancestor = parent;
77266af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
77366af876cSToby Isaac     }
77466af876cSToby Isaac     if (ancestor != p) {
77566af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
77666af876cSToby Isaac 
77766af876cSToby Isaac       ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
77866af876cSToby Isaac 
77966af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
78066af876cSToby Isaac       for (j = 0; j < closureSize; j++) {
78166af876cSToby Isaac         anchors[aOff + j] = closure[2*j];
78266af876cSToby Isaac       }
78366af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
78466af876cSToby Isaac     }
78566af876cSToby Isaac   }
786e228b242SToby Isaac   ierr = ISCreateGeneral(PETSC_COMM_SELF,size,anchors,PETSC_OWN_POINTER,&aIS);CHKERRQ(ierr);
7876dd5a8c8SToby Isaac   {
7886dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7896dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7906dd5a8c8SToby Isaac 
7916dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aSec);CHKERRQ(ierr);
7926dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aIS);CHKERRQ(ierr);
7936dd5a8c8SToby Isaac     while (aSecNew) {
7946dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
7956dd5a8c8SToby Isaac       ierr    = ISDestroy(&aIS);CHKERRQ(ierr);
7966dd5a8c8SToby Isaac       aSec    = aSecNew;
7976dd5a8c8SToby Isaac       aIS     = aISNew;
7986dd5a8c8SToby Isaac       aSecNew = NULL;
7996dd5a8c8SToby Isaac       aISNew  = NULL;
8006dd5a8c8SToby Isaac       ierr    = AnchorsFlatten(aSec,aIS,&aSecNew,&aISNew);CHKERRQ(ierr);
8016dd5a8c8SToby Isaac     }
8026dd5a8c8SToby Isaac   }
803a17985deSToby Isaac   ierr = DMPlexSetAnchors(dm,aSec,aIS);CHKERRQ(ierr);
80466af876cSToby Isaac   ierr = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
80566af876cSToby Isaac   ierr = ISDestroy(&aIS);CHKERRQ(ierr);
80666af876cSToby Isaac   PetscFunctionReturn(0);
80766af876cSToby Isaac }
80866af876cSToby Isaac 
8096461c1adSToby Isaac static PetscErrorCode DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt *dof,PetscInt *numTrueSupp)
8106461c1adSToby Isaac {
8116461c1adSToby Isaac   PetscErrorCode ierr;
8126461c1adSToby Isaac 
8136461c1adSToby Isaac   PetscFunctionBegin;
8146461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
8156461c1adSToby Isaac     PetscInt i, alldof;
8166461c1adSToby Isaac     const PetscInt *supp;
8176461c1adSToby Isaac     PetscInt count = 0;
8186461c1adSToby Isaac 
8196461c1adSToby Isaac     ierr = DMPlexGetSupportSize(dm,p,&alldof);CHKERRQ(ierr);
8206461c1adSToby Isaac     ierr = DMPlexGetSupport(dm,p,&supp);CHKERRQ(ierr);
8216461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
8226461c1adSToby Isaac       PetscInt q = supp[i], numCones, j;
8236461c1adSToby Isaac       const PetscInt *cone;
8246461c1adSToby Isaac 
8256461c1adSToby Isaac       ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
8266461c1adSToby Isaac       ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
8276461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
8286461c1adSToby Isaac         if (cone[j] == p) break;
8296461c1adSToby Isaac       }
8306461c1adSToby Isaac       if (j < numCones) count++;
8316461c1adSToby Isaac     }
8326461c1adSToby Isaac     numTrueSupp[p] = count;
8336461c1adSToby Isaac   }
8346461c1adSToby Isaac   *dof = numTrueSupp[p];
8356461c1adSToby Isaac   PetscFunctionReturn(0);
8366461c1adSToby Isaac }
8376461c1adSToby Isaac 
838776742edSToby Isaac static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
839776742edSToby Isaac {
840776742edSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
841776742edSToby Isaac   PetscSection   newSupportSection;
842776742edSToby Isaac   PetscInt       newSize, *newSupports, pStart, pEnd, p, d, depth;
8436461c1adSToby Isaac   PetscInt       *numTrueSupp;
844776742edSToby Isaac   PetscInt       *offsets;
845776742edSToby Isaac   PetscErrorCode ierr;
846776742edSToby Isaac 
847776742edSToby Isaac   PetscFunctionBegin;
848776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
849776742edSToby Isaac   /* symmetrize the hierarchy */
850776742edSToby Isaac   ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr);
851e228b242SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)),&newSupportSection);CHKERRQ(ierr);
852776742edSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
853776742edSToby Isaac   ierr = PetscSectionSetChart(newSupportSection,pStart,pEnd);CHKERRQ(ierr);
854776742edSToby Isaac   ierr = PetscCalloc1(pEnd,&offsets);CHKERRQ(ierr);
8556461c1adSToby Isaac   ierr = PetscMalloc1(pEnd,&numTrueSupp);CHKERRQ(ierr);
8566461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8576461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
858776742edSToby Isaac    * parent(q) */
859776742edSToby Isaac   for (d = 0; d <= depth; d++) {
860776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
861776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
862776742edSToby Isaac       PetscInt dof, q, qdof, parent;
863776742edSToby Isaac 
8646461c1adSToby Isaac       ierr = DMPlexGetTrueSupportSize(dm,p,&dof,numTrueSupp);CHKERRQ(ierr);
865776742edSToby Isaac       ierr = PetscSectionAddDof(newSupportSection, p, dof);CHKERRQ(ierr);
866776742edSToby Isaac       q    = p;
867776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
868776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
869776742edSToby Isaac         q = parent;
870776742edSToby Isaac 
8716461c1adSToby Isaac         ierr = DMPlexGetTrueSupportSize(dm,q,&qdof,numTrueSupp);CHKERRQ(ierr);
872776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,p,qdof);CHKERRQ(ierr);
873776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,q,dof);CHKERRQ(ierr);
874776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
875776742edSToby Isaac       }
876776742edSToby Isaac     }
877776742edSToby Isaac   }
878776742edSToby Isaac   ierr = PetscSectionSetUp(newSupportSection);CHKERRQ(ierr);
879776742edSToby Isaac   ierr = PetscSectionGetStorageSize(newSupportSection,&newSize);CHKERRQ(ierr);
880776742edSToby Isaac   ierr = PetscMalloc1(newSize,&newSupports);CHKERRQ(ierr);
881776742edSToby Isaac   for (d = 0; d <= depth; d++) {
882776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
883776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
884776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
885776742edSToby Isaac 
886776742edSToby Isaac       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
887776742edSToby Isaac       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
888776742edSToby Isaac       ierr = PetscSectionGetDof(newSupportSection, p, &newDof);CHKERRQ(ierr);
889776742edSToby Isaac       ierr = PetscSectionGetOffset(newSupportSection, p, &newOff);CHKERRQ(ierr);
890776742edSToby Isaac       for (i = 0; i < dof; i++) {
8916461c1adSToby Isaac         PetscInt numCones, j;
8926461c1adSToby Isaac         const PetscInt *cone;
8936461c1adSToby Isaac         PetscInt q = mesh->supports[off + i];
8946461c1adSToby Isaac 
8956461c1adSToby Isaac         ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
8966461c1adSToby Isaac         ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
8976461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8986461c1adSToby Isaac           if (cone[j] == p) break;
8996461c1adSToby Isaac         }
9006461c1adSToby Isaac         if (j < numCones) newSupports[newOff+offsets[p]++] = q;
901776742edSToby Isaac       }
902776742edSToby Isaac       mesh->maxSupportSize = PetscMax(mesh->maxSupportSize,newDof);
903776742edSToby Isaac 
904776742edSToby Isaac       q    = p;
905776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
906776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
907776742edSToby Isaac         q = parent;
908776742edSToby Isaac         ierr = PetscSectionGetDof(mesh->supportSection, q, &qdof);CHKERRQ(ierr);
909776742edSToby Isaac         ierr = PetscSectionGetOffset(mesh->supportSection, q, &qoff);CHKERRQ(ierr);
910776742edSToby Isaac         ierr = PetscSectionGetOffset(newSupportSection, q, &newqOff);CHKERRQ(ierr);
911776742edSToby Isaac         for (i = 0; i < qdof; i++) {
9126461c1adSToby Isaac           PetscInt numCones, j;
9136461c1adSToby Isaac           const PetscInt *cone;
9146461c1adSToby Isaac           PetscInt r = mesh->supports[qoff + i];
9156461c1adSToby Isaac 
9166461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9176461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9186461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9196461c1adSToby Isaac             if (cone[j] == q) break;
9206461c1adSToby Isaac           }
9216461c1adSToby Isaac           if (j < numCones) newSupports[newOff+offsets[p]++] = r;
922776742edSToby Isaac         }
923776742edSToby Isaac         for (i = 0; i < dof; i++) {
9246461c1adSToby Isaac           PetscInt numCones, j;
9256461c1adSToby Isaac           const PetscInt *cone;
9266461c1adSToby Isaac           PetscInt r = mesh->supports[off + i];
9276461c1adSToby Isaac 
9286461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9296461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9306461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9316461c1adSToby Isaac             if (cone[j] == p) break;
9326461c1adSToby Isaac           }
9336461c1adSToby Isaac           if (j < numCones) newSupports[newqOff+offsets[q]++] = r;
934776742edSToby Isaac         }
935776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
936776742edSToby Isaac       }
937776742edSToby Isaac     }
938776742edSToby Isaac   }
939776742edSToby Isaac   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
940776742edSToby Isaac   mesh->supportSection = newSupportSection;
941776742edSToby Isaac   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
942776742edSToby Isaac   mesh->supports = newSupports;
943776742edSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
9446461c1adSToby Isaac   ierr = PetscFree(numTrueSupp);CHKERRQ(ierr);
945776742edSToby Isaac 
946776742edSToby Isaac   PetscFunctionReturn(0);
947776742edSToby Isaac }
948776742edSToby Isaac 
949f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM,PetscSection,PetscSection,Mat);
950f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM,PetscSection,PetscSection,Mat);
951f7c74593SToby Isaac 
952776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
953f9f063d4SToby Isaac {
954f9f063d4SToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
955f9f063d4SToby Isaac   DM             refTree;
956f9f063d4SToby Isaac   PetscInt       size;
957f9f063d4SToby Isaac   PetscErrorCode ierr;
958f9f063d4SToby Isaac 
959f9f063d4SToby Isaac   PetscFunctionBegin;
960f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
961f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
962f9f063d4SToby Isaac   ierr = PetscObjectReference((PetscObject)parentSection);CHKERRQ(ierr);
963f9f063d4SToby Isaac   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
964f9f063d4SToby Isaac   mesh->parentSection = parentSection;
965f9f063d4SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&size);CHKERRQ(ierr);
966f9f063d4SToby Isaac   if (parents != mesh->parents) {
967f9f063d4SToby Isaac     ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
968f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->parents);CHKERRQ(ierr);
969580bdb30SBarry Smith     ierr = PetscArraycpy(mesh->parents, parents, size);CHKERRQ(ierr);
970f9f063d4SToby Isaac   }
971f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
972f9f063d4SToby Isaac     ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
973f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->childIDs);CHKERRQ(ierr);
974580bdb30SBarry Smith     ierr = PetscArraycpy(mesh->childIDs, childIDs, size);CHKERRQ(ierr);
975f9f063d4SToby Isaac   }
976f9f063d4SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
977f9f063d4SToby Isaac   if (refTree) {
978f9f063d4SToby Isaac     DMLabel canonLabel;
979f9f063d4SToby Isaac 
980c58f1c22SToby Isaac     ierr = DMGetLabel(refTree,"canonical",&canonLabel);CHKERRQ(ierr);
981f9f063d4SToby Isaac     if (canonLabel) {
982f9f063d4SToby Isaac       PetscInt i;
983f9f063d4SToby Isaac 
984f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
985f9f063d4SToby Isaac         PetscInt canon;
986f9f063d4SToby Isaac         ierr = DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon);CHKERRQ(ierr);
987f9f063d4SToby Isaac         if (canon >= 0) {
988f9f063d4SToby Isaac           mesh->childIDs[i] = canon;
989f9f063d4SToby Isaac         }
990f9f063d4SToby Isaac       }
991f9f063d4SToby Isaac     }
992f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
9936e0288c8SStefano Zampini   } else {
994f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
995f9f063d4SToby Isaac   }
996f9f063d4SToby Isaac   ierr = DMPlexTreeSymmetrize(dm);CHKERRQ(ierr);
997f9f063d4SToby Isaac   if (computeCanonical) {
998f9f063d4SToby Isaac     PetscInt d, dim;
999f9f063d4SToby Isaac 
1000f9f063d4SToby Isaac     /* add the canonical label */
100128f4b327SMatthew G. Knepley     ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
1002c58f1c22SToby Isaac     ierr = DMCreateLabel(dm,"canonical");CHKERRQ(ierr);
1003f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
1004f9f063d4SToby Isaac       PetscInt p, dStart, dEnd, canon = -1, cNumChildren;
1005f9f063d4SToby Isaac       const PetscInt *cChildren;
1006f9f063d4SToby Isaac 
1007f9f063d4SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
1008f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1009f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&cNumChildren,&cChildren);CHKERRQ(ierr);
1010f9f063d4SToby Isaac         if (cNumChildren) {
1011f9f063d4SToby Isaac           canon = p;
1012f9f063d4SToby Isaac           break;
1013f9f063d4SToby Isaac         }
1014f9f063d4SToby Isaac       }
1015f9f063d4SToby Isaac       if (canon == -1) continue;
1016f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1017f9f063d4SToby Isaac         PetscInt numChildren, i;
1018f9f063d4SToby Isaac         const PetscInt *children;
1019f9f063d4SToby Isaac 
1020f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&numChildren,&children);CHKERRQ(ierr);
1021f9f063d4SToby Isaac         if (numChildren) {
1022*2c71b3e2SJacob Faibussowitsch           PetscCheckFalse(numChildren != cNumChildren,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"All parent points in a stratum should have the same number of children: %d != %d", numChildren, cNumChildren);
1023c58f1c22SToby Isaac           ierr = DMSetLabelValue(dm,"canonical",p,canon);CHKERRQ(ierr);
1024f9f063d4SToby Isaac           for (i = 0; i < numChildren; i++) {
1025c58f1c22SToby Isaac             ierr = DMSetLabelValue(dm,"canonical",children[i],cChildren[i]);CHKERRQ(ierr);
1026f9f063d4SToby Isaac           }
1027f9f063d4SToby Isaac         }
1028f9f063d4SToby Isaac       }
1029f9f063d4SToby Isaac     }
1030f9f063d4SToby Isaac   }
1031776742edSToby Isaac   if (exchangeSupports) {
1032776742edSToby Isaac     ierr = DMPlexTreeExchangeSupports(dm);CHKERRQ(ierr);
1033776742edSToby Isaac   }
1034f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
1035f7c74593SToby Isaac   /* reset anchors */
1036f7c74593SToby Isaac   ierr = DMPlexSetAnchors(dm,NULL,NULL);CHKERRQ(ierr);
1037f9f063d4SToby Isaac   PetscFunctionReturn(0);
1038f9f063d4SToby Isaac }
1039f9f063d4SToby Isaac 
10400b7167a0SToby Isaac /*@
10410b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
10420b7167a0SToby Isaac   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
10430b7167a0SToby Isaac   tree root.
10440b7167a0SToby Isaac 
10450b7167a0SToby Isaac   Collective on dm
10460b7167a0SToby Isaac 
10470b7167a0SToby Isaac   Input Parameters:
10480b7167a0SToby Isaac + dm - the DMPlex object
10490b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
10500b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
10510b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
10520b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
10530b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
10540b7167a0SToby Isaac 
10550b7167a0SToby Isaac   Level: intermediate
10560b7167a0SToby Isaac 
1057a17985deSToby Isaac .seealso: DMPlexGetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
10580b7167a0SToby Isaac @*/
1059b2f41788SToby Isaac PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
10600b7167a0SToby Isaac {
10610b7167a0SToby Isaac   PetscErrorCode ierr;
10620b7167a0SToby Isaac 
10630b7167a0SToby Isaac   PetscFunctionBegin;
1064776742edSToby Isaac   ierr = DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
10650b7167a0SToby Isaac   PetscFunctionReturn(0);
10660b7167a0SToby Isaac }
10670b7167a0SToby Isaac 
1068b2f41788SToby Isaac /*@
1069b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1070b2f41788SToby Isaac   Collective on dm
1071b2f41788SToby Isaac 
1072f899ff85SJose E. Roman   Input Parameter:
1073b2f41788SToby Isaac . dm - the DMPlex object
1074b2f41788SToby Isaac 
1075b2f41788SToby Isaac   Output Parameters:
1076b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1077b2f41788SToby Isaac                   offset indexes the parent and childID list
1078b2f41788SToby Isaac . parents - a list of the point parents
1079b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1080b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1081b2f41788SToby Isaac . childSection - the inverse of the parent section
1082b2f41788SToby Isaac - children - a list of the point children
1083b2f41788SToby Isaac 
1084b2f41788SToby Isaac   Level: intermediate
1085b2f41788SToby Isaac 
1086a17985deSToby Isaac .seealso: DMPlexSetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
1087b2f41788SToby Isaac @*/
1088b2f41788SToby Isaac PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1089b2f41788SToby Isaac {
1090b2f41788SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
1091b2f41788SToby Isaac 
1092b2f41788SToby Isaac   PetscFunctionBegin;
1093b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1094b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1095b2f41788SToby Isaac   if (parents)       *parents       = mesh->parents;
1096b2f41788SToby Isaac   if (childIDs)      *childIDs      = mesh->childIDs;
1097b2f41788SToby Isaac   if (childSection)  *childSection  = mesh->childSection;
1098b2f41788SToby Isaac   if (children)      *children      = mesh->children;
1099b2f41788SToby Isaac   PetscFunctionReturn(0);
1100b2f41788SToby Isaac }
1101b2f41788SToby Isaac 
1102d961a43aSToby Isaac /*@
1103eaf898f9SPatrick Sanan   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)
1104d961a43aSToby Isaac 
1105d961a43aSToby Isaac   Input Parameters:
1106d961a43aSToby Isaac + dm - the DMPlex object
1107d961a43aSToby Isaac - point - the query point
1108d961a43aSToby Isaac 
1109d961a43aSToby Isaac   Output Parameters:
1110d961a43aSToby Isaac + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1111d961a43aSToby Isaac - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point
1112d961a43aSToby Isaac             does not have a parent
1113d961a43aSToby Isaac 
1114d961a43aSToby Isaac   Level: intermediate
1115d961a43aSToby Isaac 
1116d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeChildren()
1117d961a43aSToby Isaac @*/
1118d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1119d961a43aSToby Isaac {
1120d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1121d961a43aSToby Isaac   PetscSection   pSec;
1122d961a43aSToby Isaac   PetscErrorCode ierr;
1123d961a43aSToby Isaac 
1124d961a43aSToby Isaac   PetscFunctionBegin;
1125d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1126d961a43aSToby Isaac   pSec = mesh->parentSection;
1127d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1128d961a43aSToby Isaac     PetscInt dof;
1129d961a43aSToby Isaac 
1130d961a43aSToby Isaac     ierr = PetscSectionGetDof (pSec, point, &dof);CHKERRQ(ierr);
1131d961a43aSToby Isaac     if (dof) {
1132d961a43aSToby Isaac       PetscInt off;
1133d961a43aSToby Isaac 
1134d961a43aSToby Isaac       ierr = PetscSectionGetOffset (pSec, point, &off);CHKERRQ(ierr);
1135d961a43aSToby Isaac       if (parent)  *parent = mesh->parents[off];
1136d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
1137d961a43aSToby Isaac       PetscFunctionReturn(0);
1138d961a43aSToby Isaac     }
1139d961a43aSToby Isaac   }
1140d961a43aSToby Isaac   if (parent) {
1141d961a43aSToby Isaac     *parent = point;
1142d961a43aSToby Isaac   }
1143d961a43aSToby Isaac   if (childID) {
1144d961a43aSToby Isaac     *childID = 0;
1145d961a43aSToby Isaac   }
1146d961a43aSToby Isaac   PetscFunctionReturn(0);
1147d961a43aSToby Isaac }
1148d961a43aSToby Isaac 
1149d961a43aSToby Isaac /*@C
1150eaf898f9SPatrick Sanan   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)
1151d961a43aSToby Isaac 
1152d961a43aSToby Isaac   Input Parameters:
1153d961a43aSToby Isaac + dm - the DMPlex object
1154d961a43aSToby Isaac - point - the query point
1155d961a43aSToby Isaac 
1156d961a43aSToby Isaac   Output Parameters:
1157d961a43aSToby Isaac + numChildren - if not NULL, set to the number of children
1158d961a43aSToby Isaac - children - if not NULL, set to a list children, or set to NULL if the point has no children
1159d961a43aSToby Isaac 
1160d961a43aSToby Isaac   Level: intermediate
1161d961a43aSToby Isaac 
1162d961a43aSToby Isaac   Fortran Notes:
1163d961a43aSToby Isaac   Since it returns an array, this routine is only available in Fortran 90, and you must
1164d961a43aSToby Isaac   include petsc.h90 in your code.
1165d961a43aSToby Isaac 
1166d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeParent()
1167d961a43aSToby Isaac @*/
1168d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1169d961a43aSToby Isaac {
1170d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1171d961a43aSToby Isaac   PetscSection   childSec;
1172d961a43aSToby Isaac   PetscInt       dof = 0;
1173d961a43aSToby Isaac   PetscErrorCode ierr;
1174d961a43aSToby Isaac 
1175d961a43aSToby Isaac   PetscFunctionBegin;
1176d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1177d961a43aSToby Isaac   childSec = mesh->childSection;
1178d961a43aSToby Isaac   if (childSec && point >= childSec->pStart && point < childSec->pEnd) {
1179d961a43aSToby Isaac     ierr = PetscSectionGetDof (childSec, point, &dof);CHKERRQ(ierr);
1180d961a43aSToby Isaac   }
1181d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1182d961a43aSToby Isaac   if (children) {
1183d961a43aSToby Isaac     if (dof) {
1184d961a43aSToby Isaac       PetscInt off;
1185d961a43aSToby Isaac 
1186d961a43aSToby Isaac       ierr = PetscSectionGetOffset (childSec, point, &off);CHKERRQ(ierr);
1187d961a43aSToby Isaac       *children = &mesh->children[off];
1188d961a43aSToby Isaac     }
1189d961a43aSToby Isaac     else {
1190d961a43aSToby Isaac       *children = NULL;
1191d961a43aSToby Isaac     }
1192d961a43aSToby Isaac   }
1193d961a43aSToby Isaac   PetscFunctionReturn(0);
1194d961a43aSToby Isaac }
11950c37af3bSToby Isaac 
119652a3aeb4SToby 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)
1197b3a4bf2aSToby Isaac {
119852a3aeb4SToby Isaac   PetscInt       f, b, p, c, offset, qPoints;
1199b3a4bf2aSToby Isaac   PetscErrorCode ierr;
1200b3a4bf2aSToby Isaac 
1201b3a4bf2aSToby Isaac   PetscFunctionBegin;
1202b3a4bf2aSToby Isaac   ierr = PetscSpaceEvaluate(space,nPoints,points,work,NULL,NULL);CHKERRQ(ierr);
120352a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
120452a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
120552a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1206b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1207b3a4bf2aSToby Isaac 
120852a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
120952a3aeb4SToby Isaac         for (c = 0; c < nComps; c++) {
121052a3aeb4SToby Isaac           val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
1211b3a4bf2aSToby Isaac         }
121252a3aeb4SToby Isaac       }
121352a3aeb4SToby Isaac       ierr = MatSetValue(basisAtPoints,b,f,val,INSERT_VALUES);CHKERRQ(ierr);
1214b3a4bf2aSToby Isaac     }
1215b3a4bf2aSToby Isaac     offset += qPoints;
1216b3a4bf2aSToby Isaac   }
1217b3a4bf2aSToby Isaac   ierr = MatAssemblyBegin(basisAtPoints,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1218b3a4bf2aSToby Isaac   ierr = MatAssemblyEnd(basisAtPoints,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1219b3a4bf2aSToby Isaac   PetscFunctionReturn(0);
1220b3a4bf2aSToby Isaac }
1221b3a4bf2aSToby Isaac 
1222f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
12230c37af3bSToby Isaac {
12240c37af3bSToby Isaac   PetscDS        ds;
12250c37af3bSToby Isaac   PetscInt       spdim;
12260c37af3bSToby Isaac   PetscInt       numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
12270c37af3bSToby Isaac   const PetscInt *anchors;
1228f7c74593SToby Isaac   PetscSection   aSec;
12290c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
12300c37af3bSToby Isaac   IS             aIS;
12310c37af3bSToby Isaac   PetscErrorCode ierr;
12320c37af3bSToby Isaac 
12330c37af3bSToby Isaac   PetscFunctionBegin;
12340c37af3bSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
12350c37af3bSToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
12360c37af3bSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
12370c37af3bSToby Isaac   ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
1238a17985deSToby Isaac   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
12390c37af3bSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
12400c37af3bSToby Isaac   ierr = PetscSectionGetChart(cSec,&conStart,&conEnd);CHKERRQ(ierr);
124128f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&spdim);CHKERRQ(ierr);
12420c37af3bSToby Isaac   ierr = PetscMalloc6(spdim,&v0,spdim,&v0parent,spdim,&vtmp,spdim*spdim,&J,spdim*spdim,&Jparent,spdim*spdim,&invJparent);CHKERRQ(ierr);
12430c37af3bSToby Isaac 
12440c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
12450dd1b1feSToby Isaac     PetscObject       disc;
12460dd1b1feSToby Isaac     PetscClassId      id;
1247b3a4bf2aSToby Isaac     PetscSpace        bspace;
1248b3a4bf2aSToby Isaac     PetscDualSpace    dspace;
12499c3cf19fSMatthew G. Knepley     PetscInt          i, j, k, nPoints, Nc, offset;
125052a3aeb4SToby Isaac     PetscInt          fSize, maxDof;
1251b3a4bf2aSToby Isaac     PetscReal         *weights, *pointsRef, *pointsReal, *work;
12521683a169SBarry Smith     PetscScalar       *scwork;
12531683a169SBarry Smith     const PetscScalar *X;
12542c44ad04SToby Isaac     PetscInt          *sizes, *workIndRow, *workIndCol;
12550c37af3bSToby Isaac     Mat               Amat, Bmat, Xmat;
12562c44ad04SToby Isaac     const PetscInt    *numDof  = NULL;
1257085f0adfSToby Isaac     const PetscInt    ***perms = NULL;
1258085f0adfSToby Isaac     const PetscScalar ***flips = NULL;
12590c37af3bSToby Isaac 
12600dd1b1feSToby Isaac     ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
12610dd1b1feSToby Isaac     ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
12620dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1263b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE) disc;
1264b3a4bf2aSToby Isaac 
1265b3a4bf2aSToby Isaac       ierr = PetscFEGetBasisSpace(fe,&bspace);CHKERRQ(ierr);
1266b3a4bf2aSToby Isaac       ierr = PetscFEGetDualSpace(fe,&dspace);CHKERRQ(ierr);
1267b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetDimension(dspace,&fSize);CHKERRQ(ierr);
126852a3aeb4SToby Isaac       ierr = PetscFEGetNumComponents(fe,&Nc);CHKERRQ(ierr);
12690dd1b1feSToby Isaac     }
12700dd1b1feSToby Isaac     else if (id == PETSCFV_CLASSID) {
1271b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV) disc;
1272b3a4bf2aSToby Isaac 
127352a3aeb4SToby Isaac       ierr = PetscFVGetNumComponents(fv,&Nc);CHKERRQ(ierr);
1274b3a4bf2aSToby Isaac       ierr = PetscSpaceCreate(PetscObjectComm((PetscObject)fv),&bspace);CHKERRQ(ierr);
1275b3a4bf2aSToby Isaac       ierr = PetscSpaceSetType(bspace,PETSCSPACEPOLYNOMIAL);CHKERRQ(ierr);
1276d39dd5f5SToby Isaac       ierr = PetscSpaceSetDegree(bspace,0,PETSC_DETERMINE);CHKERRQ(ierr);
127752a3aeb4SToby Isaac       ierr = PetscSpaceSetNumComponents(bspace,Nc);CHKERRQ(ierr);
1278157782e2SToby Isaac       ierr = PetscSpaceSetNumVariables(bspace,spdim);CHKERRQ(ierr);
1279b3a4bf2aSToby Isaac       ierr = PetscSpaceSetUp(bspace);CHKERRQ(ierr);
1280b3a4bf2aSToby Isaac       ierr = PetscFVGetDualSpace(fv,&dspace);CHKERRQ(ierr);
1281b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetDimension(dspace,&fSize);CHKERRQ(ierr);
12820dd1b1feSToby Isaac     }
128398921bdaSJacob Faibussowitsch     else SETERRQ(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
12842c44ad04SToby Isaac     ierr = PetscDualSpaceGetNumDof(dspace,&numDof);CHKERRQ(ierr);
12852c44ad04SToby Isaac     for (i = 0, maxDof = 0; i <= spdim; i++) {maxDof = PetscMax(maxDof,numDof[i]);}
1286085f0adfSToby Isaac     ierr = PetscDualSpaceGetSymmetries(dspace,&perms,&flips);CHKERRQ(ierr);
12870dd1b1feSToby Isaac 
12880c37af3bSToby Isaac     ierr = MatCreate(PETSC_COMM_SELF,&Amat);CHKERRQ(ierr);
12890c37af3bSToby Isaac     ierr = MatSetSizes(Amat,fSize,fSize,fSize,fSize);CHKERRQ(ierr);
12900c37af3bSToby Isaac     ierr = MatSetType(Amat,MATSEQDENSE);CHKERRQ(ierr);
12910c37af3bSToby Isaac     ierr = MatSetUp(Amat);CHKERRQ(ierr);
12920c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Bmat);CHKERRQ(ierr);
12930c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Xmat);CHKERRQ(ierr);
12940c37af3bSToby Isaac     nPoints = 0;
12950c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
129652a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
12970c37af3bSToby Isaac       PetscQuadrature quad;
12980c37af3bSToby Isaac 
1299b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetFunctional(dspace,i,&quad);CHKERRQ(ierr);
130052a3aeb4SToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,&thisNc,&qPoints,NULL,NULL);CHKERRQ(ierr);
1301*2c71b3e2SJacob Faibussowitsch       PetscCheckFalse(thisNc != Nc,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %D does not much basis dim %D",thisNc,Nc);
13020c37af3bSToby Isaac       nPoints += qPoints;
13030c37af3bSToby Isaac     }
130452a3aeb4SToby Isaac     ierr = PetscMalloc7(fSize,&sizes,nPoints*Nc,&weights,spdim*nPoints,&pointsRef,spdim*nPoints,&pointsReal,nPoints*fSize*Nc,&work,maxDof,&workIndRow,maxDof,&workIndCol);CHKERRQ(ierr);
13052c44ad04SToby Isaac     ierr = PetscMalloc1(maxDof * maxDof,&scwork);CHKERRQ(ierr);
13060c37af3bSToby Isaac     offset = 0;
13070c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
13080c37af3bSToby Isaac       PetscInt        qPoints;
13090c37af3bSToby Isaac       const PetscReal    *p, *w;
13100c37af3bSToby Isaac       PetscQuadrature quad;
13110c37af3bSToby Isaac 
1312b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetFunctional(dspace,i,&quad);CHKERRQ(ierr);
131352a3aeb4SToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,NULL,&qPoints,&p,&w);CHKERRQ(ierr);
1314580bdb30SBarry Smith       ierr = PetscArraycpy(weights+Nc*offset,w,Nc*qPoints);CHKERRQ(ierr);
1315580bdb30SBarry Smith       ierr = PetscArraycpy(pointsRef+spdim*offset,p,spdim*qPoints);CHKERRQ(ierr);
1316b3a4bf2aSToby Isaac       sizes[i] = qPoints;
13170c37af3bSToby Isaac       offset  += qPoints;
13180c37af3bSToby Isaac     }
131952a3aeb4SToby Isaac     ierr = EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsRef,weights,work,Amat);CHKERRQ(ierr);
13200c37af3bSToby Isaac     ierr = MatLUFactor(Amat,NULL,NULL,NULL);CHKERRQ(ierr);
13210c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
13220c37af3bSToby Isaac       PetscInt        parent;
13230c37af3bSToby Isaac       PetscInt        closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
13240c37af3bSToby Isaac       PetscInt        *childOffsets, *parentOffsets;
13250c37af3bSToby Isaac 
13260c37af3bSToby Isaac       ierr = DMPlexGetTreeParent(dm,c,&parent,NULL);CHKERRQ(ierr);
13270c37af3bSToby Isaac       if (parent == c) continue;
13280c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13290c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13300c37af3bSToby Isaac         PetscInt p = closure[2*i];
13310c37af3bSToby Isaac         PetscInt conDof;
13320c37af3bSToby Isaac 
13330c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1334085f0adfSToby Isaac         if (numFields) {
13350c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
13360c37af3bSToby Isaac         }
13370c37af3bSToby Isaac         else {
13380c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
13390c37af3bSToby Isaac         }
13400c37af3bSToby Isaac         if (conDof) break;
13410c37af3bSToby Isaac       }
13420c37af3bSToby Isaac       if (i == closureSize) {
13430c37af3bSToby Isaac         ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13440c37af3bSToby Isaac         continue;
13450c37af3bSToby Isaac       }
13460c37af3bSToby Isaac 
134773a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
134873a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent);CHKERRQ(ierr);
13490c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1350c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
1351c330f8ffSToby Isaac 
1352c330f8ffSToby Isaac         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i*spdim],vtmp);
1353c330f8ffSToby Isaac         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i*spdim]);
13540c37af3bSToby Isaac       }
135552a3aeb4SToby Isaac       ierr = EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsReal,weights,work,Bmat);CHKERRQ(ierr);
13560c37af3bSToby Isaac       ierr = MatMatSolve(Amat,Bmat,Xmat);CHKERRQ(ierr);
13571683a169SBarry Smith       ierr = MatDenseGetArrayRead(Xmat,&X);CHKERRQ(ierr);
13580c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
13590c37af3bSToby Isaac       ierr = PetscMalloc2(closureSize+1,&childOffsets,closureSizeP+1,&parentOffsets);CHKERRQ(ierr);
13600c37af3bSToby Isaac       childOffsets[0] = 0;
13610c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13620c37af3bSToby Isaac         PetscInt p = closure[2*i];
13630c37af3bSToby Isaac         PetscInt dof;
13640c37af3bSToby Isaac 
1365085f0adfSToby Isaac         if (numFields) {
13660c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
13670c37af3bSToby Isaac         }
13680c37af3bSToby Isaac         else {
13690c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
13700c37af3bSToby Isaac         }
137152a3aeb4SToby Isaac         childOffsets[i+1]=childOffsets[i]+dof;
13720c37af3bSToby Isaac       }
13730c37af3bSToby Isaac       parentOffsets[0] = 0;
13740c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
13750c37af3bSToby Isaac         PetscInt p = closureP[2*i];
13760c37af3bSToby Isaac         PetscInt dof;
13770c37af3bSToby Isaac 
1378085f0adfSToby Isaac         if (numFields) {
13790c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
13800c37af3bSToby Isaac         }
13810c37af3bSToby Isaac         else {
13820c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
13830c37af3bSToby Isaac         }
138452a3aeb4SToby Isaac         parentOffsets[i+1]=parentOffsets[i]+dof;
13850c37af3bSToby Isaac       }
13860c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13872c44ad04SToby Isaac         PetscInt conDof, conOff, aDof, aOff, nWork;
13880c37af3bSToby Isaac         PetscInt p = closure[2*i];
13890c37af3bSToby Isaac         PetscInt o = closure[2*i+1];
1390085f0adfSToby Isaac         const PetscInt    *perm;
1391085f0adfSToby Isaac         const PetscScalar *flip;
13920c37af3bSToby Isaac 
13930c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1394085f0adfSToby Isaac         if (numFields) {
13950c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
13960c37af3bSToby Isaac           ierr = PetscSectionGetFieldOffset(cSec,p,f,&conOff);CHKERRQ(ierr);
13970c37af3bSToby Isaac         }
13980c37af3bSToby Isaac         else {
13990c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
14000c37af3bSToby Isaac           ierr = PetscSectionGetOffset(cSec,p,&conOff);CHKERRQ(ierr);
14010c37af3bSToby Isaac         }
14020c37af3bSToby Isaac         if (!conDof) continue;
1403085f0adfSToby Isaac         perm  = (perms && perms[i]) ? perms[i][o] : NULL;
1404085f0adfSToby Isaac         flip  = (flips && flips[i]) ? flips[i][o] : NULL;
14050c37af3bSToby Isaac         ierr  = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
14060c37af3bSToby Isaac         ierr  = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
14072c44ad04SToby Isaac         nWork = childOffsets[i+1]-childOffsets[i];
14080c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
14090c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
14100c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
14110c37af3bSToby Isaac 
1412085f0adfSToby Isaac           if (numFields) {
14130c37af3bSToby Isaac             ierr = PetscSectionGetFieldDof(section,a,f,&aSecDof);CHKERRQ(ierr);
14140c37af3bSToby Isaac             ierr = PetscSectionGetFieldOffset(section,a,f,&aSecOff);CHKERRQ(ierr);
14150c37af3bSToby Isaac           }
14160c37af3bSToby Isaac           else {
14170c37af3bSToby Isaac             ierr = PetscSectionGetDof(section,a,&aSecDof);CHKERRQ(ierr);
14180c37af3bSToby Isaac             ierr = PetscSectionGetOffset(section,a,&aSecOff);CHKERRQ(ierr);
14190c37af3bSToby Isaac           }
14200c37af3bSToby Isaac           if (!aSecDof) continue;
14210c37af3bSToby Isaac 
14220c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
14230c37af3bSToby Isaac             PetscInt q = closureP[2*j];
14240c37af3bSToby Isaac             PetscInt oq = closureP[2*j+1];
14252c44ad04SToby Isaac 
14262c44ad04SToby Isaac             if (q == a) {
142752a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1428085f0adfSToby Isaac               const PetscInt    *permP;
1429085f0adfSToby Isaac               const PetscScalar *flipP;
1430085f0adfSToby Isaac 
1431085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1432085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
14332c44ad04SToby Isaac               nWorkP = parentOffsets[j+1]-parentOffsets[j];
14342c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
14351683a169SBarry Smith                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
14362c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
14372c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
14382c44ad04SToby Isaac                 for (s = 0; s < nWorkP; s++) {
14392c44ad04SToby Isaac                   scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
14402c44ad04SToby Isaac                 }
14412c44ad04SToby Isaac               }
144252a3aeb4SToby Isaac               for (r = 0; r < nWork; r++)  {workIndRow[perm  ? perm[r]  : r] = conOff  + r;}
144352a3aeb4SToby Isaac               for (s = 0; s < nWorkP; s++) {workIndCol[permP ? permP[s] : s] = aSecOff + s;}
14442c44ad04SToby Isaac               if (flip) {
14452c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14462c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14472c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flip[r];
14482c44ad04SToby Isaac                   }
14492c44ad04SToby Isaac                 }
14502c44ad04SToby Isaac               }
14512c44ad04SToby Isaac               if (flipP) {
14522c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14532c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14542c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flipP[s];
14552c44ad04SToby Isaac                   }
14562c44ad04SToby Isaac                 }
14572c44ad04SToby Isaac               }
14582c44ad04SToby Isaac               ierr = MatSetValues(cMat,nWork,workIndRow,nWorkP,workIndCol,scwork,INSERT_VALUES);CHKERRQ(ierr);
14592c44ad04SToby Isaac               break;
14600c37af3bSToby Isaac             }
14610c37af3bSToby Isaac           }
14620c37af3bSToby Isaac         }
14630c37af3bSToby Isaac       }
14641683a169SBarry Smith       ierr = MatDenseRestoreArrayRead(Xmat,&X);CHKERRQ(ierr);
14650c37af3bSToby Isaac       ierr = PetscFree2(childOffsets,parentOffsets);CHKERRQ(ierr);
14660c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
14670c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
14680c37af3bSToby Isaac     }
14690c37af3bSToby Isaac     ierr = MatDestroy(&Amat);CHKERRQ(ierr);
14700c37af3bSToby Isaac     ierr = MatDestroy(&Bmat);CHKERRQ(ierr);
14710c37af3bSToby Isaac     ierr = MatDestroy(&Xmat);CHKERRQ(ierr);
14722c44ad04SToby Isaac     ierr = PetscFree(scwork);CHKERRQ(ierr);
14732c44ad04SToby Isaac     ierr = PetscFree7(sizes,weights,pointsRef,pointsReal,work,workIndRow,workIndCol);CHKERRQ(ierr);
1474b3a4bf2aSToby Isaac     if (id == PETSCFV_CLASSID) {
1475b3a4bf2aSToby Isaac       ierr = PetscSpaceDestroy(&bspace);CHKERRQ(ierr);
1476b3a4bf2aSToby Isaac     }
14770c37af3bSToby Isaac   }
14780c37af3bSToby Isaac   ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14790c37af3bSToby Isaac   ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14800c37af3bSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJparent);CHKERRQ(ierr);
14810c37af3bSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
14820c37af3bSToby Isaac 
14830c37af3bSToby Isaac   PetscFunctionReturn(0);
14840c37af3bSToby Isaac }
148595a0b26dSToby Isaac 
148621968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
148795a0b26dSToby Isaac {
1488f7c74593SToby Isaac   Mat               refCmat;
148921968bf8SToby Isaac   PetscDS           ds;
1490085f0adfSToby Isaac   PetscInt          numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
149121968bf8SToby Isaac   PetscScalar       ***refPointFieldMats;
149221968bf8SToby Isaac   PetscSection      refConSec, refAnSec, refSection;
149321968bf8SToby Isaac   IS                refAnIS;
149421968bf8SToby Isaac   const PetscInt    *refAnchors;
1495085f0adfSToby Isaac   const PetscInt    **perms;
1496085f0adfSToby Isaac   const PetscScalar **flips;
149795a0b26dSToby Isaac   PetscErrorCode    ierr;
149895a0b26dSToby Isaac 
149995a0b26dSToby Isaac   PetscFunctionBegin;
150021968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
150195a0b26dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1502085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
1503f7c74593SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
1504a17985deSToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
150595a0b26dSToby Isaac   ierr = ISGetIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
150692fd8e1eSJed Brown   ierr = DMGetLocalSection(refTree,&refSection);CHKERRQ(ierr);
150795a0b26dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
150895a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
150995a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldN);CHKERRQ(ierr);
151095a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
151195a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
151295a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
151395a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof*maxAnDof,&cols);CHKERRQ(ierr);
151495a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
151595a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
151695a0b26dSToby Isaac 
151795a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
151895a0b26dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
151995a0b26dSToby Isaac     if (!pDof || parent == p) continue;
152095a0b26dSToby Isaac 
1521085f0adfSToby Isaac     ierr = PetscMalloc1(maxFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
1522085f0adfSToby Isaac     ierr = PetscCalloc1(maxFields,&refPointFieldN[p-pRefStart]);CHKERRQ(ierr);
152395a0b26dSToby Isaac     ierr = DMPlexGetTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1524085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1525085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
152695a0b26dSToby Isaac 
1527085f0adfSToby Isaac       if (f < numFields) {
152895a0b26dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
152995a0b26dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
1530085f0adfSToby Isaac         ierr = PetscSectionGetFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1531085f0adfSToby Isaac       } else {
153295a0b26dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
153395a0b26dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
1534085f0adfSToby Isaac         ierr = PetscSectionGetPointSyms(refSection,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
153595a0b26dSToby Isaac       }
153695a0b26dSToby Isaac 
153795a0b26dSToby Isaac       for (r = 0; r < cDof; r++) {
153895a0b26dSToby Isaac         rows[r] = cOff + r;
153995a0b26dSToby Isaac       }
154095a0b26dSToby Isaac       numCols = 0;
154195a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
154295a0b26dSToby Isaac         PetscInt          q = closure[2*i];
154395a0b26dSToby Isaac         PetscInt          aDof, aOff, j;
1544085f0adfSToby Isaac         const PetscInt    *perm = perms ? perms[i] : NULL;
154595a0b26dSToby Isaac 
1546085f0adfSToby Isaac         if (numFields) {
154795a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
154895a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
154995a0b26dSToby Isaac         }
155095a0b26dSToby Isaac         else {
155195a0b26dSToby Isaac           ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
155295a0b26dSToby Isaac           ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
155395a0b26dSToby Isaac         }
155495a0b26dSToby Isaac 
155595a0b26dSToby Isaac         for (j = 0; j < aDof; j++) {
1556085f0adfSToby Isaac           cols[numCols++] = aOff + (perm ? perm[j] : j);
155795a0b26dSToby Isaac         }
155895a0b26dSToby Isaac       }
155995a0b26dSToby Isaac       refPointFieldN[p-pRefStart][f] = numCols;
156095a0b26dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
156195a0b26dSToby Isaac       ierr = MatGetValues(refCmat,cDof,rows,numCols,cols,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
1562085f0adfSToby Isaac       if (flips) {
1563085f0adfSToby Isaac         PetscInt colOff = 0;
1564085f0adfSToby Isaac 
1565085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1566085f0adfSToby Isaac           PetscInt          q = closure[2*i];
1567085f0adfSToby Isaac           PetscInt          aDof, aOff, j;
1568085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1569085f0adfSToby Isaac 
1570085f0adfSToby Isaac           if (numFields) {
1571085f0adfSToby Isaac             ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
1572085f0adfSToby Isaac             ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
1573085f0adfSToby Isaac           }
1574085f0adfSToby Isaac           else {
1575085f0adfSToby Isaac             ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
1576085f0adfSToby Isaac             ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
1577085f0adfSToby Isaac           }
1578085f0adfSToby Isaac           if (flip) {
1579085f0adfSToby Isaac             PetscInt k;
1580085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1581085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1582085f0adfSToby Isaac                 refPointFieldMats[p-pRefStart][f][k * numCols + colOff + j] *= flip[j];
1583085f0adfSToby Isaac               }
1584085f0adfSToby Isaac             }
1585085f0adfSToby Isaac           }
1586085f0adfSToby Isaac           colOff += aDof;
1587085f0adfSToby Isaac         }
1588085f0adfSToby Isaac       }
1589085f0adfSToby Isaac       if (numFields) {
1590085f0adfSToby Isaac         ierr = PetscSectionRestoreFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1591085f0adfSToby Isaac       } else {
1592085f0adfSToby Isaac         ierr = PetscSectionRestorePointSyms(refSection,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1593085f0adfSToby Isaac       }
159495a0b26dSToby Isaac     }
159595a0b26dSToby Isaac     ierr = DMPlexRestoreTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
159695a0b26dSToby Isaac   }
159721968bf8SToby Isaac   *childrenMats = refPointFieldMats;
159821968bf8SToby Isaac   *childrenN = refPointFieldN;
159921968bf8SToby Isaac   ierr = ISRestoreIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
160021968bf8SToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
160121968bf8SToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
160221968bf8SToby Isaac   PetscFunctionReturn(0);
160321968bf8SToby Isaac }
160421968bf8SToby Isaac 
160521968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
160621968bf8SToby Isaac {
160721968bf8SToby Isaac   PetscDS        ds;
160821968bf8SToby Isaac   PetscInt       **refPointFieldN;
160921968bf8SToby Isaac   PetscScalar    ***refPointFieldMats;
1610085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
161121968bf8SToby Isaac   PetscSection   refConSec;
161221968bf8SToby Isaac   PetscErrorCode ierr;
161321968bf8SToby Isaac 
161421968bf8SToby Isaac   PetscFunctionBegin;
161521968bf8SToby Isaac   refPointFieldN = *childrenN;
161621968bf8SToby Isaac   *childrenN = NULL;
161721968bf8SToby Isaac   refPointFieldMats = *childrenMats;
161821968bf8SToby Isaac   *childrenMats = NULL;
161921968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
162021968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1621367003a6SStefano Zampini   maxFields = PetscMax(1,numFields);
162221968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
1623e44e4e7fSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
162421968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
162521968bf8SToby Isaac     PetscInt parent, pDof;
162621968bf8SToby Isaac 
162721968bf8SToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
162821968bf8SToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
162921968bf8SToby Isaac     if (!pDof || parent == p) continue;
163021968bf8SToby Isaac 
1631085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
163221968bf8SToby Isaac       PetscInt cDof;
163321968bf8SToby Isaac 
1634085f0adfSToby Isaac       if (numFields) {
163521968bf8SToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
163621968bf8SToby Isaac       }
163721968bf8SToby Isaac       else {
163821968bf8SToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
163921968bf8SToby Isaac       }
164021968bf8SToby Isaac 
164121968bf8SToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
164221968bf8SToby Isaac     }
164321968bf8SToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
164421968bf8SToby Isaac     ierr = PetscFree(refPointFieldN[p - pRefStart]);CHKERRQ(ierr);
164521968bf8SToby Isaac   }
164621968bf8SToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
164721968bf8SToby Isaac   ierr = PetscFree(refPointFieldN);CHKERRQ(ierr);
164821968bf8SToby Isaac   PetscFunctionReturn(0);
164921968bf8SToby Isaac }
165021968bf8SToby Isaac 
165121968bf8SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
165221968bf8SToby Isaac {
165321968bf8SToby Isaac   DM             refTree;
165421968bf8SToby Isaac   PetscDS        ds;
165521968bf8SToby Isaac   Mat            refCmat;
1656085f0adfSToby Isaac   PetscInt       numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
165721968bf8SToby Isaac   PetscScalar ***refPointFieldMats, *pointWork;
165821968bf8SToby Isaac   PetscSection   refConSec, refAnSec, anSec;
165921968bf8SToby Isaac   IS             refAnIS, anIS;
166021968bf8SToby Isaac   const PetscInt *anchors;
166121968bf8SToby Isaac   PetscErrorCode ierr;
166221968bf8SToby Isaac 
166321968bf8SToby Isaac   PetscFunctionBegin;
166421968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
166521968bf8SToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
166621968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1667085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
166821968bf8SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
1669e5e52638SMatthew G. Knepley   ierr = DMCopyDisc(dm,refTree);CHKERRQ(ierr);
167021968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
167121968bf8SToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
167221968bf8SToby Isaac   ierr = DMPlexGetAnchors(dm,&anSec,&anIS);CHKERRQ(ierr);
167321968bf8SToby Isaac   ierr = ISGetIndices(anIS,&anchors);CHKERRQ(ierr);
167421968bf8SToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
167521968bf8SToby Isaac   ierr = PetscSectionGetChart(conSec,&conStart,&conEnd);CHKERRQ(ierr);
167621968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
167721968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
167821968bf8SToby Isaac   ierr = PetscMalloc1(maxDof*maxDof*maxAnDof,&pointWork);CHKERRQ(ierr);
167921968bf8SToby Isaac 
168021968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
168121968bf8SToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
168295a0b26dSToby Isaac 
168395a0b26dSToby Isaac   /* step 2: compute the preorder */
168495a0b26dSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
168595a0b26dSToby Isaac   ierr = PetscMalloc2(pEnd-pStart,&perm,pEnd-pStart,&iperm);CHKERRQ(ierr);
168695a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
168795a0b26dSToby Isaac     perm[p - pStart] = p;
168895a0b26dSToby Isaac     iperm[p - pStart] = p-pStart;
168995a0b26dSToby Isaac   }
169095a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
169195a0b26dSToby Isaac     PetscInt point = perm[p];
169295a0b26dSToby Isaac     PetscInt parent;
169395a0b26dSToby Isaac 
169495a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
169595a0b26dSToby Isaac     if (parent == point) {
169695a0b26dSToby Isaac       p++;
169795a0b26dSToby Isaac     }
169895a0b26dSToby Isaac     else {
169995a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
170095a0b26dSToby Isaac 
170195a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
170295a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
170395a0b26dSToby Isaac         PetscInt q = closure[2*i];
170495a0b26dSToby Isaac         if (iperm[q-pStart] > iperm[point-pStart]) {
170595a0b26dSToby Isaac           /* swap */
170695a0b26dSToby Isaac           perm[p]               = q;
170795a0b26dSToby Isaac           perm[iperm[q-pStart]] = point;
170895a0b26dSToby Isaac           iperm[point-pStart]   = iperm[q-pStart];
170995a0b26dSToby Isaac           iperm[q-pStart]       = p;
171095a0b26dSToby Isaac           break;
171195a0b26dSToby Isaac         }
171295a0b26dSToby Isaac       }
171395a0b26dSToby Isaac       size = closureSize;
171495a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
171595a0b26dSToby Isaac       if (i == size) {
171695a0b26dSToby Isaac         p++;
171795a0b26dSToby Isaac       }
171895a0b26dSToby Isaac     }
171995a0b26dSToby Isaac   }
172095a0b26dSToby Isaac 
172195a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
172295a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
172395a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
172495a0b26dSToby Isaac    * values outside of the Mat first.
172595a0b26dSToby Isaac    */
172695a0b26dSToby Isaac   {
172795a0b26dSToby Isaac     PetscInt nRows, row, nnz;
172895a0b26dSToby Isaac     PetscBool done;
172995a0b26dSToby Isaac     const PetscInt *ia, *ja;
173095a0b26dSToby Isaac     PetscScalar *vals;
173195a0b26dSToby Isaac 
173295a0b26dSToby Isaac     ierr = MatGetRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
1733*2c71b3e2SJacob Faibussowitsch     PetscCheckFalse(!done,PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not get RowIJ of constraint matrix");
173495a0b26dSToby Isaac     nnz  = ia[nRows];
173595a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
173695a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
173795a0b26dSToby Isaac     ierr = PetscMalloc1(nnz,&vals);CHKERRQ(ierr);
173895a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
173995a0b26dSToby Isaac       PetscInt        parent, childid, closureSize, *closure = NULL;
174095a0b26dSToby Isaac       PetscInt        point = perm[p], pointDof;
174195a0b26dSToby Isaac 
174295a0b26dSToby Isaac       ierr = DMPlexGetTreeParent(dm,point,&parent,&childid);CHKERRQ(ierr);
174395a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
174495a0b26dSToby Isaac       ierr = PetscSectionGetDof(conSec,point,&pointDof);CHKERRQ(ierr);
174595a0b26dSToby Isaac       if (!pointDof) continue;
174695a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1747085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1748085f0adfSToby Isaac         PetscInt cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
174995a0b26dSToby Isaac         PetscScalar *pointMat;
1750085f0adfSToby Isaac         const PetscInt    **perms;
1751085f0adfSToby Isaac         const PetscScalar **flips;
175295a0b26dSToby Isaac 
1753085f0adfSToby Isaac         if (numFields) {
175495a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(conSec,point,f,&cDof);CHKERRQ(ierr);
175595a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(conSec,point,f,&cOff);CHKERRQ(ierr);
175695a0b26dSToby Isaac         }
175795a0b26dSToby Isaac         else {
175895a0b26dSToby Isaac           ierr = PetscSectionGetDof(conSec,point,&cDof);CHKERRQ(ierr);
175995a0b26dSToby Isaac           ierr = PetscSectionGetOffset(conSec,point,&cOff);CHKERRQ(ierr);
176095a0b26dSToby Isaac         }
176195a0b26dSToby Isaac         if (!cDof) continue;
1762085f0adfSToby Isaac         if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);}
1763085f0adfSToby Isaac         else           {ierr = PetscSectionGetPointSyms(section,closureSize,closure,&perms,&flips);CHKERRQ(ierr);}
176495a0b26dSToby Isaac 
176595a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
176676bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
176795a0b26dSToby Isaac           for (r = 0; r < cDof; r++) {
176895a0b26dSToby Isaac             if (cDof > 1 && r) {
1769*2c71b3e2SJacob Faibussowitsch               PetscCheckFalse((ia[cOff+r+1]-ia[cOff+r]) != (ia[cOff+r]-ia[cOff+r-1]),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Two point rows have different nnz: %D vs. %D", (ia[cOff+r+1]-ia[cOff+r]), (ia[cOff+r]-ia[cOff+r-1]));
177095a0b26dSToby Isaac             }
177195a0b26dSToby Isaac           }
177276bd3646SJed Brown         }
177395a0b26dSToby Isaac         /* zero rows */
177495a0b26dSToby Isaac         for (i = ia[cOff] ; i< ia[cOff+cDof];i++) {
177595a0b26dSToby Isaac           vals[i] = 0.;
177695a0b26dSToby Isaac         }
177795a0b26dSToby Isaac         matOffset = ia[cOff];
177895a0b26dSToby Isaac         numFillCols = ia[cOff+1] - matOffset;
177995a0b26dSToby Isaac         pointMat = refPointFieldMats[childid-pRefStart][f];
178095a0b26dSToby Isaac         numCols = refPointFieldN[childid-pRefStart][f];
178195a0b26dSToby Isaac         offset = 0;
178295a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
178395a0b26dSToby Isaac           PetscInt q = closure[2*i];
178495a0b26dSToby Isaac           PetscInt aDof, aOff, j, k, qConDof, qConOff;
1785085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1786085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
178795a0b26dSToby Isaac 
178895a0b26dSToby Isaac           qConDof = qConOff = 0;
1789085f0adfSToby Isaac           if (numFields) {
179095a0b26dSToby Isaac             ierr = PetscSectionGetFieldDof(section,q,f,&aDof);CHKERRQ(ierr);
179195a0b26dSToby Isaac             ierr = PetscSectionGetFieldOffset(section,q,f,&aOff);CHKERRQ(ierr);
179295a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
179395a0b26dSToby Isaac               ierr = PetscSectionGetFieldDof(conSec,q,f,&qConDof);CHKERRQ(ierr);
179495a0b26dSToby Isaac               ierr = PetscSectionGetFieldOffset(conSec,q,f,&qConOff);CHKERRQ(ierr);
179595a0b26dSToby Isaac             }
179695a0b26dSToby Isaac           }
179795a0b26dSToby Isaac           else {
179895a0b26dSToby Isaac             ierr = PetscSectionGetDof(section,q,&aDof);CHKERRQ(ierr);
179995a0b26dSToby Isaac             ierr = PetscSectionGetOffset(section,q,&aOff);CHKERRQ(ierr);
180095a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
180195a0b26dSToby Isaac               ierr = PetscSectionGetDof(conSec,q,&qConDof);CHKERRQ(ierr);
180295a0b26dSToby Isaac               ierr = PetscSectionGetOffset(conSec,q,&qConOff);CHKERRQ(ierr);
180395a0b26dSToby Isaac             }
180495a0b26dSToby Isaac           }
180595a0b26dSToby Isaac           if (!aDof) continue;
180695a0b26dSToby Isaac           if (qConDof) {
180795a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
180895a0b26dSToby Isaac              * be filled, thanks to preordering */
180995a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
181095a0b26dSToby Isaac             PetscInt aMatOffset = ia[qConOff];
181195a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
181295a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
181395a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
181495a0b26dSToby Isaac                 PetscScalar inVal = 0;
181595a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1816085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
181795a0b26dSToby Isaac 
1818085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
181995a0b26dSToby Isaac                 }
182095a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
182195a0b26dSToby Isaac               }
182295a0b26dSToby Isaac             }
182395a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
182495a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
182595a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
182695a0b26dSToby Isaac               for (;k < numFillCols; k++) {
182795a0b26dSToby Isaac                 if (ja[matOffset + k] == col) {
182895a0b26dSToby Isaac                   break;
182995a0b26dSToby Isaac                 }
183095a0b26dSToby Isaac               }
1831*2c71b3e2SJacob Faibussowitsch               PetscCheckFalse(k == numFillCols,PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, col);
183295a0b26dSToby Isaac               for (r = 0; r < cDof; r++) {
183395a0b26dSToby Isaac                 vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
183495a0b26dSToby Isaac               }
183595a0b26dSToby Isaac             }
183695a0b26dSToby Isaac           }
183795a0b26dSToby Isaac           else {
183895a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
183995a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
184095a0b26dSToby Isaac               if (ja[matOffset + k] == aOff) {
184195a0b26dSToby Isaac                 break;
184295a0b26dSToby Isaac               }
184395a0b26dSToby Isaac             }
1844*2c71b3e2SJacob Faibussowitsch             PetscCheckFalse(k == numFillCols,PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, aOff);
184595a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1846085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1847085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1848085f0adfSToby Isaac 
1849085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
185095a0b26dSToby Isaac               }
185195a0b26dSToby Isaac             }
185295a0b26dSToby Isaac           }
185395a0b26dSToby Isaac           offset += aDof;
185495a0b26dSToby Isaac         }
1855085f0adfSToby Isaac         if (numFields) {
1856085f0adfSToby Isaac           ierr = PetscSectionRestoreFieldPointSyms(section,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1857085f0adfSToby Isaac         } else {
1858085f0adfSToby Isaac           ierr = PetscSectionRestorePointSyms(section,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1859085f0adfSToby Isaac         }
186095a0b26dSToby Isaac       }
186195a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
186295a0b26dSToby Isaac     }
186395a0b26dSToby Isaac     for (row = 0; row < nRows; row++) {
186495a0b26dSToby Isaac       ierr = MatSetValues(cMat,1,&row,ia[row+1]-ia[row],&ja[ia[row]],&vals[ia[row]],INSERT_VALUES);CHKERRQ(ierr);
186595a0b26dSToby Isaac     }
186695a0b26dSToby Isaac     ierr = MatRestoreRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
1867*2c71b3e2SJacob Faibussowitsch     PetscCheckFalse(!done,PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not restore RowIJ of constraint matrix");
186895a0b26dSToby Isaac     ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
186995a0b26dSToby Isaac     ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
187095a0b26dSToby Isaac     ierr = PetscFree(vals);CHKERRQ(ierr);
187195a0b26dSToby Isaac   }
187295a0b26dSToby Isaac 
187395a0b26dSToby Isaac   /* clean up */
187495a0b26dSToby Isaac   ierr = ISRestoreIndices(anIS,&anchors);CHKERRQ(ierr);
187595a0b26dSToby Isaac   ierr = PetscFree2(perm,iperm);CHKERRQ(ierr);
187695a0b26dSToby Isaac   ierr = PetscFree(pointWork);CHKERRQ(ierr);
187721968bf8SToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
187895a0b26dSToby Isaac   PetscFunctionReturn(0);
187995a0b26dSToby Isaac }
188095a0b26dSToby Isaac 
18816f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
18826f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
18836f5f1567SToby Isaac PetscErrorCode DMPlexTreeRefineCell (DM dm, PetscInt cell, DM *ncdm)
18846f5f1567SToby Isaac {
18856f5f1567SToby Isaac   DM K;
1886420f55faSMatthew G. Knepley   PetscMPIInt rank;
18876f5f1567SToby Isaac   PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
18886f5f1567SToby Isaac   PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations;
18896f5f1567SToby Isaac   PetscInt *Kembedding;
18906f5f1567SToby Isaac   PetscInt *cellClosure=NULL, nc;
18916f5f1567SToby Isaac   PetscScalar *newVertexCoords;
18926f5f1567SToby Isaac   PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
18936f5f1567SToby Isaac   PetscSection parentSection;
18946f5f1567SToby Isaac   PetscErrorCode ierr;
18956f5f1567SToby Isaac 
18966f5f1567SToby Isaac   PetscFunctionBegin;
1897ffc4695bSBarry Smith   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRMPI(ierr);
189828f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
18996f5f1567SToby Isaac   ierr = DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm);CHKERRQ(ierr);
190028f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ncdm,dim);CHKERRQ(ierr);
19016f5f1567SToby Isaac 
19026f5f1567SToby Isaac   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
19036f5f1567SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&parentSection);CHKERRQ(ierr);
19046f5f1567SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&K);CHKERRQ(ierr);
1905dd400576SPatrick Sanan   if (rank == 0) {
19066f5f1567SToby Isaac     /* compute the new charts */
19076f5f1567SToby Isaac     ierr = PetscMalloc5(dim+1,&pNewCount,dim+1,&pNewStart,dim+1,&pNewEnd,dim+1,&pOldStart,dim+1,&pOldEnd);CHKERRQ(ierr);
19086f5f1567SToby Isaac     offset = 0;
19096f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19106f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
19116f5f1567SToby Isaac 
19126f5f1567SToby Isaac       pNewStart[d] = offset;
19136f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(dm,d,&pOldStart[d],&pOldEnd[d]);CHKERRQ(ierr);
19146f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
19156f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
19166f5f1567SToby Isaac       /* adding the new points */
19176f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
19186f5f1567SToby Isaac       if (!d) {
19196f5f1567SToby Isaac         /* removing the cell */
19206f5f1567SToby Isaac         pNewCount[d]--;
19216f5f1567SToby Isaac       }
19226f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19236f5f1567SToby Isaac         PetscInt parent;
19246f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&parent,NULL);CHKERRQ(ierr);
19256f5f1567SToby Isaac         if (parent == k) {
19266f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
19276f5f1567SToby Isaac           pNewCount[d]--;
19286f5f1567SToby Isaac         }
19296f5f1567SToby Isaac       }
19306f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
19316f5f1567SToby Isaac       offset = pNewEnd[d];
19326f5f1567SToby Isaac 
19336f5f1567SToby Isaac     }
1934*2c71b3e2SJacob Faibussowitsch     PetscCheckFalse(cell < pOldStart[0] || cell >= pOldEnd[0],PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"%d not in cell range [%d, %d)", cell, pOldStart[0], pOldEnd[0]);
19356f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
19366f5f1567SToby Isaac     ierr = DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
19376f5f1567SToby Isaac 
19386f5f1567SToby Isaac     ierr = PetscMalloc1(pNewEnd[dim],&newConeSizes);CHKERRQ(ierr);
19396f5f1567SToby Isaac     {
1940b5a892a1SMatthew G. Knepley       DMPolytopeType pct, qct;
19416f5f1567SToby Isaac       PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
19426f5f1567SToby Isaac 
19436f5f1567SToby Isaac       ierr = DMPlexGetChart(K,&kStart,&kEnd);CHKERRQ(ierr);
19446f5f1567SToby Isaac       ierr = PetscMalloc4(kEnd-kStart,&Kembedding,kEnd-kStart,&perm,kEnd-kStart,&iperm,kEnd-kStart,&preOrient);CHKERRQ(ierr);
19456f5f1567SToby Isaac 
19466f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19476f5f1567SToby Isaac         perm[k - kStart] = k;
19486f5f1567SToby Isaac         iperm [k - kStart] = k - kStart;
19496f5f1567SToby Isaac         preOrient[k - kStart] = 0;
19506f5f1567SToby Isaac       }
19516f5f1567SToby Isaac 
19526f5f1567SToby Isaac       ierr = DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
19536f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
19546f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2*j+1];
19556f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2*j+1];
19566f5f1567SToby Isaac         PetscInt p, q;
19576f5f1567SToby Isaac 
19586f5f1567SToby Isaac         p = closureK[2*j];
19596f5f1567SToby Isaac         q = cellClosure[2*j];
1960b5a892a1SMatthew G. Knepley         ierr = DMPlexGetCellType(K, p, &pct);CHKERRQ(ierr);
1961b5a892a1SMatthew G. Knepley         ierr = DMPlexGetCellType(dm, q, &qct);CHKERRQ(ierr);
19626f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
19636f5f1567SToby Isaac           if (q >= pOldStart[d] && q < pOldEnd[d]) {
19646f5f1567SToby Isaac             Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
19656f5f1567SToby Isaac           }
19666f5f1567SToby Isaac         }
1967b5a892a1SMatthew G. Knepley         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1968b5a892a1SMatthew G. Knepley         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
19696f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
19706f5f1567SToby Isaac           PetscInt numChildren, i;
19716f5f1567SToby Isaac           const PetscInt *children;
19726f5f1567SToby Isaac 
19736f5f1567SToby Isaac           ierr = DMPlexGetTreeChildren(K,p,&numChildren,&children);CHKERRQ(ierr);
19746f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
19756f5f1567SToby Isaac             PetscInt kPerm, oPerm;
19766f5f1567SToby Isaac 
19776f5f1567SToby Isaac             k    = children[i];
19786f5f1567SToby Isaac             ierr = DMPlexReferenceTreeGetChildSymmetry(K,p,parentOrientA,0,k,parentOrientB,&oPerm,&kPerm);CHKERRQ(ierr);
19796f5f1567SToby Isaac             /* perm = what refTree position I'm in */
19806f5f1567SToby Isaac             perm[kPerm-kStart]      = k;
19816f5f1567SToby Isaac             /* iperm = who is at this position */
19826f5f1567SToby Isaac             iperm[k-kStart]         = kPerm-kStart;
19836f5f1567SToby Isaac             preOrient[kPerm-kStart] = oPerm;
19846f5f1567SToby Isaac           }
19856f5f1567SToby Isaac         }
19866f5f1567SToby Isaac       }
19876f5f1567SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
19886f5f1567SToby Isaac     }
19896f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,0,pNewEnd[dim]);CHKERRQ(ierr);
19906f5f1567SToby Isaac     offset = 0;
19916f5f1567SToby Isaac     numNewCones = 0;
19926f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19936f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
19946f5f1567SToby Isaac       PetscInt p;
19956f5f1567SToby Isaac       PetscInt size;
19966f5f1567SToby Isaac 
19976f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19986f5f1567SToby Isaac         /* skip cell 0 */
19996f5f1567SToby Isaac         if (p == cell) continue;
20006f5f1567SToby Isaac         /* old cones to new cones */
20016f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
20026f5f1567SToby Isaac         newConeSizes[offset++] = size;
20036f5f1567SToby Isaac         numNewCones += size;
20046f5f1567SToby Isaac       }
20056f5f1567SToby Isaac 
20066f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
20076f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20086f5f1567SToby Isaac         PetscInt kParent;
20096f5f1567SToby Isaac 
20106f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
20116f5f1567SToby Isaac         if (kParent != k) {
20126f5f1567SToby Isaac           Kembedding[k] = offset;
20136f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
20146f5f1567SToby Isaac           newConeSizes[offset++] = size;
20156f5f1567SToby Isaac           numNewCones += size;
20166f5f1567SToby Isaac           if (kParent != 0) {
20176f5f1567SToby Isaac             ierr = PetscSectionSetDof(parentSection,Kembedding[k],1);CHKERRQ(ierr);
20186f5f1567SToby Isaac           }
20196f5f1567SToby Isaac         }
20206f5f1567SToby Isaac       }
20216f5f1567SToby Isaac     }
20226f5f1567SToby Isaac 
20236f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
20246f5f1567SToby Isaac     ierr = PetscSectionGetStorageSize(parentSection,&numPointsWithParents);CHKERRQ(ierr);
20256f5f1567SToby Isaac     ierr = PetscMalloc2(numNewCones,&newCones,numNewCones,&newOrientations);CHKERRQ(ierr);
20266f5f1567SToby Isaac     ierr = PetscMalloc2(numPointsWithParents,&parents,numPointsWithParents,&childIDs);CHKERRQ(ierr);
20276f5f1567SToby Isaac 
20286f5f1567SToby Isaac     /* fill new cones */
20296f5f1567SToby Isaac     offset = 0;
20306f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20316f5f1567SToby Isaac       PetscInt kStart, kEnd, k, l;
20326f5f1567SToby Isaac       PetscInt p;
20336f5f1567SToby Isaac       PetscInt size;
20346f5f1567SToby Isaac       const PetscInt *cone, *orientation;
20356f5f1567SToby Isaac 
20366f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
20376f5f1567SToby Isaac         /* skip cell 0 */
20386f5f1567SToby Isaac         if (p == cell) continue;
20396f5f1567SToby Isaac         /* old cones to new cones */
20406f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
20416f5f1567SToby Isaac         ierr = DMPlexGetCone(dm,p,&cone);CHKERRQ(ierr);
20426f5f1567SToby Isaac         ierr = DMPlexGetConeOrientation(dm,p,&orientation);CHKERRQ(ierr);
20436f5f1567SToby Isaac         for (l = 0; l < size; l++) {
20446f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
20456f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
20466f5f1567SToby Isaac         }
20476f5f1567SToby Isaac       }
20486f5f1567SToby Isaac 
20496f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
20506f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20516f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
20526f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
20536f5f1567SToby Isaac 
20546f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
20556f5f1567SToby Isaac         if (kParent != k) {
20566f5f1567SToby Isaac           /* embed new cones */
20576f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
20586f5f1567SToby Isaac           ierr = DMPlexGetCone(K,kPerm,&cone);CHKERRQ(ierr);
20596f5f1567SToby Isaac           ierr = DMPlexGetConeOrientation(K,kPerm,&orientation);CHKERRQ(ierr);
20606f5f1567SToby Isaac           for (l = 0; l < size; l++) {
20616f5f1567SToby Isaac             PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size -(preO + 1) - l) % size);
20626f5f1567SToby Isaac             PetscInt newO, lSize, oTrue;
2063b5a892a1SMatthew G. Knepley             DMPolytopeType ct = DM_NUM_POLYTOPES;
20646f5f1567SToby Isaac 
20656f5f1567SToby Isaac             q                         = iperm[cone[m]];
20666f5f1567SToby Isaac             newCones[offset]          = Kembedding[q];
20676f5f1567SToby Isaac             ierr                      = DMPlexGetConeSize(K,q,&lSize);CHKERRQ(ierr);
2068b5a892a1SMatthew G. Knepley             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
2069b5a892a1SMatthew G. Knepley             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
2070b5a892a1SMatthew G. Knepley             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
20716f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
20726f5f1567SToby Isaac             newO                      = DihedralCompose(lSize,oTrue,preOrient[q]);
2073b5a892a1SMatthew G. Knepley             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
20746f5f1567SToby Isaac           }
20756f5f1567SToby Isaac           if (kParent != 0) {
20766f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
20776f5f1567SToby Isaac             ierr              = PetscSectionGetOffset(parentSection,Kembedding[k],&pOffset);CHKERRQ(ierr);
20786f5f1567SToby Isaac             parents[pOffset]  = newPoint;
20796f5f1567SToby Isaac             childIDs[pOffset] = k;
20806f5f1567SToby Isaac           }
20816f5f1567SToby Isaac         }
20826f5f1567SToby Isaac       }
20836f5f1567SToby Isaac     }
20846f5f1567SToby Isaac 
20856f5f1567SToby Isaac     ierr = PetscMalloc1(dim*(pNewEnd[dim]-pNewStart[dim]),&newVertexCoords);CHKERRQ(ierr);
20866f5f1567SToby Isaac 
20876f5f1567SToby Isaac     /* fill coordinates */
20886f5f1567SToby Isaac     offset = 0;
20896f5f1567SToby Isaac     {
2090d90620a3SMatthew G. Knepley       PetscInt kStart, kEnd, l;
20916f5f1567SToby Isaac       PetscSection vSection;
20926f5f1567SToby Isaac       PetscInt v;
20936f5f1567SToby Isaac       Vec coords;
20946f5f1567SToby Isaac       PetscScalar *coordvals;
20956f5f1567SToby Isaac       PetscInt dof, off;
2096c111c6b7SMatthew G. Knepley       PetscReal v0[3], J[9], detJ;
20976f5f1567SToby Isaac 
209876bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
2099d90620a3SMatthew G. Knepley         PetscInt k;
21006f5f1567SToby Isaac         ierr = DMPlexGetHeightStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
21016f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
210273a7f2aaSMatthew G. Knepley           ierr = DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
2103*2c71b3e2SJacob Faibussowitsch           PetscCheckFalse(detJ <= 0.,PETSC_COMM_SELF,PETSC_ERR_PLIB,"reference tree cell %d has bad determinant",k);
21046f5f1567SToby Isaac         }
2105d90620a3SMatthew G. Knepley       }
210673a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
21076f5f1567SToby Isaac       ierr = DMGetCoordinateSection(dm,&vSection);CHKERRQ(ierr);
21086f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr);
21096f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
21106f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
21116f5f1567SToby Isaac 
21126f5f1567SToby Isaac         ierr = PetscSectionGetDof(vSection,v,&dof);CHKERRQ(ierr);
21136f5f1567SToby Isaac         ierr = PetscSectionGetOffset(vSection,v,&off);CHKERRQ(ierr);
21146f5f1567SToby Isaac         for (l = 0; l < dof; l++) {
21156f5f1567SToby Isaac           newVertexCoords[offset++] = coordvals[off + l];
21166f5f1567SToby Isaac         }
21176f5f1567SToby Isaac       }
21186f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21196f5f1567SToby Isaac 
21206f5f1567SToby Isaac       ierr = DMGetCoordinateSection(K,&vSection);CHKERRQ(ierr);
21216f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(K,&coords);CHKERRQ(ierr);
21226f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
21236f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
21246f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
21259bc368c7SMatthew G. Knepley         PetscReal coord[3], newCoord[3];
21266f5f1567SToby Isaac         PetscInt  vPerm = perm[v];
21276f5f1567SToby Isaac         PetscInt  kParent;
2128c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
21296f5f1567SToby Isaac 
21306f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,v,&kParent,NULL);CHKERRQ(ierr);
21316f5f1567SToby Isaac         if (kParent != v) {
21326f5f1567SToby Isaac           /* this is a new vertex */
21336f5f1567SToby Isaac           ierr = PetscSectionGetOffset(vSection,vPerm,&off);CHKERRQ(ierr);
21349bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off+l]);
2135367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
21369bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset+l] = newCoord[l];
21376f5f1567SToby Isaac           offset += dim;
21386f5f1567SToby Isaac         }
21396f5f1567SToby Isaac       }
21406f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21416f5f1567SToby Isaac     }
21426f5f1567SToby Isaac 
21436f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
21446f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
21456f5f1567SToby Isaac       PetscInt tmp;
21466f5f1567SToby Isaac 
21476f5f1567SToby Isaac       tmp = pNewCount[d];
21486f5f1567SToby Isaac       pNewCount[d] = pNewCount[dim - d];
21496f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
21506f5f1567SToby Isaac     }
21516f5f1567SToby Isaac 
21526f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,pNewCount,newConeSizes,newCones,newOrientations,newVertexCoords);CHKERRQ(ierr);
21536f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
21546f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,parents,childIDs);CHKERRQ(ierr);
21556f5f1567SToby Isaac 
21566f5f1567SToby Isaac     /* clean up */
21576f5f1567SToby Isaac     ierr = DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
21586f5f1567SToby Isaac     ierr = PetscFree5(pNewCount,pNewStart,pNewEnd,pOldStart,pOldEnd);CHKERRQ(ierr);
21596f5f1567SToby Isaac     ierr = PetscFree(newConeSizes);CHKERRQ(ierr);
21606f5f1567SToby Isaac     ierr = PetscFree2(newCones,newOrientations);CHKERRQ(ierr);
21616f5f1567SToby Isaac     ierr = PetscFree(newVertexCoords);CHKERRQ(ierr);
21626f5f1567SToby Isaac     ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
21636f5f1567SToby Isaac     ierr = PetscFree4(Kembedding,perm,iperm,preOrient);CHKERRQ(ierr);
21646f5f1567SToby Isaac   }
21656f5f1567SToby Isaac   else {
21666f5f1567SToby Isaac     PetscInt    p, counts[4];
21676f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
21686f5f1567SToby Isaac     Vec         coordVec;
21696f5f1567SToby Isaac     PetscScalar *coords;
21706f5f1567SToby Isaac 
21716f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
21726f5f1567SToby Isaac       PetscInt dStart, dEnd;
21736f5f1567SToby Isaac 
21746f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
21756f5f1567SToby Isaac       counts[d] = dEnd - dStart;
21766f5f1567SToby Isaac     }
21776f5f1567SToby Isaac     ierr = PetscMalloc1(pEnd-pStart,&coneSizes);CHKERRQ(ierr);
21786f5f1567SToby Isaac     for (p = pStart; p < pEnd; p++) {
21796f5f1567SToby Isaac       ierr = DMPlexGetConeSize(dm,p,&coneSizes[p-pStart]);CHKERRQ(ierr);
21806f5f1567SToby Isaac     }
21816f5f1567SToby Isaac     ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
21826f5f1567SToby Isaac     ierr = DMPlexGetConeOrientations(dm, &orientations);CHKERRQ(ierr);
21836f5f1567SToby Isaac     ierr = DMGetCoordinatesLocal(dm,&coordVec);CHKERRQ(ierr);
21846f5f1567SToby Isaac     ierr = VecGetArray(coordVec,&coords);CHKERRQ(ierr);
21856f5f1567SToby Isaac 
21866f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,pStart,pEnd);CHKERRQ(ierr);
21876f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
21886f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,counts,coneSizes,cones,orientations,NULL);CHKERRQ(ierr);
21896f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
21906f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,NULL,NULL);CHKERRQ(ierr);
21916f5f1567SToby Isaac     ierr = VecRestoreArray(coordVec,&coords);CHKERRQ(ierr);
21926f5f1567SToby Isaac   }
21936f5f1567SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
21946f5f1567SToby Isaac 
21956f5f1567SToby Isaac   PetscFunctionReturn(0);
21966f5f1567SToby Isaac }
21976ecaa68aSToby Isaac 
21986ecaa68aSToby Isaac PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
21996ecaa68aSToby Isaac {
22006ecaa68aSToby Isaac   PetscSF           coarseToFineEmbedded;
22016ecaa68aSToby Isaac   PetscSection      globalCoarse, globalFine;
22026ecaa68aSToby Isaac   PetscSection      localCoarse, localFine;
22036ecaa68aSToby Isaac   PetscSection      aSec, cSec;
22046ecaa68aSToby Isaac   PetscSection      rootIndicesSec, rootMatricesSec;
220546bdb399SToby Isaac   PetscSection      leafIndicesSec, leafMatricesSec;
220646bdb399SToby Isaac   PetscInt          *rootIndices, *leafIndices;
220746bdb399SToby Isaac   PetscScalar       *rootMatrices, *leafMatrices;
22086ecaa68aSToby Isaac   IS                aIS;
22096ecaa68aSToby Isaac   const PetscInt    *anchors;
22106ecaa68aSToby Isaac   Mat               cMat;
22114acb8e1eSToby Isaac   PetscInt          numFields, maxFields;
22126ecaa68aSToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p;
22136ecaa68aSToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
22141c58ffc4SToby Isaac   PetscInt          *maxChildIds;
2215e44e4e7fSToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
22164acb8e1eSToby Isaac   const PetscInt    ***perms;
22174acb8e1eSToby Isaac   const PetscScalar ***flips;
22186ecaa68aSToby Isaac   PetscErrorCode    ierr;
22196ecaa68aSToby Isaac 
22206ecaa68aSToby Isaac   PetscFunctionBegin;
22216ecaa68aSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
22226ecaa68aSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
2223e87a4003SBarry Smith   ierr = DMGetGlobalSection(fine,&globalFine);CHKERRQ(ierr);
22246ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
222589698031SToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
222689698031SToby Isaac     const PetscInt *leaves;
22276ecaa68aSToby Isaac 
222889698031SToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
222989698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
223089698031SToby Isaac       p = leaves ? leaves[l] : l;
22316ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22326ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22336ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
22346ecaa68aSToby Isaac         numPointsWithDofs++;
22356ecaa68aSToby Isaac       }
22366ecaa68aSToby Isaac     }
22376ecaa68aSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
22387cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
223989698031SToby Isaac       p = leaves ? leaves[l] : l;
22406ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22416ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22426ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
224389698031SToby Isaac         pointsWithDofs[offset++] = l;
22446ecaa68aSToby Isaac       }
22456ecaa68aSToby Isaac     }
22466ecaa68aSToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
2247ec92bd66SToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
22486ecaa68aSToby Isaac   }
22496ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
22506ecaa68aSToby Isaac   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
22516ecaa68aSToby Isaac   for (p = pStartC; p < pEndC; p++) {
22528d2f55e7SToby Isaac     maxChildIds[p - pStartC] = -2;
22536ecaa68aSToby Isaac   }
22546ecaa68aSToby Isaac   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
22556ecaa68aSToby Isaac   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
225646bdb399SToby Isaac 
225792fd8e1eSJed Brown   ierr = DMGetLocalSection(coarse,&localCoarse);CHKERRQ(ierr);
2258e87a4003SBarry Smith   ierr = DMGetGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
225946bdb399SToby Isaac 
22606ecaa68aSToby Isaac   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
22616ecaa68aSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
22626ecaa68aSToby Isaac   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
226346bdb399SToby Isaac 
22646ecaa68aSToby Isaac   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
22656ecaa68aSToby Isaac   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
226646bdb399SToby Isaac 
226746bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
22686ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
22696ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootMatricesSec);CHKERRQ(ierr);
22706ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootIndicesSec,pStartC,pEndC);CHKERRQ(ierr);
22716ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootMatricesSec,pStartC,pEndC);CHKERRQ(ierr);
2272708c7f19SToby Isaac   ierr = PetscSectionGetNumFields(localCoarse,&numFields);CHKERRQ(ierr);
2273713c1c5dSToby Isaac   maxFields = PetscMax(1,numFields);
2274713c1c5dSToby 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);
2275f489ac74SBarry Smith   ierr = PetscMalloc2(maxFields+1,(PetscInt****)&perms,maxFields+1,(PetscScalar****)&flips);CHKERRQ(ierr);
2276713c1c5dSToby Isaac   ierr = PetscMemzero((void *) perms, (maxFields+1) * sizeof(const PetscInt **));CHKERRQ(ierr);
2277713c1c5dSToby Isaac   ierr = PetscMemzero((void *) flips, (maxFields+1) * sizeof(const PetscScalar **));CHKERRQ(ierr);
227846bdb399SToby Isaac 
227946bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
22808d2f55e7SToby Isaac     PetscInt dof, matSize   = 0;
22816ecaa68aSToby Isaac     PetscInt aDof           = 0;
22826ecaa68aSToby Isaac     PetscInt cDof           = 0;
22836ecaa68aSToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
22846ecaa68aSToby Isaac     PetscInt numRowIndices  = 0;
22856ecaa68aSToby Isaac     PetscInt numColIndices  = 0;
2286f13f9184SToby Isaac     PetscInt f;
22876ecaa68aSToby Isaac 
22886ecaa68aSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
22891cfc5b76SToby Isaac     if (dof < 0) {
22901cfc5b76SToby Isaac       dof = -(dof + 1);
22911cfc5b76SToby Isaac     }
22926ecaa68aSToby Isaac     if (p >= aStart && p < aEnd) {
22936ecaa68aSToby Isaac       ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
22946ecaa68aSToby Isaac     }
22956ecaa68aSToby Isaac     if (p >= cStart && p < cEnd) {
22966ecaa68aSToby Isaac       ierr = PetscSectionGetDof(cSec,p,&cDof);CHKERRQ(ierr);
22976ecaa68aSToby Isaac     }
2298f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2299f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
23006ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2301f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
23026ecaa68aSToby Isaac 
23036ecaa68aSToby Isaac       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
230446bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
23056ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
23066ecaa68aSToby Isaac 
23076ecaa68aSToby Isaac         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
23086ecaa68aSToby Isaac         numRowIndices += clDof;
23096ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23106ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,c,f,&clDof);CHKERRQ(ierr);
23116ecaa68aSToby Isaac           offsets[f + 1] += clDof;
23126ecaa68aSToby Isaac         }
23136ecaa68aSToby Isaac       }
23146ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
23156ecaa68aSToby Isaac         offsets[f + 1]   += offsets[f];
23166ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
23176ecaa68aSToby Isaac       }
231846bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
23194acb8e1eSToby Isaac       ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,NULL,NULL,NULL,&numColIndices,NULL,NULL,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
23206ecaa68aSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
23216ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
23226ecaa68aSToby Isaac         numColIndices = numRowIndices;
23236ecaa68aSToby Isaac         matSize = 0;
23246ecaa68aSToby Isaac       }
232546bdb399SToby Isaac       else if (numFields) { /* we send one submat for each field: sum their sizes */
23266ecaa68aSToby Isaac         matSize = 0;
23276ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23286ecaa68aSToby Isaac           PetscInt numRow, numCol;
23296ecaa68aSToby Isaac 
23306ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2331f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
23326ecaa68aSToby Isaac           matSize += numRow * numCol;
23336ecaa68aSToby Isaac         }
23346ecaa68aSToby Isaac       }
23356ecaa68aSToby Isaac       else {
23366ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
23376ecaa68aSToby Isaac       }
2338f13f9184SToby Isaac     } else if (maxChildId == -1) {
23398d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2340f13f9184SToby Isaac         PetscInt aOff, a;
23416ecaa68aSToby Isaac 
23426ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
23436ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23446ecaa68aSToby Isaac           PetscInt fDof;
23456ecaa68aSToby Isaac 
23466ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
234721968bf8SToby Isaac           offsets[f+1] = fDof;
23486ecaa68aSToby Isaac         }
23496ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
23506ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
23516ecaa68aSToby Isaac 
23526ecaa68aSToby Isaac           ierr = PetscSectionGetDof(localCoarse,anchor,&aLocalDof);CHKERRQ(ierr);
23536ecaa68aSToby Isaac           numColIndices += aLocalDof;
23546ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23556ecaa68aSToby Isaac             PetscInt fDof;
23566ecaa68aSToby Isaac 
23576ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
235821968bf8SToby Isaac             newOffsets[f+1] += fDof;
23596ecaa68aSToby Isaac           }
23606ecaa68aSToby Isaac         }
23616ecaa68aSToby Isaac         if (numFields) {
23626ecaa68aSToby Isaac           matSize = 0;
23636ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
236421968bf8SToby Isaac             matSize += offsets[f+1] * newOffsets[f+1];
23656ecaa68aSToby Isaac           }
23666ecaa68aSToby Isaac         }
23676ecaa68aSToby Isaac         else {
23686ecaa68aSToby Isaac           matSize = numColIndices * dof;
23696ecaa68aSToby Isaac         }
23706ecaa68aSToby Isaac       }
23716ecaa68aSToby Isaac       else { /* no children, and no constraints on dofs: just get the global indices */
23726ecaa68aSToby Isaac         numColIndices = dof;
23736ecaa68aSToby Isaac         matSize       = 0;
23746ecaa68aSToby Isaac       }
23758d2f55e7SToby Isaac     }
237646bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
23776ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootIndicesSec,p,numColIndices ? numColIndices+2*numFields : 0);CHKERRQ(ierr);
23786ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootMatricesSec,p,matSize);CHKERRQ(ierr);
23796ecaa68aSToby Isaac   }
23806ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootIndicesSec);CHKERRQ(ierr);
23816ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootMatricesSec);CHKERRQ(ierr);
23826ecaa68aSToby Isaac   {
23836ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
23846ecaa68aSToby Isaac 
23856ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
23866ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootMatricesSec,&numRootMatrices);CHKERRQ(ierr);
23876ecaa68aSToby Isaac     ierr = PetscMalloc2(numRootIndices,&rootIndices,numRootMatrices,&rootMatrices);CHKERRQ(ierr);
23886ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
23896ecaa68aSToby Isaac       PetscInt    numRowIndices, numColIndices, matSize, dof;
2390f13f9184SToby Isaac       PetscInt    pIndOff, pMatOff, f;
23916ecaa68aSToby Isaac       PetscInt    *pInd;
23926ecaa68aSToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
23936ecaa68aSToby Isaac       PetscScalar *pMat = NULL;
23946ecaa68aSToby Isaac 
23956ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,p,&numColIndices);CHKERRQ(ierr);
23966ecaa68aSToby Isaac       if (!numColIndices) {
23976ecaa68aSToby Isaac         continue;
23986ecaa68aSToby Isaac       }
2399f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2400f13f9184SToby Isaac         offsets[f]        = 0;
2401f13f9184SToby Isaac         newOffsets[f]     = 0;
2402f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2403f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2404f13f9184SToby Isaac       }
24056ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
24066ecaa68aSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,p,&pIndOff);CHKERRQ(ierr);
24076ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
24086ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootMatricesSec,p,&matSize);CHKERRQ(ierr);
24096ecaa68aSToby Isaac       if (matSize) {
24106ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(rootMatricesSec,p,&pMatOff);CHKERRQ(ierr);
24116ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
24126ecaa68aSToby Isaac       }
24136ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
24141cfc5b76SToby Isaac       if (dof < 0) {
24151cfc5b76SToby Isaac         dof = -(dof + 1);
24161cfc5b76SToby Isaac       }
24176ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
24186ecaa68aSToby Isaac         PetscInt i, j;
24196ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
24206ecaa68aSToby Isaac 
24216ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
24226ecaa68aSToby Isaac           PetscInt numIndices, *indices;
242371f0bbf9SMatthew G. Knepley           ierr = DMPlexGetClosureIndices(coarse,localCoarse,globalCoarse,p,PETSC_TRUE,&numIndices,&indices,offsets,NULL);CHKERRQ(ierr);
2424*2c71b3e2SJacob Faibussowitsch           PetscCheckFalse(numIndices != numColIndices,PETSC_COMM_SELF,PETSC_ERR_PLIB,"mismatching constraint indices calculations");
24256ecaa68aSToby Isaac           for (i = 0; i < numColIndices; i++) {
24266ecaa68aSToby Isaac             pInd[i] = indices[i];
24276ecaa68aSToby Isaac           }
24286ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
242946bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i+1];
243046bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i+1];
24316ecaa68aSToby Isaac           }
243271f0bbf9SMatthew G. Knepley           ierr = DMPlexRestoreClosureIndices(coarse,localCoarse,globalCoarse,p,PETSC_TRUE,&numIndices,&indices,offsets,NULL);CHKERRQ(ierr);
24336ecaa68aSToby Isaac         }
24346ecaa68aSToby Isaac         else {
24356ecaa68aSToby Isaac           PetscInt closureSize, *closure = NULL, cl;
24366ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
24376ecaa68aSToby Isaac           PetscInt numPoints,*points;
24386ecaa68aSToby Isaac 
243969291d52SBarry Smith           ierr = DMGetWorkArray(coarse,numRowIndices * numRowIndices,MPIU_SCALAR,&pMatIn);CHKERRQ(ierr);
24406ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
24416ecaa68aSToby Isaac             for (j = 0; j < numRowIndices; j++) {
24426ecaa68aSToby Isaac               pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
24436ecaa68aSToby Isaac             }
24446ecaa68aSToby Isaac           }
24456ecaa68aSToby Isaac           ierr = DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
24464acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24474acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionGetFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24484acb8e1eSToby Isaac             else           {ierr = PetscSectionGetPointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24494acb8e1eSToby Isaac           }
24506ecaa68aSToby Isaac           if (numFields) {
24516ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
24526ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
24536ecaa68aSToby Isaac 
24546ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
24556ecaa68aSToby Isaac                 PetscInt fDof;
24566ecaa68aSToby Isaac 
24576ecaa68aSToby Isaac                 ierr = PetscSectionGetFieldDof(localCoarse,c,f,&fDof);CHKERRQ(ierr);
24586ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
24596ecaa68aSToby Isaac               }
24606ecaa68aSToby Isaac             }
24616ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
24626ecaa68aSToby Isaac               offsets[f + 1]   += offsets[f];
24636ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
24646ecaa68aSToby Isaac             }
24656ecaa68aSToby Isaac           }
24664acb8e1eSToby Isaac           /* TODO : flips here ? */
24676ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
24684acb8e1eSToby Isaac           ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,perms,pMatIn,&numPoints,NULL,&points,&pMatModified,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
24694acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24704acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24714acb8e1eSToby Isaac             else           {ierr = PetscSectionRestorePointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24724acb8e1eSToby Isaac           }
24734acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24744acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionGetFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
24754acb8e1eSToby Isaac             else           {ierr = PetscSectionGetPointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
24764acb8e1eSToby Isaac           }
24776ecaa68aSToby Isaac           if (!numFields) {
24786ecaa68aSToby Isaac             for (i = 0; i < numRowIndices * numColIndices; i++) {
24796ecaa68aSToby Isaac               pMat[i] = pMatModified[i];
24806ecaa68aSToby Isaac             }
24816ecaa68aSToby Isaac           }
24826ecaa68aSToby Isaac           else {
2483f13f9184SToby Isaac             PetscInt i, j, count;
24846ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
24856ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f+1]; i++) {
24866ecaa68aSToby Isaac                 for (j = newOffsets[f]; j < newOffsets[f+1]; j++, count++) {
24876ecaa68aSToby Isaac                   pMat[count] = pMatModified[i * numColIndices + j];
24886ecaa68aSToby Isaac                 }
24896ecaa68aSToby Isaac               }
24906ecaa68aSToby Isaac             }
24916ecaa68aSToby Isaac           }
249269291d52SBarry Smith           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatModified);CHKERRQ(ierr);
24936ecaa68aSToby Isaac           ierr = DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
249469291d52SBarry Smith           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatIn);CHKERRQ(ierr);
24956ecaa68aSToby Isaac           if (numFields) {
249646bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
249746bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f+1];
249846bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f+1];
24996ecaa68aSToby Isaac             }
25004acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
25014acb8e1eSToby Isaac               PetscInt globalOff, c = points[2*cl];
25026ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
250336fa2b79SJed Brown               ierr = DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd);CHKERRQ(ierr);
25046ecaa68aSToby Isaac             }
25056ecaa68aSToby Isaac           } else {
25064acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
25074acb8e1eSToby Isaac               PetscInt c = points[2*cl], globalOff;
25084acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
25094acb8e1eSToby Isaac 
25106ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
251136fa2b79SJed Brown               ierr = DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd);CHKERRQ(ierr);
25126ecaa68aSToby Isaac             }
25136ecaa68aSToby Isaac           }
25144acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
25154acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
25164acb8e1eSToby Isaac             else           {ierr = PetscSectionRestorePointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
25174acb8e1eSToby Isaac           }
251869291d52SBarry Smith           ierr = DMRestoreWorkArray(coarse,numPoints,MPIU_SCALAR,&points);CHKERRQ(ierr);
25196ecaa68aSToby Isaac         }
25206ecaa68aSToby Isaac       }
25216ecaa68aSToby Isaac       else if (matSize) {
25226ecaa68aSToby Isaac         PetscInt cOff;
25236ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
25246ecaa68aSToby Isaac 
25256ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
2526*2c71b3e2SJacob Faibussowitsch         PetscCheckFalse(numRowIndices != dof,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Miscounted dofs");
252769291d52SBarry Smith         ierr = DMGetWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices);CHKERRQ(ierr);
252869291d52SBarry Smith         ierr = DMGetWorkArray(coarse,numColIndices,MPIU_INT,&colIndices);CHKERRQ(ierr);
25296ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(cSec,p,&cOff);CHKERRQ(ierr);
25306ecaa68aSToby Isaac         ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
25316ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
25326ecaa68aSToby Isaac         if (numFields) {
25336ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25346ecaa68aSToby Isaac             PetscInt fDof;
2535f13f9184SToby Isaac 
25366ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(cSec,p,f,&fDof);CHKERRQ(ierr);
25376ecaa68aSToby Isaac             offsets[f + 1] = fDof;
25386ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
25396ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
25406ecaa68aSToby Isaac               ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
25416ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
25426ecaa68aSToby Isaac             }
25436ecaa68aSToby Isaac           }
25446ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25456ecaa68aSToby Isaac             offsets[f + 1]       += offsets[f];
25466ecaa68aSToby Isaac             offsetsCopy[f + 1]    = offsets[f + 1];
25476ecaa68aSToby Isaac             newOffsets[f + 1]    += newOffsets[f];
25486ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
25496ecaa68aSToby Isaac           }
255036fa2b79SJed Brown           ierr = DMPlexGetIndicesPointFields_Internal(cSec,PETSC_TRUE,p,cOff,offsetsCopy,PETSC_TRUE,NULL,-1, NULL,rowIndices);CHKERRQ(ierr);
25516ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25526ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25536ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
255436fa2b79SJed Brown             ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_TRUE,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL,-1, NULL,colIndices);CHKERRQ(ierr);
25556ecaa68aSToby Isaac           }
25566ecaa68aSToby Isaac         }
25576ecaa68aSToby Isaac         else {
255836fa2b79SJed Brown           ierr = DMPlexGetIndicesPoint_Internal(cSec,PETSC_TRUE,p,cOff,offsetsCopy,PETSC_TRUE,NULL, NULL,rowIndices);CHKERRQ(ierr);
25596ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25606ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25616ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
256236fa2b79SJed Brown             ierr = DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_TRUE,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL, NULL,colIndices);CHKERRQ(ierr);
25636ecaa68aSToby Isaac           }
25646ecaa68aSToby Isaac         }
25656ecaa68aSToby Isaac         if (numFields) {
2566f13f9184SToby Isaac           PetscInt count, a;
2567f13f9184SToby Isaac 
25686ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
25696ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
25706ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
25716ecaa68aSToby Isaac             ierr = MatGetValues(cMat,iSize,&rowIndices[offsets[f]],jSize,&colIndices[newOffsets[f]],&pMat[count]);CHKERRQ(ierr);
25726ecaa68aSToby Isaac             count += iSize * jSize;
257346bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
257446bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f+1];
25756ecaa68aSToby Isaac           }
25766ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25776ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25786ecaa68aSToby Isaac             PetscInt gOff;
25796ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
258036fa2b79SJed Brown             ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL,-1, NULL,pInd);CHKERRQ(ierr);
25816ecaa68aSToby Isaac           }
25826ecaa68aSToby Isaac         }
25836ecaa68aSToby Isaac         else {
25846ecaa68aSToby Isaac           PetscInt a;
25856ecaa68aSToby Isaac           ierr = MatGetValues(cMat,numRowIndices,rowIndices,numColIndices,colIndices,pMat);CHKERRQ(ierr);
25866ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25876ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25886ecaa68aSToby Isaac             PetscInt gOff;
25896ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
259036fa2b79SJed Brown             ierr = DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL, NULL,pInd);CHKERRQ(ierr);
25916ecaa68aSToby Isaac           }
25926ecaa68aSToby Isaac         }
259369291d52SBarry Smith         ierr = DMRestoreWorkArray(coarse,numColIndices,MPIU_INT,&colIndices);CHKERRQ(ierr);
259469291d52SBarry Smith         ierr = DMRestoreWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices);CHKERRQ(ierr);
25956ecaa68aSToby Isaac       }
25966ecaa68aSToby Isaac       else {
25976ecaa68aSToby Isaac         PetscInt gOff;
25986ecaa68aSToby Isaac 
25996ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
26006ecaa68aSToby Isaac         if (numFields) {
26016ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
26026ecaa68aSToby Isaac             PetscInt fDof;
26036ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
26046ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
26056ecaa68aSToby Isaac           }
26066ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
260746bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
260846bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f+1];
26096ecaa68aSToby Isaac           }
261036fa2b79SJed Brown           ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1, NULL,pInd);CHKERRQ(ierr);
2611367003a6SStefano Zampini         } else {
261236fa2b79SJed Brown           ierr = DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL, NULL,pInd);CHKERRQ(ierr);
26136ecaa68aSToby Isaac         }
26146ecaa68aSToby Isaac       }
26156ecaa68aSToby Isaac     }
2616e44e4e7fSToby Isaac     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
26176ecaa68aSToby Isaac   }
261846bdb399SToby Isaac   {
261946bdb399SToby Isaac     PetscSF  indicesSF, matricesSF;
262046bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
262146bdb399SToby Isaac 
262246bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
262346bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafMatricesSec);CHKERRQ(ierr);
262446bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootIndicesSec,&remoteOffsetsIndices,leafIndicesSec);CHKERRQ(ierr);
262546bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootMatricesSec,&remoteOffsetsMatrices,leafMatricesSec);CHKERRQ(ierr);
262646bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootIndicesSec,remoteOffsetsIndices,leafIndicesSec,&indicesSF);CHKERRQ(ierr);
262746bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootMatricesSec,remoteOffsetsMatrices,leafMatricesSec,&matricesSF);CHKERRQ(ierr);
2628e44e4e7fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
262946bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsIndices);CHKERRQ(ierr);
263046bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsMatrices);CHKERRQ(ierr);
263146bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numLeafIndices);CHKERRQ(ierr);
263246bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafMatricesSec,&numLeafMatrices);CHKERRQ(ierr);
263346bdb399SToby Isaac     ierr = PetscMalloc2(numLeafIndices,&leafIndices,numLeafMatrices,&leafMatrices);CHKERRQ(ierr);
2634ad227feaSJunchao Zhang     ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,rootIndices,leafIndices,MPI_REPLACE);CHKERRQ(ierr);
2635ad227feaSJunchao Zhang     ierr = PetscSFBcastBegin(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices,MPI_REPLACE);CHKERRQ(ierr);
2636ad227feaSJunchao Zhang     ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,rootIndices,leafIndices,MPI_REPLACE);CHKERRQ(ierr);
2637ad227feaSJunchao Zhang     ierr = PetscSFBcastEnd(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices,MPI_REPLACE);CHKERRQ(ierr);
263846bdb399SToby Isaac     ierr = PetscSFDestroy(&matricesSF);CHKERRQ(ierr);
263946bdb399SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
264046bdb399SToby Isaac     ierr = PetscFree2(rootIndices,rootMatrices);CHKERRQ(ierr);
264146bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
264246bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootMatricesSec);CHKERRQ(ierr);
264346bdb399SToby Isaac   }
264446bdb399SToby Isaac   /* count to preallocate */
264592fd8e1eSJed Brown   ierr = DMGetLocalSection(fine,&localFine);CHKERRQ(ierr);
264646bdb399SToby Isaac   {
264746bdb399SToby Isaac     PetscInt    nGlobal;
264846bdb399SToby Isaac     PetscInt    *dnnz, *onnz;
2649b9a5774bSToby Isaac     PetscLayout rowMap, colMap;
2650b9a5774bSToby Isaac     PetscInt    rowStart, rowEnd, colStart, colEnd;
26511c58ffc4SToby Isaac     PetscInt    maxDof;
26521c58ffc4SToby Isaac     PetscInt    *rowIndices;
26531c58ffc4SToby Isaac     DM           refTree;
26541c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
26551c58ffc4SToby Isaac     PetscScalar  ***refPointFieldMats;
26561c58ffc4SToby Isaac     PetscSection refConSec, refAnSec;
26570eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,maxConDof,maxColumns,leafStart,leafEnd;
26581c58ffc4SToby Isaac     PetscScalar  *pointWork;
265946bdb399SToby Isaac 
266046bdb399SToby Isaac     ierr = PetscSectionGetConstrainedStorageSize(globalFine,&nGlobal);CHKERRQ(ierr);
266146bdb399SToby Isaac     ierr = PetscCalloc2(nGlobal,&dnnz,nGlobal,&onnz);CHKERRQ(ierr);
2662b9a5774bSToby Isaac     ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
2663b9a5774bSToby Isaac     ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
26641c58ffc4SToby Isaac     ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
2665b9a5774bSToby Isaac     ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
266646bdb399SToby Isaac     ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
26677f8983b1SJed Brown     ierr = PetscSectionGetMaxDof(localFine,&maxDof);CHKERRQ(ierr);
26680eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafIndicesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
266969291d52SBarry Smith     ierr = DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
26700eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
267146bdb399SToby Isaac       PetscInt    gDof, gcDof, gOff;
267246bdb399SToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
267346bdb399SToby Isaac       PetscInt    matSize;
267421968bf8SToby Isaac       PetscInt    i;
267546bdb399SToby Isaac 
267646bdb399SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
267746bdb399SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
267846bdb399SToby Isaac       if ((gDof - gcDof) <= 0) {
267946bdb399SToby Isaac         continue;
268046bdb399SToby Isaac       }
268146bdb399SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
2682*2c71b3e2SJacob Faibussowitsch       PetscCheckFalse(gOff < 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"I though having global dofs meant a non-negative offset");
2683*2c71b3e2SJacob Faibussowitsch       PetscCheckFalse((gOff < rowStart) || ((gOff + gDof - gcDof) > rowEnd),PETSC_COMM_SELF,PETSC_ERR_PLIB,"I thought the row map would constrain the global dofs");
268446bdb399SToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
268546bdb399SToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
268646bdb399SToby Isaac       numColIndices -= 2 * numFields;
2687*2c71b3e2SJacob Faibussowitsch       PetscCheckFalse(numColIndices <= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"global fine dof with no dofs to interpolate from");
268846bdb399SToby Isaac       pInd = &leafIndices[pIndOff];
268921968bf8SToby Isaac       offsets[0]        = 0;
269021968bf8SToby Isaac       offsetsCopy[0]    = 0;
269121968bf8SToby Isaac       newOffsets[0]     = 0;
269221968bf8SToby Isaac       newOffsetsCopy[0] = 0;
269346bdb399SToby Isaac       if (numFields) {
269421968bf8SToby Isaac         PetscInt f;
269546bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
269646bdb399SToby Isaac           PetscInt rowDof;
269746bdb399SToby Isaac 
269846bdb399SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
269921968bf8SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
270021968bf8SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
270121968bf8SToby Isaac           newOffsets[f + 1]     = pInd[numColIndices + numFields + f];
270221968bf8SToby Isaac           numD[f] = 0;
270321968bf8SToby Isaac           numO[f] = 0;
270446bdb399SToby Isaac         }
270536fa2b79SJed Brown         ierr = DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,rowIndices);CHKERRQ(ierr);
270646bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
270721968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
270821968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
270946bdb399SToby Isaac 
271046bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
271146bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
271246bdb399SToby Isaac 
271346bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
271421968bf8SToby Isaac               numD[f]++;
271546bdb399SToby Isaac             }
271646bdb399SToby Isaac             else if (gInd >= 0) { /* negative means non-entry */
271721968bf8SToby Isaac               numO[f]++;
271846bdb399SToby Isaac             }
271946bdb399SToby Isaac           }
272046bdb399SToby Isaac         }
272146bdb399SToby Isaac       }
272246bdb399SToby Isaac       else {
272336fa2b79SJed Brown         ierr = DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,rowIndices);CHKERRQ(ierr);
272421968bf8SToby Isaac         numD[0] = 0;
272521968bf8SToby Isaac         numO[0] = 0;
272646bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
272746bdb399SToby Isaac           PetscInt gInd = pInd[i];
272846bdb399SToby Isaac 
272946bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
273021968bf8SToby Isaac             numD[0]++;
273146bdb399SToby Isaac           }
273246bdb399SToby Isaac           else if (gInd >= 0) { /* negative means non-entry */
273321968bf8SToby Isaac             numO[0]++;
273446bdb399SToby Isaac           }
273546bdb399SToby Isaac         }
273646bdb399SToby Isaac       }
273746bdb399SToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
273846bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
273946bdb399SToby Isaac         PetscInt childId;
274046bdb399SToby Isaac 
274146bdb399SToby Isaac         childId = childIds[p-pStartF];
274221968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
274346bdb399SToby Isaac           if (numFields) {
2744b9a5774bSToby Isaac             PetscInt f;
2745b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
274621968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
274746bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
274821968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
274921968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
275046bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2751*2c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2752b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
275346bdb399SToby Isaac                 }
275446bdb399SToby Isaac                 else if (gIndCoarse >= 0) { /* remote */
2755*2c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2756b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
275746bdb399SToby Isaac                 }
275846bdb399SToby Isaac                 else { /* constrained */
2759*2c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(gIndFine >= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
276046bdb399SToby Isaac                 }
276146bdb399SToby Isaac               }
276246bdb399SToby Isaac             }
276346bdb399SToby Isaac           }
276446bdb399SToby Isaac           else {
2765b9a5774bSToby Isaac             PetscInt i;
2766b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
276746bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
276846bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
276946bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2770*2c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2771b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
277246bdb399SToby Isaac               }
277346bdb399SToby Isaac               else if (gIndCoarse >= 0) { /* remote */
2774*2c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2775b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
277646bdb399SToby Isaac               }
277746bdb399SToby Isaac               else { /* constrained */
2778*2c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine >= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
277946bdb399SToby Isaac               }
278046bdb399SToby Isaac             }
278146bdb399SToby Isaac           }
278246bdb399SToby Isaac         }
278346bdb399SToby Isaac         else { /* interpolate from all */
278446bdb399SToby Isaac           if (numFields) {
2785b9a5774bSToby Isaac             PetscInt f;
2786b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
278721968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
278846bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
278921968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
279046bdb399SToby Isaac                 if (gIndFine >= 0) {
2791*2c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2792b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2793b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
279446bdb399SToby Isaac                 }
279546bdb399SToby Isaac               }
279646bdb399SToby Isaac             }
279746bdb399SToby Isaac           }
279846bdb399SToby Isaac           else {
2799b9a5774bSToby Isaac             PetscInt i;
2800b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
280146bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
280246bdb399SToby Isaac               if (gIndFine >= 0) {
2803*2c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2804b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2805b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
280646bdb399SToby Isaac               }
280746bdb399SToby Isaac             }
280846bdb399SToby Isaac           }
280946bdb399SToby Isaac         }
281046bdb399SToby Isaac       }
281146bdb399SToby Isaac       else { /* interpolate from all */
281246bdb399SToby Isaac         if (numFields) {
2813b9a5774bSToby Isaac           PetscInt f;
2814b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
281521968bf8SToby Isaac             PetscInt numRows = offsets[f+1] - offsets[f], row;
281646bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
281721968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
281846bdb399SToby Isaac               if (gIndFine >= 0) {
2819*2c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2820b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2821b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
282246bdb399SToby Isaac               }
282346bdb399SToby Isaac             }
282446bdb399SToby Isaac           }
282546bdb399SToby Isaac         }
282646bdb399SToby Isaac         else { /* every dof get a full row */
2827b9a5774bSToby Isaac           PetscInt i;
2828b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
282946bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
283046bdb399SToby Isaac             if (gIndFine >= 0) {
2831*2c71b3e2SJacob Faibussowitsch               PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2832b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2833b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
283446bdb399SToby Isaac             }
283546bdb399SToby Isaac           }
283646bdb399SToby Isaac         }
283746bdb399SToby Isaac       }
283846bdb399SToby Isaac     }
283946bdb399SToby Isaac     ierr = MatXAIJSetPreallocation(mat,1,dnnz,onnz,NULL,NULL);CHKERRQ(ierr);
284046bdb399SToby Isaac     ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
284121968bf8SToby Isaac 
284221968bf8SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
284321968bf8SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
2844e44e4e7fSToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
2845e44e4e7fSToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
2846e44e4e7fSToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
28471c58ffc4SToby Isaac     ierr = PetscSectionGetMaxDof(refConSec,&maxConDof);CHKERRQ(ierr);
28487c0540e0SToby Isaac     ierr = PetscSectionGetMaxDof(leafIndicesSec,&maxColumns);CHKERRQ(ierr);
28497c0540e0SToby Isaac     ierr = PetscMalloc1(maxConDof*maxColumns,&pointWork);CHKERRQ(ierr);
28500eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2851e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2852e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2853e44e4e7fSToby Isaac       PetscInt matSize;
2854e44e4e7fSToby Isaac       PetscInt childId;
2855e44e4e7fSToby Isaac 
2856e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
2857e44e4e7fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
2858e44e4e7fSToby Isaac       if ((gDof - gcDof) <= 0) {
2859e44e4e7fSToby Isaac         continue;
2860e44e4e7fSToby Isaac       }
2861e44e4e7fSToby Isaac       childId = childIds[p-pStartF];
2862e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
2863e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
2864e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
2865e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2866e44e4e7fSToby Isaac       pInd = &leafIndices[pIndOff];
2867e44e4e7fSToby Isaac       offsets[0]        = 0;
2868e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2869e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2870e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2871e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2872e44e4e7fSToby Isaac       if (numFields) {
2873e44e4e7fSToby Isaac         PetscInt f;
2874e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2875e44e4e7fSToby Isaac           PetscInt rowDof;
2876e44e4e7fSToby Isaac 
2877e44e4e7fSToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
2878e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2879e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2880e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2881e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2882e44e4e7fSToby Isaac         }
288336fa2b79SJed Brown         ierr = DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,rowIndices);CHKERRQ(ierr);
2884e44e4e7fSToby Isaac       }
28851c58ffc4SToby Isaac       else {
288636fa2b79SJed Brown         ierr = DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,rowIndices);CHKERRQ(ierr);
28871c58ffc4SToby Isaac       }
2888e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
2889e44e4e7fSToby Isaac       if (!matSize) { /* incoming matrix is identity */
2890e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2891e44e4e7fSToby Isaac           if (numFields) {
2892e44e4e7fSToby Isaac             PetscInt f;
2893e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2894e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
2895e44e4e7fSToby Isaac               for (row = 0; row < numRows; row++) {
2896e44e4e7fSToby Isaac                 ierr = MatSetValue(mat,rowIndices[offsets[f]+row],pInd[newOffsets[f]+row],1.,INSERT_VALUES);CHKERRQ(ierr);
289721968bf8SToby Isaac               }
289821968bf8SToby Isaac             }
2899e44e4e7fSToby Isaac           }
2900e44e4e7fSToby Isaac           else {
2901e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
2902e44e4e7fSToby Isaac             for (row = 0; row < numRows; row++) {
2903e44e4e7fSToby Isaac               ierr = MatSetValue(mat,rowIndices[row],pInd[row],1.,INSERT_VALUES);CHKERRQ(ierr);
2904e44e4e7fSToby Isaac             }
2905e44e4e7fSToby Isaac           }
2906e44e4e7fSToby Isaac         }
2907e44e4e7fSToby Isaac         else { /* interpolate from all */
2908e44e4e7fSToby Isaac           if (numFields) {
2909e44e4e7fSToby Isaac             PetscInt f;
2910e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2911e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f];
2912e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
2913e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],refPointFieldMats[childId - pRefStart][f],INSERT_VALUES);CHKERRQ(ierr);
2914e44e4e7fSToby Isaac             }
2915e44e4e7fSToby Isaac           }
2916e44e4e7fSToby Isaac           else {
2917e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,refPointFieldMats[childId - pRefStart][0],INSERT_VALUES);CHKERRQ(ierr);
2918e44e4e7fSToby Isaac           }
2919e44e4e7fSToby Isaac         }
2920e44e4e7fSToby Isaac       }
2921e44e4e7fSToby Isaac       else { /* interpolate from all */
2922e44e4e7fSToby Isaac         PetscInt    pMatOff;
2923e44e4e7fSToby Isaac         PetscScalar *pMat;
2924e44e4e7fSToby Isaac 
2925e44e4e7fSToby Isaac         ierr = PetscSectionGetOffset(leafMatricesSec,p,&pMatOff);CHKERRQ(ierr);
2926e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2927e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2928e44e4e7fSToby Isaac           if (numFields) {
2929e44e4e7fSToby Isaac             PetscInt f, count;
2930e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2931e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2932e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2933e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2934e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2935e44e4e7fSToby Isaac 
2936e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],inMat,INSERT_VALUES);CHKERRQ(ierr);
2937e44e4e7fSToby Isaac               count += numCols * numInRows;
2938e44e4e7fSToby Isaac             }
2939e44e4e7fSToby Isaac           }
2940e44e4e7fSToby Isaac           else {
2941e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,pMat,INSERT_VALUES);CHKERRQ(ierr);
2942e44e4e7fSToby Isaac           }
2943e44e4e7fSToby Isaac         }
2944e44e4e7fSToby Isaac         else { /* multiply the incoming matrix by the child interpolation */
2945e44e4e7fSToby Isaac           if (numFields) {
2946e44e4e7fSToby Isaac             PetscInt f, count;
2947e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2948e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2949e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2950e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2951e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2952e44e4e7fSToby Isaac               PetscInt i, j, k;
2953*2c71b3e2SJacob Faibussowitsch               PetscCheckFalse(refPointFieldN[childId - pRefStart][f] != numInRows,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2954e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2955e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2956e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2957e44e4e7fSToby Isaac                   for (k = 0; k < numInRows; k++) {
2958e44e4e7fSToby Isaac                     val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2959e44e4e7fSToby Isaac                   }
2960e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2961e44e4e7fSToby Isaac                 }
2962e44e4e7fSToby Isaac               }
2963e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],pointWork,INSERT_VALUES);CHKERRQ(ierr);
2964e44e4e7fSToby Isaac               count += numCols * numInRows;
2965e44e4e7fSToby Isaac             }
2966e44e4e7fSToby Isaac           }
2967267d4f3fSToby Isaac           else { /* every dof gets a full row */
2968e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2969e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2970e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2971e44e4e7fSToby Isaac             PetscInt i, j, k;
2972*2c71b3e2SJacob Faibussowitsch             PetscCheckFalse(refPointFieldN[childId - pRefStart][0] != numInRows,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2973e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2974e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2975e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2976e44e4e7fSToby Isaac                 for (k = 0; k < numInRows; k++) {
2977e44e4e7fSToby Isaac                   val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2978e44e4e7fSToby Isaac                 }
2979e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2980e44e4e7fSToby Isaac               }
2981e44e4e7fSToby Isaac             }
2982e44e4e7fSToby Isaac             ierr = MatSetValues(mat,numRows,rowIndices,numCols,pInd,pointWork,INSERT_VALUES);CHKERRQ(ierr);
2983e44e4e7fSToby Isaac           }
2984e44e4e7fSToby Isaac         }
2985e44e4e7fSToby Isaac       }
2986e44e4e7fSToby Isaac     }
29871c58ffc4SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
298869291d52SBarry Smith     ierr = DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
2989e44e4e7fSToby Isaac     ierr = PetscFree(pointWork);CHKERRQ(ierr);
2990e44e4e7fSToby Isaac   }
2991e44e4e7fSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2992e44e4e7fSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2993e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
2994e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafMatricesSec);CHKERRQ(ierr);
2995e44e4e7fSToby Isaac   ierr = PetscFree2(leafIndices,leafMatrices);CHKERRQ(ierr);
29962cd485c2SBarry Smith   ierr = PetscFree2(*(PetscInt****)&perms,*(PetscScalar****)&flips);CHKERRQ(ierr);
2997e44e4e7fSToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
29986ecaa68aSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
29996ecaa68aSToby Isaac   PetscFunctionReturn(0);
30006ecaa68aSToby Isaac }
3001154bca37SToby Isaac 
30028d2f55e7SToby Isaac /*
30038d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
30048d2f55e7SToby Isaac  *
30058d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
30068d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
30078d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
30088d2f55e7SToby Isaac  *       a_{i,j} = 0;
30098d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
30108d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
30118d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
30128d2f55e7SToby Isaac  */
30138d2f55e7SToby Isaac PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
30148d2f55e7SToby Isaac {
30158d2f55e7SToby Isaac   PetscDS        ds;
30168d2f55e7SToby Isaac   PetscSection   section, cSection;
30178d2f55e7SToby Isaac   DMLabel        canonical, depth;
30188d2f55e7SToby Isaac   Mat            cMat, mat;
30198d2f55e7SToby Isaac   PetscInt       *nnz;
30208d2f55e7SToby Isaac   PetscInt       f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
30218d2f55e7SToby Isaac   PetscInt       m, n;
30228d2f55e7SToby Isaac   PetscScalar    *pointScalar;
30238d2f55e7SToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
30248d2f55e7SToby Isaac   PetscErrorCode ierr;
30258d2f55e7SToby Isaac 
30268d2f55e7SToby Isaac   PetscFunctionBegin;
302792fd8e1eSJed Brown   ierr = DMGetLocalSection(refTree,&section);CHKERRQ(ierr);
30288d2f55e7SToby Isaac   ierr = DMGetDimension(refTree, &dim);CHKERRQ(ierr);
30298d2f55e7SToby Isaac   ierr = PetscMalloc6(dim,&v0,dim,&v0parent,dim,&vtmp,dim*dim,&J,dim*dim,&Jparent,dim*dim,&invJ);CHKERRQ(ierr);
30308d2f55e7SToby Isaac   ierr = PetscMalloc2(dim,&pointScalar,dim,&pointRef);CHKERRQ(ierr);
30318d2f55e7SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
30328d2f55e7SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
30338d2f55e7SToby Isaac   ierr = PetscSectionGetNumFields(section,&numSecFields);CHKERRQ(ierr);
30348d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"canonical",&canonical);CHKERRQ(ierr);
30358d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"depth",&depth);CHKERRQ(ierr);
30368d2f55e7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSection,&cMat);CHKERRQ(ierr);
30378d2f55e7SToby Isaac   ierr = DMPlexGetChart(refTree, &pStart, &pEnd);CHKERRQ(ierr);
30388d2f55e7SToby Isaac   ierr = DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd);CHKERRQ(ierr);
30398d2f55e7SToby Isaac   ierr = MatGetSize(cMat,&n,&m);CHKERRQ(ierr); /* the injector has transpose sizes from the constraint matrix */
30408d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
30418d2f55e7SToby Isaac   ierr = PetscCalloc1(m,&nnz);CHKERRQ(ierr);
30428d2f55e7SToby 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 */
30438d2f55e7SToby Isaac     const PetscInt *children;
30448d2f55e7SToby Isaac     PetscInt numChildren;
30458d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30468d2f55e7SToby Isaac 
30478d2f55e7SToby Isaac     if (canonical) {
30488d2f55e7SToby Isaac       PetscInt pCanonical;
30498d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
30508d2f55e7SToby Isaac       if (p != pCanonical) continue;
30518d2f55e7SToby Isaac     }
30528d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
30538d2f55e7SToby Isaac     if (!numChildren) continue;
30548d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30558d2f55e7SToby Isaac       PetscInt child = children[i];
30568d2f55e7SToby Isaac       PetscInt dof;
30578d2f55e7SToby Isaac 
30588d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
30598d2f55e7SToby Isaac       numChildDof += dof;
30608d2f55e7SToby Isaac     }
30618d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
30628d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30638d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
30648d2f55e7SToby Isaac       PetscInt selfOff;
30658d2f55e7SToby Isaac 
30668d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
30678d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
30688d2f55e7SToby Isaac           PetscInt child = children[i];
30698d2f55e7SToby Isaac           PetscInt dof;
30708d2f55e7SToby Isaac 
30718d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
30728d2f55e7SToby Isaac           numChildDof += dof;
30738d2f55e7SToby Isaac         }
30748d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
30758d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
30768d2f55e7SToby Isaac       }
30778d2f55e7SToby Isaac       else {
30788d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
30798d2f55e7SToby Isaac       }
30808d2f55e7SToby Isaac       for (i = 0; i < numSelfDof; i++) {
30818d2f55e7SToby Isaac         nnz[selfOff + i] = numChildDof;
30828d2f55e7SToby Isaac       }
30838d2f55e7SToby Isaac     }
30848d2f55e7SToby Isaac   }
30858d2f55e7SToby Isaac   ierr = MatCreateAIJ(PETSC_COMM_SELF,m,n,m,n,-1,nnz,-1,NULL,&mat);CHKERRQ(ierr);
30868d2f55e7SToby Isaac   ierr = PetscFree(nnz);CHKERRQ(ierr);
30878d2f55e7SToby Isaac   /* Setp 2: compute entries */
30888d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
30898d2f55e7SToby Isaac     const PetscInt *children;
30908d2f55e7SToby Isaac     PetscInt numChildren;
30918d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30928d2f55e7SToby Isaac 
30938d2f55e7SToby Isaac     /* same conditions about when entries occur */
30948d2f55e7SToby Isaac     if (canonical) {
30958d2f55e7SToby Isaac       PetscInt pCanonical;
30968d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
30978d2f55e7SToby Isaac       if (p != pCanonical) continue;
30988d2f55e7SToby Isaac     }
30998d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
31008d2f55e7SToby Isaac     if (!numChildren) continue;
31018d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
31028d2f55e7SToby Isaac       PetscInt child = children[i];
31038d2f55e7SToby Isaac       PetscInt dof;
31048d2f55e7SToby Isaac 
31058d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
31068d2f55e7SToby Isaac       numChildDof += dof;
31078d2f55e7SToby Isaac     }
31088d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
31098d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
31108d2f55e7SToby Isaac 
31118d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
311259fc6756SToby Isaac       PetscInt       pI = -1, cI = -1;
311352a3aeb4SToby Isaac       PetscInt       selfOff, Nc, parentCell;
31148d2f55e7SToby Isaac       PetscInt       cellShapeOff;
31158d2f55e7SToby Isaac       PetscObject    disc;
31168d2f55e7SToby Isaac       PetscDualSpace dsp;
31178d2f55e7SToby Isaac       PetscClassId   classId;
31188d2f55e7SToby Isaac       PetscScalar    *pointMat;
31193b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
31208d2f55e7SToby Isaac       PetscInt       pO = PETSC_MIN_INT;
31218d2f55e7SToby Isaac       const PetscInt *depthNumDof;
31228d2f55e7SToby Isaac 
31238d2f55e7SToby Isaac       if (numSecFields) {
31248d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
31258d2f55e7SToby Isaac           PetscInt child = children[i];
31268d2f55e7SToby Isaac           PetscInt dof;
31278d2f55e7SToby Isaac 
31288d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
31298d2f55e7SToby Isaac           numChildDof += dof;
31308d2f55e7SToby Isaac         }
31318d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
31328d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
31338d2f55e7SToby Isaac       }
31348d2f55e7SToby Isaac       else {
31358d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
31368d2f55e7SToby Isaac       }
31378d2f55e7SToby Isaac 
31383b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
31398d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
31408d2f55e7SToby Isaac         parentCell = p;
31418d2f55e7SToby Isaac       }
31428d2f55e7SToby Isaac       else {
31438d2f55e7SToby Isaac         PetscInt *star = NULL;
31448d2f55e7SToby Isaac         PetscInt numStar;
31458d2f55e7SToby Isaac 
31468d2f55e7SToby Isaac         parentCell = -1;
31478d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31488d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
31498d2f55e7SToby Isaac           PetscInt c = star[2 * i];
31508d2f55e7SToby Isaac 
31518d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
31528d2f55e7SToby Isaac             parentCell = c;
31538d2f55e7SToby Isaac             break;
31548d2f55e7SToby Isaac           }
31558d2f55e7SToby Isaac         }
31568d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31578d2f55e7SToby Isaac       }
3158a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
3159c5356c36SToby Isaac       ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
3160c5356c36SToby Isaac       ierr = PetscObjectGetClassId(disc,&classId);CHKERRQ(ierr);
3161c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
3162c5356c36SToby Isaac         ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
3163c5356c36SToby Isaac       }
3164c5356c36SToby Isaac       else if (classId == PETSCFV_CLASSID) {
3165c5356c36SToby Isaac         ierr = PetscFVGetDualSpace((PetscFV)disc,&dsp);CHKERRQ(ierr);
3166c5356c36SToby Isaac       }
3167c5356c36SToby Isaac       else {
31689b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported discretization object");
3169c5356c36SToby Isaac       }
31708d2f55e7SToby Isaac       ierr = PetscDualSpaceGetNumDof(dsp,&depthNumDof);CHKERRQ(ierr);
317152a3aeb4SToby Isaac       ierr = PetscDualSpaceGetNumComponents(dsp,&Nc);CHKERRQ(ierr);
31728d2f55e7SToby Isaac       {
31738d2f55e7SToby Isaac         PetscInt *closure = NULL;
31748d2f55e7SToby Isaac         PetscInt numClosure;
31758d2f55e7SToby Isaac 
31768d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
317759fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
31788d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
31798d2f55e7SToby Isaac 
31808d2f55e7SToby Isaac           pO = closure[2 * i + 1];
318159fc6756SToby Isaac           if (point == p) {
318259fc6756SToby Isaac             pI = i;
318359fc6756SToby Isaac             break;
318459fc6756SToby Isaac           }
31858d2f55e7SToby Isaac           ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
31868d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
31878d2f55e7SToby Isaac         }
31888d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
31898d2f55e7SToby Isaac       }
31908d2f55e7SToby Isaac 
319169291d52SBarry Smith       ierr = DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat);CHKERRQ(ierr);
319269291d52SBarry Smith       ierr = DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows);CHKERRQ(ierr);
319352a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
319452a3aeb4SToby Isaac       for (i = 0; i < numSelfDof; i++) {
319552a3aeb4SToby Isaac         matRows[i] = selfOff + i;
31963b1c2a6aSToby Isaac       }
319752a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
31983b1c2a6aSToby Isaac       {
31993b1c2a6aSToby Isaac         PetscInt colOff = 0;
32003b1c2a6aSToby Isaac 
32013b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
32023b1c2a6aSToby Isaac           PetscInt child = children[i];
32033b1c2a6aSToby Isaac           PetscInt dof, off, j;
32043b1c2a6aSToby Isaac 
32053b1c2a6aSToby Isaac           if (numSecFields) {
3206c5356c36SToby Isaac             ierr = PetscSectionGetFieldDof(cSection,child,f,&dof);CHKERRQ(ierr);
3207c5356c36SToby Isaac             ierr = PetscSectionGetFieldOffset(cSection,child,f,&off);CHKERRQ(ierr);
32083b1c2a6aSToby Isaac           }
32093b1c2a6aSToby Isaac           else {
3210c5356c36SToby Isaac             ierr = PetscSectionGetDof(cSection,child,&dof);CHKERRQ(ierr);
3211c5356c36SToby Isaac             ierr = PetscSectionGetOffset(cSection,child,&off);CHKERRQ(ierr);
32123b1c2a6aSToby Isaac           }
32133b1c2a6aSToby Isaac 
321452a3aeb4SToby Isaac           for (j = 0; j < dof; j++) {
321552a3aeb4SToby Isaac             matCols[colOff++] = off + j;
32163b1c2a6aSToby Isaac           }
32173b1c2a6aSToby Isaac         }
32183b1c2a6aSToby Isaac       }
32198d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
32208d2f55e7SToby Isaac         PetscFE        fe = (PetscFE) disc;
32218d2f55e7SToby Isaac         PetscInt       fSize;
322259fc6756SToby Isaac         const PetscInt ***perms;
322359fc6756SToby Isaac         const PetscScalar ***flips;
322459fc6756SToby Isaac         const PetscInt *pperms;
322559fc6756SToby Isaac 
32268d2f55e7SToby Isaac         ierr = PetscFEGetDualSpace(fe,&dsp);CHKERRQ(ierr);
32273b1c2a6aSToby Isaac         ierr = PetscDualSpaceGetDimension(dsp,&fSize);CHKERRQ(ierr);
322859fc6756SToby Isaac         ierr = PetscDualSpaceGetSymmetries(dsp, &perms, &flips);CHKERRQ(ierr);
322959fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
323052a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
32318d2f55e7SToby Isaac           PetscQuadrature q;
323252a3aeb4SToby Isaac           PetscInt        dim, thisNc, numPoints, j, k;
32338d2f55e7SToby Isaac           const PetscReal *points;
32348d2f55e7SToby Isaac           const PetscReal *weights;
32358d2f55e7SToby Isaac           PetscInt        *closure = NULL;
32368d2f55e7SToby Isaac           PetscInt        numClosure;
323759fc6756SToby Isaac           PetscInt        iCell = pperms ? pperms[i] : i;
323859fc6756SToby Isaac           PetscInt        parentCellShapeDof = cellShapeOff + iCell;
3239ef0bb6c7SMatthew G. Knepley           PetscTabulation Tparent;
32408d2f55e7SToby Isaac 
32413b1c2a6aSToby Isaac           ierr = PetscDualSpaceGetFunctional(dsp,parentCellShapeDof,&q);CHKERRQ(ierr);
324252a3aeb4SToby Isaac           ierr = PetscQuadratureGetData(q,&dim,&thisNc,&numPoints,&points,&weights);CHKERRQ(ierr);
3243*2c71b3e2SJacob Faibussowitsch           PetscCheckFalse(thisNc != Nc,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %D does not much basis dim %D",thisNc,Nc);
3244ef0bb6c7SMatthew G. Knepley           ierr = PetscFECreateTabulation(fe,1,numPoints,points,0,&Tparent);CHKERRQ(ierr); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
32453b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
32468d2f55e7SToby Isaac             PetscInt          childCell = -1;
324752a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3248c330f8ffSToby Isaac             const PetscReal   xi0[3] = {-1.,-1.,-1.};
32498d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
32508d2f55e7SToby Isaac             const PetscScalar *point;
3251ef0bb6c7SMatthew G. Knepley             PetscTabulation Tchild;
32528d2f55e7SToby Isaac             PetscInt          childCellShapeOff, pointMatOff;
32538d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
32548d2f55e7SToby Isaac             PetscInt          d;
32558d2f55e7SToby Isaac 
32568d2f55e7SToby Isaac             for (d = 0; d < dim; d++) {
32578d2f55e7SToby Isaac               pointScalar[d] = points[dim * j + d];
32588d2f55e7SToby Isaac             }
32598d2f55e7SToby Isaac             point = pointScalar;
32608d2f55e7SToby Isaac #else
32618d2f55e7SToby Isaac             point = pointReal;
32628d2f55e7SToby Isaac #endif
32638d2f55e7SToby Isaac 
3264ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
32653b1c2a6aSToby Isaac 
32663b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
32678d2f55e7SToby Isaac               PetscInt child = children[k];
32688d2f55e7SToby Isaac               PetscInt *star = NULL;
32698d2f55e7SToby Isaac               PetscInt numStar, s;
32708d2f55e7SToby Isaac 
32718d2f55e7SToby Isaac               ierr = DMPlexGetTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
32728d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
32738d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
32748d2f55e7SToby Isaac 
32758d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
32768d2f55e7SToby Isaac                 ierr = DMPlexLocatePoint_Internal(refTree,dim,point,c,&childCell);CHKERRQ(ierr);
32778d2f55e7SToby Isaac                 if (childCell >= 0) break;
32788d2f55e7SToby Isaac               }
32798d2f55e7SToby Isaac               ierr = DMPlexRestoreTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
32808d2f55e7SToby Isaac               if (childCell >= 0) break;
32818d2f55e7SToby Isaac             }
3282*2c71b3e2SJacob Faibussowitsch             PetscCheckFalse(childCell < 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not locate quadrature point");
32838d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
32848d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent);CHKERRQ(ierr);
3285c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3286c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
32878d2f55e7SToby Isaac 
3288ef0bb6c7SMatthew G. Knepley             ierr = PetscFECreateTabulation(fe,1,1,pointRef,0,&Tchild);CHKERRQ(ierr);
32898d2f55e7SToby Isaac             ierr = DMPlexGetTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
32903b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3291c5356c36SToby Isaac               PetscInt child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
32928d2f55e7SToby Isaac               PetscInt l;
329359fc6756SToby Isaac               const PetscInt *cperms;
32948d2f55e7SToby Isaac 
32958d2f55e7SToby Isaac               ierr = DMLabelGetValue(depth,child,&childDepth);CHKERRQ(ierr);
32968d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
329759fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
32988d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
32998d2f55e7SToby Isaac                 PetscInt pointDepth;
33008d2f55e7SToby Isaac 
33018d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
330259fc6756SToby Isaac                 if (point == child) {
330359fc6756SToby Isaac                   cI = l;
330459fc6756SToby Isaac                   break;
330559fc6756SToby Isaac                 }
33068d2f55e7SToby Isaac                 ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
33078d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
33088d2f55e7SToby Isaac               }
33098d2f55e7SToby Isaac               if (l == numClosure) {
33108d2f55e7SToby Isaac                 pointMatOff += childDof;
33118d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
33128d2f55e7SToby Isaac               }
331359fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
33148d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
331559fc6756SToby Isaac                 PetscInt    lCell = cperms ? cperms[l] : l;
331659fc6756SToby Isaac                 PetscInt    childCellDof = childCellShapeOff + lCell;
331752a3aeb4SToby Isaac                 PetscReal   *childValAtPoint;
331852a3aeb4SToby Isaac                 PetscReal   val = 0.;
33198d2f55e7SToby Isaac 
3320ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
332152a3aeb4SToby Isaac                 for (m = 0; m < Nc; m++) {
332252a3aeb4SToby Isaac                   val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
332352a3aeb4SToby Isaac                 }
332452a3aeb4SToby Isaac 
332552a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
33268d2f55e7SToby Isaac               }
33278d2f55e7SToby Isaac               pointMatOff += childDof;
33288d2f55e7SToby Isaac             }
33298d2f55e7SToby Isaac             ierr = DMPlexRestoreTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
3330ef0bb6c7SMatthew G. Knepley             ierr = PetscTabulationDestroy(&Tchild);CHKERRQ(ierr);
33318d2f55e7SToby Isaac           }
3332ef0bb6c7SMatthew G. Knepley           ierr = PetscTabulationDestroy(&Tparent);CHKERRQ(ierr);
33338d2f55e7SToby Isaac         }
33348d2f55e7SToby Isaac       }
3335c5356c36SToby Isaac       else { /* just the volume-weighted averages of the children */
33363b1c2a6aSToby Isaac         PetscReal parentVol;
3337bfaa5bdcSToby Isaac         PetscInt  childCell;
33383b1c2a6aSToby Isaac 
33393b1c2a6aSToby Isaac         ierr = DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL);CHKERRQ(ierr);
3340bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
334152a3aeb4SToby Isaac           PetscInt  child = children[i], j;
33423b1c2a6aSToby Isaac           PetscReal childVol;
33433b1c2a6aSToby Isaac 
33443b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
33453b1c2a6aSToby Isaac           ierr = DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL);CHKERRQ(ierr);
334652a3aeb4SToby Isaac           for (j = 0; j < Nc; j++) {
3347bfaa5bdcSToby Isaac             pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
334852a3aeb4SToby Isaac           }
3349bfaa5bdcSToby Isaac           childCell++;
33503b1c2a6aSToby Isaac         }
33518d2f55e7SToby Isaac       }
33523b1c2a6aSToby Isaac       /* Insert pointMat into mat */
335352a3aeb4SToby Isaac       ierr = MatSetValues(mat,numSelfDof,matRows,numChildDof,matCols,pointMat,INSERT_VALUES);CHKERRQ(ierr);
335469291d52SBarry Smith       ierr = DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows);CHKERRQ(ierr);
335569291d52SBarry Smith       ierr = DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat);CHKERRQ(ierr);
33568d2f55e7SToby Isaac     }
33578d2f55e7SToby Isaac   }
33583b1c2a6aSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJ);CHKERRQ(ierr);
33598d2f55e7SToby Isaac   ierr = PetscFree2(pointScalar,pointRef);CHKERRQ(ierr);
33603b1c2a6aSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33613b1c2a6aSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33628d2f55e7SToby Isaac   *inj = mat;
33638d2f55e7SToby Isaac   PetscFunctionReturn(0);
33648d2f55e7SToby Isaac }
33658d2f55e7SToby Isaac 
3366f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3367f30e825dSToby Isaac {
3368f30e825dSToby Isaac   PetscDS        ds;
3369f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3370f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3371f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3372f30e825dSToby Isaac   PetscErrorCode ierr;
3373f30e825dSToby Isaac 
3374f30e825dSToby Isaac   PetscFunctionBegin;
3375f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
3376f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3377f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
337892fd8e1eSJed Brown   ierr = DMGetLocalSection(refTree,&refSection);CHKERRQ(ierr);
3379f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3380f30e825dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
3381f30e825dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
3382f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
3383f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof*maxDof,&cols);CHKERRQ(ierr);
3384f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3385f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3386f30e825dSToby Isaac 
3387f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3388f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3389c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3390f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3391f30e825dSToby Isaac 
3392f30e825dSToby Isaac     ierr = PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
3393f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
339452a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3395f30e825dSToby Isaac 
3396f30e825dSToby Isaac       if (numFields > 1) {
3397f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3398f30e825dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
3399f30e825dSToby Isaac       }
3400f30e825dSToby Isaac       else {
3401f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3402f30e825dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
3403f30e825dSToby Isaac       }
3404f30e825dSToby Isaac 
3405f30e825dSToby Isaac       for (r = 0; r < cDof; r++) {
3406f30e825dSToby Isaac         rows[r] = cOff + r;
3407f30e825dSToby Isaac       }
3408f30e825dSToby Isaac       numCols = 0;
3409f30e825dSToby Isaac       {
3410f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3411f30e825dSToby Isaac 
3412f30e825dSToby Isaac         if (numFields > 1) {
3413f30e825dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,parent,f,&aDof);CHKERRQ(ierr);
3414f30e825dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,parent,f,&aOff);CHKERRQ(ierr);
3415f30e825dSToby Isaac         }
3416f30e825dSToby Isaac         else {
3417f30e825dSToby Isaac           ierr = PetscSectionGetDof(refSection,parent,&aDof);CHKERRQ(ierr);
3418f30e825dSToby Isaac           ierr = PetscSectionGetOffset(refSection,parent,&aOff);CHKERRQ(ierr);
3419f30e825dSToby Isaac         }
3420f30e825dSToby Isaac 
3421f30e825dSToby Isaac         for (j = 0; j < aDof; j++) {
3422f30e825dSToby Isaac           cols[numCols++] = aOff + j;
3423f30e825dSToby Isaac         }
3424f30e825dSToby Isaac       }
3425f30e825dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3426f30e825dSToby Isaac       /* transpose of constraint matrix */
3427f30e825dSToby Isaac       ierr = MatGetValues(inj,numCols,cols,cDof,rows,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3428f30e825dSToby Isaac     }
3429f30e825dSToby Isaac   }
3430f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
3431f30e825dSToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
3432f30e825dSToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
3433f30e825dSToby Isaac   PetscFunctionReturn(0);
3434f30e825dSToby Isaac }
3435f30e825dSToby Isaac 
3436f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3437f30e825dSToby Isaac {
3438f30e825dSToby Isaac   PetscDS        ds;
3439f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3440f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3441c6154584SToby Isaac   PetscSection   refConSec, refSection;
3442f30e825dSToby Isaac   PetscErrorCode ierr;
3443f30e825dSToby Isaac 
3444f30e825dSToby Isaac   PetscFunctionBegin;
3445f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3446f30e825dSToby Isaac   *childrenMats = NULL;
3447f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
344892fd8e1eSJed Brown   ierr = DMGetLocalSection(refTree,&refSection);CHKERRQ(ierr);
3449f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3450f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
3451f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3452f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3453f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3454f30e825dSToby Isaac 
3455f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3456f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3457c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3458f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3459f30e825dSToby Isaac 
3460f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3461f30e825dSToby Isaac       PetscInt cDof;
3462f30e825dSToby Isaac 
3463f30e825dSToby Isaac       if (numFields > 1) {
3464f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3465f30e825dSToby Isaac       }
3466f30e825dSToby Isaac       else {
3467f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3468f30e825dSToby Isaac       }
3469f30e825dSToby Isaac 
3470f30e825dSToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
3471f30e825dSToby Isaac     }
3472f30e825dSToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
3473f30e825dSToby Isaac   }
3474f30e825dSToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
3475f30e825dSToby Isaac   PetscFunctionReturn(0);
3476f30e825dSToby Isaac }
3477f30e825dSToby Isaac 
3478ebf164c7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree,Mat *injRef)
3479154bca37SToby Isaac {
3480ebf164c7SToby Isaac   Mat            cMatRef;
34816148253fSToby Isaac   PetscObject    injRefObj;
34828d2f55e7SToby Isaac   PetscErrorCode ierr;
34838d2f55e7SToby Isaac 
3484154bca37SToby Isaac   PetscFunctionBegin;
3485ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,NULL,&cMatRef);CHKERRQ(ierr);
34866148253fSToby Isaac   ierr = PetscObjectQuery((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",&injRefObj);CHKERRQ(ierr);
3487ebf164c7SToby Isaac   *injRef = (Mat) injRefObj;
3488ebf164c7SToby Isaac   if (!*injRef) {
3489ebf164c7SToby Isaac     ierr = DMPlexComputeInjectorReferenceTree(refTree,injRef);CHKERRQ(ierr);
3490ebf164c7SToby Isaac     ierr = PetscObjectCompose((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",(PetscObject)*injRef);CHKERRQ(ierr);
3491ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
3492ebf164c7SToby Isaac     ierr = PetscObjectDereference((PetscObject)*injRef);CHKERRQ(ierr);
3493ebf164c7SToby Isaac   }
3494ebf164c7SToby Isaac   PetscFunctionReturn(0);
34956148253fSToby Isaac }
3496f30e825dSToby Isaac 
3497c921d74cSToby 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)
3498ebf164c7SToby Isaac {
3499c921d74cSToby Isaac   PetscInt       pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3500ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3501ebf164c7SToby Isaac   PetscSection   localCoarse, localFine, leafIndicesSec;
3502c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3503c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3504c921d74cSToby Isaac   const PetscInt *rootDegrees;
3505c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3506ebf164c7SToby Isaac   PetscSF        coarseToFineEmbedded;
3507ebf164c7SToby Isaac   PetscErrorCode ierr;
3508ebf164c7SToby Isaac 
3509ebf164c7SToby Isaac   PetscFunctionBegin;
3510ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
35118d2f55e7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
351292fd8e1eSJed Brown   ierr = DMGetLocalSection(fine,&localFine);CHKERRQ(ierr);
3513e87a4003SBarry Smith   ierr = DMGetGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3514f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
3515f30e825dSToby Isaac   ierr = PetscSectionSetChart(leafIndicesSec,pStartF, pEndF);CHKERRQ(ierr);
3516c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localFine,&maxDof);CHKERRQ(ierr);
35178d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
35187e96bdafSToby Isaac     PetscInt l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
35197e96bdafSToby Isaac     const PetscInt *leaves;
35208d2f55e7SToby Isaac 
35217e96bdafSToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
35227e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
35237e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35248d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
35258d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
35268d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
35278d2f55e7SToby Isaac         numPointsWithDofs++;
3528f30e825dSToby Isaac 
3529f30e825dSToby Isaac         ierr = PetscSectionGetDof(localFine,p,&dof);CHKERRQ(ierr);
3530f30e825dSToby Isaac         ierr = PetscSectionSetDof(leafIndicesSec,p,dof + 1);CHKERRQ(ierr);
35318d2f55e7SToby Isaac       }
35328d2f55e7SToby Isaac     }
35338d2f55e7SToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
3534f30e825dSToby Isaac     ierr = PetscSectionSetUp(leafIndicesSec);CHKERRQ(ierr);
3535f30e825dSToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numIndices);CHKERRQ(ierr);
3536c921d74cSToby Isaac     ierr = PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1),&leafInds);CHKERRQ(ierr);
3537c921d74cSToby Isaac     if (gatheredValues)  {ierr = PetscMalloc1(numIndices,&leafVals);CHKERRQ(ierr);}
35387e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
35397e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35408d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
35418d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
35428d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3543f30e825dSToby Isaac         PetscInt    off, gOff;
3544f30e825dSToby Isaac         PetscInt    *pInd;
3545c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3546f30e825dSToby Isaac 
35477e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3548f30e825dSToby Isaac 
3549f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3550f30e825dSToby Isaac 
3551c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3552c921d74cSToby Isaac         if (gatheredValues) {
3553c921d74cSToby Isaac           PetscInt i;
3554c921d74cSToby Isaac 
3555c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3556c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3557c921d74cSToby Isaac         }
3558f30e825dSToby Isaac         ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
3559f30e825dSToby Isaac 
3560f30e825dSToby Isaac         offsets[0] = 0;
3561f30e825dSToby Isaac         if (numFields) {
3562f30e825dSToby Isaac           PetscInt f;
3563f30e825dSToby Isaac 
3564f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3565f30e825dSToby Isaac             PetscInt fDof;
3566f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(localFine,p,f,&fDof);CHKERRQ(ierr);
3567f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3568f30e825dSToby Isaac           }
356936fa2b79SJed Brown           ierr = DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1, NULL,pInd);CHKERRQ(ierr);
3570367003a6SStefano Zampini         } else {
357136fa2b79SJed Brown           ierr = DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL, NULL,pInd);CHKERRQ(ierr);
3572f30e825dSToby Isaac         }
3573c921d74cSToby Isaac         if (gatheredValues) {ierr = VecGetValues(fineVec,dof,pInd,pVal);CHKERRQ(ierr);}
35748d2f55e7SToby Isaac       }
35758d2f55e7SToby Isaac     }
35768d2f55e7SToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
3577f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
35788d2f55e7SToby Isaac   }
3579f30e825dSToby Isaac 
3580f30e825dSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
358192fd8e1eSJed Brown   ierr = DMGetLocalSection(coarse,&localCoarse);CHKERRQ(ierr);
3582e87a4003SBarry Smith   ierr = DMGetGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3583f30e825dSToby Isaac 
35846148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
35856148253fSToby Isaac     MPI_Datatype threeInt;
35866148253fSToby Isaac     PetscMPIInt  rank;
35876148253fSToby Isaac     PetscInt     (*parentNodeAndIdCoarse)[3];
35886148253fSToby Isaac     PetscInt     (*parentNodeAndIdFine)[3];
35896148253fSToby Isaac     PetscInt     p, nleaves, nleavesToParents;
35906148253fSToby Isaac     PetscSF      pointSF, sfToParents;
35916148253fSToby Isaac     const PetscInt *ilocal;
35926148253fSToby Isaac     const PetscSFNode *iremote;
35936148253fSToby Isaac     PetscSFNode  *iremoteToParents;
35946148253fSToby Isaac     PetscInt     *ilocalToParents;
35956148253fSToby Isaac 
3596ffc4695bSBarry Smith     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)coarse),&rank);CHKERRMPI(ierr);
3597ffc4695bSBarry Smith     ierr = MPI_Type_contiguous(3,MPIU_INT,&threeInt);CHKERRMPI(ierr);
3598ffc4695bSBarry Smith     ierr = MPI_Type_commit(&threeInt);CHKERRMPI(ierr);
35996148253fSToby Isaac     ierr = PetscMalloc2(pEndC-pStartC,&parentNodeAndIdCoarse,pEndF-pStartF,&parentNodeAndIdFine);CHKERRQ(ierr);
36006148253fSToby Isaac     ierr = DMGetPointSF(coarse,&pointSF);CHKERRQ(ierr);
36016148253fSToby Isaac     ierr = PetscSFGetGraph(pointSF,NULL,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
36026148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
36036148253fSToby Isaac       PetscInt parent, childId;
36046148253fSToby Isaac       ierr = DMPlexGetTreeParent(coarse,p,&parent,&childId);CHKERRQ(ierr);
36056148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
36066148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
36076148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
36086148253fSToby Isaac       if (nleaves > 0) {
36096148253fSToby Isaac         PetscInt leaf = -1;
36106148253fSToby Isaac 
36116148253fSToby Isaac         if (ilocal) {
36126148253fSToby Isaac           ierr  = PetscFindInt(parent,nleaves,ilocal,&leaf);CHKERRQ(ierr);
36136148253fSToby Isaac         }
36146148253fSToby Isaac         else {
36156148253fSToby Isaac           leaf = p - pStartC;
36166148253fSToby Isaac         }
36176148253fSToby Isaac         if (leaf >= 0) {
36186148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
36196148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
36206148253fSToby Isaac         }
36216148253fSToby Isaac       }
36226148253fSToby Isaac     }
36236148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
36246148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
36256148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
36266148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
36276148253fSToby Isaac     }
3628ad227feaSJunchao Zhang     ierr = PetscSFBcastBegin(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine,MPI_REPLACE);CHKERRQ(ierr);
3629ad227feaSJunchao Zhang     ierr = PetscSFBcastEnd(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine,MPI_REPLACE);CHKERRQ(ierr);
36306148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3631f30e825dSToby Isaac       PetscInt dof;
3632f30e825dSToby Isaac 
3633f30e825dSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&dof);CHKERRQ(ierr);
3634f30e825dSToby Isaac       if (dof) {
3635f30e825dSToby Isaac         PetscInt off;
3636f30e825dSToby Isaac 
3637f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3638c921d74cSToby Isaac         if (gatheredIndices) {
3639c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3640c921d74cSToby Isaac         } else if (gatheredValues) {
3641c921d74cSToby Isaac           leafVals[off] = (PetscScalar) PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3642c921d74cSToby Isaac         }
3643f30e825dSToby Isaac       }
36446148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36456148253fSToby Isaac         nleavesToParents++;
36466148253fSToby Isaac       }
36476148253fSToby Isaac     }
36486148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&ilocalToParents);CHKERRQ(ierr);
36496148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&iremoteToParents);CHKERRQ(ierr);
36506148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
36516148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36526148253fSToby Isaac         ilocalToParents[nleavesToParents] = p - pStartF;
36536148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p-pStartF][0];
36546148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p-pStartF][1];
36556148253fSToby Isaac         nleavesToParents++;
36566148253fSToby Isaac       }
36576148253fSToby Isaac     }
36586148253fSToby Isaac     ierr = PetscSFCreate(PetscObjectComm((PetscObject)coarse),&sfToParents);CHKERRQ(ierr);
36596148253fSToby Isaac     ierr = PetscSFSetGraph(sfToParents,pEndC-pStartC,nleavesToParents,ilocalToParents,PETSC_OWN_POINTER,iremoteToParents,PETSC_OWN_POINTER);CHKERRQ(ierr);
36606148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
36616148253fSToby Isaac 
36626148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
36636148253fSToby Isaac 
36646148253fSToby Isaac     ierr = PetscFree2(parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
3665ffc4695bSBarry Smith     ierr = MPI_Type_free(&threeInt);CHKERRMPI(ierr);
36666148253fSToby Isaac   }
3667f30e825dSToby Isaac 
36686148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
36696148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
36706148253fSToby Isaac     PetscSF  sfDofsOnly;
36716148253fSToby Isaac 
36726148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
36736148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
36746148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
36756148253fSToby Isaac       if ((dof - cdof) > 0) {
36766148253fSToby Isaac         numPointsWithDofs++;
36776148253fSToby Isaac       }
36786148253fSToby Isaac     }
36796148253fSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
36806148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
36816148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
36826148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
36836148253fSToby Isaac       if ((dof - cdof) > 0) {
3684e03d9830SToby Isaac         pointsWithDofs[offset++] = p - pStartC;
36856148253fSToby Isaac       }
36866148253fSToby Isaac     }
368772502a1fSJunchao Zhang     ierr = PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly);CHKERRQ(ierr);
36886148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3689f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
36906148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
36916148253fSToby Isaac   }
3692f30e825dSToby Isaac 
36936148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
3694f30e825dSToby Isaac   ierr = PetscSFComputeDegreeBegin(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3695f30e825dSToby Isaac   ierr = PetscSFComputeDegreeEnd(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3696f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&multiRootSec);CHKERRQ(ierr);
3697f30e825dSToby Isaac   ierr = PetscSectionSetChart(multiRootSec,pStartC,pEndC);CHKERRQ(ierr);
36988d2f55e7SToby Isaac   for (p = pStartC; p < pEndC; p++) {
3699f30e825dSToby Isaac     ierr = PetscSectionSetDof(multiRootSec,p,rootDegrees[p-pStartC]);CHKERRQ(ierr);
37008d2f55e7SToby Isaac   }
3701f30e825dSToby Isaac   ierr = PetscSectionSetUp(multiRootSec);CHKERRQ(ierr);
3702f30e825dSToby Isaac   ierr = PetscSectionGetStorageSize(multiRootSec,&numMulti);CHKERRQ(ierr);
37038d2f55e7SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
3704f30e825dSToby Isaac   { /* distribute the leaf section */
3705f30e825dSToby Isaac     PetscSF multi, multiInv, indicesSF;
3706f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
37078d2f55e7SToby Isaac 
3708f30e825dSToby Isaac     ierr = PetscSFGetMultiSF(coarseToFineEmbedded,&multi);CHKERRQ(ierr);
3709f30e825dSToby Isaac     ierr = PetscSFCreateInverseSF(multi,&multiInv);CHKERRQ(ierr);
3710f30e825dSToby Isaac     ierr = PetscSFDistributeSection(multiInv,leafIndicesSec,&remoteOffsets,rootIndicesSec);CHKERRQ(ierr);
3711f30e825dSToby Isaac     ierr = PetscSFCreateSectionSF(multiInv,leafIndicesSec,remoteOffsets,rootIndicesSec,&indicesSF);CHKERRQ(ierr);
3712f30e825dSToby Isaac     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
3713f30e825dSToby Isaac     ierr = PetscSFDestroy(&multiInv);CHKERRQ(ierr);
37148d2f55e7SToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
3715c921d74cSToby Isaac     if (gatheredIndices) {
3716c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootInds);CHKERRQ(ierr);
3717ad227feaSJunchao Zhang       ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,leafInds,rootInds,MPI_REPLACE);CHKERRQ(ierr);
3718ad227feaSJunchao Zhang       ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,leafInds,rootInds,MPI_REPLACE);CHKERRQ(ierr);
3719c921d74cSToby Isaac     }
3720c921d74cSToby Isaac     if (gatheredValues) {
3721c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootVals);CHKERRQ(ierr);
3722ad227feaSJunchao Zhang       ierr = PetscSFBcastBegin(indicesSF,MPIU_SCALAR,leafVals,rootVals,MPI_REPLACE);CHKERRQ(ierr);
3723ad227feaSJunchao Zhang       ierr = PetscSFBcastEnd(indicesSF,MPIU_SCALAR,leafVals,rootVals,MPI_REPLACE);CHKERRQ(ierr);
3724c921d74cSToby Isaac     }
37258d2f55e7SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
37268d2f55e7SToby Isaac   }
3727ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
3728c921d74cSToby Isaac   ierr = PetscFree(leafInds);CHKERRQ(ierr);
3729c921d74cSToby Isaac   ierr = PetscFree(leafVals);CHKERRQ(ierr);
3730f30e825dSToby Isaac   ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3731c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3732c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3733c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3734c921d74cSToby Isaac   if (gatheredValues)  *gatheredValues  = rootVals;
3735ebf164c7SToby Isaac   PetscFunctionReturn(0);
3736ebf164c7SToby Isaac }
3737ebf164c7SToby Isaac 
3738ebf164c7SToby Isaac PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3739ebf164c7SToby Isaac {
3740ebf164c7SToby Isaac   DM             refTree;
3741c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3742ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3743ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3744ebf164c7SToby Isaac   PetscSection   cSecRef;
3745277f51e8SBarry Smith   PetscInt       *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3746ebf164c7SToby Isaac   Mat            injRef;
3747c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3748ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3749ebf164c7SToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
3750ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3751ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3752ebf164c7SToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3753ebf164c7SToby Isaac   PetscErrorCode ierr;
3754ebf164c7SToby Isaac 
3755ebf164c7SToby Isaac   PetscFunctionBegin;
3756ebf164c7SToby Isaac 
3757ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
3758ebf164c7SToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
3759ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
3760ebf164c7SToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3761ebf164c7SToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
3762ebf164c7SToby Isaac 
3763ebf164c7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
376492fd8e1eSJed Brown   ierr = DMGetLocalSection(fine,&localFine);CHKERRQ(ierr);
3765e87a4003SBarry Smith   ierr = DMGetGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3766ebf164c7SToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
3767ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
376892fd8e1eSJed Brown   ierr = DMGetLocalSection(coarse,&localCoarse);CHKERRQ(ierr);
3769e87a4003SBarry Smith   ierr = DMGetGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3770ebf164c7SToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
3771ebf164c7SToby Isaac   {
3772ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
3773ebf164c7SToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
3774ebf164c7SToby Isaac   }
3775ebf164c7SToby Isaac 
3776c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,childIds,NULL,numFields,offsets,&multiRootSec,&rootIndicesSec,&rootIndices,NULL);CHKERRQ(ierr);
37778d2f55e7SToby Isaac 
3778f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&parentIndices);CHKERRQ(ierr);
3779f30e825dSToby Isaac 
3780f30e825dSToby Isaac   /* count indices */
37818d2f55e7SToby Isaac   ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
3782c6154584SToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
3783c6154584SToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
37848d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
37858d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
3786f30e825dSToby Isaac   ierr = PetscCalloc2(rowEnd-rowStart,&nnzD,rowEnd-rowStart,&nnzO);CHKERRQ(ierr);
3787f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3788f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
37898d2f55e7SToby Isaac 
3790f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3791f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3792f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3793f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
37948d2f55e7SToby Isaac 
37958d2f55e7SToby Isaac     rowOffsets[0] = 0;
3796f30e825dSToby Isaac     offsetsCopy[0] = 0;
37978d2f55e7SToby Isaac     if (numFields) {
37988d2f55e7SToby Isaac       PetscInt f;
37998d2f55e7SToby Isaac 
3800f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3801f30e825dSToby Isaac         PetscInt fDof;
3802f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3803f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
38048d2f55e7SToby Isaac       }
380536fa2b79SJed Brown       ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,parentIndices);CHKERRQ(ierr);
3806367003a6SStefano Zampini     } else {
380736fa2b79SJed Brown       ierr = DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,parentIndices);CHKERRQ(ierr);
3808f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
38098d2f55e7SToby Isaac     }
3810f30e825dSToby Isaac 
3811f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3812f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3813f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3814f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3815f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3816f30e825dSToby Isaac       const PetscInt *childIndices;
3817f30e825dSToby Isaac 
3818f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3819f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3820f30e825dSToby Isaac       childId = rootIndices[offset++];
3821f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3822f30e825dSToby Isaac       numIndices--;
3823f30e825dSToby Isaac 
3824f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3825f30e825dSToby Isaac         PetscInt i;
3826f30e825dSToby Isaac 
3827f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3828f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3829f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3830f30e825dSToby Isaac           if (rowIndex < 0) continue;
3831*2c71b3e2SJacob Faibussowitsch           PetscCheckFalse(colIndex < 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unconstrained fine and constrained coarse");
3832a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3833f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
3834f30e825dSToby Isaac           }
3835f30e825dSToby Isaac           else {
3836f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3837f30e825dSToby Isaac           }
3838f30e825dSToby Isaac         }
3839f30e825dSToby Isaac       }
3840f30e825dSToby Isaac       else {
3841f30e825dSToby Isaac         PetscInt parentId, f, lim;
3842f30e825dSToby Isaac 
3843f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3844f30e825dSToby Isaac 
3845f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3846f30e825dSToby Isaac         offsets[0] = 0;
38478d2f55e7SToby Isaac         if (numFields) {
38488d2f55e7SToby Isaac           PetscInt f;
3849f30e825dSToby Isaac 
38508d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3851f30e825dSToby Isaac             PetscInt fDof;
3852f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
3853f30e825dSToby Isaac 
3854f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
38558d2f55e7SToby Isaac           }
38568d2f55e7SToby Isaac         }
38578d2f55e7SToby Isaac         else {
3858f30e825dSToby Isaac           PetscInt cDof;
3859f30e825dSToby Isaac 
3860f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
3861f30e825dSToby Isaac           offsets[1] = cDof;
3862f30e825dSToby Isaac         }
3863f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3864f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3865f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3866f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3867f30e825dSToby Isaac 
3868f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3869f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3870f30e825dSToby Isaac 
3871f30e825dSToby Isaac             if (colIndex < 0) continue;
3872f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3873f30e825dSToby Isaac               numD++;
3874f30e825dSToby Isaac             }
3875f30e825dSToby Isaac             else {
3876f30e825dSToby Isaac               numO++;
3877f30e825dSToby Isaac             }
3878f30e825dSToby Isaac           }
3879f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3880f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3881f30e825dSToby Isaac 
3882f30e825dSToby Isaac             if (rowIndex < 0) continue;
3883f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3884f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
38858d2f55e7SToby Isaac           }
38868d2f55e7SToby Isaac         }
38878d2f55e7SToby Isaac       }
3888f30e825dSToby Isaac     }
3889f30e825dSToby Isaac   }
3890f30e825dSToby Isaac   /* preallocate */
3891f30e825dSToby Isaac   ierr = MatXAIJSetPreallocation(mat,1,nnzD,nnzO,NULL,NULL);CHKERRQ(ierr);
3892f30e825dSToby Isaac   ierr = PetscFree2(nnzD,nnzO);CHKERRQ(ierr);
3893f30e825dSToby Isaac   /* insert values */
3894f30e825dSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
3895f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3896f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3897f30e825dSToby Isaac 
3898f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3899f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3900f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3901f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
3902f30e825dSToby Isaac 
3903f30e825dSToby Isaac     rowOffsets[0] = 0;
3904f30e825dSToby Isaac     offsetsCopy[0] = 0;
39058d2f55e7SToby Isaac     if (numFields) {
39068d2f55e7SToby Isaac       PetscInt f;
3907f30e825dSToby Isaac 
39088d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3909f30e825dSToby Isaac         PetscInt fDof;
3910f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3911f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3912f30e825dSToby Isaac       }
391336fa2b79SJed Brown       ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,parentIndices);CHKERRQ(ierr);
3914367003a6SStefano Zampini     } else {
391536fa2b79SJed Brown       ierr = DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,parentIndices);CHKERRQ(ierr);
3916f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3917f30e825dSToby Isaac     }
3918f30e825dSToby Isaac 
3919f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3920f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3921f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3922f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3923f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3924f30e825dSToby Isaac       const PetscInt *childIndices;
3925f30e825dSToby Isaac 
3926f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3927f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3928f30e825dSToby Isaac       childId = rootIndices[offset++];
3929f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3930f30e825dSToby Isaac       numIndices--;
3931f30e825dSToby Isaac 
3932f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3933f30e825dSToby Isaac         PetscInt i;
3934f30e825dSToby Isaac 
3935f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3936f30e825dSToby Isaac           ierr = MatSetValue(mat,parentIndices[i],childIndices[i],1.,INSERT_VALUES);CHKERRQ(ierr);
39378d2f55e7SToby Isaac         }
39388d2f55e7SToby Isaac       }
39398d2f55e7SToby Isaac       else {
3940f30e825dSToby Isaac         PetscInt parentId, f, lim;
39418d2f55e7SToby Isaac 
3942f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3943f30e825dSToby Isaac 
3944f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3945f30e825dSToby Isaac         offsets[0] = 0;
39468d2f55e7SToby Isaac         if (numFields) {
3947f30e825dSToby Isaac           PetscInt f;
39488d2f55e7SToby Isaac 
3949f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3950f30e825dSToby Isaac             PetscInt fDof;
3951f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
3952f30e825dSToby Isaac 
3953f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
39548d2f55e7SToby Isaac           }
39558d2f55e7SToby Isaac         }
39568d2f55e7SToby Isaac         else {
3957f30e825dSToby Isaac           PetscInt cDof;
3958f30e825dSToby Isaac 
3959f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
3960f30e825dSToby Isaac           offsets[1] = cDof;
39618d2f55e7SToby Isaac         }
3962f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3963f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3964f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3965f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3966f30e825dSToby Isaac 
3967f30e825dSToby Isaac           ierr = MatSetValues(mat,rowOffsets[f+1]-rowOffsets[f],rowIndices,offsets[f+1]-offsets[f],colIndices,childMat,INSERT_VALUES);CHKERRQ(ierr);
39688d2f55e7SToby Isaac         }
39698d2f55e7SToby Isaac       }
39708d2f55e7SToby Isaac     }
39718d2f55e7SToby Isaac   }
3972ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
3973ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
3974ec92bd66SToby Isaac   ierr = PetscFree(parentIndices);CHKERRQ(ierr);
3975f30e825dSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
3976f30e825dSToby Isaac   ierr = PetscFree(rootIndices);CHKERRQ(ierr);
3977f30e825dSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
3978f30e825dSToby Isaac 
39798d2f55e7SToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
39808d2f55e7SToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
3981154bca37SToby Isaac   PetscFunctionReturn(0);
3982154bca37SToby Isaac }
398338fc2455SToby Isaac 
39840eb7e1eaSToby Isaac static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3985ebf164c7SToby Isaac {
398662095d54SToby Isaac   PetscSF           coarseToFineEmbedded;
398762095d54SToby Isaac   PetscSection      globalCoarse, globalFine;
398862095d54SToby Isaac   PetscSection      localCoarse, localFine;
398962095d54SToby Isaac   PetscSection      aSec, cSec;
399062095d54SToby Isaac   PetscSection      rootValuesSec;
399162095d54SToby Isaac   PetscSection      leafValuesSec;
399262095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
399362095d54SToby Isaac   IS                aIS;
399462095d54SToby Isaac   const PetscInt    *anchors;
399562095d54SToby Isaac   Mat               cMat;
399662095d54SToby Isaac   PetscInt          numFields;
3997412e9a14SMatthew G. Knepley   PetscInt          pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
399862095d54SToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
399962095d54SToby Isaac   PetscInt          *maxChildIds;
400062095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
40010eb7e1eaSToby Isaac   PetscFV           fv = NULL;
40020eb7e1eaSToby Isaac   PetscInt          dim, numFVcomps = -1, fvField = -1;
40030eb7e1eaSToby Isaac   DM                cellDM = NULL, gradDM = NULL;
40040eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
40050eb7e1eaSToby Isaac   const PetscScalar *gradArray = NULL;
400662095d54SToby Isaac   PetscErrorCode    ierr;
400762095d54SToby Isaac 
4008ebf164c7SToby Isaac   PetscFunctionBegin;
4009708c7f19SToby Isaac   ierr = VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
401062095d54SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
4011412e9a14SMatthew G. Knepley   ierr = DMPlexGetSimplexOrBoxCells(coarse,0,&cellStart,&cellEnd);CHKERRQ(ierr);
401262095d54SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
4013e87a4003SBarry Smith   ierr = DMGetGlobalSection(fine,&globalFine);CHKERRQ(ierr);
40140eb7e1eaSToby Isaac   ierr = DMGetCoordinateDim(coarse,&dim);CHKERRQ(ierr);
401562095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
4016e4a60869SToby Isaac     PetscInt       nleaves, l;
4017e4a60869SToby Isaac     const PetscInt *leaves;
401862095d54SToby Isaac     PetscInt       dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
401962095d54SToby Isaac 
4020e4a60869SToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
4021e4a60869SToby Isaac 
4022e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
4023e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
4024e4a60869SToby Isaac 
402562095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
402662095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
402762095d54SToby Isaac       if ((dof - cdof) > 0) {
402862095d54SToby Isaac         numPointsWithDofs++;
402962095d54SToby Isaac       }
403062095d54SToby Isaac     }
403162095d54SToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
40324833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
4033e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
4034e4a60869SToby Isaac 
403562095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
403662095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
403762095d54SToby Isaac       if ((dof - cdof) > 0) {
4038e4a60869SToby Isaac         pointsWithDofs[offset++] = l;
403962095d54SToby Isaac       }
404062095d54SToby Isaac     }
404162095d54SToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
404262095d54SToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
404362095d54SToby Isaac   }
404462095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
404562095d54SToby Isaac   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
404662095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) {
404762095d54SToby Isaac     maxChildIds[p - pStartC] = -2;
404862095d54SToby Isaac   }
404962095d54SToby Isaac   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
405062095d54SToby Isaac   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
405162095d54SToby Isaac 
405292fd8e1eSJed Brown   ierr = DMGetLocalSection(coarse,&localCoarse);CHKERRQ(ierr);
4053e87a4003SBarry Smith   ierr = DMGetGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
405462095d54SToby Isaac 
405562095d54SToby Isaac   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
405662095d54SToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
405762095d54SToby Isaac   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
405862095d54SToby Isaac 
405962095d54SToby Isaac   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
406062095d54SToby Isaac   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
406162095d54SToby Isaac 
406262095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
406362095d54SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootValuesSec);CHKERRQ(ierr);
406462095d54SToby Isaac   ierr = PetscSectionSetChart(rootValuesSec,pStartC,pEndC);CHKERRQ(ierr);
4065708c7f19SToby Isaac   ierr = PetscSectionGetNumFields(localCoarse,&numFields);CHKERRQ(ierr);
406662095d54SToby Isaac   {
406762095d54SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
406862095d54SToby Isaac     ierr = PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO);CHKERRQ(ierr);
406962095d54SToby Isaac   }
40700eb7e1eaSToby Isaac   if (grad) {
40710eb7e1eaSToby Isaac     PetscInt i;
40720eb7e1eaSToby Isaac 
40730eb7e1eaSToby Isaac     ierr = VecGetDM(cellGeom,&cellDM);CHKERRQ(ierr);
40740eb7e1eaSToby Isaac     ierr = VecGetArrayRead(cellGeom,&cellGeomArray);CHKERRQ(ierr);
40750eb7e1eaSToby Isaac     ierr = VecGetDM(grad,&gradDM);CHKERRQ(ierr);
40760eb7e1eaSToby Isaac     ierr = VecGetArrayRead(grad,&gradArray);CHKERRQ(ierr);
40770eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1,numFields); i++) {
40780eb7e1eaSToby Isaac       PetscObject  obj;
40790eb7e1eaSToby Isaac       PetscClassId id;
40800eb7e1eaSToby Isaac 
408144a7f3ddSMatthew G. Knepley       ierr = DMGetField(coarse, i, NULL, &obj);CHKERRQ(ierr);
40820eb7e1eaSToby Isaac       ierr = PetscObjectGetClassId(obj,&id);CHKERRQ(ierr);
40830eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
40840eb7e1eaSToby Isaac         fv      = (PetscFV) obj;
40850eb7e1eaSToby Isaac         ierr    = PetscFVGetNumComponents(fv,&numFVcomps);CHKERRQ(ierr);
40860eb7e1eaSToby Isaac         fvField = i;
40870eb7e1eaSToby Isaac         break;
40880eb7e1eaSToby Isaac       }
40890eb7e1eaSToby Isaac     }
40900eb7e1eaSToby Isaac   }
409162095d54SToby Isaac 
409262095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
409362095d54SToby Isaac     PetscInt dof;
409462095d54SToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
409562095d54SToby Isaac     PetscInt numValues      = 0;
409662095d54SToby Isaac 
409762095d54SToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
409862095d54SToby Isaac     if (dof < 0) {
409962095d54SToby Isaac       dof = -(dof + 1);
410062095d54SToby Isaac     }
410162095d54SToby Isaac     offsets[0]    = 0;
410262095d54SToby Isaac     newOffsets[0] = 0;
410362095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
410462095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
410562095d54SToby Isaac 
41064833aeb0SToby Isaac       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
410762095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
410862095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
410962095d54SToby Isaac 
411062095d54SToby Isaac         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
411162095d54SToby Isaac         numValues += clDof;
411262095d54SToby Isaac       }
41134833aeb0SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
411462095d54SToby Isaac     }
411562095d54SToby Isaac     else if (maxChildId == -1) {
411662095d54SToby Isaac       ierr = PetscSectionGetDof(localCoarse,p,&numValues);CHKERRQ(ierr);
411762095d54SToby Isaac     }
411862095d54SToby Isaac     /* we will pack the column indices with the field offsets */
411978b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
41200eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
41210eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
41220eb7e1eaSToby Isaac     }
412362095d54SToby Isaac     ierr = PetscSectionSetDof(rootValuesSec,p,numValues);CHKERRQ(ierr);
412462095d54SToby Isaac   }
412562095d54SToby Isaac   ierr = PetscSectionSetUp(rootValuesSec);CHKERRQ(ierr);
412662095d54SToby Isaac   {
412762095d54SToby Isaac     PetscInt          numRootValues;
412862095d54SToby Isaac     const PetscScalar *coarseArray;
412962095d54SToby Isaac 
413062095d54SToby Isaac     ierr = PetscSectionGetStorageSize(rootValuesSec,&numRootValues);CHKERRQ(ierr);
413162095d54SToby Isaac     ierr = PetscMalloc1(numRootValues,&rootValues);CHKERRQ(ierr);
413262095d54SToby Isaac     ierr = VecGetArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr);
413362095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
413462095d54SToby Isaac       PetscInt    numValues;
413562095d54SToby Isaac       PetscInt    pValOff;
413662095d54SToby Isaac       PetscScalar *pVal;
413762095d54SToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
413862095d54SToby Isaac 
413962095d54SToby Isaac       ierr = PetscSectionGetDof(rootValuesSec,p,&numValues);CHKERRQ(ierr);
414062095d54SToby Isaac       if (!numValues) {
414162095d54SToby Isaac         continue;
414262095d54SToby Isaac       }
414362095d54SToby Isaac       ierr = PetscSectionGetOffset(rootValuesSec,p,&pValOff);CHKERRQ(ierr);
414462095d54SToby Isaac       pVal = &(rootValues[pValOff]);
414562095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
41460eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
41470eb7e1eaSToby Isaac         ierr = DMPlexVecGetClosure(coarse,NULL,vecCoarseLocal,p,&closureSize,&pVal);CHKERRQ(ierr);
41480eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
4149193eb951SToby Isaac           PetscFVCellGeom *cg;
41506dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
41510eb7e1eaSToby Isaac           PetscInt        i;
41520eb7e1eaSToby Isaac 
41530eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
41540eb7e1eaSToby Isaac 
4155193eb951SToby Isaac           ierr = DMPlexPointLocalRead(cellDM,p,cellGeomArray,(void *) &cg);CHKERRQ(ierr);
41560eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
41570eb7e1eaSToby Isaac           pVal += dim;
4158193eb951SToby Isaac           ierr = DMPlexPointGlobalRead(gradDM,p,gradArray,(void *) &gradVals);CHKERRQ(ierr);
41590eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
41600eb7e1eaSToby Isaac         }
416162095d54SToby Isaac       }
416278b7adb5SToby Isaac       else if (maxChildId == -1) {
416378b7adb5SToby Isaac         PetscInt lDof, lOff, i;
416478b7adb5SToby Isaac 
416578b7adb5SToby Isaac         ierr = PetscSectionGetDof(localCoarse,p,&lDof);CHKERRQ(ierr);
416678b7adb5SToby Isaac         ierr = PetscSectionGetOffset(localCoarse,p,&lOff);CHKERRQ(ierr);
416778b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
416878b7adb5SToby Isaac       }
416978b7adb5SToby Isaac     }
417062095d54SToby Isaac     ierr = VecRestoreArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr);
417162095d54SToby Isaac     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
417262095d54SToby Isaac   }
417362095d54SToby Isaac   {
417462095d54SToby Isaac     PetscSF  valuesSF;
417562095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
417662095d54SToby Isaac 
417762095d54SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafValuesSec);CHKERRQ(ierr);
417862095d54SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootValuesSec,&remoteOffsetsValues,leafValuesSec);CHKERRQ(ierr);
417962095d54SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootValuesSec,remoteOffsetsValues,leafValuesSec,&valuesSF);CHKERRQ(ierr);
418062095d54SToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
418162095d54SToby Isaac     ierr = PetscFree(remoteOffsetsValues);CHKERRQ(ierr);
418262095d54SToby Isaac     ierr = PetscSectionGetStorageSize(leafValuesSec,&numLeafValues);CHKERRQ(ierr);
418362095d54SToby Isaac     ierr = PetscMalloc1(numLeafValues,&leafValues);CHKERRQ(ierr);
4184ad227feaSJunchao Zhang     ierr = PetscSFBcastBegin(valuesSF,MPIU_SCALAR,rootValues,leafValues,MPI_REPLACE);CHKERRQ(ierr);
4185ad227feaSJunchao Zhang     ierr = PetscSFBcastEnd(valuesSF,MPIU_SCALAR,rootValues,leafValues,MPI_REPLACE);CHKERRQ(ierr);
418662095d54SToby Isaac     ierr = PetscSFDestroy(&valuesSF);CHKERRQ(ierr);
418762095d54SToby Isaac     ierr = PetscFree(rootValues);CHKERRQ(ierr);
418862095d54SToby Isaac     ierr = PetscSectionDestroy(&rootValuesSec);CHKERRQ(ierr);
418962095d54SToby Isaac   }
419092fd8e1eSJed Brown   ierr = DMGetLocalSection(fine,&localFine);CHKERRQ(ierr);
419162095d54SToby Isaac   {
419262095d54SToby Isaac     PetscInt    maxDof;
419362095d54SToby Isaac     PetscInt    *rowIndices;
419462095d54SToby Isaac     DM           refTree;
419562095d54SToby Isaac     PetscInt     **refPointFieldN;
419662095d54SToby Isaac     PetscScalar  ***refPointFieldMats;
419762095d54SToby Isaac     PetscSection refConSec, refAnSec;
41980eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,leafStart,leafEnd;
419962095d54SToby Isaac     PetscScalar  *pointWork;
420062095d54SToby Isaac 
4201cfc9abc1SToby Isaac     ierr = PetscSectionGetMaxDof(localFine,&maxDof);CHKERRQ(ierr);
420269291d52SBarry Smith     ierr = DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
420369291d52SBarry Smith     ierr = DMGetWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork);CHKERRQ(ierr);
420462095d54SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
4205e5e52638SMatthew G. Knepley     ierr = DMCopyDisc(fine,refTree);CHKERRQ(ierr);
420662095d54SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
420762095d54SToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
420862095d54SToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
420962095d54SToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
42100eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafValuesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
4211412e9a14SMatthew G. Knepley     ierr = DMPlexGetSimplexOrBoxCells(fine,0,&cellStart,&cellEnd);CHKERRQ(ierr);
42120eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
421362095d54SToby Isaac       PetscInt          gDof, gcDof, gOff, lDof;
421462095d54SToby Isaac       PetscInt          numValues, pValOff;
421562095d54SToby Isaac       PetscInt          childId;
421662095d54SToby Isaac       const PetscScalar *pVal;
42170eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
421862095d54SToby Isaac 
421962095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
422062095d54SToby Isaac       ierr = PetscSectionGetDof(localFine,p,&lDof);CHKERRQ(ierr);
422162095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
422262095d54SToby Isaac       if ((gDof - gcDof) <= 0) {
422362095d54SToby Isaac         continue;
422462095d54SToby Isaac       }
422562095d54SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
422662095d54SToby Isaac       ierr = PetscSectionGetDof(leafValuesSec,p,&numValues);CHKERRQ(ierr);
422762095d54SToby Isaac       if (!numValues) continue;
422862095d54SToby Isaac       ierr = PetscSectionGetOffset(leafValuesSec,p,&pValOff);CHKERRQ(ierr);
422962095d54SToby Isaac       pVal = &leafValues[pValOff];
423062095d54SToby Isaac       offsets[0]        = 0;
423162095d54SToby Isaac       offsetsCopy[0]    = 0;
423262095d54SToby Isaac       newOffsets[0]     = 0;
423362095d54SToby Isaac       newOffsetsCopy[0] = 0;
42344833aeb0SToby Isaac       childId           = cids[p - pStartF];
423562095d54SToby Isaac       if (numFields) {
423662095d54SToby Isaac         PetscInt f;
423762095d54SToby Isaac         for (f = 0; f < numFields; f++) {
423862095d54SToby Isaac           PetscInt rowDof;
423962095d54SToby Isaac 
424062095d54SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
424162095d54SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
424262095d54SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
424362095d54SToby Isaac           /* TODO: closure indices */
42449f4e70e1SToby Isaac           newOffsets[f + 1]     = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
424562095d54SToby Isaac         }
424636fa2b79SJed Brown         ierr = DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,NULL,rowIndices);CHKERRQ(ierr);
424762095d54SToby Isaac       }
424862095d54SToby Isaac       else {
42494833aeb0SToby Isaac         offsets[0]    = 0;
42504833aeb0SToby Isaac         offsets[1]    = lDof;
42514833aeb0SToby Isaac         newOffsets[0] = 0;
42524833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
425336fa2b79SJed Brown         ierr = DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,NULL,rowIndices);CHKERRQ(ierr);
425462095d54SToby Isaac       }
425562095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
42562f65e181SToby Isaac         ierr = VecSetValues(vecFine,numValues,rowIndices,pVal,INSERT_VALUES);CHKERRQ(ierr);
425762095d54SToby Isaac       } else {
425862095d54SToby Isaac         PetscInt f;
425962095d54SToby Isaac 
426078b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
426178b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
426278b7adb5SToby Isaac           fvGradData = &pVal[numValues];
426378b7adb5SToby Isaac         }
426462095d54SToby Isaac         for (f = 0; f < PetscMax(1,numFields); f++) {
426562095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
426662095d54SToby Isaac           PetscInt numRows = offsets[f+1] - offsets[f];
426762095d54SToby Isaac           PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
426862095d54SToby Isaac           const PetscScalar *cVal = &pVal[newOffsets[f]];
426962095d54SToby Isaac           PetscScalar *rVal = &pointWork[offsets[f]];
427062095d54SToby Isaac           PetscInt i, j;
427162095d54SToby Isaac 
4272708c7f19SToby Isaac #if 0
42737d3de750SJacob Faibussowitsch           ierr = PetscInfo(coarse,"childId %D, numRows %D, numCols %D, refPointFieldN %D maxDof %D\n",childId,numRows,numCols,refPointFieldN[childId - pRefStart][f], maxDof);CHKERRQ(ierr);
4274708c7f19SToby Isaac #endif
427562095d54SToby Isaac           for (i = 0; i < numRows; i++) {
427662095d54SToby Isaac             PetscScalar val = 0.;
427762095d54SToby Isaac             for (j = 0; j < numCols; j++) {
427862095d54SToby Isaac               val += childMat[i * numCols + j] * cVal[j];
427962095d54SToby Isaac             }
428062095d54SToby Isaac             rVal[i] = val;
428162095d54SToby Isaac           }
42820eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
42830eb7e1eaSToby Isaac             PetscReal   centroid[3];
42840eb7e1eaSToby Isaac             PetscScalar diff[3];
42850eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
42860eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
42870eb7e1eaSToby Isaac 
42880eb7e1eaSToby Isaac             ierr = DMPlexComputeCellGeometryFVM(fine,p,NULL,centroid,NULL);CHKERRQ(ierr);
42890eb7e1eaSToby Isaac             for (i = 0; i < dim; i++) {
42900eb7e1eaSToby Isaac               diff[i] = centroid[i] - parentCentroid[i];
42910eb7e1eaSToby Isaac             }
42920eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
42930eb7e1eaSToby Isaac               PetscScalar val = 0.;
42940eb7e1eaSToby Isaac 
429589698031SToby Isaac               for (j = 0; j < dim; j++) {
42960eb7e1eaSToby Isaac                 val += gradient[dim * i + j] * diff[j];
42970eb7e1eaSToby Isaac               }
42980eb7e1eaSToby Isaac               rVal[i] += val;
42990eb7e1eaSToby Isaac             }
43000eb7e1eaSToby Isaac           }
43012f65e181SToby Isaac           ierr = VecSetValues(vecFine,numRows,&rowIndices[offsets[f]],rVal,INSERT_VALUES);CHKERRQ(ierr);
430262095d54SToby Isaac         }
430362095d54SToby Isaac       }
430462095d54SToby Isaac     }
430562095d54SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
430669291d52SBarry Smith     ierr = DMRestoreWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork);CHKERRQ(ierr);
4307cfc9abc1SToby Isaac     ierr = DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices);CHKERRQ(ierr);
430862095d54SToby Isaac   }
43094fe3dfefSToby Isaac   ierr = PetscFree(leafValues);CHKERRQ(ierr);
431062095d54SToby Isaac   ierr = PetscSectionDestroy(&leafValuesSec);CHKERRQ(ierr);
431162095d54SToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
431262095d54SToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
4313ebf164c7SToby Isaac   PetscFunctionReturn(0);
4314ebf164c7SToby Isaac }
4315ebf164c7SToby Isaac 
4316ebf164c7SToby Isaac static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4317ebf164c7SToby Isaac {
4318c921d74cSToby Isaac   DM             refTree;
4319c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4320c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4321c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4322c921d74cSToby Isaac   PetscSection   cSecRef;
4323c921d74cSToby Isaac   PetscInt       *parentIndices, pRefStart, pRefEnd;
4324d3bc4906SToby Isaac   PetscScalar    *rootValues, *parentValues;
4325c921d74cSToby Isaac   Mat            injRef;
4326c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4327c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4328c921d74cSToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
4329c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4330c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4331c921d74cSToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4332c921d74cSToby Isaac   PetscErrorCode ierr;
4333c921d74cSToby Isaac 
4334ebf164c7SToby Isaac   PetscFunctionBegin;
4335c921d74cSToby Isaac 
4336c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
4337708c7f19SToby Isaac   ierr = VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
4338708c7f19SToby Isaac   ierr = VecSetOption(vecCoarse,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
4339c921d74cSToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
4340e5e52638SMatthew G. Knepley   ierr = DMCopyDisc(coarse,refTree);CHKERRQ(ierr);
4341c921d74cSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
4342c921d74cSToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
4343c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
4344c921d74cSToby Isaac 
4345c921d74cSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
434692fd8e1eSJed Brown   ierr = DMGetLocalSection(fine,&localFine);CHKERRQ(ierr);
4347e87a4003SBarry Smith   ierr = DMGetGlobalSection(fine,&globalFine);CHKERRQ(ierr);
4348c921d74cSToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
4349c921d74cSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
435092fd8e1eSJed Brown   ierr = DMGetLocalSection(coarse,&localCoarse);CHKERRQ(ierr);
4351e87a4003SBarry Smith   ierr = DMGetGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
4352c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
4353c921d74cSToby Isaac   {
4354c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
4355c921d74cSToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
4356c921d74cSToby Isaac   }
4357c921d74cSToby Isaac 
4358c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,cids,vecFine,numFields,offsets,&multiRootSec,&rootIndicesSec,NULL,&rootValues);CHKERRQ(ierr);
4359c921d74cSToby Isaac 
4360d3bc4906SToby Isaac   ierr = PetscMalloc2(maxDof,&parentIndices,maxDof,&parentValues);CHKERRQ(ierr);
4361c921d74cSToby Isaac 
4362c921d74cSToby Isaac   /* count indices */
436362095d54SToby Isaac   ierr = VecGetLayout(vecFine,&colMap);CHKERRQ(ierr);
436462095d54SToby Isaac   ierr = VecGetLayout(vecCoarse,&rowMap);CHKERRQ(ierr);
4365c921d74cSToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
4366c921d74cSToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
4367c921d74cSToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
4368c921d74cSToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
4369c921d74cSToby Isaac   /* insert values */
4370c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4371c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4372c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
437378b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4374c921d74cSToby Isaac 
4375c921d74cSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
4376c921d74cSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
4377c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
43782f65e181SToby Isaac     ierr = PetscSectionGetDof(localCoarse,p,&dof);CHKERRQ(ierr);
4379c921d74cSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
4380c921d74cSToby Isaac 
4381c921d74cSToby Isaac     rowOffsets[0] = 0;
4382c921d74cSToby Isaac     offsetsCopy[0] = 0;
4383c921d74cSToby Isaac     if (numFields) {
4384c921d74cSToby Isaac       PetscInt f;
4385c921d74cSToby Isaac 
4386c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4387c921d74cSToby Isaac         PetscInt fDof;
4388c921d74cSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
4389c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4390c921d74cSToby Isaac       }
439136fa2b79SJed Brown       ierr = DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,NULL,parentIndices);CHKERRQ(ierr);
4392367003a6SStefano Zampini     } else {
439336fa2b79SJed Brown       ierr = DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,NULL,parentIndices);CHKERRQ(ierr);
4394c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4395c921d74cSToby Isaac     }
4396c921d74cSToby Isaac 
4397c921d74cSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
4398c921d74cSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
4399c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
44002f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4401c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4402c921d74cSToby Isaac       PetscInt numIndices, childId, offset;
4403c921d74cSToby Isaac       const PetscScalar *childValues;
4404c921d74cSToby Isaac 
4405c921d74cSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
4406c921d74cSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
4407c921d74cSToby Isaac       childId = (PetscInt) PetscRealPart(rootValues[offset++]);
4408c921d74cSToby Isaac       childValues = &rootValues[offset];
4409c921d74cSToby Isaac       numIndices--;
4410c921d74cSToby Isaac 
4411c921d74cSToby Isaac       if (childId == -2) { /* skip */
4412c921d74cSToby Isaac         continue;
4413c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
44142f65e181SToby Isaac         PetscInt m;
44152f65e181SToby Isaac 
441678b7adb5SToby Isaac         contribute = PETSC_TRUE;
44172f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4418beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4419d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4420d3bc4906SToby Isaac 
442178b7adb5SToby Isaac         contribute = PETSC_TRUE;
4422d3bc4906SToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
4423d3bc4906SToby Isaac 
4424d3bc4906SToby Isaac         lim = PetscMax(1,numFields);
4425d3bc4906SToby Isaac         offsets[0] = 0;
4426d3bc4906SToby Isaac         if (numFields) {
4427d3bc4906SToby Isaac           PetscInt f;
4428d3bc4906SToby Isaac 
4429d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4430d3bc4906SToby Isaac             PetscInt fDof;
4431d3bc4906SToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
4432d3bc4906SToby Isaac 
4433d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4434d3bc4906SToby Isaac           }
4435d3bc4906SToby Isaac         }
4436d3bc4906SToby Isaac         else {
4437d3bc4906SToby Isaac           PetscInt cDof;
4438d3bc4906SToby Isaac 
4439d3bc4906SToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
4440d3bc4906SToby Isaac           offsets[1] = cDof;
4441d3bc4906SToby Isaac         }
4442d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4443d3bc4906SToby Isaac           PetscScalar       *childMat   = &childrenMats[childId - pRefStart][f][0];
4444d3bc4906SToby Isaac           PetscInt          n           = offsets[f+1]-offsets[f];
4445e328ff09SToby Isaac           PetscInt          m           = rowOffsets[f+1]-rowOffsets[f];
4446d3bc4906SToby Isaac           PetscInt          i, j;
4447d3bc4906SToby Isaac           const PetscScalar *colValues  = &childValues[offsets[f]];
4448d3bc4906SToby Isaac 
4449e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4450d3bc4906SToby Isaac             PetscScalar val = 0.;
4451d3bc4906SToby Isaac             for (j = 0; j < n; j++) {
4452d3bc4906SToby Isaac               val += childMat[n * i + j] * colValues[j];
4453d3bc4906SToby Isaac             }
4454e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4455d3bc4906SToby Isaac           }
4456d3bc4906SToby Isaac         }
4457c921d74cSToby Isaac       }
4458c921d74cSToby Isaac     }
445978b7adb5SToby Isaac     if (contribute) {ierr = VecSetValues(vecCoarse,dof,parentIndices,parentValues,INSERT_VALUES);CHKERRQ(ierr);}
4460c921d74cSToby Isaac   }
4461c921d74cSToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
4462c921d74cSToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
4463d3bc4906SToby Isaac   ierr = PetscFree2(parentIndices,parentValues);CHKERRQ(ierr);
4464c921d74cSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4465c921d74cSToby Isaac   ierr = PetscFree(rootValues);CHKERRQ(ierr);
4466c921d74cSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
4467ebf164c7SToby Isaac   PetscFunctionReturn(0);
4468ebf164c7SToby Isaac }
4469ebf164c7SToby Isaac 
4470ff1f73f7SToby Isaac /*@
4471ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4472ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4473ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4474ff1f73f7SToby Isaac 
4475ff1f73f7SToby Isaac   collective
4476ff1f73f7SToby Isaac 
4477ff1f73f7SToby Isaac   Input Parameters:
4478ff1f73f7SToby Isaac + dmIn        - The DMPlex mesh for the input vector
4479ff1f73f7SToby Isaac . vecIn       - The input vector
4480ff1f73f7SToby Isaac . sfRefine    - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4481ff1f73f7SToby Isaac                 the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4482ff1f73f7SToby Isaac . sfCoarsen   - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4483ff1f73f7SToby Isaac                 the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4484ff1f73f7SToby Isaac . cidsRefine  - The childIds of the points in dmOut.  These childIds relate back to the reference tree: childid[j] = k implies
4485ff1f73f7SToby Isaac                 that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4486ff1f73f7SToby Isaac                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in dmOut is exactly
4487ff1f73f7SToby Isaac                 equivalent to its root in dmIn, so no interpolation is necessary.  childid[j] = -2 indicates that this
4488ff1f73f7SToby Isaac                 point j in dmOut is not a leaf of sfRefine.
4489ff1f73f7SToby Isaac . cidsCoarsen - The childIds of the points in dmIn.  These childIds relate back to the reference tree: childid[j] = k implies
4490ff1f73f7SToby Isaac                 that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4491ff1f73f7SToby Isaac                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4492ff1f73f7SToby Isaac . useBCs      - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4493ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4494ff1f73f7SToby Isaac 
4495ff1f73f7SToby Isaac   Output Parameters:
44968966356dSPierre Jolivet . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transferred
4497ff1f73f7SToby Isaac                 projection of vecIn from dmIn to dmOut.  Note that any field discretized with a PetscFV finite volume
4498ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4499ff1f73f7SToby Isaac                 coarse points to fine points.
4500ff1f73f7SToby Isaac 
4501ff1f73f7SToby Isaac   Level: developer
4502ff1f73f7SToby Isaac 
4503fd292e60Sprj- .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree(), PetscFVGetComputeGradients()
4504ff1f73f7SToby Isaac @*/
4505ff1f73f7SToby Isaac PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
450638fc2455SToby Isaac {
4507ebf164c7SToby Isaac   PetscErrorCode ierr;
4508ebf164c7SToby Isaac 
450938fc2455SToby Isaac   PetscFunctionBegin;
451078b7adb5SToby Isaac   ierr = VecSet(vecOut,0.0);CHKERRQ(ierr);
4511ff1f73f7SToby Isaac   if (sfRefine) {
4512fbfa57b9SToby Isaac     Vec vecInLocal;
45130eb7e1eaSToby Isaac     DM  dmGrad = NULL;
45140eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4515fbfa57b9SToby Isaac 
4516fbfa57b9SToby Isaac     ierr = DMGetLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
4517fbfa57b9SToby Isaac     ierr = VecSet(vecInLocal,0.0);CHKERRQ(ierr);
45180eb7e1eaSToby Isaac     {
45190eb7e1eaSToby Isaac       PetscInt  numFields, i;
45200eb7e1eaSToby Isaac 
45210eb7e1eaSToby Isaac       ierr = DMGetNumFields(dmIn, &numFields);CHKERRQ(ierr);
45220eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
45230eb7e1eaSToby Isaac         PetscObject  obj;
45240eb7e1eaSToby Isaac         PetscClassId classid;
45250eb7e1eaSToby Isaac 
452644a7f3ddSMatthew G. Knepley         ierr = DMGetField(dmIn, i, NULL, &obj);CHKERRQ(ierr);
45270eb7e1eaSToby Isaac         ierr = PetscObjectGetClassId(obj, &classid);CHKERRQ(ierr);
45280eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
45290eb7e1eaSToby Isaac           ierr = DMPlexGetDataFVM(dmIn,(PetscFV)obj,&cellGeom,&faceGeom,&dmGrad);CHKERRQ(ierr);
45300eb7e1eaSToby Isaac           break;
45310eb7e1eaSToby Isaac         }
45320eb7e1eaSToby Isaac       }
45330eb7e1eaSToby Isaac     }
45340eb7e1eaSToby Isaac     if (useBCs) {
45350eb7e1eaSToby Isaac       ierr = DMPlexInsertBoundaryValues(dmIn,PETSC_TRUE,vecInLocal,time,faceGeom,cellGeom,NULL);CHKERRQ(ierr);
45360eb7e1eaSToby Isaac     }
4537fbfa57b9SToby Isaac     ierr = DMGlobalToLocalBegin(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
4538fbfa57b9SToby Isaac     ierr = DMGlobalToLocalEnd(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
45390eb7e1eaSToby Isaac     if (dmGrad) {
45400eb7e1eaSToby Isaac       ierr = DMGetGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
45410eb7e1eaSToby Isaac       ierr = DMPlexReconstructGradientsFVM(dmIn,vecInLocal,grad);CHKERRQ(ierr);
45420eb7e1eaSToby Isaac     }
4543ff1f73f7SToby Isaac     ierr = DMPlexTransferVecTree_Interpolate(dmIn,vecInLocal,dmOut,vecOut,sfRefine,cidsRefine,grad,cellGeom);CHKERRQ(ierr);
4544fbfa57b9SToby Isaac     ierr = DMRestoreLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
45450eb7e1eaSToby Isaac     if (dmGrad) {
45460eb7e1eaSToby Isaac       ierr = DMRestoreGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
45470eb7e1eaSToby Isaac     }
4548ebf164c7SToby Isaac   }
4549ff1f73f7SToby Isaac   if (sfCoarsen) {
4550ff1f73f7SToby Isaac     ierr = DMPlexTransferVecTree_Inject(dmIn,vecIn,dmOut,vecOut,sfCoarsen,cidsCoarsen);CHKERRQ(ierr);
4551ebf164c7SToby Isaac   }
45522f65e181SToby Isaac   ierr = VecAssemblyBegin(vecOut);CHKERRQ(ierr);
45532f65e181SToby Isaac   ierr = VecAssemblyEnd(vecOut);CHKERRQ(ierr);
455438fc2455SToby Isaac   PetscFunctionReturn(0);
455538fc2455SToby Isaac }
4556