xref: /petsc/src/dm/impls/plex/plextree.c (revision 2c44ad04efa4d1da16066c42a94872609c965d90)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2d6a7ad0dSToby Isaac #include <../src/sys/utils/hash.h>
3af0996ceSBarry Smith #include <petsc/private/isimpl.h>
4af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
5d6a7ad0dSToby Isaac #include <petscsf.h>
60c37af3bSToby Isaac #include <petscds.h>
7d6a7ad0dSToby Isaac 
8d6a7ad0dSToby Isaac /** hierarchy routines */
9d6a7ad0dSToby Isaac 
10d6a7ad0dSToby Isaac #undef __FUNCT__
11d6a7ad0dSToby Isaac #define __FUNCT__ "DMPlexSetReferenceTree"
12d6a7ad0dSToby Isaac /*@
13d6a7ad0dSToby Isaac   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
14d6a7ad0dSToby Isaac 
15d6a7ad0dSToby Isaac   Not collective
16d6a7ad0dSToby Isaac 
17d6a7ad0dSToby Isaac   Input Parameters:
18d6a7ad0dSToby Isaac + dm - The DMPlex object
19d6a7ad0dSToby Isaac - ref - The reference tree DMPlex object
20d6a7ad0dSToby Isaac 
210b7167a0SToby Isaac   Level: intermediate
22d6a7ad0dSToby Isaac 
23da43764aSToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexCreateDefaultReferenceTree()
24d6a7ad0dSToby Isaac @*/
25d6a7ad0dSToby Isaac PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
26d6a7ad0dSToby Isaac {
27d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
28d6a7ad0dSToby Isaac   PetscErrorCode  ierr;
29d6a7ad0dSToby Isaac 
30d6a7ad0dSToby Isaac   PetscFunctionBegin;
31d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3247a1df27SMatthew G. Knepley   if (ref) {PetscValidHeaderSpecific(ref, DM_CLASSID, 2);}
33d6a7ad0dSToby Isaac   ierr = PetscObjectReference((PetscObject)ref);CHKERRQ(ierr);
34d6a7ad0dSToby Isaac   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
35d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
36d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
37d6a7ad0dSToby Isaac }
38d6a7ad0dSToby Isaac 
39d6a7ad0dSToby Isaac #undef __FUNCT__
40d6a7ad0dSToby Isaac #define __FUNCT__ "DMPlexGetReferenceTree"
41d6a7ad0dSToby Isaac /*@
42d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
43d6a7ad0dSToby Isaac 
44d6a7ad0dSToby Isaac   Not collective
45d6a7ad0dSToby Isaac 
46d6a7ad0dSToby Isaac   Input Parameters:
47d6a7ad0dSToby Isaac . dm - The DMPlex object
48d6a7ad0dSToby Isaac 
49d6a7ad0dSToby Isaac   Output Parameters
50d6a7ad0dSToby Isaac . ref - The reference tree DMPlex object
51d6a7ad0dSToby Isaac 
520b7167a0SToby Isaac   Level: intermediate
53d6a7ad0dSToby Isaac 
54da43764aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexCreateDefaultReferenceTree()
55d6a7ad0dSToby Isaac @*/
56d6a7ad0dSToby Isaac PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
57d6a7ad0dSToby Isaac {
58d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
59d6a7ad0dSToby Isaac 
60d6a7ad0dSToby Isaac   PetscFunctionBegin;
61d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
62d6a7ad0dSToby Isaac   PetscValidPointer(ref,2);
63d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
64d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
65d6a7ad0dSToby Isaac }
66d6a7ad0dSToby Isaac 
67dcbd3bf7SToby Isaac #undef __FUNCT__
68dcbd3bf7SToby Isaac #define __FUNCT__ "DMPlexReferenceTreeGetChildSymmetry_Default"
69dcbd3bf7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
70dcbd3bf7SToby Isaac {
71dcbd3bf7SToby Isaac   PetscInt       coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
72dcbd3bf7SToby Isaac   PetscErrorCode ierr;
73dcbd3bf7SToby Isaac 
74dcbd3bf7SToby Isaac   PetscFunctionBegin;
75dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
76dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
77dcbd3bf7SToby Isaac     if (childB) *childB = childA;
78dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
79dcbd3bf7SToby Isaac   }
80dcbd3bf7SToby Isaac   for (dim = 0; dim < 3; dim++) {
81dcbd3bf7SToby Isaac     ierr = DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd);CHKERRQ(ierr);
82dcbd3bf7SToby Isaac     if (parent >= dStart && parent <= dEnd) {
83dcbd3bf7SToby Isaac       break;
84dcbd3bf7SToby Isaac     }
85dcbd3bf7SToby Isaac   }
86dcbd3bf7SToby Isaac   if (dim > 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim);
87dcbd3bf7SToby Isaac   if (!dim) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
88dcbd3bf7SToby Isaac   if (childA < dStart || childA >= dEnd) {
89dcbd3bf7SToby Isaac     /* this is a lower-dimensional child: bootstrap */
90dcbd3bf7SToby Isaac     PetscInt size, i, sA = -1, sB, sOrientB, sConeSize;
91dcbd3bf7SToby Isaac     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
92dcbd3bf7SToby Isaac 
93dcbd3bf7SToby Isaac     ierr = DMPlexGetSupportSize(dm,childA,&size);CHKERRQ(ierr);
94dcbd3bf7SToby Isaac     ierr = DMPlexGetSupport(dm,childA,&supp);CHKERRQ(ierr);
95dcbd3bf7SToby Isaac 
96dcbd3bf7SToby Isaac     /* find a point sA in supp(childA) that has the same parent */
97dcbd3bf7SToby Isaac     for (i = 0; i < size; i++) {
98dcbd3bf7SToby Isaac       PetscInt sParent;
99dcbd3bf7SToby Isaac 
100dcbd3bf7SToby Isaac       sA   = supp[i];
101dcbd3bf7SToby Isaac       if (sA == parent) continue;
102dcbd3bf7SToby Isaac       ierr = DMPlexGetTreeParent(dm,sA,&sParent,NULL);CHKERRQ(ierr);
103dcbd3bf7SToby Isaac       if (sParent == parent) {
104dcbd3bf7SToby Isaac         break;
105dcbd3bf7SToby Isaac       }
106dcbd3bf7SToby Isaac     }
107dcbd3bf7SToby Isaac     if (i == size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
108dcbd3bf7SToby Isaac     /* find out which point sB is in an equivalent position to sA under
109dcbd3bf7SToby Isaac      * parentOrientB */
110dcbd3bf7SToby Isaac     ierr = DMPlexReferenceTreeGetChildSymmetry_Default(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB);CHKERRQ(ierr);
111dcbd3bf7SToby Isaac     ierr = DMPlexGetConeSize(dm,sA,&sConeSize);CHKERRQ(ierr);
112dcbd3bf7SToby Isaac     ierr = DMPlexGetCone(dm,sA,&coneA);CHKERRQ(ierr);
113dcbd3bf7SToby Isaac     ierr = DMPlexGetCone(dm,sB,&coneB);CHKERRQ(ierr);
114dcbd3bf7SToby Isaac     ierr = DMPlexGetConeOrientation(dm,sA,&oA);CHKERRQ(ierr);
115dcbd3bf7SToby Isaac     ierr = DMPlexGetConeOrientation(dm,sB,&oB);CHKERRQ(ierr);
116dcbd3bf7SToby Isaac     /* step through the cone of sA in natural order */
117dcbd3bf7SToby Isaac     for (i = 0; i < sConeSize; i++) {
118dcbd3bf7SToby Isaac       if (coneA[i] == childA) {
119dcbd3bf7SToby Isaac         /* if childA is at position i in coneA,
120dcbd3bf7SToby Isaac          * then we want the point that is at sOrientB*i in coneB */
121dcbd3bf7SToby Isaac         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
122dcbd3bf7SToby Isaac         if (childB) *childB = coneB[j];
123dcbd3bf7SToby Isaac         if (childOrientB) {
124dcbd3bf7SToby Isaac           PetscInt oBtrue;
125dcbd3bf7SToby Isaac 
126dcbd3bf7SToby Isaac           ierr          = DMPlexGetConeSize(dm,childA,&coneSize);CHKERRQ(ierr);
127dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
128dcbd3bf7SToby Isaac           if (coneSize != 0 && coneSize != 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
129dcbd3bf7SToby Isaac           /* we may have to flip an edge */
130dcbd3bf7SToby Isaac           oBtrue        = coneSize ? ((sOrientB >= 0) ? oB[j] : -(oB[j] + 2)) : 0;
131dcbd3bf7SToby Isaac           ABswap        = DihedralSwap(coneSize,oA[i],oBtrue);CHKERRQ(ierr);
132dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
133dcbd3bf7SToby Isaac         }
134dcbd3bf7SToby Isaac         break;
135dcbd3bf7SToby Isaac       }
136dcbd3bf7SToby Isaac     }
137dcbd3bf7SToby Isaac     if (i == sConeSize) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
138dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
139dcbd3bf7SToby Isaac   }
140dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
141dcbd3bf7SToby Isaac   ierr   = DMPlexGetConeSize(dm,parent,&coneSize);CHKERRQ(ierr);
142dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
143dcbd3bf7SToby Isaac   if (dim == 2) {
144dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
145dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
146dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
147dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
148dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
149dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
150947b95d8SBarry Smith   } else {
151dcbd3bf7SToby Isaac     ABswapVert = ABswap;
152dcbd3bf7SToby Isaac   }
153dcbd3bf7SToby Isaac   if (childB) {
154dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
155dcbd3bf7SToby Isaac     PetscInt p, posA = -1, numChildren, i;
156dcbd3bf7SToby Isaac     const PetscInt *children;
157dcbd3bf7SToby Isaac 
158dcbd3bf7SToby Isaac     /* count which position the child is in */
159dcbd3bf7SToby Isaac     ierr = DMPlexGetTreeChildren(dm,parent,&numChildren,&children);CHKERRQ(ierr);
160dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
161dcbd3bf7SToby Isaac       p = children[i];
162dcbd3bf7SToby Isaac       if (p == childA) {
163dcbd3bf7SToby Isaac         posA = i;
164dcbd3bf7SToby Isaac         break;
165dcbd3bf7SToby Isaac       }
166dcbd3bf7SToby Isaac     }
167dcbd3bf7SToby Isaac     if (posA >= coneSize) {
168dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
169dcbd3bf7SToby Isaac        * is invariant */
170dcbd3bf7SToby Isaac       if (dim != 2 || posA != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Expected a middle triangle, got something else");
171dcbd3bf7SToby Isaac       *childB = childA;
172dcbd3bf7SToby Isaac     }
173dcbd3bf7SToby Isaac     else {
174dcbd3bf7SToby Isaac       /* figure out position B by applying ABswapVert */
175dcbd3bf7SToby Isaac       PetscInt posB;
176dcbd3bf7SToby Isaac 
177dcbd3bf7SToby Isaac       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
178dcbd3bf7SToby Isaac       if (childB) *childB = children[posB];
179dcbd3bf7SToby Isaac     }
180dcbd3bf7SToby Isaac   }
181dcbd3bf7SToby Isaac   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
182dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
183dcbd3bf7SToby Isaac }
184dcbd3bf7SToby Isaac 
185dcbd3bf7SToby Isaac #undef __FUNCT__
186dcbd3bf7SToby Isaac #define __FUNCT__ "DMPlexReferenceTreeGetChildSymmetry"
187dcbd3bf7SToby Isaac /*@
188dcbd3bf7SToby Isaac   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
189dcbd3bf7SToby Isaac 
190dcbd3bf7SToby Isaac   Input Parameters:
191dcbd3bf7SToby Isaac + dm - the reference tree DMPlex object
192dcbd3bf7SToby Isaac . parent - the parent point
193dcbd3bf7SToby Isaac . parentOrientA - the reference orientation for describing the parent
194dcbd3bf7SToby Isaac . childOrientA - the reference orientation for describing the child
195dcbd3bf7SToby Isaac . childA - the reference childID for describing the child
196dcbd3bf7SToby Isaac - parentOrientB - the new orientation for describing the parent
197dcbd3bf7SToby Isaac 
198dcbd3bf7SToby Isaac   Output Parameters:
199dcbd3bf7SToby Isaac + childOrientB - if not NULL, set to the new oreintation for describing the child
200ff1f73f7SToby Isaac - childB - if not NULL, the new childID for describing the child
201dcbd3bf7SToby Isaac 
202dcbd3bf7SToby Isaac   Level: developer
203dcbd3bf7SToby Isaac 
204dcbd3bf7SToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexSetReferenceTree(), DMPlexSetTree()
205dcbd3bf7SToby Isaac @*/
206dcbd3bf7SToby Isaac PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
207dcbd3bf7SToby Isaac {
208dcbd3bf7SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
209dcbd3bf7SToby Isaac   PetscErrorCode ierr;
210dcbd3bf7SToby Isaac 
211dcbd3bf7SToby Isaac   PetscFunctionBegin;
212dcbd3bf7SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
213dcbd3bf7SToby Isaac   if (!mesh->getchildsymmetry) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlexReferenceTreeGetChildSymmetry not implemented");
214dcbd3bf7SToby Isaac   ierr = mesh->getchildsymmetry(dm,parent,parentOrientA,childOrientA,childA,parentOrientB,childOrientB,childB);CHKERRQ(ierr);
215dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
216dcbd3bf7SToby Isaac }
217dcbd3bf7SToby Isaac 
218776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM,PetscSection,PetscInt*,PetscInt*,PetscBool,PetscBool);
219f9f063d4SToby Isaac 
220da43764aSToby Isaac #undef __FUNCT__
2210e2cc29aSToby Isaac #define __FUNCT__ "DMPlexCreateReferenceTree_Union"
2220e2cc29aSToby Isaac PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
223da43764aSToby Isaac {
2240e2cc29aSToby Isaac   MPI_Comm       comm;
2250e2cc29aSToby Isaac   PetscInt       dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
226da43764aSToby Isaac   PetscInt      *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
227da43764aSToby Isaac   DMLabel        identity, identityRef;
22810f7e118SToby Isaac   PetscSection   unionSection, unionConeSection, parentSection;
229da43764aSToby Isaac   PetscScalar   *unionCoords;
230da43764aSToby Isaac   IS             perm;
231da43764aSToby Isaac   PetscErrorCode ierr;
232da43764aSToby Isaac 
233da43764aSToby Isaac   PetscFunctionBegin;
2340e2cc29aSToby Isaac   comm = PetscObjectComm((PetscObject)K);
2350e2cc29aSToby Isaac   ierr = DMGetDimension(K, &dim);CHKERRQ(ierr);
236da43764aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
2370e2cc29aSToby Isaac   ierr = DMGetLabel(K, labelName, &identity);CHKERRQ(ierr);
2380e2cc29aSToby Isaac   ierr = DMGetLabel(Kref, labelName, &identityRef);CHKERRQ(ierr);
239da43764aSToby Isaac   ierr = DMPlexGetChart(Kref, &pRefStart, &pRefEnd);CHKERRQ(ierr);
240da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionSection);CHKERRQ(ierr);
241da43764aSToby Isaac   ierr = PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart));CHKERRQ(ierr);
242da43764aSToby Isaac   /* count points that will go in the union */
243da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
244da43764aSToby Isaac     ierr = PetscSectionSetDof(unionSection, p - pStart, 1);CHKERRQ(ierr);
245da43764aSToby Isaac   }
246da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
247da43764aSToby Isaac     PetscInt q, qSize;
248da43764aSToby Isaac     ierr = DMLabelGetValue(identityRef, p, &q);CHKERRQ(ierr);
249da43764aSToby Isaac     ierr = DMLabelGetStratumSize(identityRef, q, &qSize);CHKERRQ(ierr);
250da43764aSToby Isaac     if (qSize > 1) {
251da43764aSToby Isaac       ierr = PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1);CHKERRQ(ierr);
252da43764aSToby Isaac     }
253da43764aSToby Isaac   }
254854ce69bSBarry Smith   ierr = PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart,&permvals);CHKERRQ(ierr);
255da43764aSToby Isaac   offset = 0;
256da43764aSToby Isaac   /* stratify points in the union by topological dimension */
257da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
258da43764aSToby Isaac     PetscInt cStart, cEnd, c;
259da43764aSToby Isaac 
260da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K, d, &cStart, &cEnd);CHKERRQ(ierr);
261da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
262da43764aSToby Isaac       permvals[offset++] = c;
263da43764aSToby Isaac     }
264da43764aSToby Isaac 
265da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd);CHKERRQ(ierr);
266da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
267da43764aSToby Isaac       permvals[offset++] = c + (pEnd - pStart);
268da43764aSToby Isaac     }
269da43764aSToby Isaac   }
270da43764aSToby Isaac   ierr = ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm);CHKERRQ(ierr);
271da43764aSToby Isaac   ierr = PetscSectionSetPermutation(unionSection,perm);CHKERRQ(ierr);
272da43764aSToby Isaac   ierr = PetscSectionSetUp(unionSection);CHKERRQ(ierr);
273da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionSection,&numUnionPoints);CHKERRQ(ierr);
274da43764aSToby Isaac   ierr = PetscMalloc2(numUnionPoints,&coneSizes,dim+1,&numDimPoints);CHKERRQ(ierr);
275da43764aSToby Isaac   /* count dimension points */
276da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
277da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
278da43764aSToby Isaac     ierr = DMPlexGetHeightStratum(K,d,&cStart,NULL);CHKERRQ(ierr);
279da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff);CHKERRQ(ierr);
280da43764aSToby Isaac     if (d < dim) {
281da43764aSToby Isaac       ierr = DMPlexGetHeightStratum(K,d+1,&cStart,NULL);CHKERRQ(ierr);
282da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff2);CHKERRQ(ierr);
283da43764aSToby Isaac     }
284da43764aSToby Isaac     else {
285da43764aSToby Isaac       cOff2 = numUnionPoints;
286da43764aSToby Isaac     }
287da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
288da43764aSToby Isaac   }
289da43764aSToby Isaac   ierr = PetscSectionCreate(comm, &unionConeSection);CHKERRQ(ierr);
290da43764aSToby Isaac   ierr = PetscSectionSetChart(unionConeSection, 0, numUnionPoints);CHKERRQ(ierr);
291da43764aSToby Isaac   /* count the cones in the union */
292da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
293da43764aSToby Isaac     PetscInt dof, uOff;
294da43764aSToby Isaac 
295da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
296da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
297da43764aSToby Isaac     ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
298da43764aSToby Isaac     coneSizes[uOff] = dof;
299da43764aSToby Isaac   }
300da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
301da43764aSToby Isaac     PetscInt dof, uDof, uOff;
302da43764aSToby Isaac 
303da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
304da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
305da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
306da43764aSToby Isaac     if (uDof) {
307da43764aSToby Isaac       ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
308da43764aSToby Isaac       coneSizes[uOff] = dof;
309da43764aSToby Isaac     }
310da43764aSToby Isaac   }
311da43764aSToby Isaac   ierr = PetscSectionSetUp(unionConeSection);CHKERRQ(ierr);
312da43764aSToby Isaac   ierr = PetscSectionGetStorageSize(unionConeSection,&numCones);CHKERRQ(ierr);
313da43764aSToby Isaac   ierr = PetscMalloc2(numCones,&unionCones,numCones,&unionOrientations);CHKERRQ(ierr);
314da43764aSToby Isaac   /* write the cones in the union */
315da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
316da43764aSToby Isaac     PetscInt dof, uOff, c, cOff;
317da43764aSToby Isaac     const PetscInt *cone, *orientation;
318da43764aSToby Isaac 
319da43764aSToby Isaac     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
320da43764aSToby Isaac     ierr = DMPlexGetCone(K, p, &cone);CHKERRQ(ierr);
321da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(K, p, &orientation);CHKERRQ(ierr);
322da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
323da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
324da43764aSToby Isaac     for (c = 0; c < dof; c++) {
325da43764aSToby Isaac       PetscInt e, eOff;
326da43764aSToby Isaac       e                           = cone[c];
327da43764aSToby Isaac       ierr                        = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
328da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
329da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
330da43764aSToby Isaac     }
331da43764aSToby Isaac   }
332da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
333da43764aSToby Isaac     PetscInt dof, uDof, uOff, c, cOff;
334da43764aSToby Isaac     const PetscInt *cone, *orientation;
335da43764aSToby Isaac 
336da43764aSToby Isaac     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
337da43764aSToby Isaac     ierr = DMPlexGetCone(Kref, p, &cone);CHKERRQ(ierr);
338da43764aSToby Isaac     ierr = DMPlexGetConeOrientation(Kref, p, &orientation);CHKERRQ(ierr);
339da43764aSToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
340da43764aSToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
341da43764aSToby Isaac     if (uDof) {
342da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
343da43764aSToby Isaac       for (c = 0; c < dof; c++) {
344da43764aSToby Isaac         PetscInt e, eOff, eDof;
345da43764aSToby Isaac 
346da43764aSToby Isaac         e    = cone[c];
347da43764aSToby Isaac         ierr = PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart),&eDof);CHKERRQ(ierr);
348da43764aSToby Isaac         if (eDof) {
349da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff);CHKERRQ(ierr);
350da43764aSToby Isaac         }
351da43764aSToby Isaac         else {
352da43764aSToby Isaac           ierr = DMLabelGetValue(identityRef, e, &e);CHKERRQ(ierr);
353da43764aSToby Isaac           ierr = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
354da43764aSToby Isaac         }
355da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
356da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
357da43764aSToby Isaac       }
358da43764aSToby Isaac     }
359da43764aSToby Isaac   }
360da43764aSToby Isaac   /* get the coordinates */
361da43764aSToby Isaac   {
362da43764aSToby Isaac     PetscInt vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
363da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
364da43764aSToby Isaac     Vec      KcoordsVec, KrefCoordsVec;
365da43764aSToby Isaac     PetscScalar *Kcoords;
366da43764aSToby Isaac 
367da43764aSToby Isaac     DMGetCoordinateSection(K, &KcoordsSec);CHKERRQ(ierr);
368da43764aSToby Isaac     DMGetCoordinatesLocal(K, &KcoordsVec);CHKERRQ(ierr);
369da43764aSToby Isaac     DMGetCoordinateSection(Kref, &KrefCoordsSec);CHKERRQ(ierr);
370da43764aSToby Isaac     DMGetCoordinatesLocal(Kref, &KrefCoordsVec);CHKERRQ(ierr);
371da43764aSToby Isaac 
372da43764aSToby Isaac     numVerts = numDimPoints[0];
373da43764aSToby Isaac     ierr     = PetscMalloc1(numVerts * dim,&unionCoords);CHKERRQ(ierr);
374da43764aSToby Isaac     ierr     = DMPlexGetDepthStratum(K,0,&vStart,&vEnd);CHKERRQ(ierr);
375da43764aSToby Isaac 
376da43764aSToby Isaac     offset = 0;
377da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
378da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pStart,&vOff);CHKERRQ(ierr);
379da43764aSToby Isaac       ierr = VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords);CHKERRQ(ierr);
380da43764aSToby Isaac       for (d = 0; d < dim; d++) {
381da43764aSToby Isaac         unionCoords[offset * dim + d] = Kcoords[d];
382da43764aSToby Isaac       }
383da43764aSToby Isaac       offset++;
384da43764aSToby Isaac     }
385da43764aSToby Isaac     ierr = DMPlexGetDepthStratum(Kref,0,&vRefStart,&vRefEnd);CHKERRQ(ierr);
386da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
387da43764aSToby Isaac       ierr = PetscSectionGetDof(unionSection,v - pRefStart + (pEnd - pStart),&vDof);CHKERRQ(ierr);
388da43764aSToby Isaac       ierr = PetscSectionGetOffset(unionSection,v - pRefStart + (pEnd - pStart),&vOff);CHKERRQ(ierr);
389da43764aSToby Isaac       ierr = VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords);CHKERRQ(ierr);
390da43764aSToby Isaac       if (vDof) {
391da43764aSToby Isaac         for (d = 0; d < dim; d++) {
392da43764aSToby Isaac           unionCoords[offset * dim + d] = Kcoords[d];
393da43764aSToby Isaac         }
394da43764aSToby Isaac         offset++;
395da43764aSToby Isaac       }
396da43764aSToby Isaac     }
397da43764aSToby Isaac   }
398da43764aSToby Isaac   ierr = DMCreate(comm,ref);CHKERRQ(ierr);
399da43764aSToby Isaac   ierr = DMSetType(*ref,DMPLEX);CHKERRQ(ierr);
40028f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ref,dim);CHKERRQ(ierr);
401da43764aSToby Isaac   ierr = DMPlexCreateFromDAG(*ref,dim,numDimPoints,coneSizes,unionCones,unionOrientations,unionCoords);CHKERRQ(ierr);
40210f7e118SToby Isaac   /* set the tree */
40310f7e118SToby Isaac   ierr = PetscSectionCreate(comm,&parentSection);CHKERRQ(ierr);
40410f7e118SToby Isaac   ierr = PetscSectionSetChart(parentSection,0,numUnionPoints);CHKERRQ(ierr);
40510f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
40610f7e118SToby Isaac     PetscInt uDof, uOff;
40710f7e118SToby Isaac 
40810f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
40910f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
41010f7e118SToby Isaac     if (uDof) {
41110f7e118SToby Isaac       PetscSectionSetDof(parentSection,uOff,1);CHKERRQ(ierr);
41210f7e118SToby Isaac     }
41310f7e118SToby Isaac   }
41410f7e118SToby Isaac   ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
41510f7e118SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&parentSize);CHKERRQ(ierr);
41610f7e118SToby Isaac   ierr = PetscMalloc2(parentSize,&parents,parentSize,&childIDs);CHKERRQ(ierr);
41710f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
41810f7e118SToby Isaac     PetscInt uDof, uOff;
41910f7e118SToby Isaac 
42010f7e118SToby Isaac     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
42110f7e118SToby Isaac     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
42210f7e118SToby Isaac     if (uDof) {
42310f7e118SToby Isaac       PetscInt pOff, parent, parentU;
42410f7e118SToby Isaac       PetscSectionGetOffset(parentSection,uOff,&pOff);CHKERRQ(ierr);
42510f7e118SToby Isaac       DMLabelGetValue(identityRef,p,&parent);CHKERRQ(ierr);
42610f7e118SToby Isaac       ierr = PetscSectionGetOffset(unionSection, parent - pStart,&parentU);CHKERRQ(ierr);
42710f7e118SToby Isaac       parents[pOff] = parentU;
42810f7e118SToby Isaac       childIDs[pOff] = uOff;
42910f7e118SToby Isaac     }
43010f7e118SToby Isaac   }
431776742edSToby Isaac   ierr = DMPlexSetTree_Internal(*ref,parentSection,parents,childIDs,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
43210f7e118SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
43310f7e118SToby Isaac   ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
43410f7e118SToby Isaac 
435da43764aSToby Isaac   /* clean up */
436da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionSection);CHKERRQ(ierr);
437da43764aSToby Isaac   ierr = PetscSectionDestroy(&unionConeSection);CHKERRQ(ierr);
438da43764aSToby Isaac   ierr = ISDestroy(&perm);CHKERRQ(ierr);
439da43764aSToby Isaac   ierr = PetscFree(unionCoords);CHKERRQ(ierr);
440da43764aSToby Isaac   ierr = PetscFree2(unionCones,unionOrientations);CHKERRQ(ierr);
441da43764aSToby Isaac   ierr = PetscFree2(coneSizes,numDimPoints);CHKERRQ(ierr);
4420e2cc29aSToby Isaac   PetscFunctionReturn(0);
4430e2cc29aSToby Isaac }
4440e2cc29aSToby Isaac 
4450e2cc29aSToby Isaac #undef __FUNCT__
4460e2cc29aSToby Isaac #define __FUNCT__ "DMPlexCreateDefaultReferenceTree"
4470e2cc29aSToby Isaac /*@
4480e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4490e2cc29aSToby Isaac 
4500e2cc29aSToby Isaac   Collective on comm
4510e2cc29aSToby Isaac 
4520e2cc29aSToby Isaac   Input Parameters:
4530e2cc29aSToby Isaac + comm    - the MPI communicator
4540e2cc29aSToby Isaac . dim     - the spatial dimension
4550e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4560e2cc29aSToby Isaac 
4570e2cc29aSToby Isaac   Output Parameters:
4580e2cc29aSToby Isaac . ref     - the reference tree DMPlex object
4590e2cc29aSToby Isaac 
4600e2cc29aSToby Isaac   Level: intermediate
4610e2cc29aSToby Isaac 
4620e2cc29aSToby Isaac .keywords: reference cell
4630e2cc29aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree()
4640e2cc29aSToby Isaac @*/
4650e2cc29aSToby Isaac PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
4660e2cc29aSToby Isaac {
4670e2cc29aSToby Isaac   DM_Plex       *mesh;
4680e2cc29aSToby Isaac   DM             K, Kref;
4690e2cc29aSToby Isaac   PetscInt       p, pStart, pEnd;
4700e2cc29aSToby Isaac   DMLabel        identity;
4710e2cc29aSToby Isaac   PetscErrorCode ierr;
4720e2cc29aSToby Isaac 
4730e2cc29aSToby Isaac   PetscFunctionBegin;
4740e2cc29aSToby Isaac #if 1
4750e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4760e2cc29aSToby Isaac #endif
4770e2cc29aSToby Isaac   /* create a reference element */
4780e2cc29aSToby Isaac   ierr = DMPlexCreateReferenceCell(comm, dim, simplex, &K);CHKERRQ(ierr);
4790e2cc29aSToby Isaac   ierr = DMCreateLabel(K, "identity");CHKERRQ(ierr);
4800e2cc29aSToby Isaac   ierr = DMGetLabel(K, "identity", &identity);CHKERRQ(ierr);
4810e2cc29aSToby Isaac   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
4820e2cc29aSToby Isaac   for (p = pStart; p < pEnd; p++) {
4830e2cc29aSToby Isaac     ierr = DMLabelSetValue(identity, p, p);CHKERRQ(ierr);
4840e2cc29aSToby Isaac   }
4850e2cc29aSToby Isaac   /* refine it */
4860e2cc29aSToby Isaac   ierr = DMRefine(K,comm,&Kref);CHKERRQ(ierr);
4870e2cc29aSToby Isaac 
4880e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4890e2cc29aSToby Isaac    * points that appear in both */
4900e2cc29aSToby Isaac   ierr = DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref);CHKERRQ(ierr);
4910e2cc29aSToby Isaac   mesh = (DM_Plex *) (*ref)->data;
4920e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
493da43764aSToby Isaac   ierr = DMDestroy(&K);CHKERRQ(ierr);
494da43764aSToby Isaac   ierr = DMDestroy(&Kref);CHKERRQ(ierr);
495da43764aSToby Isaac   PetscFunctionReturn(0);
496da43764aSToby Isaac }
497da43764aSToby Isaac 
498d961a43aSToby Isaac #undef __FUNCT__
499878b19aaSToby Isaac #define __FUNCT__ "DMPlexTreeSymmetrize"
500878b19aaSToby Isaac static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
501878b19aaSToby Isaac {
502878b19aaSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
503878b19aaSToby Isaac   PetscSection   childSec, pSec;
504878b19aaSToby Isaac   PetscInt       p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
505878b19aaSToby Isaac   PetscInt       *offsets, *children, pStart, pEnd;
506878b19aaSToby Isaac   PetscErrorCode ierr;
507878b19aaSToby Isaac 
508878b19aaSToby Isaac   PetscFunctionBegin;
509878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
510878b19aaSToby Isaac   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
511878b19aaSToby Isaac   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
512878b19aaSToby Isaac   pSec = mesh->parentSection;
513878b19aaSToby Isaac   if (!pSec) PetscFunctionReturn(0);
514878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(pSec,&pSize);CHKERRQ(ierr);
515878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
516878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
517878b19aaSToby Isaac 
518878b19aaSToby Isaac     parMax = PetscMax(parMax,par+1);
519878b19aaSToby Isaac     parMin = PetscMin(parMin,par);
520878b19aaSToby Isaac   }
521878b19aaSToby Isaac   if (parMin > parMax) {
522878b19aaSToby Isaac     parMin = -1;
523878b19aaSToby Isaac     parMax = -1;
524878b19aaSToby Isaac   }
525878b19aaSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)pSec),&childSec);CHKERRQ(ierr);
526878b19aaSToby Isaac   ierr = PetscSectionSetChart(childSec,parMin,parMax);CHKERRQ(ierr);
527878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
528878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
529878b19aaSToby Isaac 
530878b19aaSToby Isaac     ierr = PetscSectionAddDof(childSec,par,1);CHKERRQ(ierr);
531878b19aaSToby Isaac   }
532878b19aaSToby Isaac   ierr = PetscSectionSetUp(childSec);CHKERRQ(ierr);
533878b19aaSToby Isaac   ierr = PetscSectionGetStorageSize(childSec,&cSize);CHKERRQ(ierr);
534878b19aaSToby Isaac   ierr = PetscMalloc1(cSize,&children);CHKERRQ(ierr);
535878b19aaSToby Isaac   ierr = PetscCalloc1(parMax-parMin,&offsets);CHKERRQ(ierr);
536878b19aaSToby Isaac   ierr = PetscSectionGetChart(pSec,&pStart,&pEnd);CHKERRQ(ierr);
537878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
538878b19aaSToby Isaac     PetscInt dof, off, i;
539878b19aaSToby Isaac 
540878b19aaSToby Isaac     ierr = PetscSectionGetDof(pSec,p,&dof);CHKERRQ(ierr);
541878b19aaSToby Isaac     ierr = PetscSectionGetOffset(pSec,p,&off);CHKERRQ(ierr);
542878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
543878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
544878b19aaSToby Isaac 
545878b19aaSToby Isaac       ierr = PetscSectionGetOffset(childSec,par,&cOff);CHKERRQ(ierr);
546878b19aaSToby Isaac       children[cOff + offsets[par-parMin]++] = p;
547878b19aaSToby Isaac     }
548878b19aaSToby Isaac   }
549878b19aaSToby Isaac   mesh->childSection = childSec;
550878b19aaSToby Isaac   mesh->children = children;
551878b19aaSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
552878b19aaSToby Isaac   PetscFunctionReturn(0);
553878b19aaSToby Isaac }
554878b19aaSToby Isaac 
555878b19aaSToby Isaac #undef __FUNCT__
5566dd5a8c8SToby Isaac #define __FUNCT__ "AnchorsFlatten"
5576dd5a8c8SToby Isaac static PetscErrorCode AnchorsFlatten (PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
5586dd5a8c8SToby Isaac {
5596dd5a8c8SToby Isaac   PetscInt       pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5606dd5a8c8SToby Isaac   const PetscInt *vals;
5616dd5a8c8SToby Isaac   PetscSection   secNew;
5626dd5a8c8SToby Isaac   PetscBool      anyNew, globalAnyNew;
5636dd5a8c8SToby Isaac   PetscBool      compress;
5646dd5a8c8SToby Isaac   PetscErrorCode ierr;
5656dd5a8c8SToby Isaac 
5666dd5a8c8SToby Isaac   PetscFunctionBegin;
5676dd5a8c8SToby Isaac   ierr = PetscSectionGetChart(section,&pStart,&pEnd);CHKERRQ(ierr);
5686dd5a8c8SToby Isaac   ierr = ISGetLocalSize(is,&size);CHKERRQ(ierr);
5696dd5a8c8SToby Isaac   ierr = ISGetIndices(is,&vals);CHKERRQ(ierr);
5706dd5a8c8SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secNew);CHKERRQ(ierr);
5716dd5a8c8SToby Isaac   ierr = PetscSectionSetChart(secNew,pStart,pEnd);CHKERRQ(ierr);
5726dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5736dd5a8c8SToby Isaac     PetscInt dof;
5746dd5a8c8SToby Isaac 
5756dd5a8c8SToby Isaac     p = vals[i];
5766dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5776dd5a8c8SToby Isaac     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5786dd5a8c8SToby Isaac     if (dof) break;
5796dd5a8c8SToby Isaac   }
5806dd5a8c8SToby Isaac   if (i == size) {
5816dd5a8c8SToby Isaac     ierr     = PetscSectionSetUp(secNew);CHKERRQ(ierr);
5826dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5836dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5846dd5a8c8SToby Isaac     sizeNew  = 0;
5856dd5a8c8SToby Isaac   }
5866dd5a8c8SToby Isaac   else {
5876dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5886dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5896dd5a8c8SToby Isaac       PetscInt dof, off;
5906dd5a8c8SToby Isaac 
5916dd5a8c8SToby Isaac       ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
5926dd5a8c8SToby Isaac       ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
5936dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5946dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5956dd5a8c8SToby Isaac 
5966dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5976dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
5986dd5a8c8SToby Isaac         }
5996dd5a8c8SToby Isaac         if (qDof) {
6006dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, qDof);CHKERRQ(ierr);
6016dd5a8c8SToby Isaac         }
6026dd5a8c8SToby Isaac         else {
6036dd5a8c8SToby Isaac           ierr = PetscSectionAddDof(secNew, p, 1);CHKERRQ(ierr);
6046dd5a8c8SToby Isaac         }
6056dd5a8c8SToby Isaac       }
6066dd5a8c8SToby Isaac     }
6076dd5a8c8SToby Isaac     ierr = PetscSectionSetUp(secNew);CHKERRQ(ierr);
6086dd5a8c8SToby Isaac     ierr = PetscSectionGetStorageSize(secNew,&sizeNew);CHKERRQ(ierr);
6096dd5a8c8SToby Isaac     ierr = PetscMalloc1(sizeNew,&valsNew);CHKERRQ(ierr);
6106dd5a8c8SToby Isaac     compress = PETSC_FALSE;
6116dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
6126dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
6136dd5a8c8SToby Isaac 
6146dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
6156dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
6166dd5a8c8SToby Isaac       ierr  = PetscSectionGetDof(secNew, p, &dofNew);CHKERRQ(ierr);
6176dd5a8c8SToby Isaac       ierr  = PetscSectionGetOffset(secNew, p, &offNew);CHKERRQ(ierr);
6186dd5a8c8SToby Isaac       count = 0;
6196dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
6206dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
6216dd5a8c8SToby Isaac 
6226dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
6236dd5a8c8SToby Isaac           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
6246dd5a8c8SToby Isaac           ierr = PetscSectionGetOffset(section, q, &qOff);CHKERRQ(ierr);
6256dd5a8c8SToby Isaac         }
6266dd5a8c8SToby Isaac         if (qDof) {
6276dd5a8c8SToby Isaac           PetscInt oldCount = count;
6286dd5a8c8SToby Isaac 
6296dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
6306dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
6316dd5a8c8SToby Isaac 
6326dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
6336dd5a8c8SToby Isaac               if (valsNew[offNew + k] == r) {
6346dd5a8c8SToby Isaac                 break;
6356dd5a8c8SToby Isaac               }
6366dd5a8c8SToby Isaac             }
6376dd5a8c8SToby Isaac             if (k == oldCount) {
6386dd5a8c8SToby Isaac               valsNew[offNew + count++] = r;
6396dd5a8c8SToby Isaac             }
6406dd5a8c8SToby Isaac           }
6416dd5a8c8SToby Isaac         }
6426dd5a8c8SToby Isaac         else {
6436dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
6446dd5a8c8SToby Isaac 
6456dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
6466dd5a8c8SToby Isaac             if (valsNew[offNew + k] == q) {
6476dd5a8c8SToby Isaac               break;
6486dd5a8c8SToby Isaac             }
6496dd5a8c8SToby Isaac           }
6506dd5a8c8SToby Isaac           if (k == oldCount) {
6516dd5a8c8SToby Isaac             valsNew[offNew + count++] = q;
6526dd5a8c8SToby Isaac           }
6536dd5a8c8SToby Isaac         }
6546dd5a8c8SToby Isaac       }
6556dd5a8c8SToby Isaac       if (count < dofNew) {
6566dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secNew, p, count);CHKERRQ(ierr);
6576dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6586dd5a8c8SToby Isaac       }
6596dd5a8c8SToby Isaac     }
6606dd5a8c8SToby Isaac   }
6616dd5a8c8SToby Isaac   ierr = ISRestoreIndices(is,&vals);CHKERRQ(ierr);
662b2566f29SBarry Smith   ierr = MPIU_Allreduce(&anyNew,&globalAnyNew,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
6636dd5a8c8SToby Isaac   if (!globalAnyNew) {
6646dd5a8c8SToby Isaac     ierr = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6656dd5a8c8SToby Isaac     *sectionNew = NULL;
6666dd5a8c8SToby Isaac     *isNew = NULL;
6676dd5a8c8SToby Isaac   }
6686dd5a8c8SToby Isaac   else {
6696dd5a8c8SToby Isaac     PetscBool globalCompress;
6706dd5a8c8SToby Isaac 
671b2566f29SBarry Smith     ierr = MPIU_Allreduce(&compress,&globalCompress,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
6726dd5a8c8SToby Isaac     if (compress) {
6736dd5a8c8SToby Isaac       PetscSection secComp;
6746dd5a8c8SToby Isaac       PetscInt *valsComp = NULL;
6756dd5a8c8SToby Isaac 
6766dd5a8c8SToby Isaac       ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secComp);CHKERRQ(ierr);
6776dd5a8c8SToby Isaac       ierr = PetscSectionSetChart(secComp,pStart,pEnd);CHKERRQ(ierr);
6786dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6796dd5a8c8SToby Isaac         PetscInt dof;
6806dd5a8c8SToby Isaac 
6816dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6826dd5a8c8SToby Isaac         ierr = PetscSectionSetDof(secComp, p, dof);CHKERRQ(ierr);
6836dd5a8c8SToby Isaac       }
6846dd5a8c8SToby Isaac       ierr = PetscSectionSetUp(secComp);CHKERRQ(ierr);
6856dd5a8c8SToby Isaac       ierr = PetscSectionGetStorageSize(secComp,&sizeNew);CHKERRQ(ierr);
6866dd5a8c8SToby Isaac       ierr = PetscMalloc1(sizeNew,&valsComp);CHKERRQ(ierr);
6876dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6886dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6896dd5a8c8SToby Isaac 
6906dd5a8c8SToby Isaac         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
6916dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secNew, p, &off);CHKERRQ(ierr);
6926dd5a8c8SToby Isaac         ierr = PetscSectionGetOffset(secComp, p, &offNew);CHKERRQ(ierr);
6936dd5a8c8SToby Isaac         for (j = 0; j < dof; j++) {
6946dd5a8c8SToby Isaac           valsComp[offNew + j] = valsNew[off + j];
6956dd5a8c8SToby Isaac         }
6966dd5a8c8SToby Isaac       }
6976dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
6986dd5a8c8SToby Isaac       secNew  = secComp;
6996dd5a8c8SToby Isaac       ierr    = PetscFree(valsNew);CHKERRQ(ierr);
7006dd5a8c8SToby Isaac       valsNew = valsComp;
7016dd5a8c8SToby Isaac     }
7026dd5a8c8SToby Isaac     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is),sizeNew,valsNew,PETSC_OWN_POINTER,isNew);CHKERRQ(ierr);
7036dd5a8c8SToby Isaac   }
7046dd5a8c8SToby Isaac   PetscFunctionReturn(0);
7056dd5a8c8SToby Isaac }
7066dd5a8c8SToby Isaac 
7076dd5a8c8SToby Isaac #undef __FUNCT__
708f7c74593SToby Isaac #define __FUNCT__ "DMPlexCreateAnchors_Tree"
709f7c74593SToby Isaac static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
71066af876cSToby Isaac {
71166af876cSToby Isaac   PetscInt       p, pStart, pEnd, *anchors, size;
71266af876cSToby Isaac   PetscInt       aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
71366af876cSToby Isaac   PetscSection   aSec;
714f9f063d4SToby Isaac   DMLabel        canonLabel;
71566af876cSToby Isaac   IS             aIS;
71666af876cSToby Isaac   PetscErrorCode ierr;
71766af876cSToby Isaac 
71866af876cSToby Isaac   PetscFunctionBegin;
71966af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
72066af876cSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
721c58f1c22SToby Isaac   ierr = DMGetLabel(dm,"canonical",&canonLabel);CHKERRQ(ierr);
72266af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
72366af876cSToby Isaac     PetscInt parent;
72466af876cSToby Isaac 
725f9f063d4SToby Isaac     if (canonLabel) {
726f9f063d4SToby Isaac       PetscInt canon;
727f9f063d4SToby Isaac 
728f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
729f9f063d4SToby Isaac       if (p != canon) continue;
730f9f063d4SToby Isaac     }
73166af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
73266af876cSToby Isaac     if (parent != p) {
73366af876cSToby Isaac       aMin = PetscMin(aMin,p);
73466af876cSToby Isaac       aMax = PetscMax(aMax,p+1);
73566af876cSToby Isaac     }
73666af876cSToby Isaac   }
73766af876cSToby Isaac   if (aMin > aMax) {
73866af876cSToby Isaac     aMin = -1;
73966af876cSToby Isaac     aMax = -1;
74066af876cSToby Isaac   }
741e228b242SToby Isaac   ierr = PetscSectionCreate(PETSC_COMM_SELF,&aSec);CHKERRQ(ierr);
74266af876cSToby Isaac   ierr = PetscSectionSetChart(aSec,aMin,aMax);CHKERRQ(ierr);
74366af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
74466af876cSToby Isaac     PetscInt parent, ancestor = p;
74566af876cSToby Isaac 
746f9f063d4SToby Isaac     if (canonLabel) {
747f9f063d4SToby Isaac       PetscInt canon;
748f9f063d4SToby Isaac 
749f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
750f9f063d4SToby Isaac       if (p != canon) continue;
751f9f063d4SToby Isaac     }
75266af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
75366af876cSToby Isaac     while (parent != ancestor) {
75466af876cSToby Isaac       ancestor = parent;
75566af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
75666af876cSToby Isaac     }
75766af876cSToby Isaac     if (ancestor != p) {
75866af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
75966af876cSToby Isaac 
76066af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
76166af876cSToby Isaac       ierr = PetscSectionSetDof(aSec,p,closureSize);CHKERRQ(ierr);
76266af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
76366af876cSToby Isaac     }
76466af876cSToby Isaac   }
76566af876cSToby Isaac   ierr = PetscSectionSetUp(aSec);CHKERRQ(ierr);
76666af876cSToby Isaac   ierr = PetscSectionGetStorageSize(aSec,&size);CHKERRQ(ierr);
76766af876cSToby Isaac   ierr = PetscMalloc1(size,&anchors);CHKERRQ(ierr);
76866af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
76966af876cSToby Isaac     PetscInt parent, ancestor = p;
77066af876cSToby Isaac 
771f9f063d4SToby Isaac     if (canonLabel) {
772f9f063d4SToby Isaac       PetscInt canon;
773f9f063d4SToby Isaac 
774f9f063d4SToby Isaac       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
775f9f063d4SToby Isaac       if (p != canon) continue;
776f9f063d4SToby Isaac     }
77766af876cSToby Isaac     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
77866af876cSToby Isaac     while (parent != ancestor) {
77966af876cSToby Isaac       ancestor = parent;
78066af876cSToby Isaac       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
78166af876cSToby Isaac     }
78266af876cSToby Isaac     if (ancestor != p) {
78366af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
78466af876cSToby Isaac 
78566af876cSToby Isaac       ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
78666af876cSToby Isaac 
78766af876cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
78866af876cSToby Isaac       for (j = 0; j < closureSize; j++) {
78966af876cSToby Isaac         anchors[aOff + j] = closure[2*j];
79066af876cSToby Isaac       }
79166af876cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
79266af876cSToby Isaac     }
79366af876cSToby Isaac   }
794e228b242SToby Isaac   ierr = ISCreateGeneral(PETSC_COMM_SELF,size,anchors,PETSC_OWN_POINTER,&aIS);CHKERRQ(ierr);
7956dd5a8c8SToby Isaac   {
7966dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7976dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7986dd5a8c8SToby Isaac 
7996dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aSec);CHKERRQ(ierr);
8006dd5a8c8SToby Isaac     ierr = PetscObjectReference((PetscObject)aIS);CHKERRQ(ierr);
8016dd5a8c8SToby Isaac     while (aSecNew) {
8026dd5a8c8SToby Isaac       ierr    = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
8036dd5a8c8SToby Isaac       ierr    = ISDestroy(&aIS);CHKERRQ(ierr);
8046dd5a8c8SToby Isaac       aSec    = aSecNew;
8056dd5a8c8SToby Isaac       aIS     = aISNew;
8066dd5a8c8SToby Isaac       aSecNew = NULL;
8076dd5a8c8SToby Isaac       aISNew  = NULL;
8086dd5a8c8SToby Isaac       ierr    = AnchorsFlatten(aSec,aIS,&aSecNew,&aISNew);CHKERRQ(ierr);
8096dd5a8c8SToby Isaac     }
8106dd5a8c8SToby Isaac   }
811a17985deSToby Isaac   ierr = DMPlexSetAnchors(dm,aSec,aIS);CHKERRQ(ierr);
81266af876cSToby Isaac   ierr = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
81366af876cSToby Isaac   ierr = ISDestroy(&aIS);CHKERRQ(ierr);
81466af876cSToby Isaac   PetscFunctionReturn(0);
81566af876cSToby Isaac }
81666af876cSToby Isaac 
81766af876cSToby Isaac #undef __FUNCT__
8186461c1adSToby Isaac #define __FUNCT__ "DMPlexGetTrueSupportSize"
8196461c1adSToby Isaac static PetscErrorCode DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt *dof,PetscInt *numTrueSupp)
8206461c1adSToby Isaac {
8216461c1adSToby Isaac   PetscErrorCode ierr;
8226461c1adSToby Isaac 
8236461c1adSToby Isaac   PetscFunctionBegin;
8246461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
8256461c1adSToby Isaac     PetscInt i, alldof;
8266461c1adSToby Isaac     const PetscInt *supp;
8276461c1adSToby Isaac     PetscInt count = 0;
8286461c1adSToby Isaac 
8296461c1adSToby Isaac     ierr = DMPlexGetSupportSize(dm,p,&alldof);CHKERRQ(ierr);
8306461c1adSToby Isaac     ierr = DMPlexGetSupport(dm,p,&supp);CHKERRQ(ierr);
8316461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
8326461c1adSToby Isaac       PetscInt q = supp[i], numCones, j;
8336461c1adSToby Isaac       const PetscInt *cone;
8346461c1adSToby Isaac 
8356461c1adSToby Isaac       ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
8366461c1adSToby Isaac       ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
8376461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
8386461c1adSToby Isaac         if (cone[j] == p) break;
8396461c1adSToby Isaac       }
8406461c1adSToby Isaac       if (j < numCones) count++;
8416461c1adSToby Isaac     }
8426461c1adSToby Isaac     numTrueSupp[p] = count;
8436461c1adSToby Isaac   }
8446461c1adSToby Isaac   *dof = numTrueSupp[p];
8456461c1adSToby Isaac   PetscFunctionReturn(0);
8466461c1adSToby Isaac }
8476461c1adSToby Isaac 
8486461c1adSToby Isaac #undef __FUNCT__
849776742edSToby Isaac #define __FUNCT__ "DMPlexTreeExchangeSupports"
850776742edSToby Isaac static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
851776742edSToby Isaac {
852776742edSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
853776742edSToby Isaac   PetscSection newSupportSection;
854776742edSToby Isaac   PetscInt newSize, *newSupports, pStart, pEnd, p, d, depth;
8556461c1adSToby Isaac   PetscInt *numTrueSupp;
856776742edSToby Isaac   PetscInt *offsets;
857776742edSToby Isaac   PetscErrorCode ierr;
858776742edSToby Isaac 
859776742edSToby Isaac   PetscFunctionBegin;
860776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
861776742edSToby Isaac   /* symmetrize the hierarchy */
862776742edSToby Isaac   ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr);
863e228b242SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)),&newSupportSection);CHKERRQ(ierr);
864776742edSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
865776742edSToby Isaac   ierr = PetscSectionSetChart(newSupportSection,pStart,pEnd);CHKERRQ(ierr);
866776742edSToby Isaac   ierr = PetscCalloc1(pEnd,&offsets);CHKERRQ(ierr);
8676461c1adSToby Isaac   ierr = PetscMalloc1(pEnd,&numTrueSupp);CHKERRQ(ierr);
8686461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8696461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
870776742edSToby Isaac    * parent(q) */
871776742edSToby Isaac   for (d = 0; d <= depth; d++) {
872776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
873776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
874776742edSToby Isaac       PetscInt dof, q, qdof, parent;
875776742edSToby Isaac 
8766461c1adSToby Isaac       ierr = DMPlexGetTrueSupportSize(dm,p,&dof,numTrueSupp);CHKERRQ(ierr);
877776742edSToby Isaac       ierr = PetscSectionAddDof(newSupportSection, p, dof);CHKERRQ(ierr);
878776742edSToby Isaac       q    = p;
879776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
880776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
881776742edSToby Isaac         q = parent;
882776742edSToby Isaac 
8836461c1adSToby Isaac         ierr = DMPlexGetTrueSupportSize(dm,q,&qdof,numTrueSupp);CHKERRQ(ierr);
884776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,p,qdof);CHKERRQ(ierr);
885776742edSToby Isaac         ierr = PetscSectionAddDof(newSupportSection,q,dof);CHKERRQ(ierr);
886776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
887776742edSToby Isaac       }
888776742edSToby Isaac     }
889776742edSToby Isaac   }
890776742edSToby Isaac   ierr = PetscSectionSetUp(newSupportSection);CHKERRQ(ierr);
891776742edSToby Isaac   ierr = PetscSectionGetStorageSize(newSupportSection,&newSize);CHKERRQ(ierr);
892776742edSToby Isaac   ierr = PetscMalloc1(newSize,&newSupports);CHKERRQ(ierr);
893776742edSToby Isaac   for (d = 0; d <= depth; d++) {
894776742edSToby Isaac     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
895776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
896776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
897776742edSToby Isaac 
898776742edSToby Isaac       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
899776742edSToby Isaac       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
900776742edSToby Isaac       ierr = PetscSectionGetDof(newSupportSection, p, &newDof);CHKERRQ(ierr);
901776742edSToby Isaac       ierr = PetscSectionGetOffset(newSupportSection, p, &newOff);CHKERRQ(ierr);
902776742edSToby Isaac       for (i = 0; i < dof; i++) {
9036461c1adSToby Isaac         PetscInt numCones, j;
9046461c1adSToby Isaac         const PetscInt *cone;
9056461c1adSToby Isaac         PetscInt q = mesh->supports[off + i];
9066461c1adSToby Isaac 
9076461c1adSToby Isaac         ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
9086461c1adSToby Isaac         ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
9096461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
9106461c1adSToby Isaac           if (cone[j] == p) break;
9116461c1adSToby Isaac         }
9126461c1adSToby Isaac         if (j < numCones) newSupports[newOff+offsets[p]++] = q;
913776742edSToby Isaac       }
914776742edSToby Isaac       mesh->maxSupportSize = PetscMax(mesh->maxSupportSize,newDof);
915776742edSToby Isaac 
916776742edSToby Isaac       q    = p;
917776742edSToby Isaac       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
918776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
919776742edSToby Isaac         q = parent;
920776742edSToby Isaac         ierr = PetscSectionGetDof(mesh->supportSection, q, &qdof);CHKERRQ(ierr);
921776742edSToby Isaac         ierr = PetscSectionGetOffset(mesh->supportSection, q, &qoff);CHKERRQ(ierr);
922776742edSToby Isaac         ierr = PetscSectionGetOffset(newSupportSection, q, &newqOff);CHKERRQ(ierr);
923776742edSToby Isaac         for (i = 0; i < qdof; i++) {
9246461c1adSToby Isaac           PetscInt numCones, j;
9256461c1adSToby Isaac           const PetscInt *cone;
9266461c1adSToby Isaac           PetscInt r = mesh->supports[qoff + i];
9276461c1adSToby Isaac 
9286461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9296461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9306461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9316461c1adSToby Isaac             if (cone[j] == q) break;
9326461c1adSToby Isaac           }
9336461c1adSToby Isaac           if (j < numCones) newSupports[newOff+offsets[p]++] = r;
934776742edSToby Isaac         }
935776742edSToby Isaac         for (i = 0; i < dof; i++) {
9366461c1adSToby Isaac           PetscInt numCones, j;
9376461c1adSToby Isaac           const PetscInt *cone;
9386461c1adSToby Isaac           PetscInt r = mesh->supports[off + i];
9396461c1adSToby Isaac 
9406461c1adSToby Isaac           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
9416461c1adSToby Isaac           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
9426461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9436461c1adSToby Isaac             if (cone[j] == p) break;
9446461c1adSToby Isaac           }
9456461c1adSToby Isaac           if (j < numCones) newSupports[newqOff+offsets[q]++] = r;
946776742edSToby Isaac         }
947776742edSToby Isaac         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
948776742edSToby Isaac       }
949776742edSToby Isaac     }
950776742edSToby Isaac   }
951776742edSToby Isaac   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
952776742edSToby Isaac   mesh->supportSection = newSupportSection;
953776742edSToby Isaac   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
954776742edSToby Isaac   mesh->supports = newSupports;
955776742edSToby Isaac   ierr = PetscFree(offsets);CHKERRQ(ierr);
9566461c1adSToby Isaac   ierr = PetscFree(numTrueSupp);CHKERRQ(ierr);
957776742edSToby Isaac 
958776742edSToby Isaac   PetscFunctionReturn(0);
959776742edSToby Isaac }
960776742edSToby Isaac 
961f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM,PetscSection,PetscSection,Mat);
962f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM,PetscSection,PetscSection,Mat);
963f7c74593SToby Isaac 
964776742edSToby Isaac #undef __FUNCT__
965f9f063d4SToby Isaac #define __FUNCT__ "DMPlexSetTree_Internal"
966776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
967f9f063d4SToby Isaac {
968f9f063d4SToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
969f9f063d4SToby Isaac   DM             refTree;
970f9f063d4SToby Isaac   PetscInt       size;
971f9f063d4SToby Isaac   PetscErrorCode ierr;
972f9f063d4SToby Isaac 
973f9f063d4SToby Isaac   PetscFunctionBegin;
974f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
975f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
976f9f063d4SToby Isaac   ierr = PetscObjectReference((PetscObject)parentSection);CHKERRQ(ierr);
977f9f063d4SToby Isaac   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
978f9f063d4SToby Isaac   mesh->parentSection = parentSection;
979f9f063d4SToby Isaac   ierr = PetscSectionGetStorageSize(parentSection,&size);CHKERRQ(ierr);
980f9f063d4SToby Isaac   if (parents != mesh->parents) {
981f9f063d4SToby Isaac     ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
982f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->parents);CHKERRQ(ierr);
983f9f063d4SToby Isaac     ierr = PetscMemcpy(mesh->parents, parents, size * sizeof(*parents));CHKERRQ(ierr);
984f9f063d4SToby Isaac   }
985f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
986f9f063d4SToby Isaac     ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
987f9f063d4SToby Isaac     ierr = PetscMalloc1(size,&mesh->childIDs);CHKERRQ(ierr);
988f9f063d4SToby Isaac     ierr = PetscMemcpy(mesh->childIDs, childIDs, size * sizeof(*childIDs));CHKERRQ(ierr);
989f9f063d4SToby Isaac   }
990f9f063d4SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
991f9f063d4SToby Isaac   if (refTree) {
992f9f063d4SToby Isaac     DMLabel canonLabel;
993f9f063d4SToby Isaac 
994c58f1c22SToby Isaac     ierr = DMGetLabel(refTree,"canonical",&canonLabel);CHKERRQ(ierr);
995f9f063d4SToby Isaac     if (canonLabel) {
996f9f063d4SToby Isaac       PetscInt i;
997f9f063d4SToby Isaac 
998f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
999f9f063d4SToby Isaac         PetscInt canon;
1000f9f063d4SToby Isaac         ierr = DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon);CHKERRQ(ierr);
1001f9f063d4SToby Isaac         if (canon >= 0) {
1002f9f063d4SToby Isaac           mesh->childIDs[i] = canon;
1003f9f063d4SToby Isaac         }
1004f9f063d4SToby Isaac       }
1005f9f063d4SToby Isaac     }
1006f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
1007f7c74593SToby Isaac   }
1008f7c74593SToby Isaac   else {
1009f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
1010f9f063d4SToby Isaac   }
1011f9f063d4SToby Isaac   ierr = DMPlexTreeSymmetrize(dm);CHKERRQ(ierr);
1012f9f063d4SToby Isaac   if (computeCanonical) {
1013f9f063d4SToby Isaac     PetscInt d, dim;
1014f9f063d4SToby Isaac 
1015f9f063d4SToby Isaac     /* add the canonical label */
101628f4b327SMatthew G. Knepley     ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
1017c58f1c22SToby Isaac     ierr = DMCreateLabel(dm,"canonical");CHKERRQ(ierr);
1018f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
1019f9f063d4SToby Isaac       PetscInt p, dStart, dEnd, canon = -1, cNumChildren;
1020f9f063d4SToby Isaac       const PetscInt *cChildren;
1021f9f063d4SToby Isaac 
1022f9f063d4SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
1023f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1024f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&cNumChildren,&cChildren);CHKERRQ(ierr);
1025f9f063d4SToby Isaac         if (cNumChildren) {
1026f9f063d4SToby Isaac           canon = p;
1027f9f063d4SToby Isaac           break;
1028f9f063d4SToby Isaac         }
1029f9f063d4SToby Isaac       }
1030f9f063d4SToby Isaac       if (canon == -1) continue;
1031f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1032f9f063d4SToby Isaac         PetscInt numChildren, i;
1033f9f063d4SToby Isaac         const PetscInt *children;
1034f9f063d4SToby Isaac 
1035f9f063d4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,p,&numChildren,&children);CHKERRQ(ierr);
1036f9f063d4SToby Isaac         if (numChildren) {
1037f9f063d4SToby Isaac           if (numChildren != cNumChildren) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"All parent points in a stratum should have the same number of children: %d != %d", numChildren, cNumChildren);
1038c58f1c22SToby Isaac           ierr = DMSetLabelValue(dm,"canonical",p,canon);CHKERRQ(ierr);
1039f9f063d4SToby Isaac           for (i = 0; i < numChildren; i++) {
1040c58f1c22SToby Isaac             ierr = DMSetLabelValue(dm,"canonical",children[i],cChildren[i]);CHKERRQ(ierr);
1041f9f063d4SToby Isaac           }
1042f9f063d4SToby Isaac         }
1043f9f063d4SToby Isaac       }
1044f9f063d4SToby Isaac     }
1045f9f063d4SToby Isaac   }
1046776742edSToby Isaac   if (exchangeSupports) {
1047776742edSToby Isaac     ierr = DMPlexTreeExchangeSupports(dm);CHKERRQ(ierr);
1048776742edSToby Isaac   }
1049f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
1050f7c74593SToby Isaac   /* reset anchors */
1051f7c74593SToby Isaac   ierr = DMPlexSetAnchors(dm,NULL,NULL);CHKERRQ(ierr);
1052f9f063d4SToby Isaac   PetscFunctionReturn(0);
1053f9f063d4SToby Isaac }
1054f9f063d4SToby Isaac 
1055f9f063d4SToby Isaac #undef __FUNCT__
10560b7167a0SToby Isaac #define __FUNCT__ "DMPlexSetTree"
10570b7167a0SToby Isaac /*@
10580b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
10590b7167a0SToby Isaac   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
10600b7167a0SToby Isaac   tree root.
10610b7167a0SToby Isaac 
10620b7167a0SToby Isaac   Collective on dm
10630b7167a0SToby Isaac 
10640b7167a0SToby Isaac   Input Parameters:
10650b7167a0SToby Isaac + dm - the DMPlex object
10660b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
10670b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
10680b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
10690b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
10700b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
10710b7167a0SToby Isaac 
10720b7167a0SToby Isaac   Level: intermediate
10730b7167a0SToby Isaac 
1074a17985deSToby Isaac .seealso: DMPlexGetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
10750b7167a0SToby Isaac @*/
1076b2f41788SToby Isaac PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
10770b7167a0SToby Isaac {
10780b7167a0SToby Isaac   PetscErrorCode ierr;
10790b7167a0SToby Isaac 
10800b7167a0SToby Isaac   PetscFunctionBegin;
1081776742edSToby Isaac   ierr = DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
10820b7167a0SToby Isaac   PetscFunctionReturn(0);
10830b7167a0SToby Isaac }
10840b7167a0SToby Isaac 
10850b7167a0SToby Isaac #undef __FUNCT__
1086b2f41788SToby Isaac #define __FUNCT__ "DMPlexGetTree"
1087b2f41788SToby Isaac /*@
1088b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1089b2f41788SToby Isaac   Collective on dm
1090b2f41788SToby Isaac 
1091b2f41788SToby Isaac   Input Parameters:
1092b2f41788SToby Isaac . dm - the DMPlex object
1093b2f41788SToby Isaac 
1094b2f41788SToby Isaac   Output Parameters:
1095b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1096b2f41788SToby Isaac                   offset indexes the parent and childID list
1097b2f41788SToby Isaac . parents - a list of the point parents
1098b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1099b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1100b2f41788SToby Isaac . childSection - the inverse of the parent section
1101b2f41788SToby Isaac - children - a list of the point children
1102b2f41788SToby Isaac 
1103b2f41788SToby Isaac   Level: intermediate
1104b2f41788SToby Isaac 
1105a17985deSToby Isaac .seealso: DMPlexSetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
1106b2f41788SToby Isaac @*/
1107b2f41788SToby Isaac PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1108b2f41788SToby Isaac {
1109b2f41788SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
1110b2f41788SToby Isaac 
1111b2f41788SToby Isaac   PetscFunctionBegin;
1112b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1113b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1114b2f41788SToby Isaac   if (parents)       *parents       = mesh->parents;
1115b2f41788SToby Isaac   if (childIDs)      *childIDs      = mesh->childIDs;
1116b2f41788SToby Isaac   if (childSection)  *childSection  = mesh->childSection;
1117b2f41788SToby Isaac   if (children)      *children      = mesh->children;
1118b2f41788SToby Isaac   PetscFunctionReturn(0);
1119b2f41788SToby Isaac }
1120b2f41788SToby Isaac 
1121b2f41788SToby Isaac #undef __FUNCT__
1122d961a43aSToby Isaac #define __FUNCT__ "DMPlexGetTreeParent"
1123d961a43aSToby Isaac /*@
1124d961a43aSToby Isaac   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the Sieve DAG)
1125d961a43aSToby Isaac 
1126d961a43aSToby Isaac   Input Parameters:
1127d961a43aSToby Isaac + dm - the DMPlex object
1128d961a43aSToby Isaac - point - the query point
1129d961a43aSToby Isaac 
1130d961a43aSToby Isaac   Output Parameters:
1131d961a43aSToby Isaac + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1132d961a43aSToby Isaac - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point
1133d961a43aSToby Isaac             does not have a parent
1134d961a43aSToby Isaac 
1135d961a43aSToby Isaac   Level: intermediate
1136d961a43aSToby Isaac 
1137d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeChildren()
1138d961a43aSToby Isaac @*/
1139d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1140d961a43aSToby Isaac {
1141d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1142d961a43aSToby Isaac   PetscSection   pSec;
1143d961a43aSToby Isaac   PetscErrorCode ierr;
1144d961a43aSToby Isaac 
1145d961a43aSToby Isaac   PetscFunctionBegin;
1146d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1147d961a43aSToby Isaac   pSec = mesh->parentSection;
1148d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1149d961a43aSToby Isaac     PetscInt dof;
1150d961a43aSToby Isaac 
1151d961a43aSToby Isaac     ierr = PetscSectionGetDof (pSec, point, &dof);CHKERRQ(ierr);
1152d961a43aSToby Isaac     if (dof) {
1153d961a43aSToby Isaac       PetscInt off;
1154d961a43aSToby Isaac 
1155d961a43aSToby Isaac       ierr = PetscSectionGetOffset (pSec, point, &off);CHKERRQ(ierr);
1156d961a43aSToby Isaac       if (parent)  *parent = mesh->parents[off];
1157d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
1158d961a43aSToby Isaac       PetscFunctionReturn(0);
1159d961a43aSToby Isaac     }
1160d961a43aSToby Isaac   }
1161d961a43aSToby Isaac   if (parent) {
1162d961a43aSToby Isaac     *parent = point;
1163d961a43aSToby Isaac   }
1164d961a43aSToby Isaac   if (childID) {
1165d961a43aSToby Isaac     *childID = 0;
1166d961a43aSToby Isaac   }
1167d961a43aSToby Isaac   PetscFunctionReturn(0);
1168d961a43aSToby Isaac }
1169d961a43aSToby Isaac 
1170d961a43aSToby Isaac #undef __FUNCT__
1171d961a43aSToby Isaac #define __FUNCT__ "DMPlexGetTreeChildren"
1172d961a43aSToby Isaac /*@C
1173d961a43aSToby Isaac   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the Sieve DAG)
1174d961a43aSToby Isaac 
1175d961a43aSToby Isaac   Input Parameters:
1176d961a43aSToby Isaac + dm - the DMPlex object
1177d961a43aSToby Isaac - point - the query point
1178d961a43aSToby Isaac 
1179d961a43aSToby Isaac   Output Parameters:
1180d961a43aSToby Isaac + numChildren - if not NULL, set to the number of children
1181d961a43aSToby Isaac - children - if not NULL, set to a list children, or set to NULL if the point has no children
1182d961a43aSToby Isaac 
1183d961a43aSToby Isaac   Level: intermediate
1184d961a43aSToby Isaac 
1185d961a43aSToby Isaac   Fortran Notes:
1186d961a43aSToby Isaac   Since it returns an array, this routine is only available in Fortran 90, and you must
1187d961a43aSToby Isaac   include petsc.h90 in your code.
1188d961a43aSToby Isaac 
1189d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeParent()
1190d961a43aSToby Isaac @*/
1191d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1192d961a43aSToby Isaac {
1193d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1194d961a43aSToby Isaac   PetscSection   childSec;
1195d961a43aSToby Isaac   PetscInt       dof = 0;
1196d961a43aSToby Isaac   PetscErrorCode ierr;
1197d961a43aSToby Isaac 
1198d961a43aSToby Isaac   PetscFunctionBegin;
1199d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1200d961a43aSToby Isaac   childSec = mesh->childSection;
1201d961a43aSToby Isaac   if (childSec && point >= childSec->pStart && point < childSec->pEnd) {
1202d961a43aSToby Isaac     ierr = PetscSectionGetDof (childSec, point, &dof);CHKERRQ(ierr);
1203d961a43aSToby Isaac   }
1204d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1205d961a43aSToby Isaac   if (children) {
1206d961a43aSToby Isaac     if (dof) {
1207d961a43aSToby Isaac       PetscInt off;
1208d961a43aSToby Isaac 
1209d961a43aSToby Isaac       ierr = PetscSectionGetOffset (childSec, point, &off);CHKERRQ(ierr);
1210d961a43aSToby Isaac       *children = &mesh->children[off];
1211d961a43aSToby Isaac     }
1212d961a43aSToby Isaac     else {
1213d961a43aSToby Isaac       *children = NULL;
1214d961a43aSToby Isaac     }
1215d961a43aSToby Isaac   }
1216d961a43aSToby Isaac   PetscFunctionReturn(0);
1217d961a43aSToby Isaac }
12180c37af3bSToby Isaac 
12190c37af3bSToby Isaac #undef __FUNCT__
1220b3a4bf2aSToby Isaac #define __FUNCT__ "EvaluateBasis"
1221b3a4bf2aSToby Isaac static PetscErrorCode EvaluateBasis(PetscSpace space, PetscInt nFunctionals, PetscInt nPoints, const PetscInt *pointsPerFn, const PetscReal *points, const PetscReal *weights, PetscReal *work, Mat basisAtPoints)
1222b3a4bf2aSToby Isaac {
1223b3a4bf2aSToby Isaac   PetscInt       i, j, k, offset, qPoints;
1224b3a4bf2aSToby Isaac   PetscErrorCode ierr;
1225b3a4bf2aSToby Isaac 
1226b3a4bf2aSToby Isaac   PetscFunctionBegin;
1227b3a4bf2aSToby Isaac   ierr = PetscSpaceEvaluate(space,nPoints,points,work,NULL,NULL);CHKERRQ(ierr);
1228b3a4bf2aSToby Isaac   for (i = 0, offset = 0; i < nFunctionals; i++) {
1229b3a4bf2aSToby Isaac     qPoints = pointsPerFn[i];
1230b3a4bf2aSToby Isaac     for (j = 0; j < nFunctionals; j++) {
1231b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1232b3a4bf2aSToby Isaac 
1233b3a4bf2aSToby Isaac       for (k = 0; k < qPoints; k++) {
1234b3a4bf2aSToby Isaac         val += work[(offset + k) * nFunctionals + j] * weights[k];
1235b3a4bf2aSToby Isaac       }
1236b3a4bf2aSToby Isaac       ierr = MatSetValue(basisAtPoints,j,i,val,INSERT_VALUES);CHKERRQ(ierr);
1237b3a4bf2aSToby Isaac     }
1238b3a4bf2aSToby Isaac     offset += qPoints;
1239b3a4bf2aSToby Isaac   }
1240b3a4bf2aSToby Isaac   ierr = MatAssemblyBegin(basisAtPoints,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1241b3a4bf2aSToby Isaac   ierr = MatAssemblyEnd(basisAtPoints,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1242b3a4bf2aSToby Isaac   PetscFunctionReturn(0);
1243b3a4bf2aSToby Isaac }
1244b3a4bf2aSToby Isaac 
1245b3a4bf2aSToby Isaac #undef __FUNCT__
1246f7c74593SToby Isaac #define __FUNCT__ "DMPlexComputeAnchorMatrix_Tree_Direct"
1247f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
12480c37af3bSToby Isaac {
12490c37af3bSToby Isaac   PetscDS        ds;
12500c37af3bSToby Isaac   PetscInt       spdim;
12510c37af3bSToby Isaac   PetscInt       numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
12520c37af3bSToby Isaac   const PetscInt *anchors;
1253f7c74593SToby Isaac   PetscSection   aSec;
12540c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
12550c37af3bSToby Isaac   IS             aIS;
12560c37af3bSToby Isaac   PetscErrorCode ierr;
12570c37af3bSToby Isaac 
12580c37af3bSToby Isaac   PetscFunctionBegin;
12590c37af3bSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
12600c37af3bSToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
12610c37af3bSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
12620c37af3bSToby Isaac   ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
1263a17985deSToby Isaac   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
12640c37af3bSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
12650c37af3bSToby Isaac   ierr = PetscSectionGetChart(cSec,&conStart,&conEnd);CHKERRQ(ierr);
126628f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&spdim);CHKERRQ(ierr);
12670c37af3bSToby Isaac   ierr = PetscMalloc6(spdim,&v0,spdim,&v0parent,spdim,&vtmp,spdim*spdim,&J,spdim*spdim,&Jparent,spdim*spdim,&invJparent);CHKERRQ(ierr);
12680c37af3bSToby Isaac 
12690c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
12700dd1b1feSToby Isaac     PetscObject disc;
12710dd1b1feSToby Isaac     PetscClassId id;
1272b3a4bf2aSToby Isaac     PetscSpace     bspace;
1273b3a4bf2aSToby Isaac     PetscDualSpace dspace;
12740c37af3bSToby Isaac     PetscInt i, j, k, nPoints, offset;
1275*2c44ad04SToby Isaac     PetscInt fSize, fComp, maxDof;
1276b3a4bf2aSToby Isaac     PetscReal   *weights, *pointsRef, *pointsReal, *work;
1277*2c44ad04SToby Isaac     PetscScalar *scwork, *X;
1278*2c44ad04SToby Isaac     PetscInt  *sizes, *workIndRow, *workIndCol;
12790c37af3bSToby Isaac     Mat Amat, Bmat, Xmat;
1280*2c44ad04SToby Isaac     const PetscInt    *numDof  = NULL;
1281085f0adfSToby Isaac     const PetscInt    ***perms = NULL;
1282085f0adfSToby Isaac     const PetscScalar ***flips = NULL;
12830c37af3bSToby Isaac 
12840dd1b1feSToby Isaac     ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
12850dd1b1feSToby Isaac     ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
12860dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1287b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE) disc;
1288b3a4bf2aSToby Isaac 
1289b3a4bf2aSToby Isaac       ierr = PetscFEGetBasisSpace(fe,&bspace);CHKERRQ(ierr);
1290b3a4bf2aSToby Isaac       ierr = PetscFEGetDualSpace(fe,&dspace);CHKERRQ(ierr);
1291b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetDimension(dspace,&fSize);CHKERRQ(ierr);
12920c37af3bSToby Isaac       ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr);
12930dd1b1feSToby Isaac     }
12940dd1b1feSToby Isaac     else if (id == PETSCFV_CLASSID) {
1295b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV) disc;
1296b3a4bf2aSToby Isaac 
1297b3a4bf2aSToby Isaac       ierr = PetscSpaceCreate(PetscObjectComm((PetscObject)fv),&bspace);CHKERRQ(ierr);
1298b3a4bf2aSToby Isaac       ierr = PetscSpaceSetType(bspace,PETSCSPACEPOLYNOMIAL);CHKERRQ(ierr);
1299b3a4bf2aSToby Isaac       ierr = PetscSpaceSetOrder(bspace,0);CHKERRQ(ierr);
1300b3a4bf2aSToby Isaac       ierr = PetscSpacePolynomialSetNumVariables(bspace,spdim);CHKERRQ(ierr);
1301b3a4bf2aSToby Isaac       ierr = PetscSpaceSetUp(bspace);CHKERRQ(ierr);
1302b3a4bf2aSToby Isaac       ierr = PetscFVGetDualSpace(fv,&dspace);CHKERRQ(ierr);
1303b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetDimension(dspace,&fSize);CHKERRQ(ierr);
13040dd1b1feSToby Isaac       ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr);
13050dd1b1feSToby Isaac     }
13060dd1b1feSToby Isaac     else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
1307*2c44ad04SToby Isaac     ierr = PetscDualSpaceGetNumDof(dspace,&numDof);CHKERRQ(ierr);
1308*2c44ad04SToby Isaac     for (i = 0, maxDof = 0; i <= spdim; i++) {maxDof = PetscMax(maxDof,numDof[i]);}
1309085f0adfSToby Isaac     ierr = PetscDualSpaceGetSymmetries(dspace,&perms,&flips);CHKERRQ(ierr);
13100dd1b1feSToby Isaac 
13110c37af3bSToby Isaac     ierr = MatCreate(PETSC_COMM_SELF,&Amat);CHKERRQ(ierr);
13120c37af3bSToby Isaac     ierr = MatSetSizes(Amat,fSize,fSize,fSize,fSize);CHKERRQ(ierr);
13130c37af3bSToby Isaac     ierr = MatSetType(Amat,MATSEQDENSE);CHKERRQ(ierr);
13140c37af3bSToby Isaac     ierr = MatSetUp(Amat);CHKERRQ(ierr);
13150c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Bmat);CHKERRQ(ierr);
13160c37af3bSToby Isaac     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Xmat);CHKERRQ(ierr);
13170c37af3bSToby Isaac     nPoints = 0;
13180c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
13190c37af3bSToby Isaac       PetscInt        qPoints;
13200c37af3bSToby Isaac       PetscQuadrature quad;
13210c37af3bSToby Isaac 
1322b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetFunctional(dspace,i,&quad);CHKERRQ(ierr);
13230c37af3bSToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,&qPoints,NULL,NULL);CHKERRQ(ierr);
13240c37af3bSToby Isaac       nPoints += qPoints;
13250c37af3bSToby Isaac     }
1326*2c44ad04SToby Isaac     ierr = PetscMalloc7(fSize,&sizes,nPoints,&weights,spdim*nPoints,&pointsRef,spdim*nPoints,&pointsReal,fSize*nPoints,&work,maxDof,&workIndRow,maxDof,&workIndCol);CHKERRQ(ierr);
1327*2c44ad04SToby Isaac     ierr = PetscMalloc1(maxDof * maxDof,&scwork);CHKERRQ(ierr);
13280c37af3bSToby Isaac     offset = 0;
13290c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
13300c37af3bSToby Isaac       PetscInt        qPoints;
13310c37af3bSToby Isaac       const PetscReal    *p, *w;
13320c37af3bSToby Isaac       PetscQuadrature quad;
13330c37af3bSToby Isaac 
1334b3a4bf2aSToby Isaac       ierr = PetscDualSpaceGetFunctional(dspace,i,&quad);CHKERRQ(ierr);
13350c37af3bSToby Isaac       ierr = PetscQuadratureGetData(quad,NULL,&qPoints,&p,&w);CHKERRQ(ierr);
13360c37af3bSToby Isaac       ierr = PetscMemcpy(weights+offset,w,qPoints*sizeof(*w));CHKERRQ(ierr);
13370c37af3bSToby Isaac       ierr = PetscMemcpy(pointsRef+spdim*offset,p,spdim*qPoints*sizeof(*p));CHKERRQ(ierr);
1338b3a4bf2aSToby Isaac       sizes[i] = qPoints;
13390c37af3bSToby Isaac       offset  += qPoints;
13400c37af3bSToby Isaac     }
1341b3a4bf2aSToby Isaac     ierr = EvaluateBasis(bspace,fSize,nPoints,sizes,pointsRef,weights,work,Amat);CHKERRQ(ierr);
13420c37af3bSToby Isaac     ierr = MatLUFactor(Amat,NULL,NULL,NULL);CHKERRQ(ierr);
13430c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
13440c37af3bSToby Isaac       PetscInt        parent;
13450c37af3bSToby Isaac       PetscInt        closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
13460c37af3bSToby Isaac       PetscInt        *childOffsets, *parentOffsets;
13470c37af3bSToby Isaac 
13480c37af3bSToby Isaac       ierr = DMPlexGetTreeParent(dm,c,&parent,NULL);CHKERRQ(ierr);
13490c37af3bSToby Isaac       if (parent == c) continue;
13500c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13510c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13520c37af3bSToby Isaac         PetscInt p = closure[2*i];
13530c37af3bSToby Isaac         PetscInt conDof;
13540c37af3bSToby Isaac 
13550c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1356085f0adfSToby Isaac         if (numFields) {
13570c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
13580c37af3bSToby Isaac         }
13590c37af3bSToby Isaac         else {
13600c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
13610c37af3bSToby Isaac         }
13620c37af3bSToby Isaac         if (conDof) break;
13630c37af3bSToby Isaac       }
13640c37af3bSToby Isaac       if (i == closureSize) {
13650c37af3bSToby Isaac         ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
13660c37af3bSToby Isaac         continue;
13670c37af3bSToby Isaac       }
13680c37af3bSToby Isaac 
136973a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
137073a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent);CHKERRQ(ierr);
13710c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1372b3a4bf2aSToby Isaac         CoordinatesRefToReal(spdim, spdim, v0, J, &pointsRef[i*spdim],vtmp);
1373b3a4bf2aSToby Isaac         CoordinatesRealToRef(spdim, spdim, v0parent, invJparent, vtmp, &pointsReal[i*spdim]);
13740c37af3bSToby Isaac       }
1375b3a4bf2aSToby Isaac       ierr = EvaluateBasis(bspace,fSize,nPoints,sizes,pointsReal,weights,work,Bmat);CHKERRQ(ierr);
13760c37af3bSToby Isaac       ierr = MatMatSolve(Amat,Bmat,Xmat);CHKERRQ(ierr);
1377*2c44ad04SToby Isaac       ierr = MatDenseGetArray(Xmat,&X);CHKERRQ(ierr);
13780c37af3bSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
13790c37af3bSToby Isaac       ierr = PetscMalloc2(closureSize+1,&childOffsets,closureSizeP+1,&parentOffsets);CHKERRQ(ierr);
13800c37af3bSToby Isaac       childOffsets[0] = 0;
13810c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13820c37af3bSToby Isaac         PetscInt p = closure[2*i];
13830c37af3bSToby Isaac         PetscInt dof;
13840c37af3bSToby Isaac 
1385085f0adfSToby Isaac         if (numFields) {
13860c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
13870c37af3bSToby Isaac         }
13880c37af3bSToby Isaac         else {
13890c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
13900c37af3bSToby Isaac         }
13910c37af3bSToby Isaac         childOffsets[i+1]=childOffsets[i]+dof / fComp;
13920c37af3bSToby Isaac       }
13930c37af3bSToby Isaac       parentOffsets[0] = 0;
13940c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
13950c37af3bSToby Isaac         PetscInt p = closureP[2*i];
13960c37af3bSToby Isaac         PetscInt dof;
13970c37af3bSToby Isaac 
1398085f0adfSToby Isaac         if (numFields) {
13990c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
14000c37af3bSToby Isaac         }
14010c37af3bSToby Isaac         else {
14020c37af3bSToby Isaac           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
14030c37af3bSToby Isaac         }
14040c37af3bSToby Isaac         parentOffsets[i+1]=parentOffsets[i]+dof / fComp;
14050c37af3bSToby Isaac       }
14060c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
1407*2c44ad04SToby Isaac         PetscInt conDof, conOff, aDof, aOff, nWork;
14080c37af3bSToby Isaac         PetscInt p = closure[2*i];
14090c37af3bSToby Isaac         PetscInt o = closure[2*i+1];
1410085f0adfSToby Isaac         const PetscInt    *perm;
1411085f0adfSToby Isaac         const PetscScalar *flip;
14120c37af3bSToby Isaac 
14130c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1414085f0adfSToby Isaac         if (numFields) {
14150c37af3bSToby Isaac           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
14160c37af3bSToby Isaac           ierr = PetscSectionGetFieldOffset(cSec,p,f,&conOff);CHKERRQ(ierr);
14170c37af3bSToby Isaac         }
14180c37af3bSToby Isaac         else {
14190c37af3bSToby Isaac           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
14200c37af3bSToby Isaac           ierr = PetscSectionGetOffset(cSec,p,&conOff);CHKERRQ(ierr);
14210c37af3bSToby Isaac         }
14220c37af3bSToby Isaac         if (!conDof) continue;
1423085f0adfSToby Isaac         perm  = (perms && perms[i]) ? perms[i][o] : NULL;
1424085f0adfSToby Isaac         flip  = (flips && flips[i]) ? flips[i][o] : NULL;
14250c37af3bSToby Isaac         ierr  = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
14260c37af3bSToby Isaac         ierr  = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
1427*2c44ad04SToby Isaac         nWork = childOffsets[i+1]-childOffsets[i];
14280c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
14290c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
14300c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
14310c37af3bSToby Isaac 
1432085f0adfSToby Isaac           if (numFields) {
14330c37af3bSToby Isaac             ierr = PetscSectionGetFieldDof(section,a,f,&aSecDof);CHKERRQ(ierr);
14340c37af3bSToby Isaac             ierr = PetscSectionGetFieldOffset(section,a,f,&aSecOff);CHKERRQ(ierr);
14350c37af3bSToby Isaac           }
14360c37af3bSToby Isaac           else {
14370c37af3bSToby Isaac             ierr = PetscSectionGetDof(section,a,&aSecDof);CHKERRQ(ierr);
14380c37af3bSToby Isaac             ierr = PetscSectionGetOffset(section,a,&aSecOff);CHKERRQ(ierr);
14390c37af3bSToby Isaac           }
14400c37af3bSToby Isaac           if (!aSecDof) continue;
14410c37af3bSToby Isaac 
14420c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
14430c37af3bSToby Isaac             PetscInt q = closureP[2*j];
14440c37af3bSToby Isaac             PetscInt oq = closureP[2*j+1];
1445*2c44ad04SToby Isaac 
1446*2c44ad04SToby Isaac             if (q == a) {
1447*2c44ad04SToby Isaac               PetscInt r, s, t, nWorkP;
1448085f0adfSToby Isaac               const PetscInt    *permP;
1449085f0adfSToby Isaac               const PetscScalar *flipP;
1450085f0adfSToby Isaac 
1451085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1452085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
1453*2c44ad04SToby Isaac               nWorkP = parentOffsets[j+1]-parentOffsets[j];
1454*2c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
1455*2c44ad04SToby Isaac                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArray is
1456*2c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
1457*2c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
1458*2c44ad04SToby Isaac                 for (s = 0; s < nWorkP; s++) {
1459*2c44ad04SToby Isaac                   scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
1460*2c44ad04SToby Isaac                 }
1461*2c44ad04SToby Isaac               }
1462*2c44ad04SToby Isaac               for (r = 0; r < nWork; r++)  {workIndRow[perm  ? perm[r]  : r] = conOff  + fComp * r;}
1463*2c44ad04SToby Isaac               for (s = 0; s < nWorkP; s++) {workIndCol[permP ? permP[s] : s] = aSecOff + fComp * s;}
1464*2c44ad04SToby Isaac               if (flip) {
1465*2c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1466*2c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
1467*2c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flip[r];
1468*2c44ad04SToby Isaac                   }
1469*2c44ad04SToby Isaac                 }
1470*2c44ad04SToby Isaac               }
1471*2c44ad04SToby Isaac               if (flipP) {
1472*2c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1473*2c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
1474*2c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flipP[s];
1475*2c44ad04SToby Isaac                   }
1476*2c44ad04SToby Isaac                 }
1477*2c44ad04SToby Isaac               }
14780c37af3bSToby Isaac               for (t = 0; t < fComp; t++) {
1479*2c44ad04SToby Isaac                 ierr = MatSetValues(cMat,nWork,workIndRow,nWorkP,workIndCol,scwork,INSERT_VALUES);CHKERRQ(ierr);
1480*2c44ad04SToby Isaac                 if (t < fComp - 1) {
1481*2c44ad04SToby Isaac                   for (r = 0; r < nWork;  r++) {workIndRow[r]++;}
1482*2c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {workIndCol[s]++;}
1483*2c44ad04SToby Isaac                 }
1484*2c44ad04SToby Isaac               }
1485*2c44ad04SToby Isaac               break;
14860c37af3bSToby Isaac             }
14870c37af3bSToby Isaac           }
14880c37af3bSToby Isaac         }
14890c37af3bSToby Isaac       }
1490*2c44ad04SToby Isaac       ierr = MatDenseRestoreArray(Xmat,&X);CHKERRQ(ierr);
14910c37af3bSToby Isaac       ierr = PetscFree2(childOffsets,parentOffsets);CHKERRQ(ierr);
14920c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
14930c37af3bSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
14940c37af3bSToby Isaac     }
14950c37af3bSToby Isaac     ierr = MatDestroy(&Amat);CHKERRQ(ierr);
14960c37af3bSToby Isaac     ierr = MatDestroy(&Bmat);CHKERRQ(ierr);
14970c37af3bSToby Isaac     ierr = MatDestroy(&Xmat);CHKERRQ(ierr);
1498*2c44ad04SToby Isaac     ierr = PetscFree(scwork);CHKERRQ(ierr);
1499*2c44ad04SToby Isaac     ierr = PetscFree7(sizes,weights,pointsRef,pointsReal,work,workIndRow,workIndCol);CHKERRQ(ierr);
1500b3a4bf2aSToby Isaac     if (id == PETSCFV_CLASSID) {
1501b3a4bf2aSToby Isaac       ierr = PetscSpaceDestroy(&bspace);CHKERRQ(ierr);
1502b3a4bf2aSToby Isaac     }
15030c37af3bSToby Isaac   }
15040c37af3bSToby Isaac   ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
15050c37af3bSToby Isaac   ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
15060c37af3bSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJparent);CHKERRQ(ierr);
15070c37af3bSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
15080c37af3bSToby Isaac 
15090c37af3bSToby Isaac   PetscFunctionReturn(0);
15100c37af3bSToby Isaac }
151195a0b26dSToby Isaac 
151295a0b26dSToby Isaac #undef __FUNCT__
151321968bf8SToby Isaac #define __FUNCT__ "DMPlexReferenceTreeGetChildrenMatrices"
151421968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
151595a0b26dSToby Isaac {
1516f7c74593SToby Isaac   Mat               refCmat;
151721968bf8SToby Isaac   PetscDS           ds;
1518085f0adfSToby Isaac   PetscInt          numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
151921968bf8SToby Isaac   PetscScalar       ***refPointFieldMats;
152021968bf8SToby Isaac   PetscSection      refConSec, refAnSec, refSection;
152121968bf8SToby Isaac   IS                refAnIS;
152221968bf8SToby Isaac   const PetscInt    *refAnchors;
1523085f0adfSToby Isaac   const PetscInt    **perms;
1524085f0adfSToby Isaac   const PetscScalar **flips;
152595a0b26dSToby Isaac   PetscErrorCode    ierr;
152695a0b26dSToby Isaac 
152795a0b26dSToby Isaac   PetscFunctionBegin;
152821968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
152995a0b26dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1530085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
1531f7c74593SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
1532a17985deSToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
153395a0b26dSToby Isaac   ierr = ISGetIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
153495a0b26dSToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
153595a0b26dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
153695a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
153795a0b26dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldN);CHKERRQ(ierr);
153895a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
153995a0b26dSToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
154095a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
154195a0b26dSToby Isaac   ierr = PetscMalloc1(maxDof*maxAnDof,&cols);CHKERRQ(ierr);
154295a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
154395a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
154495a0b26dSToby Isaac 
154595a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
154695a0b26dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
154795a0b26dSToby Isaac     if (!pDof || parent == p) continue;
154895a0b26dSToby Isaac 
1549085f0adfSToby Isaac     ierr = PetscMalloc1(maxFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
1550085f0adfSToby Isaac     ierr = PetscCalloc1(maxFields,&refPointFieldN[p-pRefStart]);CHKERRQ(ierr);
155195a0b26dSToby Isaac     ierr = DMPlexGetTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1552085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1553085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
155495a0b26dSToby Isaac 
1555085f0adfSToby Isaac       if (f < numFields) {
155695a0b26dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
155795a0b26dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
1558085f0adfSToby Isaac         ierr = PetscSectionGetFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1559085f0adfSToby Isaac       } else {
156095a0b26dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
156195a0b26dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
1562085f0adfSToby Isaac         ierr = PetscSectionGetPointSyms(refSection,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
156395a0b26dSToby Isaac       }
156495a0b26dSToby Isaac 
156595a0b26dSToby Isaac       for (r = 0; r < cDof; r++) {
156695a0b26dSToby Isaac         rows[r] = cOff + r;
156795a0b26dSToby Isaac       }
156895a0b26dSToby Isaac       numCols = 0;
156995a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
157095a0b26dSToby Isaac         PetscInt          q = closure[2*i];
157195a0b26dSToby Isaac         PetscInt          aDof, aOff, j;
1572085f0adfSToby Isaac         const PetscInt    *perm = perms ? perms[i] : NULL;
157395a0b26dSToby Isaac 
1574085f0adfSToby Isaac         if (numFields) {
157595a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
157695a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
157795a0b26dSToby Isaac         }
157895a0b26dSToby Isaac         else {
157995a0b26dSToby Isaac           ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
158095a0b26dSToby Isaac           ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
158195a0b26dSToby Isaac         }
158295a0b26dSToby Isaac 
158395a0b26dSToby Isaac         for (j = 0; j < aDof; j++) {
1584085f0adfSToby Isaac           cols[numCols++] = aOff + (perm ? perm[j] : j);
158595a0b26dSToby Isaac         }
158695a0b26dSToby Isaac       }
158795a0b26dSToby Isaac       refPointFieldN[p-pRefStart][f] = numCols;
158895a0b26dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
158995a0b26dSToby Isaac       ierr = MatGetValues(refCmat,cDof,rows,numCols,cols,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
1590085f0adfSToby Isaac       if (flips) {
1591085f0adfSToby Isaac         PetscInt colOff = 0;
1592085f0adfSToby Isaac 
1593085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1594085f0adfSToby Isaac           PetscInt          q = closure[2*i];
1595085f0adfSToby Isaac           PetscInt          aDof, aOff, j;
1596085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1597085f0adfSToby Isaac 
1598085f0adfSToby Isaac           if (numFields) {
1599085f0adfSToby Isaac             ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
1600085f0adfSToby Isaac             ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
1601085f0adfSToby Isaac           }
1602085f0adfSToby Isaac           else {
1603085f0adfSToby Isaac             ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
1604085f0adfSToby Isaac             ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
1605085f0adfSToby Isaac           }
1606085f0adfSToby Isaac           if (flip) {
1607085f0adfSToby Isaac             PetscInt k;
1608085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1609085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1610085f0adfSToby Isaac                 refPointFieldMats[p-pRefStart][f][k * numCols + colOff + j] *= flip[j];
1611085f0adfSToby Isaac               }
1612085f0adfSToby Isaac             }
1613085f0adfSToby Isaac           }
1614085f0adfSToby Isaac           colOff += aDof;
1615085f0adfSToby Isaac         }
1616085f0adfSToby Isaac       }
1617085f0adfSToby Isaac       if (numFields) {
1618085f0adfSToby Isaac         ierr = PetscSectionRestoreFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1619085f0adfSToby Isaac       } else {
1620085f0adfSToby Isaac         ierr = PetscSectionRestorePointSyms(refSection,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1621085f0adfSToby Isaac       }
162295a0b26dSToby Isaac     }
162395a0b26dSToby Isaac     ierr = DMPlexRestoreTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
162495a0b26dSToby Isaac   }
162521968bf8SToby Isaac   *childrenMats = refPointFieldMats;
162621968bf8SToby Isaac   *childrenN = refPointFieldN;
162721968bf8SToby Isaac   ierr = ISRestoreIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
162821968bf8SToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
162921968bf8SToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
163021968bf8SToby Isaac   PetscFunctionReturn(0);
163121968bf8SToby Isaac }
163221968bf8SToby Isaac 
163321968bf8SToby Isaac #undef __FUNCT__
163421968bf8SToby Isaac #define __FUNCT__ "DMPlexReferenceTreeRestoreChildrenMatrices"
163521968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
163621968bf8SToby Isaac {
163721968bf8SToby Isaac   PetscDS        ds;
163821968bf8SToby Isaac   PetscInt       **refPointFieldN;
163921968bf8SToby Isaac   PetscScalar    ***refPointFieldMats;
1640085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
164121968bf8SToby Isaac   PetscSection   refConSec;
164221968bf8SToby Isaac   PetscErrorCode ierr;
164321968bf8SToby Isaac 
164421968bf8SToby Isaac   PetscFunctionBegin;
164521968bf8SToby Isaac   refPointFieldN = *childrenN;
164621968bf8SToby Isaac   *childrenN = NULL;
164721968bf8SToby Isaac   refPointFieldMats = *childrenMats;
164821968bf8SToby Isaac   *childrenMats = NULL;
164921968bf8SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
165021968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1651085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);CHKERRQ(ierr);
165221968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
1653e44e4e7fSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
165421968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
165521968bf8SToby Isaac     PetscInt parent, pDof;
165621968bf8SToby Isaac 
165721968bf8SToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
165821968bf8SToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
165921968bf8SToby Isaac     if (!pDof || parent == p) continue;
166021968bf8SToby Isaac 
1661085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
166221968bf8SToby Isaac       PetscInt cDof;
166321968bf8SToby Isaac 
1664085f0adfSToby Isaac       if (numFields) {
166521968bf8SToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
166621968bf8SToby Isaac       }
166721968bf8SToby Isaac       else {
166821968bf8SToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
166921968bf8SToby Isaac       }
167021968bf8SToby Isaac 
167121968bf8SToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
167221968bf8SToby Isaac     }
167321968bf8SToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
167421968bf8SToby Isaac     ierr = PetscFree(refPointFieldN[p - pRefStart]);CHKERRQ(ierr);
167521968bf8SToby Isaac   }
167621968bf8SToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
167721968bf8SToby Isaac   ierr = PetscFree(refPointFieldN);CHKERRQ(ierr);
167821968bf8SToby Isaac   PetscFunctionReturn(0);
167921968bf8SToby Isaac }
168021968bf8SToby Isaac 
168121968bf8SToby Isaac #undef __FUNCT__
168221968bf8SToby Isaac #define __FUNCT__ "DMPlexComputeAnchorMatrix_Tree_FromReference"
168321968bf8SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
168421968bf8SToby Isaac {
168521968bf8SToby Isaac   DM             refTree;
168621968bf8SToby Isaac   PetscDS        ds;
168721968bf8SToby Isaac   Mat            refCmat;
1688085f0adfSToby Isaac   PetscInt       numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
168921968bf8SToby Isaac   PetscScalar ***refPointFieldMats, *pointWork;
169021968bf8SToby Isaac   PetscSection   refConSec, refAnSec, anSec;
169121968bf8SToby Isaac   IS             refAnIS, anIS;
169221968bf8SToby Isaac   const PetscInt *anchors;
169321968bf8SToby Isaac   PetscErrorCode ierr;
169421968bf8SToby Isaac 
169521968bf8SToby Isaac   PetscFunctionBegin;
169621968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
169721968bf8SToby Isaac   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
169821968bf8SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1699085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
170021968bf8SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
170121968bf8SToby Isaac   ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
170221968bf8SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
170321968bf8SToby Isaac   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
170421968bf8SToby Isaac   ierr = DMPlexGetAnchors(dm,&anSec,&anIS);CHKERRQ(ierr);
170521968bf8SToby Isaac   ierr = ISGetIndices(anIS,&anchors);CHKERRQ(ierr);
170621968bf8SToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
170721968bf8SToby Isaac   ierr = PetscSectionGetChart(conSec,&conStart,&conEnd);CHKERRQ(ierr);
170821968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
170921968bf8SToby Isaac   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
171021968bf8SToby Isaac   ierr = PetscMalloc1(maxDof*maxDof*maxAnDof,&pointWork);CHKERRQ(ierr);
171121968bf8SToby Isaac 
171221968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
171321968bf8SToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
171495a0b26dSToby Isaac 
171595a0b26dSToby Isaac   /* step 2: compute the preorder */
171695a0b26dSToby Isaac   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
171795a0b26dSToby Isaac   ierr = PetscMalloc2(pEnd-pStart,&perm,pEnd-pStart,&iperm);CHKERRQ(ierr);
171895a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
171995a0b26dSToby Isaac     perm[p - pStart] = p;
172095a0b26dSToby Isaac     iperm[p - pStart] = p-pStart;
172195a0b26dSToby Isaac   }
172295a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
172395a0b26dSToby Isaac     PetscInt point = perm[p];
172495a0b26dSToby Isaac     PetscInt parent;
172595a0b26dSToby Isaac 
172695a0b26dSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
172795a0b26dSToby Isaac     if (parent == point) {
172895a0b26dSToby Isaac       p++;
172995a0b26dSToby Isaac     }
173095a0b26dSToby Isaac     else {
173195a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
173295a0b26dSToby Isaac 
173395a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
173495a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
173595a0b26dSToby Isaac         PetscInt q = closure[2*i];
173695a0b26dSToby Isaac         if (iperm[q-pStart] > iperm[point-pStart]) {
173795a0b26dSToby Isaac           /* swap */
173895a0b26dSToby Isaac           perm[p]               = q;
173995a0b26dSToby Isaac           perm[iperm[q-pStart]] = point;
174095a0b26dSToby Isaac           iperm[point-pStart]   = iperm[q-pStart];
174195a0b26dSToby Isaac           iperm[q-pStart]       = p;
174295a0b26dSToby Isaac           break;
174395a0b26dSToby Isaac         }
174495a0b26dSToby Isaac       }
174595a0b26dSToby Isaac       size = closureSize;
174695a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
174795a0b26dSToby Isaac       if (i == size) {
174895a0b26dSToby Isaac         p++;
174995a0b26dSToby Isaac       }
175095a0b26dSToby Isaac     }
175195a0b26dSToby Isaac   }
175295a0b26dSToby Isaac 
175395a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
175495a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
175595a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
175695a0b26dSToby Isaac    * values outside of the Mat first.
175795a0b26dSToby Isaac    */
175895a0b26dSToby Isaac   {
175995a0b26dSToby Isaac     PetscInt nRows, row, nnz;
176095a0b26dSToby Isaac     PetscBool done;
176195a0b26dSToby Isaac     const PetscInt *ia, *ja;
176295a0b26dSToby Isaac     PetscScalar *vals;
176395a0b26dSToby Isaac 
176495a0b26dSToby Isaac     ierr = MatGetRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
176595a0b26dSToby Isaac     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not get RowIJ of constraint matrix");
176695a0b26dSToby Isaac     nnz  = ia[nRows];
176795a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
176895a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
176995a0b26dSToby Isaac     ierr = PetscMalloc1(nnz,&vals);CHKERRQ(ierr);
177095a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
177195a0b26dSToby Isaac       PetscInt        parent, childid, closureSize, *closure = NULL;
177295a0b26dSToby Isaac       PetscInt        point = perm[p], pointDof;
177395a0b26dSToby Isaac 
177495a0b26dSToby Isaac       ierr = DMPlexGetTreeParent(dm,point,&parent,&childid);CHKERRQ(ierr);
177595a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
177695a0b26dSToby Isaac       ierr = PetscSectionGetDof(conSec,point,&pointDof);CHKERRQ(ierr);
177795a0b26dSToby Isaac       if (!pointDof) continue;
177895a0b26dSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1779085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1780085f0adfSToby Isaac         PetscInt cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
178195a0b26dSToby Isaac         PetscScalar *pointMat;
1782085f0adfSToby Isaac         const PetscInt    **perms;
1783085f0adfSToby Isaac         const PetscScalar **flips;
178495a0b26dSToby Isaac 
1785085f0adfSToby Isaac         if (numFields) {
178695a0b26dSToby Isaac           ierr = PetscSectionGetFieldDof(conSec,point,f,&cDof);CHKERRQ(ierr);
178795a0b26dSToby Isaac           ierr = PetscSectionGetFieldOffset(conSec,point,f,&cOff);CHKERRQ(ierr);
178895a0b26dSToby Isaac         }
178995a0b26dSToby Isaac         else {
179095a0b26dSToby Isaac           ierr = PetscSectionGetDof(conSec,point,&cDof);CHKERRQ(ierr);
179195a0b26dSToby Isaac           ierr = PetscSectionGetOffset(conSec,point,&cOff);CHKERRQ(ierr);
179295a0b26dSToby Isaac         }
179395a0b26dSToby Isaac         if (!cDof) continue;
1794085f0adfSToby Isaac         if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);}
1795085f0adfSToby Isaac         else           {ierr = PetscSectionGetPointSyms(section,closureSize,closure,&perms,&flips);CHKERRQ(ierr);}
179695a0b26dSToby Isaac 
179795a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
179895a0b26dSToby Isaac #if defined(PETSC_USE_DEBUG)
179995a0b26dSToby Isaac         for (r = 0; r < cDof; r++) {
180095a0b26dSToby Isaac           if (cDof > 1 && r) {
180121968bf8SToby Isaac             if ((ia[cOff+r+1]-ia[cOff+r]) != (ia[cOff+r]-ia[cOff+r-1])) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Two point rows have different nnz: %D vs. %D", (ia[cOff+r+1]-ia[cOff+r]), (ia[cOff+r]-ia[cOff+r-1]));
180295a0b26dSToby Isaac           }
180395a0b26dSToby Isaac         }
180495a0b26dSToby Isaac #endif
180595a0b26dSToby Isaac         /* zero rows */
180695a0b26dSToby Isaac         for (i = ia[cOff] ; i< ia[cOff+cDof];i++) {
180795a0b26dSToby Isaac           vals[i] = 0.;
180895a0b26dSToby Isaac         }
180995a0b26dSToby Isaac         matOffset = ia[cOff];
181095a0b26dSToby Isaac         numFillCols = ia[cOff+1] - matOffset;
181195a0b26dSToby Isaac         pointMat = refPointFieldMats[childid-pRefStart][f];
181295a0b26dSToby Isaac         numCols = refPointFieldN[childid-pRefStart][f];
181395a0b26dSToby Isaac         offset = 0;
181495a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
181595a0b26dSToby Isaac           PetscInt q = closure[2*i];
181695a0b26dSToby Isaac           PetscInt aDof, aOff, j, k, qConDof, qConOff;
1817085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1818085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
181995a0b26dSToby Isaac 
182095a0b26dSToby Isaac           qConDof = qConOff = 0;
1821085f0adfSToby Isaac           if (numFields) {
182295a0b26dSToby Isaac             ierr = PetscSectionGetFieldDof(section,q,f,&aDof);CHKERRQ(ierr);
182395a0b26dSToby Isaac             ierr = PetscSectionGetFieldOffset(section,q,f,&aOff);CHKERRQ(ierr);
182495a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
182595a0b26dSToby Isaac               ierr = PetscSectionGetFieldDof(conSec,q,f,&qConDof);CHKERRQ(ierr);
182695a0b26dSToby Isaac               ierr = PetscSectionGetFieldOffset(conSec,q,f,&qConOff);CHKERRQ(ierr);
182795a0b26dSToby Isaac             }
182895a0b26dSToby Isaac           }
182995a0b26dSToby Isaac           else {
183095a0b26dSToby Isaac             ierr = PetscSectionGetDof(section,q,&aDof);CHKERRQ(ierr);
183195a0b26dSToby Isaac             ierr = PetscSectionGetOffset(section,q,&aOff);CHKERRQ(ierr);
183295a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
183395a0b26dSToby Isaac               ierr = PetscSectionGetDof(conSec,q,&qConDof);CHKERRQ(ierr);
183495a0b26dSToby Isaac               ierr = PetscSectionGetOffset(conSec,q,&qConOff);CHKERRQ(ierr);
183595a0b26dSToby Isaac             }
183695a0b26dSToby Isaac           }
183795a0b26dSToby Isaac           if (!aDof) continue;
183895a0b26dSToby Isaac           if (qConDof) {
183995a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
184095a0b26dSToby Isaac              * be filled, thanks to preordering */
184195a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
184295a0b26dSToby Isaac             PetscInt aMatOffset = ia[qConOff];
184395a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
184495a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
184595a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
184695a0b26dSToby Isaac                 PetscScalar inVal = 0;
184795a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1848085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
184995a0b26dSToby Isaac 
1850085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
185195a0b26dSToby Isaac                 }
185295a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
185395a0b26dSToby Isaac               }
185495a0b26dSToby Isaac             }
185595a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
185695a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
185795a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
185895a0b26dSToby Isaac               for (;k < numFillCols; k++) {
185995a0b26dSToby Isaac                 if (ja[matOffset + k] == col) {
186095a0b26dSToby Isaac                   break;
186195a0b26dSToby Isaac                 }
186295a0b26dSToby Isaac               }
186395a0b26dSToby Isaac               if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, col);
186495a0b26dSToby Isaac               for (r = 0; r < cDof; r++) {
186595a0b26dSToby Isaac                 vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
186695a0b26dSToby Isaac               }
186795a0b26dSToby Isaac             }
186895a0b26dSToby Isaac           }
186995a0b26dSToby Isaac           else {
187095a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
187195a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
187295a0b26dSToby Isaac               if (ja[matOffset + k] == aOff) {
187395a0b26dSToby Isaac                 break;
187495a0b26dSToby Isaac               }
187595a0b26dSToby Isaac             }
187695a0b26dSToby Isaac             if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, aOff);
187795a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1878085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1879085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1880085f0adfSToby Isaac 
1881085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
188295a0b26dSToby Isaac               }
188395a0b26dSToby Isaac             }
188495a0b26dSToby Isaac           }
188595a0b26dSToby Isaac           offset += aDof;
188695a0b26dSToby Isaac         }
1887085f0adfSToby Isaac         if (numFields) {
1888085f0adfSToby Isaac           ierr = PetscSectionRestoreFieldPointSyms(section,f,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1889085f0adfSToby Isaac         } else {
1890085f0adfSToby Isaac           ierr = PetscSectionRestorePointSyms(section,closureSize,closure,&perms,&flips);CHKERRQ(ierr);
1891085f0adfSToby Isaac         }
189295a0b26dSToby Isaac       }
189395a0b26dSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
189495a0b26dSToby Isaac     }
189595a0b26dSToby Isaac     for (row = 0; row < nRows; row++) {
189695a0b26dSToby Isaac       ierr = MatSetValues(cMat,1,&row,ia[row+1]-ia[row],&ja[ia[row]],&vals[ia[row]],INSERT_VALUES);CHKERRQ(ierr);
189795a0b26dSToby Isaac     }
189895a0b26dSToby Isaac     ierr = MatRestoreRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
189995a0b26dSToby Isaac     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not restore RowIJ of constraint matrix");
190095a0b26dSToby Isaac     ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
190195a0b26dSToby Isaac     ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
190295a0b26dSToby Isaac     ierr = PetscFree(vals);CHKERRQ(ierr);
190395a0b26dSToby Isaac   }
190495a0b26dSToby Isaac 
190595a0b26dSToby Isaac   /* clean up */
190695a0b26dSToby Isaac   ierr = ISRestoreIndices(anIS,&anchors);CHKERRQ(ierr);
190795a0b26dSToby Isaac   ierr = PetscFree2(perm,iperm);CHKERRQ(ierr);
190895a0b26dSToby Isaac   ierr = PetscFree(pointWork);CHKERRQ(ierr);
190921968bf8SToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
191095a0b26dSToby Isaac   PetscFunctionReturn(0);
191195a0b26dSToby Isaac }
191295a0b26dSToby Isaac 
19136f5f1567SToby Isaac #undef __FUNCT__
19146f5f1567SToby Isaac #define __FUNCT__ "DMPlexTreeRefineCell"
19156f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
19166f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
19176f5f1567SToby Isaac PetscErrorCode DMPlexTreeRefineCell (DM dm, PetscInt cell, DM *ncdm)
19186f5f1567SToby Isaac {
19196f5f1567SToby Isaac   DM K;
1920420f55faSMatthew G. Knepley   PetscMPIInt rank;
19216f5f1567SToby Isaac   PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
19226f5f1567SToby Isaac   PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations;
19236f5f1567SToby Isaac   PetscInt *Kembedding;
19246f5f1567SToby Isaac   PetscInt *cellClosure=NULL, nc;
19256f5f1567SToby Isaac   PetscScalar *newVertexCoords;
19266f5f1567SToby Isaac   PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
19276f5f1567SToby Isaac   PetscSection parentSection;
19286f5f1567SToby Isaac   PetscErrorCode ierr;
19296f5f1567SToby Isaac 
19306f5f1567SToby Isaac   PetscFunctionBegin;
19316f5f1567SToby Isaac   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRQ(ierr);
193228f4b327SMatthew G. Knepley   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
19336f5f1567SToby Isaac   ierr = DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm);CHKERRQ(ierr);
193428f4b327SMatthew G. Knepley   ierr = DMSetDimension(*ncdm,dim);CHKERRQ(ierr);
19356f5f1567SToby Isaac 
19366f5f1567SToby Isaac   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
19376f5f1567SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&parentSection);CHKERRQ(ierr);
19386f5f1567SToby Isaac   ierr = DMPlexGetReferenceTree(dm,&K);CHKERRQ(ierr);
19396f5f1567SToby Isaac   if (!rank) {
19406f5f1567SToby Isaac     /* compute the new charts */
19416f5f1567SToby Isaac     ierr = PetscMalloc5(dim+1,&pNewCount,dim+1,&pNewStart,dim+1,&pNewEnd,dim+1,&pOldStart,dim+1,&pOldEnd);CHKERRQ(ierr);
19426f5f1567SToby Isaac     offset = 0;
19436f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19446f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
19456f5f1567SToby Isaac 
19466f5f1567SToby Isaac       pNewStart[d] = offset;
19476f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(dm,d,&pOldStart[d],&pOldEnd[d]);CHKERRQ(ierr);
19486f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
19496f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
19506f5f1567SToby Isaac       /* adding the new points */
19516f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
19526f5f1567SToby Isaac       if (!d) {
19536f5f1567SToby Isaac         /* removing the cell */
19546f5f1567SToby Isaac         pNewCount[d]--;
19556f5f1567SToby Isaac       }
19566f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19576f5f1567SToby Isaac         PetscInt parent;
19586f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&parent,NULL);CHKERRQ(ierr);
19596f5f1567SToby Isaac         if (parent == k) {
19606f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
19616f5f1567SToby Isaac           pNewCount[d]--;
19626f5f1567SToby Isaac         }
19636f5f1567SToby Isaac       }
19646f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
19656f5f1567SToby Isaac       offset = pNewEnd[d];
19666f5f1567SToby Isaac 
19676f5f1567SToby Isaac     }
19686f5f1567SToby Isaac     if (cell < pOldStart[0] || cell >= pOldEnd[0]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"%d not in cell range [%d, %d)", cell, pOldStart[0], pOldEnd[0]);
19696f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
19706f5f1567SToby Isaac     ierr = DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
19716f5f1567SToby Isaac 
19726f5f1567SToby Isaac     ierr = PetscMalloc1(pNewEnd[dim],&newConeSizes);CHKERRQ(ierr);
19736f5f1567SToby Isaac     {
19746f5f1567SToby Isaac       PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
19756f5f1567SToby Isaac 
19766f5f1567SToby Isaac       ierr = DMPlexGetChart(K,&kStart,&kEnd);CHKERRQ(ierr);
19776f5f1567SToby Isaac       ierr = PetscMalloc4(kEnd-kStart,&Kembedding,kEnd-kStart,&perm,kEnd-kStart,&iperm,kEnd-kStart,&preOrient);CHKERRQ(ierr);
19786f5f1567SToby Isaac 
19796f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19806f5f1567SToby Isaac         perm[k - kStart] = k;
19816f5f1567SToby Isaac         iperm [k - kStart] = k - kStart;
19826f5f1567SToby Isaac         preOrient[k - kStart] = 0;
19836f5f1567SToby Isaac       }
19846f5f1567SToby Isaac 
19856f5f1567SToby Isaac       ierr = DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
19866f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
19876f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2*j+1];
19886f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2*j+1];
19896f5f1567SToby Isaac         PetscInt p, q;
19906f5f1567SToby Isaac 
19916f5f1567SToby Isaac         p = closureK[2*j];
19926f5f1567SToby Isaac         q = cellClosure[2*j];
19936f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
19946f5f1567SToby Isaac           if (q >= pOldStart[d] && q < pOldEnd[d]) {
19956f5f1567SToby Isaac             Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
19966f5f1567SToby Isaac           }
19976f5f1567SToby Isaac         }
19986f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
19996f5f1567SToby Isaac           PetscInt numChildren, i;
20006f5f1567SToby Isaac           const PetscInt *children;
20016f5f1567SToby Isaac 
20026f5f1567SToby Isaac           ierr = DMPlexGetTreeChildren(K,p,&numChildren,&children);CHKERRQ(ierr);
20036f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
20046f5f1567SToby Isaac             PetscInt kPerm, oPerm;
20056f5f1567SToby Isaac 
20066f5f1567SToby Isaac             k    = children[i];
20076f5f1567SToby Isaac             ierr = DMPlexReferenceTreeGetChildSymmetry(K,p,parentOrientA,0,k,parentOrientB,&oPerm,&kPerm);CHKERRQ(ierr);
20086f5f1567SToby Isaac             /* perm = what refTree position I'm in */
20096f5f1567SToby Isaac             perm[kPerm-kStart]      = k;
20106f5f1567SToby Isaac             /* iperm = who is at this position */
20116f5f1567SToby Isaac             iperm[k-kStart]         = kPerm-kStart;
20126f5f1567SToby Isaac             preOrient[kPerm-kStart] = oPerm;
20136f5f1567SToby Isaac           }
20146f5f1567SToby Isaac         }
20156f5f1567SToby Isaac       }
20166f5f1567SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
20176f5f1567SToby Isaac     }
20186f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,0,pNewEnd[dim]);CHKERRQ(ierr);
20196f5f1567SToby Isaac     offset = 0;
20206f5f1567SToby Isaac     numNewCones = 0;
20216f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20226f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
20236f5f1567SToby Isaac       PetscInt p;
20246f5f1567SToby Isaac       PetscInt size;
20256f5f1567SToby Isaac 
20266f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
20276f5f1567SToby Isaac         /* skip cell 0 */
20286f5f1567SToby Isaac         if (p == cell) continue;
20296f5f1567SToby Isaac         /* old cones to new cones */
20306f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
20316f5f1567SToby Isaac         newConeSizes[offset++] = size;
20326f5f1567SToby Isaac         numNewCones += size;
20336f5f1567SToby Isaac       }
20346f5f1567SToby Isaac 
20356f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
20366f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20376f5f1567SToby Isaac         PetscInt kParent;
20386f5f1567SToby Isaac 
20396f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
20406f5f1567SToby Isaac         if (kParent != k) {
20416f5f1567SToby Isaac           Kembedding[k] = offset;
20426f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
20436f5f1567SToby Isaac           newConeSizes[offset++] = size;
20446f5f1567SToby Isaac           numNewCones += size;
20456f5f1567SToby Isaac           if (kParent != 0) {
20466f5f1567SToby Isaac             ierr = PetscSectionSetDof(parentSection,Kembedding[k],1);CHKERRQ(ierr);
20476f5f1567SToby Isaac           }
20486f5f1567SToby Isaac         }
20496f5f1567SToby Isaac       }
20506f5f1567SToby Isaac     }
20516f5f1567SToby Isaac 
20526f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
20536f5f1567SToby Isaac     ierr = PetscSectionGetStorageSize(parentSection,&numPointsWithParents);CHKERRQ(ierr);
20546f5f1567SToby Isaac     ierr = PetscMalloc2(numNewCones,&newCones,numNewCones,&newOrientations);CHKERRQ(ierr);
20556f5f1567SToby Isaac     ierr = PetscMalloc2(numPointsWithParents,&parents,numPointsWithParents,&childIDs);CHKERRQ(ierr);
20566f5f1567SToby Isaac 
20576f5f1567SToby Isaac     /* fill new cones */
20586f5f1567SToby Isaac     offset = 0;
20596f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20606f5f1567SToby Isaac       PetscInt kStart, kEnd, k, l;
20616f5f1567SToby Isaac       PetscInt p;
20626f5f1567SToby Isaac       PetscInt size;
20636f5f1567SToby Isaac       const PetscInt *cone, *orientation;
20646f5f1567SToby Isaac 
20656f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
20666f5f1567SToby Isaac         /* skip cell 0 */
20676f5f1567SToby Isaac         if (p == cell) continue;
20686f5f1567SToby Isaac         /* old cones to new cones */
20696f5f1567SToby Isaac         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
20706f5f1567SToby Isaac         ierr = DMPlexGetCone(dm,p,&cone);CHKERRQ(ierr);
20716f5f1567SToby Isaac         ierr = DMPlexGetConeOrientation(dm,p,&orientation);CHKERRQ(ierr);
20726f5f1567SToby Isaac         for (l = 0; l < size; l++) {
20736f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
20746f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
20756f5f1567SToby Isaac         }
20766f5f1567SToby Isaac       }
20776f5f1567SToby Isaac 
20786f5f1567SToby Isaac       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
20796f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20806f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
20816f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
20826f5f1567SToby Isaac 
20836f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
20846f5f1567SToby Isaac         if (kParent != k) {
20856f5f1567SToby Isaac           /* embed new cones */
20866f5f1567SToby Isaac           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
20876f5f1567SToby Isaac           ierr = DMPlexGetCone(K,kPerm,&cone);CHKERRQ(ierr);
20886f5f1567SToby Isaac           ierr = DMPlexGetConeOrientation(K,kPerm,&orientation);CHKERRQ(ierr);
20896f5f1567SToby Isaac           for (l = 0; l < size; l++) {
20906f5f1567SToby Isaac             PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size -(preO + 1) - l) % size);
20916f5f1567SToby Isaac             PetscInt newO, lSize, oTrue;
20926f5f1567SToby Isaac 
20936f5f1567SToby Isaac             q                         = iperm[cone[m]];
20946f5f1567SToby Isaac             newCones[offset]          = Kembedding[q];
20956f5f1567SToby Isaac             ierr                      = DMPlexGetConeSize(K,q,&lSize);CHKERRQ(ierr);
20966f5f1567SToby Isaac             oTrue                     = orientation[m];
20976f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
20986f5f1567SToby Isaac             newO                      = DihedralCompose(lSize,oTrue,preOrient[q]);
20996f5f1567SToby Isaac             newOrientations[offset++] = newO;
21006f5f1567SToby Isaac           }
21016f5f1567SToby Isaac           if (kParent != 0) {
21026f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
21036f5f1567SToby Isaac             ierr              = PetscSectionGetOffset(parentSection,Kembedding[k],&pOffset);CHKERRQ(ierr);
21046f5f1567SToby Isaac             parents[pOffset]  = newPoint;
21056f5f1567SToby Isaac             childIDs[pOffset] = k;
21066f5f1567SToby Isaac           }
21076f5f1567SToby Isaac         }
21086f5f1567SToby Isaac       }
21096f5f1567SToby Isaac     }
21106f5f1567SToby Isaac 
21116f5f1567SToby Isaac     ierr = PetscMalloc1(dim*(pNewEnd[dim]-pNewStart[dim]),&newVertexCoords);CHKERRQ(ierr);
21126f5f1567SToby Isaac 
21136f5f1567SToby Isaac     /* fill coordinates */
21146f5f1567SToby Isaac     offset = 0;
21156f5f1567SToby Isaac     {
2116d90620a3SMatthew G. Knepley       PetscInt kStart, kEnd, l;
21176f5f1567SToby Isaac       PetscSection vSection;
21186f5f1567SToby Isaac       PetscInt v;
21196f5f1567SToby Isaac       Vec coords;
21206f5f1567SToby Isaac       PetscScalar *coordvals;
21216f5f1567SToby Isaac       PetscInt dof, off;
2122c111c6b7SMatthew G. Knepley       PetscReal v0[3], J[9], detJ;
21236f5f1567SToby Isaac 
21246f5f1567SToby Isaac #if defined(PETSC_USE_DEBUG)
2125d90620a3SMatthew G. Knepley       {
2126d90620a3SMatthew G. Knepley         PetscInt k;
21276f5f1567SToby Isaac         ierr = DMPlexGetHeightStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
21286f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
212973a7f2aaSMatthew G. Knepley           ierr = DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
21306f5f1567SToby Isaac           if (detJ <= 0.) SETERRQ1 (PETSC_COMM_SELF,PETSC_ERR_PLIB,"reference tree cell %d has bad determinant",k);
21316f5f1567SToby Isaac         }
2132d90620a3SMatthew G. Knepley       }
21336f5f1567SToby Isaac #endif
213473a7f2aaSMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
21356f5f1567SToby Isaac       ierr = DMGetCoordinateSection(dm,&vSection);CHKERRQ(ierr);
21366f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr);
21376f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
21386f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
21396f5f1567SToby Isaac 
21406f5f1567SToby Isaac         ierr = PetscSectionGetDof(vSection,v,&dof);CHKERRQ(ierr);
21416f5f1567SToby Isaac         ierr = PetscSectionGetOffset(vSection,v,&off);CHKERRQ(ierr);
21426f5f1567SToby Isaac         for (l = 0; l < dof; l++) {
21436f5f1567SToby Isaac           newVertexCoords[offset++] = coordvals[off + l];
21446f5f1567SToby Isaac         }
21456f5f1567SToby Isaac       }
21466f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21476f5f1567SToby Isaac 
21486f5f1567SToby Isaac       ierr = DMGetCoordinateSection(K,&vSection);CHKERRQ(ierr);
21496f5f1567SToby Isaac       ierr = DMGetCoordinatesLocal(K,&coords);CHKERRQ(ierr);
21506f5f1567SToby Isaac       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
21516f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
21526f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
21539bc368c7SMatthew G. Knepley         PetscReal coord[3], newCoord[3];
21546f5f1567SToby Isaac         PetscInt  vPerm = perm[v];
21556f5f1567SToby Isaac         PetscInt  kParent;
21566f5f1567SToby Isaac 
21576f5f1567SToby Isaac         ierr = DMPlexGetTreeParent(K,v,&kParent,NULL);CHKERRQ(ierr);
21586f5f1567SToby Isaac         if (kParent != v) {
21596f5f1567SToby Isaac           /* this is a new vertex */
21606f5f1567SToby Isaac           ierr = PetscSectionGetOffset(vSection,vPerm,&off);CHKERRQ(ierr);
21619bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off+l]);
21629bc368c7SMatthew G. Knepley           CoordinatesRefToReal(dim, dim, v0, J, coord, newCoord);CHKERRQ(ierr);
21639bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset+l] = newCoord[l];
21646f5f1567SToby Isaac           offset += dim;
21656f5f1567SToby Isaac         }
21666f5f1567SToby Isaac       }
21676f5f1567SToby Isaac       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
21686f5f1567SToby Isaac     }
21696f5f1567SToby Isaac 
21706f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
21716f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
21726f5f1567SToby Isaac       PetscInt tmp;
21736f5f1567SToby Isaac 
21746f5f1567SToby Isaac       tmp = pNewCount[d];
21756f5f1567SToby Isaac       pNewCount[d] = pNewCount[dim - d];
21766f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
21776f5f1567SToby Isaac     }
21786f5f1567SToby Isaac 
21796f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,pNewCount,newConeSizes,newCones,newOrientations,newVertexCoords);CHKERRQ(ierr);
21806f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
21816f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,parents,childIDs);CHKERRQ(ierr);
21826f5f1567SToby Isaac 
21836f5f1567SToby Isaac     /* clean up */
21846f5f1567SToby Isaac     ierr = DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
21856f5f1567SToby Isaac     ierr = PetscFree5(pNewCount,pNewStart,pNewEnd,pOldStart,pOldEnd);CHKERRQ(ierr);
21866f5f1567SToby Isaac     ierr = PetscFree(newConeSizes);CHKERRQ(ierr);
21876f5f1567SToby Isaac     ierr = PetscFree2(newCones,newOrientations);CHKERRQ(ierr);
21886f5f1567SToby Isaac     ierr = PetscFree(newVertexCoords);CHKERRQ(ierr);
21896f5f1567SToby Isaac     ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
21906f5f1567SToby Isaac     ierr = PetscFree4(Kembedding,perm,iperm,preOrient);CHKERRQ(ierr);
21916f5f1567SToby Isaac   }
21926f5f1567SToby Isaac   else {
21936f5f1567SToby Isaac     PetscInt    p, counts[4];
21946f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
21956f5f1567SToby Isaac     Vec         coordVec;
21966f5f1567SToby Isaac     PetscScalar *coords;
21976f5f1567SToby Isaac 
21986f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
21996f5f1567SToby Isaac       PetscInt dStart, dEnd;
22006f5f1567SToby Isaac 
22016f5f1567SToby Isaac       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
22026f5f1567SToby Isaac       counts[d] = dEnd - dStart;
22036f5f1567SToby Isaac     }
22046f5f1567SToby Isaac     ierr = PetscMalloc1(pEnd-pStart,&coneSizes);CHKERRQ(ierr);
22056f5f1567SToby Isaac     for (p = pStart; p < pEnd; p++) {
22066f5f1567SToby Isaac       ierr = DMPlexGetConeSize(dm,p,&coneSizes[p-pStart]);CHKERRQ(ierr);
22076f5f1567SToby Isaac     }
22086f5f1567SToby Isaac     ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
22096f5f1567SToby Isaac     ierr = DMPlexGetConeOrientations(dm, &orientations);CHKERRQ(ierr);
22106f5f1567SToby Isaac     ierr = DMGetCoordinatesLocal(dm,&coordVec);CHKERRQ(ierr);
22116f5f1567SToby Isaac     ierr = VecGetArray(coordVec,&coords);CHKERRQ(ierr);
22126f5f1567SToby Isaac 
22136f5f1567SToby Isaac     ierr = PetscSectionSetChart(parentSection,pStart,pEnd);CHKERRQ(ierr);
22146f5f1567SToby Isaac     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
22156f5f1567SToby Isaac     ierr = DMPlexCreateFromDAG(*ncdm,dim,counts,coneSizes,cones,orientations,NULL);CHKERRQ(ierr);
22166f5f1567SToby Isaac     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
22176f5f1567SToby Isaac     ierr = DMPlexSetTree(*ncdm,parentSection,NULL,NULL);CHKERRQ(ierr);
22186f5f1567SToby Isaac     ierr = VecRestoreArray(coordVec,&coords);CHKERRQ(ierr);
22196f5f1567SToby Isaac   }
22206f5f1567SToby Isaac   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
22216f5f1567SToby Isaac 
22226f5f1567SToby Isaac   PetscFunctionReturn(0);
22236f5f1567SToby Isaac }
22246ecaa68aSToby Isaac 
22256ecaa68aSToby Isaac #undef __FUNCT__
22266ecaa68aSToby Isaac #define __FUNCT__ "DMPlexComputeInterpolatorTree"
22276ecaa68aSToby Isaac PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
22286ecaa68aSToby Isaac {
22296ecaa68aSToby Isaac   PetscSF           coarseToFineEmbedded;
22306ecaa68aSToby Isaac   PetscSection      globalCoarse, globalFine;
22316ecaa68aSToby Isaac   PetscSection      localCoarse, localFine;
22326ecaa68aSToby Isaac   PetscSection      aSec, cSec;
22336ecaa68aSToby Isaac   PetscSection      rootIndicesSec, rootMatricesSec;
223446bdb399SToby Isaac   PetscSection      leafIndicesSec, leafMatricesSec;
223546bdb399SToby Isaac   PetscInt          *rootIndices, *leafIndices;
223646bdb399SToby Isaac   PetscScalar       *rootMatrices, *leafMatrices;
22376ecaa68aSToby Isaac   IS                aIS;
22386ecaa68aSToby Isaac   const PetscInt    *anchors;
22396ecaa68aSToby Isaac   Mat               cMat;
22404acb8e1eSToby Isaac   PetscInt          numFields, maxFields;
22416ecaa68aSToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p;
22426ecaa68aSToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
22431c58ffc4SToby Isaac   PetscInt          *maxChildIds;
2244e44e4e7fSToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
22454acb8e1eSToby Isaac   const PetscInt    ***perms;
22464acb8e1eSToby Isaac   const PetscScalar ***flips;
22476ecaa68aSToby Isaac   PetscErrorCode    ierr;
22486ecaa68aSToby Isaac 
22496ecaa68aSToby Isaac   PetscFunctionBegin;
22506ecaa68aSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
22516ecaa68aSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
22526ecaa68aSToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
22536ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
225489698031SToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
225589698031SToby Isaac     const PetscInt *leaves;
22566ecaa68aSToby Isaac 
225789698031SToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
225889698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
225989698031SToby Isaac       p = leaves ? leaves[l] : l;
22606ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22616ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22626ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
22636ecaa68aSToby Isaac         numPointsWithDofs++;
22646ecaa68aSToby Isaac       }
22656ecaa68aSToby Isaac     }
22666ecaa68aSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
22677cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
226889698031SToby Isaac       p = leaves ? leaves[l] : l;
22696ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
22706ecaa68aSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
22716ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
227289698031SToby Isaac         pointsWithDofs[offset++] = l;
22736ecaa68aSToby Isaac       }
22746ecaa68aSToby Isaac     }
22756ecaa68aSToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
2276ec92bd66SToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
22776ecaa68aSToby Isaac   }
22786ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
22796ecaa68aSToby Isaac   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
22806ecaa68aSToby Isaac   for (p = pStartC; p < pEndC; p++) {
22818d2f55e7SToby Isaac     maxChildIds[p - pStartC] = -2;
22826ecaa68aSToby Isaac   }
22836ecaa68aSToby Isaac   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
22846ecaa68aSToby Isaac   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
228546bdb399SToby Isaac 
22866ecaa68aSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
22876ecaa68aSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
228846bdb399SToby Isaac 
22896ecaa68aSToby Isaac   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
22906ecaa68aSToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
22916ecaa68aSToby Isaac   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
229246bdb399SToby Isaac 
22936ecaa68aSToby Isaac   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
22946ecaa68aSToby Isaac   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
229546bdb399SToby Isaac 
229646bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
22976ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
22986ecaa68aSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootMatricesSec);CHKERRQ(ierr);
22996ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootIndicesSec,pStartC,pEndC);CHKERRQ(ierr);
23006ecaa68aSToby Isaac   ierr = PetscSectionSetChart(rootMatricesSec,pStartC,pEndC);CHKERRQ(ierr);
2301708c7f19SToby Isaac   ierr = PetscSectionGetNumFields(localCoarse,&numFields);CHKERRQ(ierr);
23024acb8e1eSToby Isaac   maxFields = PetscMax(1,numFields) + 1;
2303e44e4e7fSToby Isaac   ierr = PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO);CHKERRQ(ierr);
23041a834cf9SToby Isaac   ierr = PetscMalloc2(maxFields,&perms,maxFields,&flips);CHKERRQ(ierr);
23051a834cf9SToby Isaac   ierr = PetscMemzero((void *) perms, maxFields * sizeof(const PetscInt **));CHKERRQ(ierr);
23061a834cf9SToby Isaac   ierr = PetscMemzero((void *) flips, maxFields * sizeof(const PetscScalar **));CHKERRQ(ierr);
230746bdb399SToby Isaac 
230846bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
23098d2f55e7SToby Isaac     PetscInt dof, matSize   = 0;
23106ecaa68aSToby Isaac     PetscInt aDof           = 0;
23116ecaa68aSToby Isaac     PetscInt cDof           = 0;
23126ecaa68aSToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
23136ecaa68aSToby Isaac     PetscInt numRowIndices  = 0;
23146ecaa68aSToby Isaac     PetscInt numColIndices  = 0;
2315f13f9184SToby Isaac     PetscInt f;
23166ecaa68aSToby Isaac 
23176ecaa68aSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
23181cfc5b76SToby Isaac     if (dof < 0) {
23191cfc5b76SToby Isaac       dof = -(dof + 1);
23201cfc5b76SToby Isaac     }
23216ecaa68aSToby Isaac     if (p >= aStart && p < aEnd) {
23226ecaa68aSToby Isaac       ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
23236ecaa68aSToby Isaac     }
23246ecaa68aSToby Isaac     if (p >= cStart && p < cEnd) {
23256ecaa68aSToby Isaac       ierr = PetscSectionGetDof(cSec,p,&cDof);CHKERRQ(ierr);
23266ecaa68aSToby Isaac     }
2327f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2328f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
23296ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2330f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
23316ecaa68aSToby Isaac 
23326ecaa68aSToby Isaac       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
233346bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
23346ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
23356ecaa68aSToby Isaac 
23366ecaa68aSToby Isaac         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
23376ecaa68aSToby Isaac         numRowIndices += clDof;
23386ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23396ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,c,f,&clDof);CHKERRQ(ierr);
23406ecaa68aSToby Isaac           offsets[f + 1] += clDof;
23416ecaa68aSToby Isaac         }
23426ecaa68aSToby Isaac       }
23436ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
23446ecaa68aSToby Isaac         offsets[f + 1]   += offsets[f];
23456ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
23466ecaa68aSToby Isaac       }
234746bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
23484acb8e1eSToby Isaac       ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,NULL,NULL,NULL,&numColIndices,NULL,NULL,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
23496ecaa68aSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
23506ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
23516ecaa68aSToby Isaac         numColIndices = numRowIndices;
23526ecaa68aSToby Isaac         matSize = 0;
23536ecaa68aSToby Isaac       }
235446bdb399SToby Isaac       else if (numFields) { /* we send one submat for each field: sum their sizes */
23556ecaa68aSToby Isaac         matSize = 0;
23566ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23576ecaa68aSToby Isaac           PetscInt numRow, numCol;
23586ecaa68aSToby Isaac 
23596ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2360f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
23616ecaa68aSToby Isaac           matSize += numRow * numCol;
23626ecaa68aSToby Isaac         }
23636ecaa68aSToby Isaac       }
23646ecaa68aSToby Isaac       else {
23656ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
23666ecaa68aSToby Isaac       }
2367f13f9184SToby Isaac     } else if (maxChildId == -1) {
23688d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2369f13f9184SToby Isaac         PetscInt aOff, a;
23706ecaa68aSToby Isaac 
23716ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
23726ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23736ecaa68aSToby Isaac           PetscInt fDof;
23746ecaa68aSToby Isaac 
23756ecaa68aSToby Isaac           ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
237621968bf8SToby Isaac           offsets[f+1] = fDof;
23776ecaa68aSToby Isaac         }
23786ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
23796ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
23806ecaa68aSToby Isaac 
23816ecaa68aSToby Isaac           ierr = PetscSectionGetDof(localCoarse,anchor,&aLocalDof);CHKERRQ(ierr);
23826ecaa68aSToby Isaac           numColIndices += aLocalDof;
23836ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23846ecaa68aSToby Isaac             PetscInt fDof;
23856ecaa68aSToby Isaac 
23866ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
238721968bf8SToby Isaac             newOffsets[f+1] += fDof;
23886ecaa68aSToby Isaac           }
23896ecaa68aSToby Isaac         }
23906ecaa68aSToby Isaac         if (numFields) {
23916ecaa68aSToby Isaac           matSize = 0;
23926ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
239321968bf8SToby Isaac             matSize += offsets[f+1] * newOffsets[f+1];
23946ecaa68aSToby Isaac           }
23956ecaa68aSToby Isaac         }
23966ecaa68aSToby Isaac         else {
23976ecaa68aSToby Isaac           matSize = numColIndices * dof;
23986ecaa68aSToby Isaac         }
23996ecaa68aSToby Isaac       }
24006ecaa68aSToby Isaac       else { /* no children, and no constraints on dofs: just get the global indices */
24016ecaa68aSToby Isaac         numColIndices = dof;
24026ecaa68aSToby Isaac         matSize       = 0;
24036ecaa68aSToby Isaac       }
24048d2f55e7SToby Isaac     }
240546bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
24066ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootIndicesSec,p,numColIndices ? numColIndices+2*numFields : 0);CHKERRQ(ierr);
24076ecaa68aSToby Isaac     ierr = PetscSectionSetDof(rootMatricesSec,p,matSize);CHKERRQ(ierr);
24086ecaa68aSToby Isaac   }
24096ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootIndicesSec);CHKERRQ(ierr);
24106ecaa68aSToby Isaac   ierr = PetscSectionSetUp(rootMatricesSec);CHKERRQ(ierr);
24116ecaa68aSToby Isaac   {
24126ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
24136ecaa68aSToby Isaac 
24146ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
24156ecaa68aSToby Isaac     ierr = PetscSectionGetStorageSize(rootMatricesSec,&numRootMatrices);CHKERRQ(ierr);
24166ecaa68aSToby Isaac     ierr = PetscMalloc2(numRootIndices,&rootIndices,numRootMatrices,&rootMatrices);CHKERRQ(ierr);
24176ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
24186ecaa68aSToby Isaac       PetscInt    numRowIndices, numColIndices, matSize, dof;
2419f13f9184SToby Isaac       PetscInt    pIndOff, pMatOff, f;
24206ecaa68aSToby Isaac       PetscInt    *pInd;
24216ecaa68aSToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
24226ecaa68aSToby Isaac       PetscScalar *pMat = NULL;
24236ecaa68aSToby Isaac 
24246ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,p,&numColIndices);CHKERRQ(ierr);
24256ecaa68aSToby Isaac       if (!numColIndices) {
24266ecaa68aSToby Isaac         continue;
24276ecaa68aSToby Isaac       }
2428f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2429f13f9184SToby Isaac         offsets[f]        = 0;
2430f13f9184SToby Isaac         newOffsets[f]     = 0;
2431f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2432f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2433f13f9184SToby Isaac       }
24346ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
24356ecaa68aSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,p,&pIndOff);CHKERRQ(ierr);
24366ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
24376ecaa68aSToby Isaac       ierr = PetscSectionGetDof(rootMatricesSec,p,&matSize);CHKERRQ(ierr);
24386ecaa68aSToby Isaac       if (matSize) {
24396ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(rootMatricesSec,p,&pMatOff);CHKERRQ(ierr);
24406ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
24416ecaa68aSToby Isaac       }
24426ecaa68aSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
24431cfc5b76SToby Isaac       if (dof < 0) {
24441cfc5b76SToby Isaac         dof = -(dof + 1);
24451cfc5b76SToby Isaac       }
24466ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
24476ecaa68aSToby Isaac         PetscInt i, j;
24486ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
24496ecaa68aSToby Isaac 
24506ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
24516ecaa68aSToby Isaac           PetscInt numIndices, *indices;
24526ecaa68aSToby Isaac           ierr = DMPlexGetClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
24536ecaa68aSToby Isaac           if (numIndices != numColIndices) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"mismatching constraint indices calculations");
24546ecaa68aSToby Isaac           for (i = 0; i < numColIndices; i++) {
24556ecaa68aSToby Isaac             pInd[i] = indices[i];
24566ecaa68aSToby Isaac           }
24576ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
245846bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i+1];
245946bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i+1];
24606ecaa68aSToby Isaac           }
246146bdb399SToby Isaac           ierr = DMPlexRestoreClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
24626ecaa68aSToby Isaac         }
24636ecaa68aSToby Isaac         else {
24646ecaa68aSToby Isaac           PetscInt closureSize, *closure = NULL, cl;
24656ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
24666ecaa68aSToby Isaac           PetscInt numPoints,*points;
24676ecaa68aSToby Isaac 
24686ecaa68aSToby Isaac           ierr = DMGetWorkArray(coarse,numRowIndices * numRowIndices,PETSC_SCALAR,&pMatIn);CHKERRQ(ierr);
24696ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
24706ecaa68aSToby Isaac             for (j = 0; j < numRowIndices; j++) {
24716ecaa68aSToby Isaac               pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
24726ecaa68aSToby Isaac             }
24736ecaa68aSToby Isaac           }
24746ecaa68aSToby Isaac           ierr = DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
24754acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24764acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionGetFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24774acb8e1eSToby Isaac             else           {ierr = PetscSectionGetPointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
24784acb8e1eSToby Isaac           }
24796ecaa68aSToby Isaac           if (numFields) {
24806ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
24816ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
24826ecaa68aSToby Isaac 
24836ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
24846ecaa68aSToby Isaac                 PetscInt fDof;
24856ecaa68aSToby Isaac 
24866ecaa68aSToby Isaac                 ierr = PetscSectionGetFieldDof(localCoarse,c,f,&fDof);CHKERRQ(ierr);
24876ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
24886ecaa68aSToby Isaac               }
24896ecaa68aSToby Isaac             }
24906ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
24916ecaa68aSToby Isaac               offsets[f + 1]   += offsets[f];
24926ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
24936ecaa68aSToby Isaac             }
24946ecaa68aSToby Isaac           }
24954acb8e1eSToby Isaac           /* TODO : flips here ? */
24966ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
24974acb8e1eSToby Isaac           ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,perms,pMatIn,&numPoints,NULL,&points,&pMatModified,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
24984acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24994acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
25004acb8e1eSToby Isaac             else           {ierr = PetscSectionRestorePointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]);CHKERRQ(ierr);}
25014acb8e1eSToby Isaac           }
25024acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
25034acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionGetFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
25044acb8e1eSToby Isaac             else           {ierr = PetscSectionGetPointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
25054acb8e1eSToby Isaac           }
25066ecaa68aSToby Isaac           if (!numFields) {
25076ecaa68aSToby Isaac             for (i = 0; i < numRowIndices * numColIndices; i++) {
25086ecaa68aSToby Isaac               pMat[i] = pMatModified[i];
25096ecaa68aSToby Isaac             }
25106ecaa68aSToby Isaac           }
25116ecaa68aSToby Isaac           else {
2512f13f9184SToby Isaac             PetscInt i, j, count;
25136ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
25146ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f+1]; i++) {
25156ecaa68aSToby Isaac                 for (j = newOffsets[f]; j < newOffsets[f+1]; j++, count++) {
25166ecaa68aSToby Isaac                   pMat[count] = pMatModified[i * numColIndices + j];
25176ecaa68aSToby Isaac                 }
25186ecaa68aSToby Isaac               }
25196ecaa68aSToby Isaac             }
25206ecaa68aSToby Isaac           }
25216ecaa68aSToby Isaac           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,PETSC_SCALAR,&pMatModified);CHKERRQ(ierr);
25226ecaa68aSToby Isaac           ierr = DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
25236ecaa68aSToby Isaac           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,PETSC_SCALAR,&pMatIn);CHKERRQ(ierr);
25246ecaa68aSToby Isaac           if (numFields) {
252546bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
252646bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f+1];
252746bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f+1];
25286ecaa68aSToby Isaac             }
25294acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
25304acb8e1eSToby Isaac               PetscInt globalOff, c = points[2*cl];
25316ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
25324acb8e1eSToby Isaac               DMPlexGetIndicesPointFields_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, pInd);
25336ecaa68aSToby Isaac             }
25346ecaa68aSToby Isaac           } else {
25354acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
25364acb8e1eSToby Isaac               PetscInt c = points[2*cl], globalOff;
25374acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
25384acb8e1eSToby Isaac 
25396ecaa68aSToby Isaac               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
25404acb8e1eSToby Isaac               DMPlexGetIndicesPoint_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perm, pInd);
25416ecaa68aSToby Isaac             }
25426ecaa68aSToby Isaac           }
25434acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
25444acb8e1eSToby Isaac             if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
25454acb8e1eSToby Isaac             else           {ierr = PetscSectionRestorePointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
25464acb8e1eSToby Isaac           }
254728552ed4SToby Isaac           ierr = DMRestoreWorkArray(coarse,numPoints,PETSC_SCALAR,&points);CHKERRQ(ierr);
25486ecaa68aSToby Isaac         }
25496ecaa68aSToby Isaac       }
25506ecaa68aSToby Isaac       else if (matSize) {
25516ecaa68aSToby Isaac         PetscInt cOff;
25526ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
25536ecaa68aSToby Isaac 
25546ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
2555628cbfb8SToby Isaac         if (numRowIndices != dof) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Miscounted dofs");
25566ecaa68aSToby Isaac         ierr = DMGetWorkArray(coarse,numRowIndices,PETSC_INT,&rowIndices);CHKERRQ(ierr);
25576ecaa68aSToby Isaac         ierr = DMGetWorkArray(coarse,numColIndices,PETSC_INT,&colIndices);CHKERRQ(ierr);
25586ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(cSec,p,&cOff);CHKERRQ(ierr);
25596ecaa68aSToby Isaac         ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
25606ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
25616ecaa68aSToby Isaac         if (numFields) {
25626ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25636ecaa68aSToby Isaac             PetscInt fDof;
2564f13f9184SToby Isaac 
25656ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(cSec,p,f,&fDof);CHKERRQ(ierr);
25666ecaa68aSToby Isaac             offsets[f + 1] = fDof;
25676ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
25686ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
25696ecaa68aSToby Isaac               ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
25706ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
25716ecaa68aSToby Isaac             }
25726ecaa68aSToby Isaac           }
25736ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25746ecaa68aSToby Isaac             offsets[f + 1]       += offsets[f];
25756ecaa68aSToby Isaac             offsetsCopy[f + 1]    = offsets[f + 1];
25766ecaa68aSToby Isaac             newOffsets[f + 1]    += newOffsets[f];
25776ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
25786ecaa68aSToby Isaac           }
25794acb8e1eSToby Isaac           DMPlexGetIndicesPointFields_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,NULL,-1,rowIndices);CHKERRQ(ierr);
25806ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25816ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25826ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
25834acb8e1eSToby Isaac             DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL,-1,colIndices);CHKERRQ(ierr);
25846ecaa68aSToby Isaac           }
25856ecaa68aSToby Isaac         }
25866ecaa68aSToby Isaac         else {
25874acb8e1eSToby Isaac           DMPlexGetIndicesPoint_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,NULL,rowIndices);CHKERRQ(ierr);
25886ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25896ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25906ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
25914acb8e1eSToby Isaac             DMPlexGetIndicesPoint_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL,colIndices);CHKERRQ(ierr);
25926ecaa68aSToby Isaac           }
25936ecaa68aSToby Isaac         }
25946ecaa68aSToby Isaac         if (numFields) {
2595f13f9184SToby Isaac           PetscInt count, a;
2596f13f9184SToby Isaac 
25976ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
25986ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
25996ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
26006ecaa68aSToby Isaac             ierr = MatGetValues(cMat,iSize,&rowIndices[offsets[f]],jSize,&colIndices[newOffsets[f]],&pMat[count]);CHKERRQ(ierr);
26016ecaa68aSToby Isaac             count += iSize * jSize;
260246bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
260346bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f+1];
26046ecaa68aSToby Isaac           }
26056ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
26066ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
26076ecaa68aSToby Isaac             PetscInt gOff;
26086ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
26094acb8e1eSToby Isaac             DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL,-1,pInd);CHKERRQ(ierr);
26106ecaa68aSToby Isaac           }
26116ecaa68aSToby Isaac         }
26126ecaa68aSToby Isaac         else {
26136ecaa68aSToby Isaac           PetscInt a;
26146ecaa68aSToby Isaac           ierr = MatGetValues(cMat,numRowIndices,rowIndices,numColIndices,colIndices,pMat);CHKERRQ(ierr);
26156ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
26166ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
26176ecaa68aSToby Isaac             PetscInt gOff;
26186ecaa68aSToby Isaac             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
26194acb8e1eSToby Isaac             DMPlexGetIndicesPoint_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL,pInd);CHKERRQ(ierr);
26206ecaa68aSToby Isaac           }
26216ecaa68aSToby Isaac         }
26226ecaa68aSToby Isaac         ierr = DMRestoreWorkArray(coarse,numColIndices,PETSC_INT,&colIndices);CHKERRQ(ierr);
26236ecaa68aSToby Isaac         ierr = DMRestoreWorkArray(coarse,numRowIndices,PETSC_INT,&rowIndices);CHKERRQ(ierr);
26246ecaa68aSToby Isaac       }
26256ecaa68aSToby Isaac       else {
26266ecaa68aSToby Isaac         PetscInt gOff;
26276ecaa68aSToby Isaac 
26286ecaa68aSToby Isaac         ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
26296ecaa68aSToby Isaac         if (numFields) {
26306ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
26316ecaa68aSToby Isaac             PetscInt fDof;
26326ecaa68aSToby Isaac             ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
26336ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
26346ecaa68aSToby Isaac           }
26356ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
263646bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
263746bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f+1];
26386ecaa68aSToby Isaac           }
26394acb8e1eSToby Isaac           DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1,pInd);CHKERRQ(ierr);
26406ecaa68aSToby Isaac         }
26416ecaa68aSToby Isaac         else {
26424acb8e1eSToby Isaac           DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,pInd);CHKERRQ(ierr);
26436ecaa68aSToby Isaac         }
26446ecaa68aSToby Isaac       }
26456ecaa68aSToby Isaac     }
2646e44e4e7fSToby Isaac     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
26476ecaa68aSToby Isaac   }
264846bdb399SToby Isaac   {
264946bdb399SToby Isaac     PetscSF  indicesSF, matricesSF;
265046bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
265146bdb399SToby Isaac 
265246bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
265346bdb399SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafMatricesSec);CHKERRQ(ierr);
265446bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootIndicesSec,&remoteOffsetsIndices,leafIndicesSec);CHKERRQ(ierr);
265546bdb399SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootMatricesSec,&remoteOffsetsMatrices,leafMatricesSec);CHKERRQ(ierr);
265646bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootIndicesSec,remoteOffsetsIndices,leafIndicesSec,&indicesSF);CHKERRQ(ierr);
265746bdb399SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootMatricesSec,remoteOffsetsMatrices,leafMatricesSec,&matricesSF);CHKERRQ(ierr);
2658e44e4e7fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
265946bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsIndices);CHKERRQ(ierr);
266046bdb399SToby Isaac     ierr = PetscFree(remoteOffsetsMatrices);CHKERRQ(ierr);
266146bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numLeafIndices);CHKERRQ(ierr);
266246bdb399SToby Isaac     ierr = PetscSectionGetStorageSize(leafMatricesSec,&numLeafMatrices);CHKERRQ(ierr);
266346bdb399SToby Isaac     ierr = PetscMalloc2(numLeafIndices,&leafIndices,numLeafMatrices,&leafMatrices);CHKERRQ(ierr);
266446bdb399SToby Isaac     ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2665267d4f3fSToby Isaac     ierr = PetscSFBcastBegin(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
266646bdb399SToby Isaac     ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2667267d4f3fSToby Isaac     ierr = PetscSFBcastEnd(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
266846bdb399SToby Isaac     ierr = PetscSFDestroy(&matricesSF);CHKERRQ(ierr);
266946bdb399SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
267046bdb399SToby Isaac     ierr = PetscFree2(rootIndices,rootMatrices);CHKERRQ(ierr);
267146bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
267246bdb399SToby Isaac     ierr = PetscSectionDestroy(&rootMatricesSec);CHKERRQ(ierr);
267346bdb399SToby Isaac   }
267446bdb399SToby Isaac   /* count to preallocate */
267546bdb399SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
267646bdb399SToby Isaac   {
267746bdb399SToby Isaac     PetscInt    nGlobal;
267846bdb399SToby Isaac     PetscInt    *dnnz, *onnz;
2679b9a5774bSToby Isaac     PetscLayout rowMap, colMap;
2680b9a5774bSToby Isaac     PetscInt    rowStart, rowEnd, colStart, colEnd;
26811c58ffc4SToby Isaac     PetscInt    maxDof;
26821c58ffc4SToby Isaac     PetscInt    *rowIndices;
26831c58ffc4SToby Isaac     DM           refTree;
26841c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
26851c58ffc4SToby Isaac     PetscScalar  ***refPointFieldMats;
26861c58ffc4SToby Isaac     PetscSection refConSec, refAnSec;
26870eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,maxConDof,maxColumns,leafStart,leafEnd;
26881c58ffc4SToby Isaac     PetscScalar  *pointWork;
268946bdb399SToby Isaac 
269046bdb399SToby Isaac     ierr = PetscSectionGetConstrainedStorageSize(globalFine,&nGlobal);CHKERRQ(ierr);
269146bdb399SToby Isaac     ierr = PetscCalloc2(nGlobal,&dnnz,nGlobal,&onnz);CHKERRQ(ierr);
2692b9a5774bSToby Isaac     ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
2693b9a5774bSToby Isaac     ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
26941c58ffc4SToby Isaac     ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
2695b9a5774bSToby Isaac     ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
269646bdb399SToby Isaac     ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
26971c58ffc4SToby Isaac     ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr);
26980eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafIndicesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
26991c58ffc4SToby Isaac     ierr = DMGetWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
27000eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
270146bdb399SToby Isaac       PetscInt    gDof, gcDof, gOff;
270246bdb399SToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
270346bdb399SToby Isaac       PetscInt    matSize;
270421968bf8SToby Isaac       PetscInt    i;
270546bdb399SToby Isaac 
270646bdb399SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
270746bdb399SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
270846bdb399SToby Isaac       if ((gDof - gcDof) <= 0) {
270946bdb399SToby Isaac         continue;
271046bdb399SToby Isaac       }
271146bdb399SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
271246bdb399SToby Isaac       if (gOff < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"I though having global dofs meant a non-negative offset");
2713b9a5774bSToby Isaac       if ((gOff < rowStart) || ((gOff + gDof - gcDof) > rowEnd)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"I thought the row map would constrain the global dofs");
271446bdb399SToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
271546bdb399SToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
271646bdb399SToby Isaac       numColIndices -= 2 * numFields;
27171c58ffc4SToby Isaac       if (numColIndices <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"global fine dof with no dofs to interpolate from");
271846bdb399SToby Isaac       pInd = &leafIndices[pIndOff];
271921968bf8SToby Isaac       offsets[0]        = 0;
272021968bf8SToby Isaac       offsetsCopy[0]    = 0;
272121968bf8SToby Isaac       newOffsets[0]     = 0;
272221968bf8SToby Isaac       newOffsetsCopy[0] = 0;
272346bdb399SToby Isaac       if (numFields) {
272421968bf8SToby Isaac         PetscInt f;
272546bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
272646bdb399SToby Isaac           PetscInt rowDof;
272746bdb399SToby Isaac 
272846bdb399SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
272921968bf8SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
273021968bf8SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
273121968bf8SToby Isaac           newOffsets[f + 1]     = pInd[numColIndices + numFields + f];
273221968bf8SToby Isaac           numD[f] = 0;
273321968bf8SToby Isaac           numO[f] = 0;
273446bdb399SToby Isaac         }
27354acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,rowIndices);CHKERRQ(ierr);
273646bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
273721968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
273821968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
273946bdb399SToby Isaac 
274046bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
274146bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
274246bdb399SToby Isaac 
274346bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
274421968bf8SToby Isaac               numD[f]++;
274546bdb399SToby Isaac             }
274646bdb399SToby Isaac             else if (gInd >= 0) { /* negative means non-entry */
274721968bf8SToby Isaac               numO[f]++;
274846bdb399SToby Isaac             }
274946bdb399SToby Isaac           }
275046bdb399SToby Isaac         }
275146bdb399SToby Isaac       }
275246bdb399SToby Isaac       else {
27534acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,rowIndices);CHKERRQ(ierr);
275421968bf8SToby Isaac         numD[0] = 0;
275521968bf8SToby Isaac         numO[0] = 0;
275646bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
275746bdb399SToby Isaac           PetscInt gInd = pInd[i];
275846bdb399SToby Isaac 
275946bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
276021968bf8SToby Isaac             numD[0]++;
276146bdb399SToby Isaac           }
276246bdb399SToby Isaac           else if (gInd >= 0) { /* negative means non-entry */
276321968bf8SToby Isaac             numO[0]++;
276446bdb399SToby Isaac           }
276546bdb399SToby Isaac         }
276646bdb399SToby Isaac       }
276746bdb399SToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
276846bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
276946bdb399SToby Isaac         PetscInt childId;
277046bdb399SToby Isaac 
277146bdb399SToby Isaac         childId = childIds[p-pStartF];
277221968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
277346bdb399SToby Isaac           if (numFields) {
2774b9a5774bSToby Isaac             PetscInt f;
2775b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
277621968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
277746bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
277821968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
277921968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
278046bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2781b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2782b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
278346bdb399SToby Isaac                 }
278446bdb399SToby Isaac                 else if (gIndCoarse >= 0) { /* remote */
2785b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2786b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
278746bdb399SToby Isaac                 }
278846bdb399SToby Isaac                 else { /* constrained */
278946bdb399SToby Isaac                   if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
279046bdb399SToby Isaac                 }
279146bdb399SToby Isaac               }
279246bdb399SToby Isaac             }
279346bdb399SToby Isaac           }
279446bdb399SToby Isaac           else {
2795b9a5774bSToby Isaac             PetscInt i;
2796b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
279746bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
279846bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
279946bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2800b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2801b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
280246bdb399SToby Isaac               }
280346bdb399SToby Isaac               else if (gIndCoarse >= 0) { /* remote */
2804b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2805b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
280646bdb399SToby Isaac               }
280746bdb399SToby Isaac               else { /* constrained */
280846bdb399SToby Isaac                 if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
280946bdb399SToby Isaac               }
281046bdb399SToby Isaac             }
281146bdb399SToby Isaac           }
281246bdb399SToby Isaac         }
281346bdb399SToby Isaac         else { /* interpolate from all */
281446bdb399SToby Isaac           if (numFields) {
2815b9a5774bSToby Isaac             PetscInt f;
2816b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
281721968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
281846bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
281921968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
282046bdb399SToby Isaac                 if (gIndFine >= 0) {
2821b9a5774bSToby Isaac                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2822b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2823b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
282446bdb399SToby Isaac                 }
282546bdb399SToby Isaac               }
282646bdb399SToby Isaac             }
282746bdb399SToby Isaac           }
282846bdb399SToby Isaac           else {
2829b9a5774bSToby Isaac             PetscInt i;
2830b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
283146bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
283246bdb399SToby Isaac               if (gIndFine >= 0) {
2833b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2834b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2835b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
283646bdb399SToby Isaac               }
283746bdb399SToby Isaac             }
283846bdb399SToby Isaac           }
283946bdb399SToby Isaac         }
284046bdb399SToby Isaac       }
284146bdb399SToby Isaac       else { /* interpolate from all */
284246bdb399SToby Isaac         if (numFields) {
2843b9a5774bSToby Isaac           PetscInt f;
2844b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
284521968bf8SToby Isaac             PetscInt numRows = offsets[f+1] - offsets[f], row;
284646bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
284721968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
284846bdb399SToby Isaac               if (gIndFine >= 0) {
2849b9a5774bSToby Isaac                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2850b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2851b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
285246bdb399SToby Isaac               }
285346bdb399SToby Isaac             }
285446bdb399SToby Isaac           }
285546bdb399SToby Isaac         }
285646bdb399SToby Isaac         else { /* every dof get a full row */
2857b9a5774bSToby Isaac           PetscInt i;
2858b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
285946bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
286046bdb399SToby Isaac             if (gIndFine >= 0) {
2861b9a5774bSToby Isaac               if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2862b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2863b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
286446bdb399SToby Isaac             }
286546bdb399SToby Isaac           }
286646bdb399SToby Isaac         }
286746bdb399SToby Isaac       }
286846bdb399SToby Isaac     }
286946bdb399SToby Isaac     ierr = MatXAIJSetPreallocation(mat,1,dnnz,onnz,NULL,NULL);CHKERRQ(ierr);
287046bdb399SToby Isaac     ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
287121968bf8SToby Isaac 
287221968bf8SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
287321968bf8SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
2874e44e4e7fSToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
2875e44e4e7fSToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
2876e44e4e7fSToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
28771c58ffc4SToby Isaac     ierr = PetscSectionGetMaxDof(refConSec,&maxConDof);CHKERRQ(ierr);
28787c0540e0SToby Isaac     ierr = PetscSectionGetMaxDof(leafIndicesSec,&maxColumns);CHKERRQ(ierr);
28797c0540e0SToby Isaac     ierr = PetscMalloc1(maxConDof*maxColumns,&pointWork);CHKERRQ(ierr);
28800eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2881e44e4e7fSToby Isaac       PetscInt    gDof, gcDof, gOff;
2882e44e4e7fSToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
2883e44e4e7fSToby Isaac       PetscInt    matSize;
2884e44e4e7fSToby Isaac       PetscInt    childId;
2885e44e4e7fSToby Isaac 
2886e44e4e7fSToby Isaac 
2887e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
2888e44e4e7fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
2889e44e4e7fSToby Isaac       if ((gDof - gcDof) <= 0) {
2890e44e4e7fSToby Isaac         continue;
2891e44e4e7fSToby Isaac       }
2892e44e4e7fSToby Isaac       childId = childIds[p-pStartF];
2893e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
2894e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
2895e44e4e7fSToby Isaac       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
2896e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2897e44e4e7fSToby Isaac       pInd = &leafIndices[pIndOff];
2898e44e4e7fSToby Isaac       offsets[0]        = 0;
2899e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2900e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2901e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2902e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2903e44e4e7fSToby Isaac       if (numFields) {
2904e44e4e7fSToby Isaac         PetscInt f;
2905e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2906e44e4e7fSToby Isaac           PetscInt rowDof;
2907e44e4e7fSToby Isaac 
2908e44e4e7fSToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
2909e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2910e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2911e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2912e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2913e44e4e7fSToby Isaac         }
29144acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,rowIndices);CHKERRQ(ierr);
2915e44e4e7fSToby Isaac       }
29161c58ffc4SToby Isaac       else {
29174acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,rowIndices);CHKERRQ(ierr);
29181c58ffc4SToby Isaac       }
2919e44e4e7fSToby Isaac       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
2920e44e4e7fSToby Isaac       if (!matSize) { /* incoming matrix is identity */
2921e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2922e44e4e7fSToby Isaac           if (numFields) {
2923e44e4e7fSToby Isaac             PetscInt f;
2924e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2925e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
2926e44e4e7fSToby Isaac               for (row = 0; row < numRows; row++) {
2927e44e4e7fSToby Isaac                 ierr = MatSetValue(mat,rowIndices[offsets[f]+row],pInd[newOffsets[f]+row],1.,INSERT_VALUES);CHKERRQ(ierr);
292821968bf8SToby Isaac               }
292921968bf8SToby Isaac             }
2930e44e4e7fSToby Isaac           }
2931e44e4e7fSToby Isaac           else {
2932e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
2933e44e4e7fSToby Isaac             for (row = 0; row < numRows; row++) {
2934e44e4e7fSToby Isaac               ierr = MatSetValue(mat,rowIndices[row],pInd[row],1.,INSERT_VALUES);CHKERRQ(ierr);
2935e44e4e7fSToby Isaac             }
2936e44e4e7fSToby Isaac           }
2937e44e4e7fSToby Isaac         }
2938e44e4e7fSToby Isaac         else { /* interpolate from all */
2939e44e4e7fSToby Isaac           if (numFields) {
2940e44e4e7fSToby Isaac             PetscInt f;
2941e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2942e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f];
2943e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
2944e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],refPointFieldMats[childId - pRefStart][f],INSERT_VALUES);CHKERRQ(ierr);
2945e44e4e7fSToby Isaac             }
2946e44e4e7fSToby Isaac           }
2947e44e4e7fSToby Isaac           else {
2948e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,refPointFieldMats[childId - pRefStart][0],INSERT_VALUES);CHKERRQ(ierr);
2949e44e4e7fSToby Isaac           }
2950e44e4e7fSToby Isaac         }
2951e44e4e7fSToby Isaac       }
2952e44e4e7fSToby Isaac       else { /* interpolate from all */
2953e44e4e7fSToby Isaac         PetscInt    pMatOff;
2954e44e4e7fSToby Isaac         PetscScalar *pMat;
2955e44e4e7fSToby Isaac 
2956e44e4e7fSToby Isaac         ierr = PetscSectionGetOffset(leafMatricesSec,p,&pMatOff);CHKERRQ(ierr);
2957e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2958e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2959e44e4e7fSToby Isaac           if (numFields) {
2960e44e4e7fSToby Isaac             PetscInt f, count;
2961e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2962e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2963e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2964e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2965e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2966e44e4e7fSToby Isaac 
2967e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],inMat,INSERT_VALUES);CHKERRQ(ierr);
2968e44e4e7fSToby Isaac               count += numCols * numInRows;
2969e44e4e7fSToby Isaac             }
2970e44e4e7fSToby Isaac           }
2971e44e4e7fSToby Isaac           else {
2972e44e4e7fSToby Isaac             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,pMat,INSERT_VALUES);CHKERRQ(ierr);
2973e44e4e7fSToby Isaac           }
2974e44e4e7fSToby Isaac         }
2975e44e4e7fSToby Isaac         else { /* multiply the incoming matrix by the child interpolation */
2976e44e4e7fSToby Isaac           if (numFields) {
2977e44e4e7fSToby Isaac             PetscInt f, count;
2978e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2979e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2980e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2981e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2982e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2983e44e4e7fSToby Isaac               PetscInt i, j, k;
2984e44e4e7fSToby Isaac               if (refPointFieldN[childId - pRefStart][f] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2985e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2986e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2987e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2988e44e4e7fSToby Isaac                   for (k = 0; k < numInRows; k++) {
2989e44e4e7fSToby Isaac                     val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2990e44e4e7fSToby Isaac                   }
2991e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2992e44e4e7fSToby Isaac                 }
2993e44e4e7fSToby Isaac               }
2994e44e4e7fSToby Isaac               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],pointWork,INSERT_VALUES);CHKERRQ(ierr);
2995e44e4e7fSToby Isaac               count += numCols * numInRows;
2996e44e4e7fSToby Isaac             }
2997e44e4e7fSToby Isaac           }
2998267d4f3fSToby Isaac           else { /* every dof gets a full row */
2999e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
3000e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
3001e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
3002e44e4e7fSToby Isaac             PetscInt i, j, k;
3003e44e4e7fSToby Isaac             if (refPointFieldN[childId - pRefStart][0] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
3004e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
3005e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
3006e44e4e7fSToby Isaac                 PetscScalar val = 0.;
3007e44e4e7fSToby Isaac                 for (k = 0; k < numInRows; k++) {
3008e44e4e7fSToby Isaac                   val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
3009e44e4e7fSToby Isaac                 }
3010e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
3011e44e4e7fSToby Isaac               }
3012e44e4e7fSToby Isaac             }
3013e44e4e7fSToby Isaac             ierr = MatSetValues(mat,numRows,rowIndices,numCols,pInd,pointWork,INSERT_VALUES);CHKERRQ(ierr);
3014e44e4e7fSToby Isaac           }
3015e44e4e7fSToby Isaac         }
3016e44e4e7fSToby Isaac       }
3017e44e4e7fSToby Isaac     }
30181c58ffc4SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
30191c58ffc4SToby Isaac     ierr = DMRestoreWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
3020e44e4e7fSToby Isaac     ierr = PetscFree(pointWork);CHKERRQ(ierr);
3021e44e4e7fSToby Isaac   }
3022e44e4e7fSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
3023e44e4e7fSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
3024e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
3025e44e4e7fSToby Isaac   ierr = PetscSectionDestroy(&leafMatricesSec);CHKERRQ(ierr);
3026e44e4e7fSToby Isaac   ierr = PetscFree2(leafIndices,leafMatrices);CHKERRQ(ierr);
30274acb8e1eSToby Isaac   ierr = PetscFree2(perms,flips);CHKERRQ(ierr);
3028e44e4e7fSToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
30296ecaa68aSToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
30306ecaa68aSToby Isaac   PetscFunctionReturn(0);
30316ecaa68aSToby Isaac }
3032154bca37SToby Isaac 
3033154bca37SToby Isaac #undef __FUNCT__
30348d2f55e7SToby Isaac #define __FUNCT__ "DMPlexComputeInjectorReferenceTree"
30358d2f55e7SToby Isaac /*
30368d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
30378d2f55e7SToby Isaac  *
30388d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
30398d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
30408d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
30418d2f55e7SToby Isaac  *       a_{i,j} = 0;
30428d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
30438d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
30448d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
30458d2f55e7SToby Isaac  */
30468d2f55e7SToby Isaac PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
30478d2f55e7SToby Isaac {
30488d2f55e7SToby Isaac   PetscDS        ds;
30498d2f55e7SToby Isaac   PetscSection   section, cSection;
30508d2f55e7SToby Isaac   DMLabel        canonical, depth;
30518d2f55e7SToby Isaac   Mat            cMat, mat;
30528d2f55e7SToby Isaac   PetscInt       *nnz;
30538d2f55e7SToby Isaac   PetscInt       f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
30548d2f55e7SToby Isaac   PetscInt       m, n;
30558d2f55e7SToby Isaac   PetscScalar    *pointScalar;
30568d2f55e7SToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
30578d2f55e7SToby Isaac   PetscErrorCode ierr;
30588d2f55e7SToby Isaac 
30598d2f55e7SToby Isaac   PetscFunctionBegin;
30608d2f55e7SToby Isaac   ierr = DMGetDefaultSection(refTree,&section);CHKERRQ(ierr);
30618d2f55e7SToby Isaac   ierr = DMGetDimension(refTree, &dim);CHKERRQ(ierr);
30628d2f55e7SToby Isaac   ierr = PetscMalloc6(dim,&v0,dim,&v0parent,dim,&vtmp,dim*dim,&J,dim*dim,&Jparent,dim*dim,&invJ);CHKERRQ(ierr);
30638d2f55e7SToby Isaac   ierr = PetscMalloc2(dim,&pointScalar,dim,&pointRef);CHKERRQ(ierr);
30648d2f55e7SToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
30658d2f55e7SToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
30668d2f55e7SToby Isaac   ierr = PetscSectionGetNumFields(section,&numSecFields);CHKERRQ(ierr);
30678d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"canonical",&canonical);CHKERRQ(ierr);
30688d2f55e7SToby Isaac   ierr = DMGetLabel(refTree,"depth",&depth);CHKERRQ(ierr);
30698d2f55e7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSection,&cMat);CHKERRQ(ierr);
30708d2f55e7SToby Isaac   ierr = DMPlexGetChart(refTree, &pStart, &pEnd);CHKERRQ(ierr);
30718d2f55e7SToby Isaac   ierr = DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd);CHKERRQ(ierr);
30728d2f55e7SToby Isaac   ierr = MatGetSize(cMat,&n,&m);CHKERRQ(ierr); /* the injector has transpose sizes from the constraint matrix */
30738d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
30748d2f55e7SToby Isaac   ierr = PetscCalloc1(m,&nnz);CHKERRQ(ierr);
30758d2f55e7SToby 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 */
30768d2f55e7SToby Isaac     const PetscInt *children;
30778d2f55e7SToby Isaac     PetscInt numChildren;
30788d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30798d2f55e7SToby Isaac 
30808d2f55e7SToby Isaac     if (canonical) {
30818d2f55e7SToby Isaac       PetscInt pCanonical;
30828d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
30838d2f55e7SToby Isaac       if (p != pCanonical) continue;
30848d2f55e7SToby Isaac     }
30858d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
30868d2f55e7SToby Isaac     if (!numChildren) continue;
30878d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30888d2f55e7SToby Isaac       PetscInt child = children[i];
30898d2f55e7SToby Isaac       PetscInt dof;
30908d2f55e7SToby Isaac 
30918d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
30928d2f55e7SToby Isaac       numChildDof += dof;
30938d2f55e7SToby Isaac     }
30948d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
30958d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30968d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
30978d2f55e7SToby Isaac       PetscInt selfOff;
30988d2f55e7SToby Isaac 
30998d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
31008d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
31018d2f55e7SToby Isaac           PetscInt child = children[i];
31028d2f55e7SToby Isaac           PetscInt dof;
31038d2f55e7SToby Isaac 
31048d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
31058d2f55e7SToby Isaac           numChildDof += dof;
31068d2f55e7SToby Isaac         }
31078d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
31088d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
31098d2f55e7SToby Isaac       }
31108d2f55e7SToby Isaac       else {
31118d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
31128d2f55e7SToby Isaac       }
31138d2f55e7SToby Isaac       for (i = 0; i < numSelfDof; i++) {
31148d2f55e7SToby Isaac         nnz[selfOff + i] = numChildDof;
31158d2f55e7SToby Isaac       }
31168d2f55e7SToby Isaac     }
31178d2f55e7SToby Isaac   }
31188d2f55e7SToby Isaac   ierr = MatCreateAIJ(PETSC_COMM_SELF,m,n,m,n,-1,nnz,-1,NULL,&mat);CHKERRQ(ierr);
31198d2f55e7SToby Isaac   ierr = PetscFree(nnz);CHKERRQ(ierr);
31208d2f55e7SToby Isaac   /* Setp 2: compute entries */
31218d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
31228d2f55e7SToby Isaac     const PetscInt *children;
31238d2f55e7SToby Isaac     PetscInt numChildren;
31248d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
31258d2f55e7SToby Isaac 
31268d2f55e7SToby Isaac     /* same conditions about when entries occur */
31278d2f55e7SToby Isaac     if (canonical) {
31288d2f55e7SToby Isaac       PetscInt pCanonical;
31298d2f55e7SToby Isaac       ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr);
31308d2f55e7SToby Isaac       if (p != pCanonical) continue;
31318d2f55e7SToby Isaac     }
31328d2f55e7SToby Isaac     ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr);
31338d2f55e7SToby Isaac     if (!numChildren) continue;
31348d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
31358d2f55e7SToby Isaac       PetscInt child = children[i];
31368d2f55e7SToby Isaac       PetscInt dof;
31378d2f55e7SToby Isaac 
31388d2f55e7SToby Isaac       ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr);
31398d2f55e7SToby Isaac       numChildDof += dof;
31408d2f55e7SToby Isaac     }
31418d2f55e7SToby Isaac     ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr);
31428d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
31438d2f55e7SToby Isaac 
31448d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
31458d2f55e7SToby Isaac       PetscInt       selfOff, fComp, numSelfShapes, numChildShapes, parentCell;
31468d2f55e7SToby Isaac       PetscInt       cellShapeOff;
31478d2f55e7SToby Isaac       PetscObject    disc;
31488d2f55e7SToby Isaac       PetscDualSpace dsp;
31498d2f55e7SToby Isaac       PetscClassId   classId;
31508d2f55e7SToby Isaac       PetscScalar    *pointMat;
31513b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
31528d2f55e7SToby Isaac       PetscInt       pO = PETSC_MIN_INT;
31538d2f55e7SToby Isaac       const PetscInt *depthNumDof;
31548d2f55e7SToby Isaac 
31558d2f55e7SToby Isaac       if (numSecFields) {
31568d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
31578d2f55e7SToby Isaac           PetscInt child = children[i];
31588d2f55e7SToby Isaac           PetscInt dof;
31598d2f55e7SToby Isaac 
31608d2f55e7SToby Isaac           ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr);
31618d2f55e7SToby Isaac           numChildDof += dof;
31628d2f55e7SToby Isaac         }
31638d2f55e7SToby Isaac         ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr);
31648d2f55e7SToby Isaac         ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr);
31658d2f55e7SToby Isaac         ierr = PetscSectionGetFieldComponents(section,f,&fComp);CHKERRQ(ierr);
31668d2f55e7SToby Isaac       }
31678d2f55e7SToby Isaac       else {
31688d2f55e7SToby Isaac         ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr);
31698d2f55e7SToby Isaac         fComp = 1;
31708d2f55e7SToby Isaac       }
31718d2f55e7SToby Isaac       numSelfShapes  = numSelfDof  / fComp;
31728d2f55e7SToby Isaac       numChildShapes = numChildDof / fComp;
31738d2f55e7SToby Isaac 
31743b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
31758d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
31768d2f55e7SToby Isaac         parentCell = p;
31778d2f55e7SToby Isaac       }
31788d2f55e7SToby Isaac       else {
31798d2f55e7SToby Isaac         PetscInt *star = NULL;
31808d2f55e7SToby Isaac         PetscInt numStar;
31818d2f55e7SToby Isaac 
31828d2f55e7SToby Isaac         parentCell = -1;
31838d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31848d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
31858d2f55e7SToby Isaac           PetscInt c = star[2 * i];
31868d2f55e7SToby Isaac 
31878d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
31888d2f55e7SToby Isaac             parentCell = c;
31898d2f55e7SToby Isaac             break;
31908d2f55e7SToby Isaac           }
31918d2f55e7SToby Isaac         }
31928d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
31938d2f55e7SToby Isaac       }
31948d2f55e7SToby Isaac       /* determine the offset of p's shape functions withing parentCell's shape functions */
3195c5356c36SToby Isaac       ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
3196c5356c36SToby Isaac       ierr = PetscObjectGetClassId(disc,&classId);CHKERRQ(ierr);
3197c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
3198c5356c36SToby Isaac         ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
3199c5356c36SToby Isaac       }
3200c5356c36SToby Isaac       else if (classId == PETSCFV_CLASSID) {
3201c5356c36SToby Isaac         ierr = PetscFVGetDualSpace((PetscFV)disc,&dsp);CHKERRQ(ierr);
3202c5356c36SToby Isaac       }
3203c5356c36SToby Isaac       else {
3204c5356c36SToby Isaac         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported discretization object");CHKERRQ(ierr);
3205c5356c36SToby Isaac       }
32068d2f55e7SToby Isaac       ierr = PetscDualSpaceGetNumDof(dsp,&depthNumDof);CHKERRQ(ierr);
32078d2f55e7SToby Isaac       {
32088d2f55e7SToby Isaac         PetscInt *closure = NULL;
32098d2f55e7SToby Isaac         PetscInt numClosure;
32108d2f55e7SToby Isaac 
32118d2f55e7SToby Isaac         ierr = DMPlexGetTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
32128d2f55e7SToby Isaac         for (i = 0, cellShapeOff = 0; i < numClosure; i++) {
32138d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
32148d2f55e7SToby Isaac 
32158d2f55e7SToby Isaac           pO = closure[2 * i + 1];
32168d2f55e7SToby Isaac           if (point == p) break;
32178d2f55e7SToby Isaac           ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
32188d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
32198d2f55e7SToby Isaac         }
32208d2f55e7SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
32218d2f55e7SToby Isaac       }
32228d2f55e7SToby Isaac 
32238d2f55e7SToby Isaac       ierr = DMGetWorkArray(refTree, numSelfShapes * numChildShapes, PETSC_SCALAR,&pointMat);CHKERRQ(ierr);
32243b1c2a6aSToby Isaac       ierr = DMGetWorkArray(refTree, numSelfShapes + numChildShapes, PETSC_INT,&matRows);CHKERRQ(ierr);
32253b1c2a6aSToby Isaac       matCols = matRows + numSelfShapes;
32263b1c2a6aSToby Isaac       for (i = 0; i < numSelfShapes; i++) {
32273b1c2a6aSToby Isaac         matRows[i] = selfOff + i * fComp;
32283b1c2a6aSToby Isaac       }
32293b1c2a6aSToby Isaac       {
32303b1c2a6aSToby Isaac         PetscInt colOff = 0;
32313b1c2a6aSToby Isaac 
32323b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
32333b1c2a6aSToby Isaac           PetscInt child = children[i];
32343b1c2a6aSToby Isaac           PetscInt dof, off, j;
32353b1c2a6aSToby Isaac 
32363b1c2a6aSToby Isaac           if (numSecFields) {
3237c5356c36SToby Isaac             ierr = PetscSectionGetFieldDof(cSection,child,f,&dof);CHKERRQ(ierr);
3238c5356c36SToby Isaac             ierr = PetscSectionGetFieldOffset(cSection,child,f,&off);CHKERRQ(ierr);
32393b1c2a6aSToby Isaac           }
32403b1c2a6aSToby Isaac           else {
3241c5356c36SToby Isaac             ierr = PetscSectionGetDof(cSection,child,&dof);CHKERRQ(ierr);
3242c5356c36SToby Isaac             ierr = PetscSectionGetOffset(cSection,child,&off);CHKERRQ(ierr);
32433b1c2a6aSToby Isaac           }
32443b1c2a6aSToby Isaac 
32453b1c2a6aSToby Isaac           for (j = 0; j < dof / fComp; j++) {
32463b1c2a6aSToby Isaac             matCols[colOff++] = off + j * fComp;
32473b1c2a6aSToby Isaac           }
32483b1c2a6aSToby Isaac         }
32493b1c2a6aSToby Isaac       }
32508d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
32518d2f55e7SToby Isaac         PetscFE        fe = (PetscFE) disc;
32528d2f55e7SToby Isaac         PetscInt       fSize;
32538d2f55e7SToby Isaac 
32548d2f55e7SToby Isaac         ierr = PetscFEGetDualSpace(fe,&dsp);CHKERRQ(ierr);
32553b1c2a6aSToby Isaac         ierr = PetscDualSpaceGetDimension(dsp,&fSize);CHKERRQ(ierr);
32568d2f55e7SToby Isaac         for (i = 0; i < numSelfShapes; i++) { /* for every shape function */
32578d2f55e7SToby Isaac           PetscQuadrature q;
32588d2f55e7SToby Isaac           PetscInt        dim, numPoints, j, k;
32598d2f55e7SToby Isaac           const PetscReal *points;
32608d2f55e7SToby Isaac           const PetscReal *weights;
32618d2f55e7SToby Isaac           PetscInt        *closure = NULL;
32628d2f55e7SToby Isaac           PetscInt        numClosure;
32633b1c2a6aSToby Isaac           PetscInt        parentCellShapeDof = cellShapeOff + (pO < 0 ? (numSelfShapes - 1 - i) : i);
32648d2f55e7SToby Isaac           PetscReal       *Bparent;
32658d2f55e7SToby Isaac 
32663b1c2a6aSToby Isaac           ierr = PetscDualSpaceGetFunctional(dsp,parentCellShapeDof,&q);CHKERRQ(ierr);
32673b1c2a6aSToby Isaac           ierr = PetscQuadratureGetData(q,&dim,&numPoints,&points,&weights);CHKERRQ(ierr);
32683b1c2a6aSToby Isaac           ierr = PetscFEGetTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
32698d2f55e7SToby Isaac           for (k = 0; k < numChildShapes; k++) {
32708d2f55e7SToby Isaac             pointMat[numChildShapes * i + k] = 0.;
32718d2f55e7SToby Isaac           }
32723b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
32738d2f55e7SToby Isaac             PetscInt          childCell = -1;
32743b1c2a6aSToby Isaac             PetscReal         parentValAtPoint;
32758d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
32768d2f55e7SToby Isaac             const PetscScalar *point;
32778d2f55e7SToby Isaac             PetscReal         *Bchild;
32788d2f55e7SToby Isaac             PetscInt          childCellShapeOff, pointMatOff;
32798d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
32808d2f55e7SToby Isaac             PetscInt          d;
32818d2f55e7SToby Isaac 
32828d2f55e7SToby Isaac             for (d = 0; d < dim; d++) {
32838d2f55e7SToby Isaac               pointScalar[d] = points[dim * j + d];
32848d2f55e7SToby Isaac             }
32858d2f55e7SToby Isaac             point = pointScalar;
32868d2f55e7SToby Isaac #else
32878d2f55e7SToby Isaac             point = pointReal;
32888d2f55e7SToby Isaac #endif
32898d2f55e7SToby Isaac 
32903b1c2a6aSToby Isaac             parentValAtPoint = Bparent[(fSize * j + parentCellShapeDof) * fComp];
32913b1c2a6aSToby Isaac 
32923b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
32938d2f55e7SToby Isaac               PetscInt child = children[k];
32948d2f55e7SToby Isaac               PetscInt *star = NULL;
32958d2f55e7SToby Isaac               PetscInt numStar, s;
32968d2f55e7SToby Isaac 
32978d2f55e7SToby Isaac               ierr = DMPlexGetTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
32988d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
32998d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
33008d2f55e7SToby Isaac 
33018d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
33028d2f55e7SToby Isaac                 ierr = DMPlexLocatePoint_Internal(refTree,dim,point,c,&childCell);CHKERRQ(ierr);
33038d2f55e7SToby Isaac                 if (childCell >= 0) break;
33048d2f55e7SToby Isaac               }
33058d2f55e7SToby Isaac               ierr = DMPlexRestoreTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr);
33068d2f55e7SToby Isaac               if (childCell >= 0) break;
33078d2f55e7SToby Isaac             }
33088d2f55e7SToby Isaac             if (childCell < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not locate quadrature point");CHKERRQ(ierr);
33098d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
33108d2f55e7SToby Isaac             ierr = DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent);CHKERRQ(ierr);
33118d2f55e7SToby Isaac             CoordinatesRefToReal(dim, dim, v0parent, Jparent, pointReal, vtmp);
33128d2f55e7SToby Isaac             CoordinatesRealToRef(dim, dim, v0, invJ, vtmp, pointRef);
33138d2f55e7SToby Isaac 
33148d2f55e7SToby Isaac             ierr = PetscFEGetTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr);
33158d2f55e7SToby Isaac             ierr = DMPlexGetTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
33163b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3317c5356c36SToby Isaac               PetscInt child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
33188d2f55e7SToby Isaac               PetscInt l;
33198d2f55e7SToby Isaac 
33208d2f55e7SToby Isaac               ierr = DMLabelGetValue(depth,child,&childDepth);CHKERRQ(ierr);
33218d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
33228d2f55e7SToby Isaac               for (l = 0, childCellShapeOff = 0; l < numClosure; l++) {
33238d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
33248d2f55e7SToby Isaac                 PetscInt pointDepth;
33258d2f55e7SToby Isaac 
33268d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
33278d2f55e7SToby Isaac                 if (point == child) break;
33288d2f55e7SToby Isaac                 ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr);
33298d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
33308d2f55e7SToby Isaac               }
33318d2f55e7SToby Isaac               if (l == numClosure) {
33328d2f55e7SToby Isaac                 pointMatOff += childDof;
33338d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
33348d2f55e7SToby Isaac               }
33358d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
33363b1c2a6aSToby Isaac                 PetscInt    childCellDof    = childCellShapeOff + (childO ? (childDof - 1 - l) : l);
33373b1c2a6aSToby Isaac                 PetscReal   childValAtPoint = Bchild[childCellDof * fComp];
33388d2f55e7SToby Isaac 
33393b1c2a6aSToby Isaac                 pointMat[i * numChildShapes + pointMatOff + l] += weights[j] * parentValAtPoint * childValAtPoint;
33408d2f55e7SToby Isaac               }
33418d2f55e7SToby Isaac               pointMatOff += childDof;
33428d2f55e7SToby Isaac             }
33438d2f55e7SToby Isaac             ierr = DMPlexRestoreTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr);
33448d2f55e7SToby Isaac             ierr = PetscFERestoreTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr);
33458d2f55e7SToby Isaac           }
33468d2f55e7SToby Isaac           ierr = PetscFERestoreTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr);
33478d2f55e7SToby Isaac         }
33488d2f55e7SToby Isaac       }
3349c5356c36SToby Isaac       else { /* just the volume-weighted averages of the children */
33503b1c2a6aSToby Isaac         PetscInt  childShapeOff;
33513b1c2a6aSToby Isaac         PetscReal parentVol;
33523b1c2a6aSToby Isaac 
33533b1c2a6aSToby Isaac         ierr = DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL);CHKERRQ(ierr);
33543b1c2a6aSToby Isaac         for (i = 0, childShapeOff = 0; i < numChildren; i++) {
33553b1c2a6aSToby Isaac           PetscInt  child = children[i];
33563b1c2a6aSToby Isaac           PetscReal childVol;
33573b1c2a6aSToby Isaac 
33583b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
33593b1c2a6aSToby Isaac           ierr = DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL);CHKERRQ(ierr);
33603b1c2a6aSToby Isaac           pointMat[childShapeOff] = childVol / parentVol;
33613b1c2a6aSToby Isaac           childShapeOff++;
33623b1c2a6aSToby Isaac         }
33638d2f55e7SToby Isaac       }
33643b1c2a6aSToby Isaac       /* Insert pointMat into mat */
33653b1c2a6aSToby Isaac       for (i = 0; i < fComp; i++) {
33663b1c2a6aSToby Isaac         PetscInt j;
33673b1c2a6aSToby Isaac         ierr = MatSetValues(mat,numSelfShapes,matRows,numChildShapes,matCols,pointMat,INSERT_VALUES);CHKERRQ(ierr);
33683b1c2a6aSToby Isaac 
33693b1c2a6aSToby Isaac         for (j = 0; j < numSelfShapes; j++) {
33703b1c2a6aSToby Isaac           matRows[j]++;
33713b1c2a6aSToby Isaac         }
33723b1c2a6aSToby Isaac         for (j = 0; j < numChildShapes; j++) {
33733b1c2a6aSToby Isaac           matCols[j]++;
33743b1c2a6aSToby Isaac         }
33753b1c2a6aSToby Isaac       }
33763b1c2a6aSToby Isaac       ierr = DMRestoreWorkArray(refTree, numSelfShapes + numChildShapes, PETSC_INT,&matRows);CHKERRQ(ierr);
33778d2f55e7SToby Isaac       ierr = DMRestoreWorkArray(refTree, numSelfShapes * numChildShapes, PETSC_SCALAR,&pointMat);CHKERRQ(ierr);
33788d2f55e7SToby Isaac     }
33798d2f55e7SToby Isaac   }
33803b1c2a6aSToby Isaac   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJ);CHKERRQ(ierr);
33818d2f55e7SToby Isaac   ierr = PetscFree2(pointScalar,pointRef);CHKERRQ(ierr);
33823b1c2a6aSToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33833b1c2a6aSToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
33848d2f55e7SToby Isaac   *inj = mat;
33858d2f55e7SToby Isaac   PetscFunctionReturn(0);
33868d2f55e7SToby Isaac }
33878d2f55e7SToby Isaac 
33888d2f55e7SToby Isaac #undef __FUNCT__
3389f30e825dSToby Isaac #define __FUNCT__ "DMPlexReferenceTreeGetChildrenMatrices_Injection"
3390f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3391f30e825dSToby Isaac {
3392f30e825dSToby Isaac   PetscDS        ds;
3393f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3394f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3395f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3396f30e825dSToby Isaac   PetscErrorCode ierr;
3397f30e825dSToby Isaac 
3398f30e825dSToby Isaac   PetscFunctionBegin;
3399f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
3400f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3401f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
3402f30e825dSToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
3403f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3404f30e825dSToby Isaac   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
3405f30e825dSToby Isaac   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
3406f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
3407f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof*maxDof,&cols);CHKERRQ(ierr);
3408f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3409f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3410f30e825dSToby Isaac 
3411f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3412f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3413c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3414f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3415f30e825dSToby Isaac 
3416f30e825dSToby Isaac     ierr = PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
3417f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3418f30e825dSToby Isaac       PetscInt cDof, cOff, numCols, r, fComp;
3419f30e825dSToby Isaac       PetscObject disc;
3420f30e825dSToby Isaac       PetscClassId id;
3421f30e825dSToby Isaac       PetscFE fe = NULL;
3422f30e825dSToby Isaac       PetscFV fv = NULL;
3423f30e825dSToby Isaac 
3424f30e825dSToby Isaac       ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
3425f30e825dSToby Isaac       ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
3426f30e825dSToby Isaac       if (id == PETSCFE_CLASSID) {
3427f30e825dSToby Isaac         fe = (PetscFE) disc;
3428f30e825dSToby Isaac         ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr);
3429f30e825dSToby Isaac       }
3430f30e825dSToby Isaac       else if (id == PETSCFV_CLASSID) {
3431f30e825dSToby Isaac         fv = (PetscFV) disc;
3432f30e825dSToby Isaac         ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr);
3433f30e825dSToby Isaac       }
3434f30e825dSToby Isaac       else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
3435f30e825dSToby Isaac 
3436f30e825dSToby Isaac       if (numFields > 1) {
3437f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3438f30e825dSToby Isaac         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
3439f30e825dSToby Isaac       }
3440f30e825dSToby Isaac       else {
3441f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3442f30e825dSToby Isaac         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
3443f30e825dSToby Isaac       }
3444f30e825dSToby Isaac 
3445f30e825dSToby Isaac       for (r = 0; r < cDof; r++) {
3446f30e825dSToby Isaac         rows[r] = cOff + r;
3447f30e825dSToby Isaac       }
3448f30e825dSToby Isaac       numCols = 0;
3449f30e825dSToby Isaac       {
3450f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3451f30e825dSToby Isaac 
3452f30e825dSToby Isaac         if (numFields > 1) {
3453f30e825dSToby Isaac           ierr = PetscSectionGetFieldDof(refSection,parent,f,&aDof);CHKERRQ(ierr);
3454f30e825dSToby Isaac           ierr = PetscSectionGetFieldOffset(refSection,parent,f,&aOff);CHKERRQ(ierr);
3455f30e825dSToby Isaac         }
3456f30e825dSToby Isaac         else {
3457f30e825dSToby Isaac           ierr = PetscSectionGetDof(refSection,parent,&aDof);CHKERRQ(ierr);
3458f30e825dSToby Isaac           ierr = PetscSectionGetOffset(refSection,parent,&aOff);CHKERRQ(ierr);
3459f30e825dSToby Isaac         }
3460f30e825dSToby Isaac 
3461f30e825dSToby Isaac         for (j = 0; j < aDof; j++) {
3462f30e825dSToby Isaac           cols[numCols++] = aOff + j;
3463f30e825dSToby Isaac         }
3464f30e825dSToby Isaac       }
3465f30e825dSToby Isaac       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3466f30e825dSToby Isaac       /* transpose of constraint matrix */
3467f30e825dSToby Isaac       ierr = MatGetValues(inj,numCols,cols,cDof,rows,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
3468f30e825dSToby Isaac     }
3469f30e825dSToby Isaac   }
3470f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
3471f30e825dSToby Isaac   ierr = PetscFree(rows);CHKERRQ(ierr);
3472f30e825dSToby Isaac   ierr = PetscFree(cols);CHKERRQ(ierr);
3473f30e825dSToby Isaac   PetscFunctionReturn(0);
3474f30e825dSToby Isaac }
3475f30e825dSToby Isaac 
3476f30e825dSToby Isaac #undef __FUNCT__
3477f30e825dSToby Isaac #define __FUNCT__ "DMPlexReferenceTreeRestoreChildrenMatrices_Injection"
3478f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3479f30e825dSToby Isaac {
3480f30e825dSToby Isaac   PetscDS        ds;
3481f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3482f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3483c6154584SToby Isaac   PetscSection   refConSec, refSection;
3484f30e825dSToby Isaac   PetscErrorCode ierr;
3485f30e825dSToby Isaac 
3486f30e825dSToby Isaac   PetscFunctionBegin;
3487f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3488f30e825dSToby Isaac   *childrenMats = NULL;
3489f30e825dSToby Isaac   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
3490c6154584SToby Isaac   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
3491f30e825dSToby Isaac   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
3492f30e825dSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
3493f30e825dSToby Isaac   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3494f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3495f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3496f30e825dSToby Isaac 
3497f30e825dSToby Isaac     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
3498f30e825dSToby Isaac     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
3499c6154584SToby Isaac     ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr);
3500f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3501f30e825dSToby Isaac 
3502f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3503f30e825dSToby Isaac       PetscInt cDof;
3504f30e825dSToby Isaac 
3505f30e825dSToby Isaac       if (numFields > 1) {
3506f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
3507f30e825dSToby Isaac       }
3508f30e825dSToby Isaac       else {
3509f30e825dSToby Isaac         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
3510f30e825dSToby Isaac       }
3511f30e825dSToby Isaac 
3512f30e825dSToby Isaac       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
3513f30e825dSToby Isaac     }
3514f30e825dSToby Isaac     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
3515f30e825dSToby Isaac   }
3516f30e825dSToby Isaac   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
3517f30e825dSToby Isaac   PetscFunctionReturn(0);
3518f30e825dSToby Isaac }
3519f30e825dSToby Isaac 
3520f30e825dSToby Isaac #undef __FUNCT__
3521ebf164c7SToby Isaac #define __FUNCT__ "DMPlexReferenceTreeGetInjector"
3522ebf164c7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree,Mat *injRef)
3523154bca37SToby Isaac {
3524ebf164c7SToby Isaac   Mat            cMatRef;
35256148253fSToby Isaac   PetscObject    injRefObj;
35268d2f55e7SToby Isaac   PetscErrorCode ierr;
35278d2f55e7SToby Isaac 
3528154bca37SToby Isaac   PetscFunctionBegin;
3529ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,NULL,&cMatRef);CHKERRQ(ierr);
35306148253fSToby Isaac   ierr = PetscObjectQuery((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",&injRefObj);CHKERRQ(ierr);
3531ebf164c7SToby Isaac   *injRef = (Mat) injRefObj;
3532ebf164c7SToby Isaac   if (!*injRef) {
3533ebf164c7SToby Isaac     ierr = DMPlexComputeInjectorReferenceTree(refTree,injRef);CHKERRQ(ierr);
3534ebf164c7SToby Isaac     ierr = PetscObjectCompose((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",(PetscObject)*injRef);CHKERRQ(ierr);
3535ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
3536ebf164c7SToby Isaac     ierr = PetscObjectDereference((PetscObject)*injRef);CHKERRQ(ierr);
3537ebf164c7SToby Isaac   }
3538ebf164c7SToby Isaac   PetscFunctionReturn(0);
35396148253fSToby Isaac }
3540f30e825dSToby Isaac 
3541ebf164c7SToby Isaac #undef __FUNCT__
3542c921d74cSToby Isaac #define __FUNCT__ "DMPlexTransferInjectorTree"
3543c921d74cSToby 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)
3544ebf164c7SToby Isaac {
3545c921d74cSToby Isaac   PetscInt       pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3546ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3547ebf164c7SToby Isaac   PetscSection   localCoarse, localFine, leafIndicesSec;
3548c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3549c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3550c921d74cSToby Isaac   const PetscInt *rootDegrees;
3551c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3552ebf164c7SToby Isaac   PetscSF        coarseToFineEmbedded;
3553ebf164c7SToby Isaac   PetscErrorCode ierr;
3554ebf164c7SToby Isaac 
3555ebf164c7SToby Isaac   PetscFunctionBegin;
3556ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
35578d2f55e7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
3558f30e825dSToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
35598d2f55e7SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3560f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
3561f30e825dSToby Isaac   ierr = PetscSectionSetChart(leafIndicesSec,pStartF, pEndF);CHKERRQ(ierr);
3562c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localFine,&maxDof);CHKERRQ(ierr);
35638d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
35647e96bdafSToby Isaac     PetscInt l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
35657e96bdafSToby Isaac     const PetscInt *leaves;
35668d2f55e7SToby Isaac 
35677e96bdafSToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
35687e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
35697e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35708d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
35718d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
35728d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
35738d2f55e7SToby Isaac         numPointsWithDofs++;
3574f30e825dSToby Isaac 
3575f30e825dSToby Isaac         ierr = PetscSectionGetDof(localFine,p,&dof);CHKERRQ(ierr);
3576f30e825dSToby Isaac         ierr = PetscSectionSetDof(leafIndicesSec,p,dof + 1);CHKERRQ(ierr);
35778d2f55e7SToby Isaac       }
35788d2f55e7SToby Isaac     }
35798d2f55e7SToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
3580f30e825dSToby Isaac     ierr = PetscSectionSetUp(leafIndicesSec);CHKERRQ(ierr);
3581f30e825dSToby Isaac     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numIndices);CHKERRQ(ierr);
3582c921d74cSToby Isaac     ierr = PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1),&leafInds);CHKERRQ(ierr);
3583c921d74cSToby Isaac     if (gatheredValues)  {ierr = PetscMalloc1(numIndices,&leafVals);CHKERRQ(ierr);}
35847e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
35857e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35868d2f55e7SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
35878d2f55e7SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
35888d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3589f30e825dSToby Isaac         PetscInt    off, gOff;
3590f30e825dSToby Isaac         PetscInt    *pInd;
3591c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3592f30e825dSToby Isaac 
35937e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3594f30e825dSToby Isaac 
3595f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3596f30e825dSToby Isaac 
3597c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3598c921d74cSToby Isaac         if (gatheredValues) {
3599c921d74cSToby Isaac           PetscInt i;
3600c921d74cSToby Isaac 
3601c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3602c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3603c921d74cSToby Isaac         }
3604f30e825dSToby Isaac         ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
3605f30e825dSToby Isaac 
3606f30e825dSToby Isaac         offsets[0] = 0;
3607f30e825dSToby Isaac         if (numFields) {
3608f30e825dSToby Isaac           PetscInt f;
3609f30e825dSToby Isaac 
3610f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3611f30e825dSToby Isaac             PetscInt fDof;
3612f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(localFine,p,f,&fDof);CHKERRQ(ierr);
3613f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3614f30e825dSToby Isaac           }
36154acb8e1eSToby Isaac           DMPlexGetIndicesPointFields_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1,pInd);CHKERRQ(ierr);
3616f30e825dSToby Isaac         }
3617f30e825dSToby Isaac         else {
36184acb8e1eSToby Isaac           DMPlexGetIndicesPoint_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,pInd);CHKERRQ(ierr);
3619f30e825dSToby Isaac         }
3620c921d74cSToby Isaac         if (gatheredValues) {ierr = VecGetValues(fineVec,dof,pInd,pVal);CHKERRQ(ierr);}
36218d2f55e7SToby Isaac       }
36228d2f55e7SToby Isaac     }
36238d2f55e7SToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
3624f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
36258d2f55e7SToby Isaac   }
3626f30e825dSToby Isaac 
3627f30e825dSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
3628f30e825dSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
3629f30e825dSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3630f30e825dSToby Isaac 
36316148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
36326148253fSToby Isaac     MPI_Datatype threeInt;
36336148253fSToby Isaac     PetscMPIInt  rank;
36346148253fSToby Isaac     PetscInt     (*parentNodeAndIdCoarse)[3];
36356148253fSToby Isaac     PetscInt     (*parentNodeAndIdFine)[3];
36366148253fSToby Isaac     PetscInt     p, nleaves, nleavesToParents;
36376148253fSToby Isaac     PetscSF      pointSF, sfToParents;
36386148253fSToby Isaac     const PetscInt *ilocal;
36396148253fSToby Isaac     const PetscSFNode *iremote;
36406148253fSToby Isaac     PetscSFNode  *iremoteToParents;
36416148253fSToby Isaac     PetscInt     *ilocalToParents;
36426148253fSToby Isaac 
36436148253fSToby Isaac     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)coarse),&rank);CHKERRQ(ierr);
36446148253fSToby Isaac     ierr = MPI_Type_contiguous(3,MPIU_INT,&threeInt);CHKERRQ(ierr);
36456148253fSToby Isaac     ierr = MPI_Type_commit(&threeInt);CHKERRQ(ierr);
36466148253fSToby Isaac     ierr = PetscMalloc2(pEndC-pStartC,&parentNodeAndIdCoarse,pEndF-pStartF,&parentNodeAndIdFine);CHKERRQ(ierr);
36476148253fSToby Isaac     ierr = DMGetPointSF(coarse,&pointSF);CHKERRQ(ierr);
36486148253fSToby Isaac     ierr = PetscSFGetGraph(pointSF,NULL,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
36496148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
36506148253fSToby Isaac       PetscInt parent, childId;
36516148253fSToby Isaac       ierr = DMPlexGetTreeParent(coarse,p,&parent,&childId);CHKERRQ(ierr);
36526148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
36536148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
36546148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
36556148253fSToby Isaac       if (nleaves > 0) {
36566148253fSToby Isaac         PetscInt leaf = -1;
36576148253fSToby Isaac 
36586148253fSToby Isaac         if (ilocal) {
36596148253fSToby Isaac           ierr  = PetscFindInt(parent,nleaves,ilocal,&leaf);CHKERRQ(ierr);
36606148253fSToby Isaac         }
36616148253fSToby Isaac         else {
36626148253fSToby Isaac           leaf = p - pStartC;
36636148253fSToby Isaac         }
36646148253fSToby Isaac         if (leaf >= 0) {
36656148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
36666148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
36676148253fSToby Isaac         }
36686148253fSToby Isaac       }
36696148253fSToby Isaac     }
36706148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
36716148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
36726148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
36736148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
36746148253fSToby Isaac     }
36756148253fSToby Isaac     ierr = PetscSFBcastBegin(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36766148253fSToby Isaac     ierr = PetscSFBcastEnd(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
36776148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3678f30e825dSToby Isaac       PetscInt dof;
3679f30e825dSToby Isaac 
3680f30e825dSToby Isaac       ierr = PetscSectionGetDof(leafIndicesSec,p,&dof);CHKERRQ(ierr);
3681f30e825dSToby Isaac       if (dof) {
3682f30e825dSToby Isaac         PetscInt off;
3683f30e825dSToby Isaac 
3684f30e825dSToby Isaac         ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr);
3685c921d74cSToby Isaac         if (gatheredIndices) {
3686c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3687c921d74cSToby Isaac         } else if (gatheredValues) {
3688c921d74cSToby Isaac           leafVals[off] = (PetscScalar) PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3689c921d74cSToby Isaac         }
3690f30e825dSToby Isaac       }
36916148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36926148253fSToby Isaac         nleavesToParents++;
36936148253fSToby Isaac       }
36946148253fSToby Isaac     }
36956148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&ilocalToParents);CHKERRQ(ierr);
36966148253fSToby Isaac     ierr = PetscMalloc1(nleavesToParents,&iremoteToParents);CHKERRQ(ierr);
36976148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
36986148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36996148253fSToby Isaac         ilocalToParents[nleavesToParents] = p - pStartF;
37006148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p-pStartF][0];
37016148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p-pStartF][1];
37026148253fSToby Isaac         nleavesToParents++;
37036148253fSToby Isaac       }
37046148253fSToby Isaac     }
37056148253fSToby Isaac     ierr = PetscSFCreate(PetscObjectComm((PetscObject)coarse),&sfToParents);CHKERRQ(ierr);
37066148253fSToby Isaac     ierr = PetscSFSetGraph(sfToParents,pEndC-pStartC,nleavesToParents,ilocalToParents,PETSC_OWN_POINTER,iremoteToParents,PETSC_OWN_POINTER);CHKERRQ(ierr);
37076148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
37086148253fSToby Isaac 
37096148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
37106148253fSToby Isaac 
37116148253fSToby Isaac     ierr = PetscFree2(parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr);
37126148253fSToby Isaac     ierr = MPI_Type_free(&threeInt);CHKERRQ(ierr);
37136148253fSToby Isaac   }
3714f30e825dSToby Isaac 
37156148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
37166148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
37176148253fSToby Isaac     PetscSF  sfDofsOnly;
37186148253fSToby Isaac 
37196148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
37206148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
37216148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
37226148253fSToby Isaac       if ((dof - cdof) > 0) {
37236148253fSToby Isaac         numPointsWithDofs++;
37246148253fSToby Isaac       }
37256148253fSToby Isaac     }
37266148253fSToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
37276148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
37286148253fSToby Isaac       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
37296148253fSToby Isaac       ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
37306148253fSToby Isaac       if ((dof - cdof) > 0) {
3731e03d9830SToby Isaac         pointsWithDofs[offset++] = p - pStartC;
37326148253fSToby Isaac       }
37336148253fSToby Isaac     }
37346148253fSToby Isaac     ierr = PetscSFCreateEmbeddedSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly);CHKERRQ(ierr);
37356148253fSToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3736f30e825dSToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
37376148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
37386148253fSToby Isaac   }
3739f30e825dSToby Isaac 
37406148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
3741f30e825dSToby Isaac   ierr = PetscSFComputeDegreeBegin(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3742f30e825dSToby Isaac   ierr = PetscSFComputeDegreeEnd(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr);
3743f30e825dSToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&multiRootSec);CHKERRQ(ierr);
3744f30e825dSToby Isaac   ierr = PetscSectionSetChart(multiRootSec,pStartC,pEndC);CHKERRQ(ierr);
37458d2f55e7SToby Isaac   for (p = pStartC; p < pEndC; p++) {
3746f30e825dSToby Isaac     ierr = PetscSectionSetDof(multiRootSec,p,rootDegrees[p-pStartC]);CHKERRQ(ierr);
37478d2f55e7SToby Isaac   }
3748f30e825dSToby Isaac   ierr = PetscSectionSetUp(multiRootSec);CHKERRQ(ierr);
3749f30e825dSToby Isaac   ierr = PetscSectionGetStorageSize(multiRootSec,&numMulti);CHKERRQ(ierr);
37508d2f55e7SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
3751f30e825dSToby Isaac   { /* distribute the leaf section */
3752f30e825dSToby Isaac     PetscSF multi, multiInv, indicesSF;
3753f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
37548d2f55e7SToby Isaac 
3755f30e825dSToby Isaac     ierr = PetscSFGetMultiSF(coarseToFineEmbedded,&multi);CHKERRQ(ierr);
3756f30e825dSToby Isaac     ierr = PetscSFCreateInverseSF(multi,&multiInv);CHKERRQ(ierr);
3757f30e825dSToby Isaac     ierr = PetscSFDistributeSection(multiInv,leafIndicesSec,&remoteOffsets,rootIndicesSec);CHKERRQ(ierr);
3758f30e825dSToby Isaac     ierr = PetscSFCreateSectionSF(multiInv,leafIndicesSec,remoteOffsets,rootIndicesSec,&indicesSF);CHKERRQ(ierr);
3759f30e825dSToby Isaac     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
3760f30e825dSToby Isaac     ierr = PetscSFDestroy(&multiInv);CHKERRQ(ierr);
37618d2f55e7SToby Isaac     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
3762c921d74cSToby Isaac     if (gatheredIndices) {
3763c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootInds);CHKERRQ(ierr);
3764c921d74cSToby Isaac       ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr);
3765c921d74cSToby Isaac       ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr);
3766c921d74cSToby Isaac     }
3767c921d74cSToby Isaac     if (gatheredValues) {
3768c921d74cSToby Isaac       ierr = PetscMalloc1(numRootIndices,&rootVals);CHKERRQ(ierr);
3769c921d74cSToby Isaac       ierr = PetscSFBcastBegin(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr);
3770c921d74cSToby Isaac       ierr = PetscSFBcastEnd(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr);
3771c921d74cSToby Isaac     }
37728d2f55e7SToby Isaac     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
37738d2f55e7SToby Isaac   }
3774ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
3775c921d74cSToby Isaac   ierr = PetscFree(leafInds);CHKERRQ(ierr);
3776c921d74cSToby Isaac   ierr = PetscFree(leafVals);CHKERRQ(ierr);
3777f30e825dSToby Isaac   ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
3778c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3779c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3780c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3781c921d74cSToby Isaac   if (gatheredValues)  *gatheredValues  = rootVals;
3782ebf164c7SToby Isaac   PetscFunctionReturn(0);
3783ebf164c7SToby Isaac }
3784ebf164c7SToby Isaac 
3785ebf164c7SToby Isaac #undef __FUNCT__
3786ebf164c7SToby Isaac #define __FUNCT__ "DMPlexComputeInjectorTree"
3787ebf164c7SToby Isaac PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3788ebf164c7SToby Isaac {
3789ebf164c7SToby Isaac   DM             refTree;
3790c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3791ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3792ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3793ebf164c7SToby Isaac   PetscSection   cSecRef;
3794c921d74cSToby Isaac   PetscInt       *rootIndices, *parentIndices, pRefStart, pRefEnd;
3795ebf164c7SToby Isaac   Mat            injRef;
3796c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3797ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3798ebf164c7SToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
3799ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3800ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3801ebf164c7SToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3802ebf164c7SToby Isaac   PetscErrorCode ierr;
3803ebf164c7SToby Isaac 
3804ebf164c7SToby Isaac   PetscFunctionBegin;
3805ebf164c7SToby Isaac 
3806ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
3807ebf164c7SToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
3808ebf164c7SToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
3809ebf164c7SToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
3810ebf164c7SToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
3811ebf164c7SToby Isaac 
3812ebf164c7SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
3813ebf164c7SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
3814ebf164c7SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
3815ebf164c7SToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
3816ebf164c7SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
3817ebf164c7SToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
3818ebf164c7SToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
3819ebf164c7SToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
3820ebf164c7SToby Isaac   {
3821ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
3822ebf164c7SToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
3823ebf164c7SToby Isaac   }
3824ebf164c7SToby Isaac 
3825c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,childIds,NULL,numFields,offsets,&multiRootSec,&rootIndicesSec,&rootIndices,NULL);CHKERRQ(ierr);
38268d2f55e7SToby Isaac 
3827f30e825dSToby Isaac   ierr = PetscMalloc1(maxDof,&parentIndices);CHKERRQ(ierr);
3828f30e825dSToby Isaac 
3829f30e825dSToby Isaac   /* count indices */
38308d2f55e7SToby Isaac   ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
3831c6154584SToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
3832c6154584SToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
38338d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
38348d2f55e7SToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
3835f30e825dSToby Isaac   ierr = PetscCalloc2(rowEnd-rowStart,&nnzD,rowEnd-rowStart,&nnzO);CHKERRQ(ierr);
3836f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3837f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
38388d2f55e7SToby Isaac 
3839f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3840f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3841f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3842f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
38438d2f55e7SToby Isaac 
38448d2f55e7SToby Isaac     rowOffsets[0] = 0;
3845f30e825dSToby Isaac     offsetsCopy[0] = 0;
38468d2f55e7SToby Isaac     if (numFields) {
38478d2f55e7SToby Isaac       PetscInt f;
38488d2f55e7SToby Isaac 
3849f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3850f30e825dSToby Isaac         PetscInt fDof;
3851f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3852f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
38538d2f55e7SToby Isaac       }
38544acb8e1eSToby Isaac       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,parentIndices);CHKERRQ(ierr);
38558d2f55e7SToby Isaac     }
38568d2f55e7SToby Isaac     else {
38574acb8e1eSToby Isaac       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,parentIndices);CHKERRQ(ierr);
3858f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
38598d2f55e7SToby Isaac     }
3860f30e825dSToby Isaac 
3861f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3862f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3863f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3864f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3865f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3866f30e825dSToby Isaac       const PetscInt *childIndices;
3867f30e825dSToby Isaac 
3868f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3869f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3870f30e825dSToby Isaac       childId = rootIndices[offset++];
3871f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3872f30e825dSToby Isaac       numIndices--;
3873f30e825dSToby Isaac 
3874f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3875f30e825dSToby Isaac         PetscInt i;
3876f30e825dSToby Isaac 
3877f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3878f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3879f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3880f30e825dSToby Isaac           if (rowIndex < 0) continue;
3881f30e825dSToby Isaac           if (colIndex < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unconstrained fine and constrained coarse");
3882a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3883f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
3884f30e825dSToby Isaac           }
3885f30e825dSToby Isaac           else {
3886f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3887f30e825dSToby Isaac           }
3888f30e825dSToby Isaac         }
3889f30e825dSToby Isaac       }
3890f30e825dSToby Isaac       else {
3891f30e825dSToby Isaac         PetscInt parentId, f, lim;
3892f30e825dSToby Isaac 
3893f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3894f30e825dSToby Isaac 
3895f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3896f30e825dSToby Isaac         offsets[0] = 0;
38978d2f55e7SToby Isaac         if (numFields) {
38988d2f55e7SToby Isaac           PetscInt f;
3899f30e825dSToby Isaac 
39008d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3901f30e825dSToby Isaac             PetscInt fDof;
3902f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
3903f30e825dSToby Isaac 
3904f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
39058d2f55e7SToby Isaac           }
39068d2f55e7SToby Isaac         }
39078d2f55e7SToby Isaac         else {
3908f30e825dSToby Isaac           PetscInt cDof;
3909f30e825dSToby Isaac 
3910f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
3911f30e825dSToby Isaac           offsets[1] = cDof;
3912f30e825dSToby Isaac         }
3913f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3914f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3915f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3916f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3917f30e825dSToby Isaac 
3918f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3919f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3920f30e825dSToby Isaac 
3921f30e825dSToby Isaac             if (colIndex < 0) continue;
3922f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3923f30e825dSToby Isaac               numD++;
3924f30e825dSToby Isaac             }
3925f30e825dSToby Isaac             else {
3926f30e825dSToby Isaac               numO++;
3927f30e825dSToby Isaac             }
3928f30e825dSToby Isaac           }
3929f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3930f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3931f30e825dSToby Isaac 
3932f30e825dSToby Isaac             if (rowIndex < 0) continue;
3933f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3934f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
39358d2f55e7SToby Isaac           }
39368d2f55e7SToby Isaac         }
39378d2f55e7SToby Isaac       }
3938f30e825dSToby Isaac     }
3939f30e825dSToby Isaac   }
3940f30e825dSToby Isaac   /* preallocate */
3941f30e825dSToby Isaac   ierr = MatXAIJSetPreallocation(mat,1,nnzD,nnzO,NULL,NULL);CHKERRQ(ierr);
3942f30e825dSToby Isaac   ierr = PetscFree2(nnzD,nnzO);CHKERRQ(ierr);
3943f30e825dSToby Isaac   /* insert values */
3944f30e825dSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
3945f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3946f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3947f30e825dSToby Isaac 
3948f30e825dSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
3949f30e825dSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
3950f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
3951f30e825dSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
3952f30e825dSToby Isaac 
3953f30e825dSToby Isaac     rowOffsets[0] = 0;
3954f30e825dSToby Isaac     offsetsCopy[0] = 0;
39558d2f55e7SToby Isaac     if (numFields) {
39568d2f55e7SToby Isaac       PetscInt f;
3957f30e825dSToby Isaac 
39588d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3959f30e825dSToby Isaac         PetscInt fDof;
3960f30e825dSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
3961f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3962f30e825dSToby Isaac       }
39634acb8e1eSToby Isaac       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,parentIndices);CHKERRQ(ierr);
3964f30e825dSToby Isaac     }
3965f30e825dSToby Isaac     else {
39664acb8e1eSToby Isaac       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,parentIndices);CHKERRQ(ierr);
3967f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3968f30e825dSToby Isaac     }
3969f30e825dSToby Isaac 
3970f30e825dSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
3971f30e825dSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
3972f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3973f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3974f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3975f30e825dSToby Isaac       const PetscInt *childIndices;
3976f30e825dSToby Isaac 
3977f30e825dSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
3978f30e825dSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
3979f30e825dSToby Isaac       childId = rootIndices[offset++];
3980f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3981f30e825dSToby Isaac       numIndices--;
3982f30e825dSToby Isaac 
3983f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3984f30e825dSToby Isaac         PetscInt i;
3985f30e825dSToby Isaac 
3986f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3987f30e825dSToby Isaac           ierr = MatSetValue(mat,parentIndices[i],childIndices[i],1.,INSERT_VALUES);CHKERRQ(ierr);
39888d2f55e7SToby Isaac         }
39898d2f55e7SToby Isaac       }
39908d2f55e7SToby Isaac       else {
3991f30e825dSToby Isaac         PetscInt parentId, f, lim;
39928d2f55e7SToby Isaac 
3993f30e825dSToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
3994f30e825dSToby Isaac 
3995f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3996f30e825dSToby Isaac         offsets[0] = 0;
39978d2f55e7SToby Isaac         if (numFields) {
3998f30e825dSToby Isaac           PetscInt f;
39998d2f55e7SToby Isaac 
4000f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
4001f30e825dSToby Isaac             PetscInt fDof;
4002f30e825dSToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
4003f30e825dSToby Isaac 
4004f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
40058d2f55e7SToby Isaac           }
40068d2f55e7SToby Isaac         }
40078d2f55e7SToby Isaac         else {
4008f30e825dSToby Isaac           PetscInt cDof;
4009f30e825dSToby Isaac 
4010f30e825dSToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
4011f30e825dSToby Isaac           offsets[1] = cDof;
40128d2f55e7SToby Isaac         }
4013f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
4014f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
4015f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
4016f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
4017f30e825dSToby Isaac 
4018f30e825dSToby Isaac           ierr = MatSetValues(mat,rowOffsets[f+1]-rowOffsets[f],rowIndices,offsets[f+1]-offsets[f],colIndices,childMat,INSERT_VALUES);CHKERRQ(ierr);
40198d2f55e7SToby Isaac         }
40208d2f55e7SToby Isaac       }
40218d2f55e7SToby Isaac     }
40228d2f55e7SToby Isaac   }
4023ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
4024ec92bd66SToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
4025ec92bd66SToby Isaac   ierr = PetscFree(parentIndices);CHKERRQ(ierr);
4026f30e825dSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4027f30e825dSToby Isaac   ierr = PetscFree(rootIndices);CHKERRQ(ierr);
4028f30e825dSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
4029f30e825dSToby Isaac 
40308d2f55e7SToby Isaac   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
40318d2f55e7SToby Isaac   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
4032154bca37SToby Isaac   PetscFunctionReturn(0);
4033154bca37SToby Isaac }
403438fc2455SToby Isaac 
403538fc2455SToby Isaac #undef __FUNCT__
4036ebf164c7SToby Isaac #define __FUNCT__ "DMPlexTransferVecTree_Interpolate"
40370eb7e1eaSToby Isaac static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
4038ebf164c7SToby Isaac {
40394833aeb0SToby Isaac   PetscDS           ds;
404062095d54SToby Isaac   PetscSF           coarseToFineEmbedded;
404162095d54SToby Isaac   PetscSection      globalCoarse, globalFine;
404262095d54SToby Isaac   PetscSection      localCoarse, localFine;
404362095d54SToby Isaac   PetscSection      aSec, cSec;
404462095d54SToby Isaac   PetscSection      rootValuesSec;
404562095d54SToby Isaac   PetscSection      leafValuesSec;
404662095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
404762095d54SToby Isaac   IS                aIS;
404862095d54SToby Isaac   const PetscInt    *anchors;
404962095d54SToby Isaac   Mat               cMat;
405062095d54SToby Isaac   PetscInt          numFields;
405189698031SToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd, cellEndInterior;
405262095d54SToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
405362095d54SToby Isaac   PetscInt          *maxChildIds;
405462095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
40550eb7e1eaSToby Isaac   PetscFV           fv = NULL;
40560eb7e1eaSToby Isaac   PetscInt          dim, numFVcomps = -1, fvField = -1;
40570eb7e1eaSToby Isaac   DM                cellDM = NULL, gradDM = NULL;
40580eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
40590eb7e1eaSToby Isaac   const PetscScalar *gradArray = NULL;
406062095d54SToby Isaac   PetscErrorCode    ierr;
406162095d54SToby Isaac 
4062ebf164c7SToby Isaac   PetscFunctionBegin;
4063708c7f19SToby Isaac   ierr = VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
406462095d54SToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
40650eb7e1eaSToby Isaac   ierr = DMPlexGetHeightStratum(coarse,0,&cellStart,&cellEnd);CHKERRQ(ierr);
406689698031SToby Isaac   ierr = DMPlexGetHybridBounds(coarse,&cellEndInterior,NULL,NULL,NULL);CHKERRQ(ierr);
406789698031SToby Isaac   cellEnd = (cellEndInterior < 0) ? cellEnd : cellEndInterior;
406862095d54SToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
406962095d54SToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
40700eb7e1eaSToby Isaac   ierr = DMGetCoordinateDim(coarse,&dim);CHKERRQ(ierr);
407162095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
4072e4a60869SToby Isaac     PetscInt       nleaves, l;
4073e4a60869SToby Isaac     const PetscInt *leaves;
407462095d54SToby Isaac     PetscInt       dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
407562095d54SToby Isaac 
4076e4a60869SToby Isaac     ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
4077e4a60869SToby Isaac 
4078e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
4079e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
4080e4a60869SToby Isaac 
408162095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
408262095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
408362095d54SToby Isaac       if ((dof - cdof) > 0) {
408462095d54SToby Isaac         numPointsWithDofs++;
408562095d54SToby Isaac       }
408662095d54SToby Isaac     }
408762095d54SToby Isaac     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
40884833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
4089e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
4090e4a60869SToby Isaac 
409162095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
409262095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
409362095d54SToby Isaac       if ((dof - cdof) > 0) {
4094e4a60869SToby Isaac         pointsWithDofs[offset++] = l;
409562095d54SToby Isaac       }
409662095d54SToby Isaac     }
409762095d54SToby Isaac     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
409862095d54SToby Isaac     ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr);
409962095d54SToby Isaac   }
410062095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
410162095d54SToby Isaac   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
410262095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) {
410362095d54SToby Isaac     maxChildIds[p - pStartC] = -2;
410462095d54SToby Isaac   }
410562095d54SToby Isaac   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
410662095d54SToby Isaac   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
410762095d54SToby Isaac 
410862095d54SToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
410962095d54SToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
411062095d54SToby Isaac 
411162095d54SToby Isaac   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
411262095d54SToby Isaac   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
411362095d54SToby Isaac   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
411462095d54SToby Isaac 
411562095d54SToby Isaac   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
411662095d54SToby Isaac   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
411762095d54SToby Isaac 
411862095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
411962095d54SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootValuesSec);CHKERRQ(ierr);
412062095d54SToby Isaac   ierr = PetscSectionSetChart(rootValuesSec,pStartC,pEndC);CHKERRQ(ierr);
4121708c7f19SToby Isaac   ierr = PetscSectionGetNumFields(localCoarse,&numFields);CHKERRQ(ierr);
412262095d54SToby Isaac   {
412362095d54SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
412462095d54SToby Isaac     ierr = PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO);CHKERRQ(ierr);
412562095d54SToby Isaac   }
41260eb7e1eaSToby Isaac   if (grad) {
41270eb7e1eaSToby Isaac     PetscInt i;
41280eb7e1eaSToby Isaac 
41290eb7e1eaSToby Isaac     ierr = VecGetDM(cellGeom,&cellDM);CHKERRQ(ierr);
41300eb7e1eaSToby Isaac     ierr = VecGetArrayRead(cellGeom,&cellGeomArray);CHKERRQ(ierr);
41310eb7e1eaSToby Isaac     ierr = VecGetDM(grad,&gradDM);CHKERRQ(ierr);
41320eb7e1eaSToby Isaac     ierr = VecGetArrayRead(grad,&gradArray);CHKERRQ(ierr);
41330eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1,numFields); i++) {
41340eb7e1eaSToby Isaac       PetscObject  obj;
41350eb7e1eaSToby Isaac       PetscClassId id;
41360eb7e1eaSToby Isaac 
41370eb7e1eaSToby Isaac       ierr = DMGetField(coarse, i, &obj);CHKERRQ(ierr);
41380eb7e1eaSToby Isaac       ierr = PetscObjectGetClassId(obj,&id);CHKERRQ(ierr);
41390eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
41400eb7e1eaSToby Isaac         fv      = (PetscFV) obj;
41410eb7e1eaSToby Isaac         ierr    = PetscFVGetNumComponents(fv,&numFVcomps);CHKERRQ(ierr);
41420eb7e1eaSToby Isaac         fvField = i;
41430eb7e1eaSToby Isaac         break;
41440eb7e1eaSToby Isaac       }
41450eb7e1eaSToby Isaac     }
41460eb7e1eaSToby Isaac   }
414762095d54SToby Isaac 
414862095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
414962095d54SToby Isaac     PetscInt dof;
415062095d54SToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
415162095d54SToby Isaac     PetscInt numValues      = 0;
415262095d54SToby Isaac 
415362095d54SToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
415462095d54SToby Isaac     if (dof < 0) {
415562095d54SToby Isaac       dof = -(dof + 1);
415662095d54SToby Isaac     }
415762095d54SToby Isaac     offsets[0]    = 0;
415862095d54SToby Isaac     newOffsets[0] = 0;
415962095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
416062095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
416162095d54SToby Isaac 
41624833aeb0SToby Isaac       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
416362095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
416462095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
416562095d54SToby Isaac 
416662095d54SToby Isaac         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
416762095d54SToby Isaac         numValues += clDof;
416862095d54SToby Isaac       }
41694833aeb0SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
417062095d54SToby Isaac     }
417162095d54SToby Isaac     else if (maxChildId == -1) {
417262095d54SToby Isaac       ierr = PetscSectionGetDof(localCoarse,p,&numValues);CHKERRQ(ierr);
417362095d54SToby Isaac     }
417462095d54SToby Isaac     /* we will pack the column indices with the field offsets */
417578b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
41760eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
41770eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
41780eb7e1eaSToby Isaac     }
417962095d54SToby Isaac     ierr = PetscSectionSetDof(rootValuesSec,p,numValues);CHKERRQ(ierr);
418062095d54SToby Isaac   }
418162095d54SToby Isaac   ierr = PetscSectionSetUp(rootValuesSec);CHKERRQ(ierr);
418262095d54SToby Isaac   {
418362095d54SToby Isaac     PetscInt          numRootValues;
418462095d54SToby Isaac     const PetscScalar *coarseArray;
418562095d54SToby Isaac 
418662095d54SToby Isaac     ierr = PetscSectionGetStorageSize(rootValuesSec,&numRootValues);CHKERRQ(ierr);
418762095d54SToby Isaac     ierr = PetscMalloc1(numRootValues,&rootValues);CHKERRQ(ierr);
418862095d54SToby Isaac     ierr = VecGetArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr);
418962095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
419062095d54SToby Isaac       PetscInt    numValues;
419162095d54SToby Isaac       PetscInt    pValOff;
419262095d54SToby Isaac       PetscScalar *pVal;
419362095d54SToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
419462095d54SToby Isaac 
419562095d54SToby Isaac       ierr = PetscSectionGetDof(rootValuesSec,p,&numValues);CHKERRQ(ierr);
419662095d54SToby Isaac       if (!numValues) {
419762095d54SToby Isaac         continue;
419862095d54SToby Isaac       }
419962095d54SToby Isaac       ierr = PetscSectionGetOffset(rootValuesSec,p,&pValOff);CHKERRQ(ierr);
420062095d54SToby Isaac       pVal = &(rootValues[pValOff]);
420162095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
42020eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
42030eb7e1eaSToby Isaac         ierr = DMPlexVecGetClosure(coarse,NULL,vecCoarseLocal,p,&closureSize,&pVal);CHKERRQ(ierr);
42040eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
4205193eb951SToby Isaac           PetscFVCellGeom *cg;
42066dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
42070eb7e1eaSToby Isaac           PetscInt        i;
42080eb7e1eaSToby Isaac 
42090eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
42100eb7e1eaSToby Isaac 
4211193eb951SToby Isaac           ierr = DMPlexPointLocalRead(cellDM,p,cellGeomArray,(void *) &cg);CHKERRQ(ierr);
42120eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
42130eb7e1eaSToby Isaac           pVal += dim;
4214193eb951SToby Isaac           ierr = DMPlexPointGlobalRead(gradDM,p,gradArray,(void *) &gradVals);CHKERRQ(ierr);
42150eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
42160eb7e1eaSToby Isaac         }
421762095d54SToby Isaac       }
421878b7adb5SToby Isaac       else if (maxChildId == -1) {
421978b7adb5SToby Isaac         PetscInt lDof, lOff, i;
422078b7adb5SToby Isaac 
422178b7adb5SToby Isaac         ierr = PetscSectionGetDof(localCoarse,p,&lDof);CHKERRQ(ierr);
422278b7adb5SToby Isaac         ierr = PetscSectionGetOffset(localCoarse,p,&lOff);CHKERRQ(ierr);
422378b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
422478b7adb5SToby Isaac       }
422578b7adb5SToby Isaac     }
422662095d54SToby Isaac     ierr = VecRestoreArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr);
422762095d54SToby Isaac     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
422862095d54SToby Isaac   }
422962095d54SToby Isaac   {
423062095d54SToby Isaac     PetscSF  valuesSF;
423162095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
423262095d54SToby Isaac 
423362095d54SToby Isaac     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafValuesSec);CHKERRQ(ierr);
423462095d54SToby Isaac     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootValuesSec,&remoteOffsetsValues,leafValuesSec);CHKERRQ(ierr);
423562095d54SToby Isaac     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootValuesSec,remoteOffsetsValues,leafValuesSec,&valuesSF);CHKERRQ(ierr);
423662095d54SToby Isaac     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
423762095d54SToby Isaac     ierr = PetscFree(remoteOffsetsValues);CHKERRQ(ierr);
423862095d54SToby Isaac     ierr = PetscSectionGetStorageSize(leafValuesSec,&numLeafValues);CHKERRQ(ierr);
423962095d54SToby Isaac     ierr = PetscMalloc1(numLeafValues,&leafValues);CHKERRQ(ierr);
424062095d54SToby Isaac     ierr = PetscSFBcastBegin(valuesSF,MPIU_SCALAR,rootValues,leafValues);CHKERRQ(ierr);
424162095d54SToby Isaac     ierr = PetscSFBcastEnd(valuesSF,MPIU_SCALAR,rootValues,leafValues);CHKERRQ(ierr);
424262095d54SToby Isaac     ierr = PetscSFDestroy(&valuesSF);CHKERRQ(ierr);
424362095d54SToby Isaac     ierr = PetscFree(rootValues);CHKERRQ(ierr);
424462095d54SToby Isaac     ierr = PetscSectionDestroy(&rootValuesSec);CHKERRQ(ierr);
424562095d54SToby Isaac   }
424662095d54SToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
424762095d54SToby Isaac   {
424862095d54SToby Isaac     PetscInt    maxDof;
424962095d54SToby Isaac     PetscInt    *rowIndices;
425062095d54SToby Isaac     DM           refTree;
425162095d54SToby Isaac     PetscInt     **refPointFieldN;
425262095d54SToby Isaac     PetscScalar  ***refPointFieldMats;
425362095d54SToby Isaac     PetscSection refConSec, refAnSec;
42540eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,leafStart,leafEnd;
425562095d54SToby Isaac     PetscScalar  *pointWork;
425662095d54SToby Isaac 
425762095d54SToby Isaac     ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr);
425862095d54SToby Isaac     ierr = DMGetWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
425962095d54SToby Isaac     ierr = DMGetWorkArray(fine,maxDof,PETSC_SCALAR,&pointWork);CHKERRQ(ierr);
426062095d54SToby Isaac     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
42614833aeb0SToby Isaac     ierr = DMGetDS(fine,&ds);CHKERRQ(ierr);
42624833aeb0SToby Isaac     ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
426362095d54SToby Isaac     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
426462095d54SToby Isaac     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
426562095d54SToby Isaac     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
426662095d54SToby Isaac     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
42670eb7e1eaSToby Isaac     ierr = PetscSectionGetChart(leafValuesSec,&leafStart,&leafEnd);CHKERRQ(ierr);
42680eb7e1eaSToby Isaac     ierr = DMPlexGetHeightStratum(fine,0,&cellStart,&cellEnd);CHKERRQ(ierr);
426989698031SToby Isaac     ierr = DMPlexGetHybridBounds(fine,&cellEndInterior,NULL,NULL,NULL);CHKERRQ(ierr);
427089698031SToby Isaac     cellEnd = (cellEndInterior < 0) ? cellEnd : cellEndInterior;
42710eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
427262095d54SToby Isaac       PetscInt          gDof, gcDof, gOff, lDof;
427362095d54SToby Isaac       PetscInt          numValues, pValOff;
427462095d54SToby Isaac       PetscInt          childId;
427562095d54SToby Isaac       const PetscScalar *pVal;
42760eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
427762095d54SToby Isaac 
427862095d54SToby Isaac       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
427962095d54SToby Isaac       ierr = PetscSectionGetDof(localFine,p,&lDof);CHKERRQ(ierr);
428062095d54SToby Isaac       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
428162095d54SToby Isaac       if ((gDof - gcDof) <= 0) {
428262095d54SToby Isaac         continue;
428362095d54SToby Isaac       }
428462095d54SToby Isaac       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
428562095d54SToby Isaac       ierr = PetscSectionGetDof(leafValuesSec,p,&numValues);CHKERRQ(ierr);
428662095d54SToby Isaac       if (!numValues) continue;
428762095d54SToby Isaac       ierr = PetscSectionGetOffset(leafValuesSec,p,&pValOff);CHKERRQ(ierr);
428862095d54SToby Isaac       pVal = &leafValues[pValOff];
428962095d54SToby Isaac       offsets[0]        = 0;
429062095d54SToby Isaac       offsetsCopy[0]    = 0;
429162095d54SToby Isaac       newOffsets[0]     = 0;
429262095d54SToby Isaac       newOffsetsCopy[0] = 0;
42934833aeb0SToby Isaac       childId           = cids[p - pStartF];
429462095d54SToby Isaac       if (numFields) {
429562095d54SToby Isaac         PetscInt f;
429662095d54SToby Isaac         for (f = 0; f < numFields; f++) {
429762095d54SToby Isaac           PetscInt rowDof;
429862095d54SToby Isaac 
429962095d54SToby Isaac           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
430062095d54SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
430162095d54SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
430262095d54SToby Isaac           /* TODO: closure indices */
43039f4e70e1SToby Isaac           newOffsets[f + 1]     = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
430462095d54SToby Isaac         }
43054acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,rowIndices);CHKERRQ(ierr);
430662095d54SToby Isaac       }
430762095d54SToby Isaac       else {
43084833aeb0SToby Isaac         offsets[0]    = 0;
43094833aeb0SToby Isaac         offsets[1]    = lDof;
43104833aeb0SToby Isaac         newOffsets[0] = 0;
43114833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
43124acb8e1eSToby Isaac         ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,NULL,rowIndices);CHKERRQ(ierr);
431362095d54SToby Isaac       }
431462095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
43152f65e181SToby Isaac         ierr = VecSetValues(vecFine,numValues,rowIndices,pVal,INSERT_VALUES);CHKERRQ(ierr);
431662095d54SToby Isaac       } else {
431762095d54SToby Isaac         PetscInt f;
431862095d54SToby Isaac 
431978b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
432078b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
432178b7adb5SToby Isaac           fvGradData = &pVal[numValues];
432278b7adb5SToby Isaac         }
432362095d54SToby Isaac         for (f = 0; f < PetscMax(1,numFields); f++) {
432462095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
432562095d54SToby Isaac           PetscInt numRows = offsets[f+1] - offsets[f];
432662095d54SToby Isaac           PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
432762095d54SToby Isaac           const PetscScalar *cVal = &pVal[newOffsets[f]];
432862095d54SToby Isaac           PetscScalar *rVal = &pointWork[offsets[f]];
432962095d54SToby Isaac           PetscInt i, j;
433062095d54SToby Isaac 
4331708c7f19SToby Isaac #if 0
4332708c7f19SToby Isaac           ierr = PetscInfo6(coarse,"field %D, numFields %D, childId %D, numRows %D, numCols %D, refPointFieldN %D\n",f,numFields,childId,numRows,numCols,refPointFieldN[childId - pRefStart][f]);CHKERRQ(ierr);
4333708c7f19SToby Isaac #endif
433462095d54SToby Isaac           for (i = 0; i < numRows; i++) {
433562095d54SToby Isaac             PetscScalar val = 0.;
433662095d54SToby Isaac             for (j = 0; j < numCols; j++) {
433762095d54SToby Isaac               val += childMat[i * numCols + j] * cVal[j];
433862095d54SToby Isaac             }
433962095d54SToby Isaac             rVal[i] = val;
434062095d54SToby Isaac           }
43410eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
43420eb7e1eaSToby Isaac             PetscReal   centroid[3];
43430eb7e1eaSToby Isaac             PetscScalar diff[3];
43440eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
43450eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
43460eb7e1eaSToby Isaac 
43470eb7e1eaSToby Isaac             ierr = DMPlexComputeCellGeometryFVM(fine,p,NULL,centroid,NULL);CHKERRQ(ierr);
43480eb7e1eaSToby Isaac             for (i = 0; i < dim; i++) {
43490eb7e1eaSToby Isaac               diff[i] = centroid[i] - parentCentroid[i];
43500eb7e1eaSToby Isaac             }
43510eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
43520eb7e1eaSToby Isaac               PetscScalar val = 0.;
43530eb7e1eaSToby Isaac 
435489698031SToby Isaac               for (j = 0; j < dim; j++) {
43550eb7e1eaSToby Isaac                 val += gradient[dim * i + j] * diff[j];
43560eb7e1eaSToby Isaac               }
43570eb7e1eaSToby Isaac               rVal[i] += val;
43580eb7e1eaSToby Isaac             }
43590eb7e1eaSToby Isaac           }
43602f65e181SToby Isaac           ierr = VecSetValues(vecFine,numRows,&rowIndices[offsets[f]],rVal,INSERT_VALUES);CHKERRQ(ierr);
436162095d54SToby Isaac         }
436262095d54SToby Isaac       }
436362095d54SToby Isaac     }
436462095d54SToby Isaac     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
436562095d54SToby Isaac     ierr = DMRestoreWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
436662095d54SToby Isaac     ierr = DMRestoreWorkArray(fine,maxDof,PETSC_SCALAR,&pointWork);CHKERRQ(ierr);
436762095d54SToby Isaac   }
43684fe3dfefSToby Isaac   ierr = PetscFree(leafValues);CHKERRQ(ierr);
436962095d54SToby Isaac   ierr = PetscSectionDestroy(&leafValuesSec);CHKERRQ(ierr);
437062095d54SToby Isaac   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
437162095d54SToby Isaac   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
4372ebf164c7SToby Isaac   PetscFunctionReturn(0);
4373ebf164c7SToby Isaac }
4374ebf164c7SToby Isaac 
4375ebf164c7SToby Isaac #undef __FUNCT__
4376ebf164c7SToby Isaac #define __FUNCT__ "DMPlexTransferVecTree_Inject"
4377ebf164c7SToby Isaac static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4378ebf164c7SToby Isaac {
43794833aeb0SToby Isaac   PetscDS        ds;
4380c921d74cSToby Isaac   DM             refTree;
4381c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4382c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4383c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4384c921d74cSToby Isaac   PetscSection   cSecRef;
4385c921d74cSToby Isaac   PetscInt       *parentIndices, pRefStart, pRefEnd;
4386d3bc4906SToby Isaac   PetscScalar    *rootValues, *parentValues;
4387c921d74cSToby Isaac   Mat            injRef;
4388c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4389c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4390c921d74cSToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
4391c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4392c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4393c921d74cSToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4394c921d74cSToby Isaac   PetscErrorCode ierr;
4395c921d74cSToby Isaac 
4396ebf164c7SToby Isaac   PetscFunctionBegin;
4397c921d74cSToby Isaac 
4398c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
4399708c7f19SToby Isaac   ierr = VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
4400708c7f19SToby Isaac   ierr = VecSetOption(vecCoarse,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr);
4401c921d74cSToby Isaac   ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr);
44024833aeb0SToby Isaac   ierr = DMGetDS(coarse,&ds);CHKERRQ(ierr);
44034833aeb0SToby Isaac   ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
4404c921d74cSToby Isaac   ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr);
4405c921d74cSToby Isaac   ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr);
4406c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr);
4407c921d74cSToby Isaac 
4408c921d74cSToby Isaac   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
4409c921d74cSToby Isaac   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
4410c921d74cSToby Isaac   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
4411c921d74cSToby Isaac   ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr);
4412c921d74cSToby Isaac   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
4413c921d74cSToby Isaac   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
4414c921d74cSToby Isaac   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
4415c921d74cSToby Isaac   ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr);
4416c921d74cSToby Isaac   {
4417c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
4418c921d74cSToby Isaac     ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr);
4419c921d74cSToby Isaac   }
4420c921d74cSToby Isaac 
4421c921d74cSToby Isaac   ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,cids,vecFine,numFields,offsets,&multiRootSec,&rootIndicesSec,NULL,&rootValues);CHKERRQ(ierr);
4422c921d74cSToby Isaac 
4423d3bc4906SToby Isaac   ierr = PetscMalloc2(maxDof,&parentIndices,maxDof,&parentValues);CHKERRQ(ierr);
4424c921d74cSToby Isaac 
4425c921d74cSToby Isaac   /* count indices */
442662095d54SToby Isaac   ierr = VecGetLayout(vecFine,&colMap);CHKERRQ(ierr);
442762095d54SToby Isaac   ierr = VecGetLayout(vecCoarse,&rowMap);CHKERRQ(ierr);
4428c921d74cSToby Isaac   ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
4429c921d74cSToby Isaac   ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
4430c921d74cSToby Isaac   ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
4431c921d74cSToby Isaac   ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
4432c921d74cSToby Isaac   /* insert values */
4433c921d74cSToby Isaac   ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4434c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4435c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
443678b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4437c921d74cSToby Isaac 
4438c921d74cSToby Isaac     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
4439c921d74cSToby Isaac     ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr);
4440c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
44412f65e181SToby Isaac     ierr = PetscSectionGetDof(localCoarse,p,&dof);CHKERRQ(ierr);
4442c921d74cSToby Isaac     ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
4443c921d74cSToby Isaac 
4444c921d74cSToby Isaac     rowOffsets[0] = 0;
4445c921d74cSToby Isaac     offsetsCopy[0] = 0;
4446c921d74cSToby Isaac     if (numFields) {
4447c921d74cSToby Isaac       PetscInt f;
4448c921d74cSToby Isaac 
4449c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4450c921d74cSToby Isaac         PetscInt fDof;
4451c921d74cSToby Isaac         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
4452c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4453c921d74cSToby Isaac       }
44544acb8e1eSToby Isaac       DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,parentIndices);CHKERRQ(ierr);
4455c921d74cSToby Isaac     }
4456c921d74cSToby Isaac     else {
44574acb8e1eSToby Isaac       DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,parentIndices);CHKERRQ(ierr);
4458c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4459c921d74cSToby Isaac     }
4460c921d74cSToby Isaac 
4461c921d74cSToby Isaac     ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr);
4462c921d74cSToby Isaac     ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr);
4463c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
44642f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4465c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4466c921d74cSToby Isaac       PetscInt numIndices, childId, offset;
4467c921d74cSToby Isaac       const PetscScalar *childValues;
4468c921d74cSToby Isaac 
4469c921d74cSToby Isaac       ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr);
4470c921d74cSToby Isaac       ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr);
4471c921d74cSToby Isaac       childId = (PetscInt) PetscRealPart(rootValues[offset++]);
4472c921d74cSToby Isaac       childValues = &rootValues[offset];
4473c921d74cSToby Isaac       numIndices--;
4474c921d74cSToby Isaac 
4475c921d74cSToby Isaac       if (childId == -2) { /* skip */
4476c921d74cSToby Isaac         continue;
4477c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
44782f65e181SToby Isaac         PetscInt m;
44792f65e181SToby Isaac 
448078b7adb5SToby Isaac         contribute = PETSC_TRUE;
44812f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4482beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4483d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4484d3bc4906SToby Isaac 
448578b7adb5SToby Isaac         contribute = PETSC_TRUE;
4486d3bc4906SToby Isaac         ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr);
4487d3bc4906SToby Isaac 
4488d3bc4906SToby Isaac         lim = PetscMax(1,numFields);
4489d3bc4906SToby Isaac         offsets[0] = 0;
4490d3bc4906SToby Isaac         if (numFields) {
4491d3bc4906SToby Isaac           PetscInt f;
4492d3bc4906SToby Isaac 
4493d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4494d3bc4906SToby Isaac             PetscInt fDof;
4495d3bc4906SToby Isaac             ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr);
4496d3bc4906SToby Isaac 
4497d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4498d3bc4906SToby Isaac           }
4499d3bc4906SToby Isaac         }
4500d3bc4906SToby Isaac         else {
4501d3bc4906SToby Isaac           PetscInt cDof;
4502d3bc4906SToby Isaac 
4503d3bc4906SToby Isaac           ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr);
4504d3bc4906SToby Isaac           offsets[1] = cDof;
4505d3bc4906SToby Isaac         }
4506d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4507d3bc4906SToby Isaac           PetscScalar       *childMat   = &childrenMats[childId - pRefStart][f][0];
4508d3bc4906SToby Isaac           PetscInt          n           = offsets[f+1]-offsets[f];
4509d3bc4906SToby Isaac           PetscInt          i, j;
4510d3bc4906SToby Isaac           const PetscScalar *colValues  = &childValues[offsets[f]];
4511d3bc4906SToby Isaac 
45122f65e181SToby Isaac           for (i = rowOffsets[f]; i < rowOffsets[f + 1]; i++) {
4513d3bc4906SToby Isaac             PetscScalar val = 0.;
4514d3bc4906SToby Isaac             for (j = 0; j < n; j++) {
4515d3bc4906SToby Isaac               val += childMat[n * i + j] * colValues[j];
4516d3bc4906SToby Isaac             }
4517beedf8abSToby Isaac             parentValues[i] += val;
4518d3bc4906SToby Isaac           }
4519d3bc4906SToby Isaac         }
4520c921d74cSToby Isaac       }
4521c921d74cSToby Isaac     }
452278b7adb5SToby Isaac     if (contribute) {ierr = VecSetValues(vecCoarse,dof,parentIndices,parentValues,INSERT_VALUES);CHKERRQ(ierr);}
4523c921d74cSToby Isaac   }
4524c921d74cSToby Isaac   ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr);
4525c921d74cSToby Isaac   ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
4526d3bc4906SToby Isaac   ierr = PetscFree2(parentIndices,parentValues);CHKERRQ(ierr);
4527c921d74cSToby Isaac   ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr);
4528c921d74cSToby Isaac   ierr = PetscFree(rootValues);CHKERRQ(ierr);
4529c921d74cSToby Isaac   ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr);
4530ebf164c7SToby Isaac   PetscFunctionReturn(0);
4531ebf164c7SToby Isaac }
4532ebf164c7SToby Isaac 
4533ebf164c7SToby Isaac #undef __FUNCT__
453438fc2455SToby Isaac #define __FUNCT__ "DMPlexTransferVecTree"
4535ff1f73f7SToby Isaac /*@
4536ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4537ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4538ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4539ff1f73f7SToby Isaac 
4540ff1f73f7SToby Isaac   collective
4541ff1f73f7SToby Isaac 
4542ff1f73f7SToby Isaac   Input Parameters:
4543ff1f73f7SToby Isaac + dmIn        - The DMPlex mesh for the input vector
4544ff1f73f7SToby Isaac . vecIn       - The input vector
4545ff1f73f7SToby Isaac . sfRefine    - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4546ff1f73f7SToby Isaac                 the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4547ff1f73f7SToby Isaac . sfCoarsen   - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4548ff1f73f7SToby Isaac                 the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4549ff1f73f7SToby Isaac . cidsRefine  - The childIds of the points in dmOut.  These childIds relate back to the reference tree: childid[j] = k implies
4550ff1f73f7SToby Isaac                 that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4551ff1f73f7SToby Isaac                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in dmOut is exactly
4552ff1f73f7SToby Isaac                 equivalent to its root in dmIn, so no interpolation is necessary.  childid[j] = -2 indicates that this
4553ff1f73f7SToby Isaac                 point j in dmOut is not a leaf of sfRefine.
4554ff1f73f7SToby Isaac . cidsCoarsen - The childIds of the points in dmIn.  These childIds relate back to the reference tree: childid[j] = k implies
4555ff1f73f7SToby Isaac                 that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4556ff1f73f7SToby Isaac                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4557ff1f73f7SToby Isaac . useBCs      - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4558ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4559ff1f73f7SToby Isaac 
4560ff1f73f7SToby Isaac   Output Parameters:
4561ff1f73f7SToby Isaac . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transfered
4562ff1f73f7SToby Isaac                 projection of vecIn from dmIn to dmOut.  Note that any field discretized with a PetscFV finite volume
4563ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4564ff1f73f7SToby Isaac                 coarse points to fine points.
4565ff1f73f7SToby Isaac 
4566ff1f73f7SToby Isaac   Level: developer
4567ff1f73f7SToby Isaac 
4568ff1f73f7SToby Isaac .seealso(): DMPlexSetReferenceTree(), DMPlexGetReferenceTree(), PetscFVGetComputeGradients()
4569ff1f73f7SToby Isaac @*/
4570ff1f73f7SToby Isaac PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
457138fc2455SToby Isaac {
4572ebf164c7SToby Isaac   PetscErrorCode ierr;
4573ebf164c7SToby Isaac 
457438fc2455SToby Isaac   PetscFunctionBegin;
457578b7adb5SToby Isaac   ierr = VecSet(vecOut,0.0);CHKERRQ(ierr);
4576ff1f73f7SToby Isaac   if (sfRefine) {
4577fbfa57b9SToby Isaac     Vec vecInLocal;
45780eb7e1eaSToby Isaac     DM  dmGrad = NULL;
45790eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4580fbfa57b9SToby Isaac 
4581fbfa57b9SToby Isaac     ierr = DMGetLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
4582fbfa57b9SToby Isaac     ierr = VecSet(vecInLocal,0.0);CHKERRQ(ierr);
45830eb7e1eaSToby Isaac     {
45840eb7e1eaSToby Isaac       PetscInt  numFields, i;
45850eb7e1eaSToby Isaac 
45860eb7e1eaSToby Isaac       ierr = DMGetNumFields(dmIn, &numFields);CHKERRQ(ierr);
45870eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
45880eb7e1eaSToby Isaac         PetscObject  obj;
45890eb7e1eaSToby Isaac         PetscClassId classid;
45900eb7e1eaSToby Isaac 
45910eb7e1eaSToby Isaac         ierr = DMGetField(dmIn, i, &obj);CHKERRQ(ierr);
45920eb7e1eaSToby Isaac         ierr = PetscObjectGetClassId(obj, &classid);CHKERRQ(ierr);
45930eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
45940eb7e1eaSToby Isaac           ierr = DMPlexGetDataFVM(dmIn,(PetscFV)obj,&cellGeom,&faceGeom,&dmGrad);CHKERRQ(ierr);
45950eb7e1eaSToby Isaac           break;
45960eb7e1eaSToby Isaac         }
45970eb7e1eaSToby Isaac       }
45980eb7e1eaSToby Isaac     }
45990eb7e1eaSToby Isaac     if (useBCs) {
46000eb7e1eaSToby Isaac       ierr = DMPlexInsertBoundaryValues(dmIn,PETSC_TRUE,vecInLocal,time,faceGeom,cellGeom,NULL);CHKERRQ(ierr);
46010eb7e1eaSToby Isaac     }
4602fbfa57b9SToby Isaac     ierr = DMGlobalToLocalBegin(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
4603fbfa57b9SToby Isaac     ierr = DMGlobalToLocalEnd(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
46040eb7e1eaSToby Isaac     if (dmGrad) {
46050eb7e1eaSToby Isaac       ierr = DMGetGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
46060eb7e1eaSToby Isaac       ierr = DMPlexReconstructGradientsFVM(dmIn,vecInLocal,grad);CHKERRQ(ierr);
46070eb7e1eaSToby Isaac     }
4608ff1f73f7SToby Isaac     ierr = DMPlexTransferVecTree_Interpolate(dmIn,vecInLocal,dmOut,vecOut,sfRefine,cidsRefine,grad,cellGeom);CHKERRQ(ierr);
4609fbfa57b9SToby Isaac     ierr = DMRestoreLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr);
46100eb7e1eaSToby Isaac     if (dmGrad) {
46110eb7e1eaSToby Isaac       ierr = DMRestoreGlobalVector(dmGrad,&grad);CHKERRQ(ierr);
46120eb7e1eaSToby Isaac     }
4613ebf164c7SToby Isaac   }
4614ff1f73f7SToby Isaac   if (sfCoarsen) {
4615ff1f73f7SToby Isaac     ierr = DMPlexTransferVecTree_Inject(dmIn,vecIn,dmOut,vecOut,sfCoarsen,cidsCoarsen);CHKERRQ(ierr);
4616ebf164c7SToby Isaac   }
46172f65e181SToby Isaac   ierr = VecAssemblyBegin(vecOut);CHKERRQ(ierr);
46182f65e181SToby Isaac   ierr = VecAssemblyEnd(vecOut);CHKERRQ(ierr);
461938fc2455SToby Isaac   PetscFunctionReturn(0);
462038fc2455SToby Isaac }
4621