xref: /petsc/src/dm/impls/plex/plextree.c (revision be5899b337ba0cfa5eb720cdae190eefe60949dd)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc/private/isimpl.h>
4 #include <petsc/private/petscfeimpl.h>
5 #include <petscsf.h>
6 #include <petscds.h>
7 
8 /** hierarchy routines */
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "DMPlexSetReferenceTree"
12 /*@
13   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
14 
15   Not collective
16 
17   Input Parameters:
18 + dm - The DMPlex object
19 - ref - The reference tree DMPlex object
20 
21   Level: intermediate
22 
23 .seealso: DMPlexGetReferenceTree(), DMPlexCreateDefaultReferenceTree()
24 @*/
25 PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
26 {
27   DM_Plex        *mesh = (DM_Plex *)dm->data;
28   PetscErrorCode  ierr;
29 
30   PetscFunctionBegin;
31   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
32   if (ref) {PetscValidHeaderSpecific(ref, DM_CLASSID, 2);}
33   ierr = PetscObjectReference((PetscObject)ref);CHKERRQ(ierr);
34   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
35   mesh->referenceTree = ref;
36   PetscFunctionReturn(0);
37 }
38 
39 #undef __FUNCT__
40 #define __FUNCT__ "DMPlexGetReferenceTree"
41 /*@
42   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
43 
44   Not collective
45 
46   Input Parameters:
47 . dm - The DMPlex object
48 
49   Output Parameters
50 . ref - The reference tree DMPlex object
51 
52   Level: intermediate
53 
54 .seealso: DMPlexSetReferenceTree(), DMPlexCreateDefaultReferenceTree()
55 @*/
56 PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
57 {
58   DM_Plex        *mesh = (DM_Plex *)dm->data;
59 
60   PetscFunctionBegin;
61   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
62   PetscValidPointer(ref,2);
63   *ref = mesh->referenceTree;
64   PetscFunctionReturn(0);
65 }
66 
67 #undef __FUNCT__
68 #define __FUNCT__ "DMPlexReferenceTreeGetChildSymmetry_Default"
69 static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
70 {
71   PetscInt       coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
72   PetscErrorCode ierr;
73 
74   PetscFunctionBegin;
75   if (parentOrientA == parentOrientB) {
76     if (childOrientB) *childOrientB = childOrientA;
77     if (childB) *childB = childA;
78     PetscFunctionReturn(0);
79   }
80   for (dim = 0; dim < 3; dim++) {
81     ierr = DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd);CHKERRQ(ierr);
82     if (parent >= dStart && parent <= dEnd) {
83       break;
84     }
85   }
86   if (dim > 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim);
87   if (!dim) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
88   if (childA < dStart || childA >= dEnd) {
89     /* this is a lower-dimensional child: bootstrap */
90     PetscInt size, i, sA = -1, sB, sOrientB, sConeSize;
91     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
92 
93     ierr = DMPlexGetSupportSize(dm,childA,&size);CHKERRQ(ierr);
94     ierr = DMPlexGetSupport(dm,childA,&supp);CHKERRQ(ierr);
95 
96     /* find a point sA in supp(childA) that has the same parent */
97     for (i = 0; i < size; i++) {
98       PetscInt sParent;
99 
100       sA   = supp[i];
101       if (sA == parent) continue;
102       ierr = DMPlexGetTreeParent(dm,sA,&sParent,NULL);CHKERRQ(ierr);
103       if (sParent == parent) {
104         break;
105       }
106     }
107     if (i == size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
108     /* find out which point sB is in an equivalent position to sA under
109      * parentOrientB */
110     ierr = DMPlexReferenceTreeGetChildSymmetry_Default(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB);CHKERRQ(ierr);
111     ierr = DMPlexGetConeSize(dm,sA,&sConeSize);CHKERRQ(ierr);
112     ierr = DMPlexGetCone(dm,sA,&coneA);CHKERRQ(ierr);
113     ierr = DMPlexGetCone(dm,sB,&coneB);CHKERRQ(ierr);
114     ierr = DMPlexGetConeOrientation(dm,sA,&oA);CHKERRQ(ierr);
115     ierr = DMPlexGetConeOrientation(dm,sB,&oB);CHKERRQ(ierr);
116     /* step through the cone of sA in natural order */
117     for (i = 0; i < sConeSize; i++) {
118       if (coneA[i] == childA) {
119         /* if childA is at position i in coneA,
120          * then we want the point that is at sOrientB*i in coneB */
121         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
122         if (childB) *childB = coneB[j];
123         if (childOrientB) {
124           PetscInt oBtrue;
125 
126           ierr          = DMPlexGetConeSize(dm,childA,&coneSize);CHKERRQ(ierr);
127           /* compose sOrientB and oB[j] */
128           if (coneSize != 0 && coneSize != 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
129           /* we may have to flip an edge */
130           oBtrue        = coneSize ? ((sOrientB >= 0) ? oB[j] : -(oB[j] + 2)) : 0;
131           ABswap        = DihedralSwap(coneSize,oA[i],oBtrue);CHKERRQ(ierr);
132           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
133         }
134         break;
135       }
136     }
137     if (i == sConeSize) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
138     PetscFunctionReturn(0);
139   }
140   /* get the cone size and symmetry swap */
141   ierr   = DMPlexGetConeSize(dm,parent,&coneSize);CHKERRQ(ierr);
142   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
143   if (dim == 2) {
144     /* orientations refer to cones: we want them to refer to vertices:
145      * if it's a rotation, they are the same, but if the order is reversed, a
146      * permutation that puts side i first does *not* put vertex i first */
147     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
148     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
149     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
150   } else {
151     ABswapVert = ABswap;
152   }
153   if (childB) {
154     /* assume that each child corresponds to a vertex, in the same order */
155     PetscInt p, posA = -1, numChildren, i;
156     const PetscInt *children;
157 
158     /* count which position the child is in */
159     ierr = DMPlexGetTreeChildren(dm,parent,&numChildren,&children);CHKERRQ(ierr);
160     for (i = 0; i < numChildren; i++) {
161       p = children[i];
162       if (p == childA) {
163         posA = i;
164         break;
165       }
166     }
167     if (posA >= coneSize) {
168       /* this is the triangle in the middle of a uniformly refined triangle: it
169        * is invariant */
170       if (dim != 2 || posA != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Expected a middle triangle, got something else");
171       *childB = childA;
172     }
173     else {
174       /* figure out position B by applying ABswapVert */
175       PetscInt posB;
176 
177       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
178       if (childB) *childB = children[posB];
179     }
180   }
181   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
182   PetscFunctionReturn(0);
183 }
184 
185 #undef __FUNCT__
186 #define __FUNCT__ "DMPlexReferenceTreeGetChildSymmetry"
187 /*@
188   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
189 
190   Input Parameters:
191 + dm - the reference tree DMPlex object
192 . parent - the parent point
193 . parentOrientA - the reference orientation for describing the parent
194 . childOrientA - the reference orientation for describing the child
195 . childA - the reference childID for describing the child
196 - parentOrientB - the new orientation for describing the parent
197 
198   Output Parameters:
199 + childOrientB - if not NULL, set to the new oreintation for describing the child
200 . childB - if not NULL, the new childID for describing the child
201 
202   Level: developer
203 
204 .seealso: DMPlexGetReferenceTree(), DMPlexSetReferenceTree(), DMPlexSetTree()
205 @*/
206 PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
207 {
208   DM_Plex        *mesh = (DM_Plex *)dm->data;
209   PetscErrorCode ierr;
210 
211   PetscFunctionBegin;
212   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
213   if (!mesh->getchildsymmetry) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlexReferenceTreeGetChildSymmetry not implemented");
214   ierr = mesh->getchildsymmetry(dm,parent,parentOrientA,childOrientA,childA,parentOrientB,childOrientB,childB);CHKERRQ(ierr);
215   PetscFunctionReturn(0);
216 }
217 
218 static PetscErrorCode DMPlexSetTree_Internal(DM,PetscSection,PetscInt*,PetscInt*,PetscBool,PetscBool);
219 
220 #undef __FUNCT__
221 #define __FUNCT__ "DMPlexCreateReferenceTree_Union"
222 PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
223 {
224   MPI_Comm       comm;
225   PetscInt       dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
226   PetscInt      *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
227   DMLabel        identity, identityRef;
228   PetscSection   unionSection, unionConeSection, parentSection;
229   PetscScalar   *unionCoords;
230   IS             perm;
231   PetscErrorCode ierr;
232 
233   PetscFunctionBegin;
234   comm = PetscObjectComm((PetscObject)K);
235   ierr = DMGetDimension(K, &dim);CHKERRQ(ierr);
236   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
237   ierr = DMGetLabel(K, labelName, &identity);CHKERRQ(ierr);
238   ierr = DMGetLabel(Kref, labelName, &identityRef);CHKERRQ(ierr);
239   ierr = DMPlexGetChart(Kref, &pRefStart, &pRefEnd);CHKERRQ(ierr);
240   ierr = PetscSectionCreate(comm, &unionSection);CHKERRQ(ierr);
241   ierr = PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart));CHKERRQ(ierr);
242   /* count points that will go in the union */
243   for (p = pStart; p < pEnd; p++) {
244     ierr = PetscSectionSetDof(unionSection, p - pStart, 1);CHKERRQ(ierr);
245   }
246   for (p = pRefStart; p < pRefEnd; p++) {
247     PetscInt q, qSize;
248     ierr = DMLabelGetValue(identityRef, p, &q);CHKERRQ(ierr);
249     ierr = DMLabelGetStratumSize(identityRef, q, &qSize);CHKERRQ(ierr);
250     if (qSize > 1) {
251       ierr = PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1);CHKERRQ(ierr);
252     }
253   }
254   ierr = PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart,&permvals);CHKERRQ(ierr);
255   offset = 0;
256   /* stratify points in the union by topological dimension */
257   for (d = 0; d <= dim; d++) {
258     PetscInt cStart, cEnd, c;
259 
260     ierr = DMPlexGetHeightStratum(K, d, &cStart, &cEnd);CHKERRQ(ierr);
261     for (c = cStart; c < cEnd; c++) {
262       permvals[offset++] = c;
263     }
264 
265     ierr = DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd);CHKERRQ(ierr);
266     for (c = cStart; c < cEnd; c++) {
267       permvals[offset++] = c + (pEnd - pStart);
268     }
269   }
270   ierr = ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm);CHKERRQ(ierr);
271   ierr = PetscSectionSetPermutation(unionSection,perm);CHKERRQ(ierr);
272   ierr = PetscSectionSetUp(unionSection);CHKERRQ(ierr);
273   ierr = PetscSectionGetStorageSize(unionSection,&numUnionPoints);CHKERRQ(ierr);
274   ierr = PetscMalloc2(numUnionPoints,&coneSizes,dim+1,&numDimPoints);CHKERRQ(ierr);
275   /* count dimension points */
276   for (d = 0; d <= dim; d++) {
277     PetscInt cStart, cOff, cOff2;
278     ierr = DMPlexGetHeightStratum(K,d,&cStart,NULL);CHKERRQ(ierr);
279     ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff);CHKERRQ(ierr);
280     if (d < dim) {
281       ierr = DMPlexGetHeightStratum(K,d+1,&cStart,NULL);CHKERRQ(ierr);
282       ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff2);CHKERRQ(ierr);
283     }
284     else {
285       cOff2 = numUnionPoints;
286     }
287     numDimPoints[dim - d] = cOff2 - cOff;
288   }
289   ierr = PetscSectionCreate(comm, &unionConeSection);CHKERRQ(ierr);
290   ierr = PetscSectionSetChart(unionConeSection, 0, numUnionPoints);CHKERRQ(ierr);
291   /* count the cones in the union */
292   for (p = pStart; p < pEnd; p++) {
293     PetscInt dof, uOff;
294 
295     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
296     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
297     ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
298     coneSizes[uOff] = dof;
299   }
300   for (p = pRefStart; p < pRefEnd; p++) {
301     PetscInt dof, uDof, uOff;
302 
303     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
304     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
305     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
306     if (uDof) {
307       ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr);
308       coneSizes[uOff] = dof;
309     }
310   }
311   ierr = PetscSectionSetUp(unionConeSection);CHKERRQ(ierr);
312   ierr = PetscSectionGetStorageSize(unionConeSection,&numCones);CHKERRQ(ierr);
313   ierr = PetscMalloc2(numCones,&unionCones,numCones,&unionOrientations);CHKERRQ(ierr);
314   /* write the cones in the union */
315   for (p = pStart; p < pEnd; p++) {
316     PetscInt dof, uOff, c, cOff;
317     const PetscInt *cone, *orientation;
318 
319     ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr);
320     ierr = DMPlexGetCone(K, p, &cone);CHKERRQ(ierr);
321     ierr = DMPlexGetConeOrientation(K, p, &orientation);CHKERRQ(ierr);
322     ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr);
323     ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
324     for (c = 0; c < dof; c++) {
325       PetscInt e, eOff;
326       e                           = cone[c];
327       ierr                        = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
328       unionCones[cOff + c]        = eOff;
329       unionOrientations[cOff + c] = orientation[c];
330     }
331   }
332   for (p = pRefStart; p < pRefEnd; p++) {
333     PetscInt dof, uDof, uOff, c, cOff;
334     const PetscInt *cone, *orientation;
335 
336     ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr);
337     ierr = DMPlexGetCone(Kref, p, &cone);CHKERRQ(ierr);
338     ierr = DMPlexGetConeOrientation(Kref, p, &orientation);CHKERRQ(ierr);
339     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
340     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
341     if (uDof) {
342       ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr);
343       for (c = 0; c < dof; c++) {
344         PetscInt e, eOff, eDof;
345 
346         e    = cone[c];
347         ierr = PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart),&eDof);CHKERRQ(ierr);
348         if (eDof) {
349           ierr = PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff);CHKERRQ(ierr);
350         }
351         else {
352           ierr = DMLabelGetValue(identityRef, e, &e);CHKERRQ(ierr);
353           ierr = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr);
354         }
355         unionCones[cOff + c]        = eOff;
356         unionOrientations[cOff + c] = orientation[c];
357       }
358     }
359   }
360   /* get the coordinates */
361   {
362     PetscInt vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
363     PetscSection KcoordsSec, KrefCoordsSec;
364     Vec      KcoordsVec, KrefCoordsVec;
365     PetscScalar *Kcoords;
366 
367     DMGetCoordinateSection(K, &KcoordsSec);CHKERRQ(ierr);
368     DMGetCoordinatesLocal(K, &KcoordsVec);CHKERRQ(ierr);
369     DMGetCoordinateSection(Kref, &KrefCoordsSec);CHKERRQ(ierr);
370     DMGetCoordinatesLocal(Kref, &KrefCoordsVec);CHKERRQ(ierr);
371 
372     numVerts = numDimPoints[0];
373     ierr     = PetscMalloc1(numVerts * dim,&unionCoords);CHKERRQ(ierr);
374     ierr     = DMPlexGetDepthStratum(K,0,&vStart,&vEnd);CHKERRQ(ierr);
375 
376     offset = 0;
377     for (v = vStart; v < vEnd; v++) {
378       ierr = PetscSectionGetOffset(unionSection,v - pStart,&vOff);CHKERRQ(ierr);
379       ierr = VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords);CHKERRQ(ierr);
380       for (d = 0; d < dim; d++) {
381         unionCoords[offset * dim + d] = Kcoords[d];
382       }
383       offset++;
384     }
385     ierr = DMPlexGetDepthStratum(Kref,0,&vRefStart,&vRefEnd);CHKERRQ(ierr);
386     for (v = vRefStart; v < vRefEnd; v++) {
387       ierr = PetscSectionGetDof(unionSection,v - pRefStart + (pEnd - pStart),&vDof);CHKERRQ(ierr);
388       ierr = PetscSectionGetOffset(unionSection,v - pRefStart + (pEnd - pStart),&vOff);CHKERRQ(ierr);
389       ierr = VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords);CHKERRQ(ierr);
390       if (vDof) {
391         for (d = 0; d < dim; d++) {
392           unionCoords[offset * dim + d] = Kcoords[d];
393         }
394         offset++;
395       }
396     }
397   }
398   ierr = DMCreate(comm,ref);CHKERRQ(ierr);
399   ierr = DMSetType(*ref,DMPLEX);CHKERRQ(ierr);
400   ierr = DMSetDimension(*ref,dim);CHKERRQ(ierr);
401   ierr = DMPlexCreateFromDAG(*ref,dim,numDimPoints,coneSizes,unionCones,unionOrientations,unionCoords);CHKERRQ(ierr);
402   /* set the tree */
403   ierr = PetscSectionCreate(comm,&parentSection);CHKERRQ(ierr);
404   ierr = PetscSectionSetChart(parentSection,0,numUnionPoints);CHKERRQ(ierr);
405   for (p = pRefStart; p < pRefEnd; p++) {
406     PetscInt uDof, uOff;
407 
408     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
409     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
410     if (uDof) {
411       PetscSectionSetDof(parentSection,uOff,1);CHKERRQ(ierr);
412     }
413   }
414   ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
415   ierr = PetscSectionGetStorageSize(parentSection,&parentSize);CHKERRQ(ierr);
416   ierr = PetscMalloc2(parentSize,&parents,parentSize,&childIDs);CHKERRQ(ierr);
417   for (p = pRefStart; p < pRefEnd; p++) {
418     PetscInt uDof, uOff;
419 
420     ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr);
421     ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr);
422     if (uDof) {
423       PetscInt pOff, parent, parentU;
424       PetscSectionGetOffset(parentSection,uOff,&pOff);CHKERRQ(ierr);
425       DMLabelGetValue(identityRef,p,&parent);CHKERRQ(ierr);
426       ierr = PetscSectionGetOffset(unionSection, parent - pStart,&parentU);CHKERRQ(ierr);
427       parents[pOff] = parentU;
428       childIDs[pOff] = uOff;
429     }
430   }
431   ierr = DMPlexSetTree_Internal(*ref,parentSection,parents,childIDs,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
432   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
433   ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
434 
435   /* clean up */
436   ierr = PetscSectionDestroy(&unionSection);CHKERRQ(ierr);
437   ierr = PetscSectionDestroy(&unionConeSection);CHKERRQ(ierr);
438   ierr = ISDestroy(&perm);CHKERRQ(ierr);
439   ierr = PetscFree(unionCoords);CHKERRQ(ierr);
440   ierr = PetscFree2(unionCones,unionOrientations);CHKERRQ(ierr);
441   ierr = PetscFree2(coneSizes,numDimPoints);CHKERRQ(ierr);
442   PetscFunctionReturn(0);
443 }
444 
445 #undef __FUNCT__
446 #define __FUNCT__ "DMPlexCreateDefaultReferenceTree"
447 /*@
448   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
449 
450   Collective on comm
451 
452   Input Parameters:
453 + comm    - the MPI communicator
454 . dim     - the spatial dimension
455 - simplex - Flag for simplex, otherwise use a tensor-product cell
456 
457   Output Parameters:
458 . ref     - the reference tree DMPlex object
459 
460   Level: intermediate
461 
462 .keywords: reference cell
463 .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree()
464 @*/
465 PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
466 {
467   DM_Plex       *mesh;
468   DM             K, Kref;
469   PetscInt       p, pStart, pEnd;
470   DMLabel        identity;
471   PetscErrorCode ierr;
472 
473   PetscFunctionBegin;
474 #if 1
475   comm = PETSC_COMM_SELF;
476 #endif
477   /* create a reference element */
478   ierr = DMPlexCreateReferenceCell(comm, dim, simplex, &K);CHKERRQ(ierr);
479   ierr = DMCreateLabel(K, "identity");CHKERRQ(ierr);
480   ierr = DMGetLabel(K, "identity", &identity);CHKERRQ(ierr);
481   ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr);
482   for (p = pStart; p < pEnd; p++) {
483     ierr = DMLabelSetValue(identity, p, p);CHKERRQ(ierr);
484   }
485   /* refine it */
486   ierr = DMRefine(K,comm,&Kref);CHKERRQ(ierr);
487 
488   /* the reference tree is the union of these two, without duplicating
489    * points that appear in both */
490   ierr = DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref);CHKERRQ(ierr);
491   mesh = (DM_Plex *) (*ref)->data;
492   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
493   ierr = DMDestroy(&K);CHKERRQ(ierr);
494   ierr = DMDestroy(&Kref);CHKERRQ(ierr);
495   PetscFunctionReturn(0);
496 }
497 
498 #undef __FUNCT__
499 #define __FUNCT__ "DMPlexTreeSymmetrize"
500 static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
501 {
502   DM_Plex        *mesh = (DM_Plex *)dm->data;
503   PetscSection   childSec, pSec;
504   PetscInt       p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
505   PetscInt       *offsets, *children, pStart, pEnd;
506   PetscErrorCode ierr;
507 
508   PetscFunctionBegin;
509   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
510   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
511   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
512   pSec = mesh->parentSection;
513   if (!pSec) PetscFunctionReturn(0);
514   ierr = PetscSectionGetStorageSize(pSec,&pSize);CHKERRQ(ierr);
515   for (p = 0; p < pSize; p++) {
516     PetscInt par = mesh->parents[p];
517 
518     parMax = PetscMax(parMax,par+1);
519     parMin = PetscMin(parMin,par);
520   }
521   if (parMin > parMax) {
522     parMin = -1;
523     parMax = -1;
524   }
525   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)pSec),&childSec);CHKERRQ(ierr);
526   ierr = PetscSectionSetChart(childSec,parMin,parMax);CHKERRQ(ierr);
527   for (p = 0; p < pSize; p++) {
528     PetscInt par = mesh->parents[p];
529 
530     ierr = PetscSectionAddDof(childSec,par,1);CHKERRQ(ierr);
531   }
532   ierr = PetscSectionSetUp(childSec);CHKERRQ(ierr);
533   ierr = PetscSectionGetStorageSize(childSec,&cSize);CHKERRQ(ierr);
534   ierr = PetscMalloc1(cSize,&children);CHKERRQ(ierr);
535   ierr = PetscCalloc1(parMax-parMin,&offsets);CHKERRQ(ierr);
536   ierr = PetscSectionGetChart(pSec,&pStart,&pEnd);CHKERRQ(ierr);
537   for (p = pStart; p < pEnd; p++) {
538     PetscInt dof, off, i;
539 
540     ierr = PetscSectionGetDof(pSec,p,&dof);CHKERRQ(ierr);
541     ierr = PetscSectionGetOffset(pSec,p,&off);CHKERRQ(ierr);
542     for (i = 0; i < dof; i++) {
543       PetscInt par = mesh->parents[off + i], cOff;
544 
545       ierr = PetscSectionGetOffset(childSec,par,&cOff);CHKERRQ(ierr);
546       children[cOff + offsets[par-parMin]++] = p;
547     }
548   }
549   mesh->childSection = childSec;
550   mesh->children = children;
551   ierr = PetscFree(offsets);CHKERRQ(ierr);
552   PetscFunctionReturn(0);
553 }
554 
555 #undef __FUNCT__
556 #define __FUNCT__ "AnchorsFlatten"
557 static PetscErrorCode AnchorsFlatten (PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
558 {
559   PetscInt       pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
560   const PetscInt *vals;
561   PetscSection   secNew;
562   PetscBool      anyNew, globalAnyNew;
563   PetscBool      compress;
564   PetscErrorCode ierr;
565 
566   PetscFunctionBegin;
567   ierr = PetscSectionGetChart(section,&pStart,&pEnd);CHKERRQ(ierr);
568   ierr = ISGetLocalSize(is,&size);CHKERRQ(ierr);
569   ierr = ISGetIndices(is,&vals);CHKERRQ(ierr);
570   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secNew);CHKERRQ(ierr);
571   ierr = PetscSectionSetChart(secNew,pStart,pEnd);CHKERRQ(ierr);
572   for (i = 0; i < size; i++) {
573     PetscInt dof;
574 
575     p = vals[i];
576     if (p < pStart || p >= pEnd) continue;
577     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
578     if (dof) break;
579   }
580   if (i == size) {
581     ierr     = PetscSectionSetUp(secNew);CHKERRQ(ierr);
582     anyNew   = PETSC_FALSE;
583     compress = PETSC_FALSE;
584     sizeNew  = 0;
585   }
586   else {
587     anyNew = PETSC_TRUE;
588     for (p = pStart; p < pEnd; p++) {
589       PetscInt dof, off;
590 
591       ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
592       ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
593       for (i = 0; i < dof; i++) {
594         PetscInt q = vals[off + i], qDof = 0;
595 
596         if (q >= pStart && q < pEnd) {
597           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
598         }
599         if (qDof) {
600           ierr = PetscSectionAddDof(secNew, p, qDof);CHKERRQ(ierr);
601         }
602         else {
603           ierr = PetscSectionAddDof(secNew, p, 1);CHKERRQ(ierr);
604         }
605       }
606     }
607     ierr = PetscSectionSetUp(secNew);CHKERRQ(ierr);
608     ierr = PetscSectionGetStorageSize(secNew,&sizeNew);CHKERRQ(ierr);
609     ierr = PetscMalloc1(sizeNew,&valsNew);CHKERRQ(ierr);
610     compress = PETSC_FALSE;
611     for (p = pStart; p < pEnd; p++) {
612       PetscInt dof, off, count, offNew, dofNew;
613 
614       ierr  = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
615       ierr  = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
616       ierr  = PetscSectionGetDof(secNew, p, &dofNew);CHKERRQ(ierr);
617       ierr  = PetscSectionGetOffset(secNew, p, &offNew);CHKERRQ(ierr);
618       count = 0;
619       for (i = 0; i < dof; i++) {
620         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
621 
622         if (q >= pStart && q < pEnd) {
623           ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr);
624           ierr = PetscSectionGetOffset(section, q, &qOff);CHKERRQ(ierr);
625         }
626         if (qDof) {
627           PetscInt oldCount = count;
628 
629           for (j = 0; j < qDof; j++) {
630             PetscInt k, r = vals[qOff + j];
631 
632             for (k = 0; k < oldCount; k++) {
633               if (valsNew[offNew + k] == r) {
634                 break;
635               }
636             }
637             if (k == oldCount) {
638               valsNew[offNew + count++] = r;
639             }
640           }
641         }
642         else {
643           PetscInt k, oldCount = count;
644 
645           for (k = 0; k < oldCount; k++) {
646             if (valsNew[offNew + k] == q) {
647               break;
648             }
649           }
650           if (k == oldCount) {
651             valsNew[offNew + count++] = q;
652           }
653         }
654       }
655       if (count < dofNew) {
656         ierr = PetscSectionSetDof(secNew, p, count);CHKERRQ(ierr);
657         compress = PETSC_TRUE;
658       }
659     }
660   }
661   ierr = ISRestoreIndices(is,&vals);CHKERRQ(ierr);
662   ierr = MPIU_Allreduce(&anyNew,&globalAnyNew,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
663   if (!globalAnyNew) {
664     ierr = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
665     *sectionNew = NULL;
666     *isNew = NULL;
667   }
668   else {
669     PetscBool globalCompress;
670 
671     ierr = MPIU_Allreduce(&compress,&globalCompress,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr);
672     if (compress) {
673       PetscSection secComp;
674       PetscInt *valsComp = NULL;
675 
676       ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secComp);CHKERRQ(ierr);
677       ierr = PetscSectionSetChart(secComp,pStart,pEnd);CHKERRQ(ierr);
678       for (p = pStart; p < pEnd; p++) {
679         PetscInt dof;
680 
681         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
682         ierr = PetscSectionSetDof(secComp, p, dof);CHKERRQ(ierr);
683       }
684       ierr = PetscSectionSetUp(secComp);CHKERRQ(ierr);
685       ierr = PetscSectionGetStorageSize(secComp,&sizeNew);CHKERRQ(ierr);
686       ierr = PetscMalloc1(sizeNew,&valsComp);CHKERRQ(ierr);
687       for (p = pStart; p < pEnd; p++) {
688         PetscInt dof, off, offNew, j;
689 
690         ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr);
691         ierr = PetscSectionGetOffset(secNew, p, &off);CHKERRQ(ierr);
692         ierr = PetscSectionGetOffset(secComp, p, &offNew);CHKERRQ(ierr);
693         for (j = 0; j < dof; j++) {
694           valsComp[offNew + j] = valsNew[off + j];
695         }
696       }
697       ierr    = PetscSectionDestroy(&secNew);CHKERRQ(ierr);
698       secNew  = secComp;
699       ierr    = PetscFree(valsNew);CHKERRQ(ierr);
700       valsNew = valsComp;
701     }
702     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is),sizeNew,valsNew,PETSC_OWN_POINTER,isNew);CHKERRQ(ierr);
703   }
704   PetscFunctionReturn(0);
705 }
706 
707 #undef __FUNCT__
708 #define __FUNCT__ "DMPlexCreateAnchors_Tree"
709 static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
710 {
711   PetscInt       p, pStart, pEnd, *anchors, size;
712   PetscInt       aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
713   PetscSection   aSec;
714   DMLabel        canonLabel;
715   IS             aIS;
716   PetscErrorCode ierr;
717 
718   PetscFunctionBegin;
719   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
720   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
721   ierr = DMGetLabel(dm,"canonical",&canonLabel);CHKERRQ(ierr);
722   for (p = pStart; p < pEnd; p++) {
723     PetscInt parent;
724 
725     if (canonLabel) {
726       PetscInt canon;
727 
728       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
729       if (p != canon) continue;
730     }
731     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
732     if (parent != p) {
733       aMin = PetscMin(aMin,p);
734       aMax = PetscMax(aMax,p+1);
735     }
736   }
737   if (aMin > aMax) {
738     aMin = -1;
739     aMax = -1;
740   }
741   ierr = PetscSectionCreate(PETSC_COMM_SELF,&aSec);CHKERRQ(ierr);
742   ierr = PetscSectionSetChart(aSec,aMin,aMax);CHKERRQ(ierr);
743   for (p = aMin; p < aMax; p++) {
744     PetscInt parent, ancestor = p;
745 
746     if (canonLabel) {
747       PetscInt canon;
748 
749       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
750       if (p != canon) continue;
751     }
752     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
753     while (parent != ancestor) {
754       ancestor = parent;
755       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
756     }
757     if (ancestor != p) {
758       PetscInt closureSize, *closure = NULL;
759 
760       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
761       ierr = PetscSectionSetDof(aSec,p,closureSize);CHKERRQ(ierr);
762       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
763     }
764   }
765   ierr = PetscSectionSetUp(aSec);CHKERRQ(ierr);
766   ierr = PetscSectionGetStorageSize(aSec,&size);CHKERRQ(ierr);
767   ierr = PetscMalloc1(size,&anchors);CHKERRQ(ierr);
768   for (p = aMin; p < aMax; p++) {
769     PetscInt parent, ancestor = p;
770 
771     if (canonLabel) {
772       PetscInt canon;
773 
774       ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr);
775       if (p != canon) continue;
776     }
777     ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr);
778     while (parent != ancestor) {
779       ancestor = parent;
780       ierr     = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr);
781     }
782     if (ancestor != p) {
783       PetscInt j, closureSize, *closure = NULL, aOff;
784 
785       ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
786 
787       ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
788       for (j = 0; j < closureSize; j++) {
789         anchors[aOff + j] = closure[2*j];
790       }
791       ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
792     }
793   }
794   ierr = ISCreateGeneral(PETSC_COMM_SELF,size,anchors,PETSC_OWN_POINTER,&aIS);CHKERRQ(ierr);
795   {
796     PetscSection aSecNew = aSec;
797     IS           aISNew  = aIS;
798 
799     ierr = PetscObjectReference((PetscObject)aSec);CHKERRQ(ierr);
800     ierr = PetscObjectReference((PetscObject)aIS);CHKERRQ(ierr);
801     while (aSecNew) {
802       ierr    = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
803       ierr    = ISDestroy(&aIS);CHKERRQ(ierr);
804       aSec    = aSecNew;
805       aIS     = aISNew;
806       aSecNew = NULL;
807       aISNew  = NULL;
808       ierr    = AnchorsFlatten(aSec,aIS,&aSecNew,&aISNew);CHKERRQ(ierr);
809     }
810   }
811   ierr = DMPlexSetAnchors(dm,aSec,aIS);CHKERRQ(ierr);
812   ierr = PetscSectionDestroy(&aSec);CHKERRQ(ierr);
813   ierr = ISDestroy(&aIS);CHKERRQ(ierr);
814   PetscFunctionReturn(0);
815 }
816 
817 #undef __FUNCT__
818 #define __FUNCT__ "DMPlexGetTrueSupportSize"
819 static PetscErrorCode DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt *dof,PetscInt *numTrueSupp)
820 {
821   PetscErrorCode ierr;
822 
823   PetscFunctionBegin;
824   if (numTrueSupp[p] == -1) {
825     PetscInt i, alldof;
826     const PetscInt *supp;
827     PetscInt count = 0;
828 
829     ierr = DMPlexGetSupportSize(dm,p,&alldof);CHKERRQ(ierr);
830     ierr = DMPlexGetSupport(dm,p,&supp);CHKERRQ(ierr);
831     for (i = 0; i < alldof; i++) {
832       PetscInt q = supp[i], numCones, j;
833       const PetscInt *cone;
834 
835       ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
836       ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
837       for (j = 0; j < numCones; j++) {
838         if (cone[j] == p) break;
839       }
840       if (j < numCones) count++;
841     }
842     numTrueSupp[p] = count;
843   }
844   *dof = numTrueSupp[p];
845   PetscFunctionReturn(0);
846 }
847 
848 #undef __FUNCT__
849 #define __FUNCT__ "DMPlexTreeExchangeSupports"
850 static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
851 {
852   DM_Plex *mesh = (DM_Plex *)dm->data;
853   PetscSection newSupportSection;
854   PetscInt newSize, *newSupports, pStart, pEnd, p, d, depth;
855   PetscInt *numTrueSupp;
856   PetscInt *offsets;
857   PetscErrorCode ierr;
858 
859   PetscFunctionBegin;
860   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
861   /* symmetrize the hierarchy */
862   ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr);
863   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)),&newSupportSection);CHKERRQ(ierr);
864   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
865   ierr = PetscSectionSetChart(newSupportSection,pStart,pEnd);CHKERRQ(ierr);
866   ierr = PetscCalloc1(pEnd,&offsets);CHKERRQ(ierr);
867   ierr = PetscMalloc1(pEnd,&numTrueSupp);CHKERRQ(ierr);
868   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
869   /* if a point is in the (true) support of q, it should be in the support of
870    * parent(q) */
871   for (d = 0; d <= depth; d++) {
872     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
873     for (p = pStart; p < pEnd; ++p) {
874       PetscInt dof, q, qdof, parent;
875 
876       ierr = DMPlexGetTrueSupportSize(dm,p,&dof,numTrueSupp);CHKERRQ(ierr);
877       ierr = PetscSectionAddDof(newSupportSection, p, dof);CHKERRQ(ierr);
878       q    = p;
879       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
880       while (parent != q && parent >= pStart && parent < pEnd) {
881         q = parent;
882 
883         ierr = DMPlexGetTrueSupportSize(dm,q,&qdof,numTrueSupp);CHKERRQ(ierr);
884         ierr = PetscSectionAddDof(newSupportSection,p,qdof);CHKERRQ(ierr);
885         ierr = PetscSectionAddDof(newSupportSection,q,dof);CHKERRQ(ierr);
886         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
887       }
888     }
889   }
890   ierr = PetscSectionSetUp(newSupportSection);CHKERRQ(ierr);
891   ierr = PetscSectionGetStorageSize(newSupportSection,&newSize);CHKERRQ(ierr);
892   ierr = PetscMalloc1(newSize,&newSupports);CHKERRQ(ierr);
893   for (d = 0; d <= depth; d++) {
894     ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr);
895     for (p = pStart; p < pEnd; p++) {
896       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
897 
898       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
899       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
900       ierr = PetscSectionGetDof(newSupportSection, p, &newDof);CHKERRQ(ierr);
901       ierr = PetscSectionGetOffset(newSupportSection, p, &newOff);CHKERRQ(ierr);
902       for (i = 0; i < dof; i++) {
903         PetscInt numCones, j;
904         const PetscInt *cone;
905         PetscInt q = mesh->supports[off + i];
906 
907         ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr);
908         ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr);
909         for (j = 0; j < numCones; j++) {
910           if (cone[j] == p) break;
911         }
912         if (j < numCones) newSupports[newOff+offsets[p]++] = q;
913       }
914       mesh->maxSupportSize = PetscMax(mesh->maxSupportSize,newDof);
915 
916       q    = p;
917       ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
918       while (parent != q && parent >= pStart && parent < pEnd) {
919         q = parent;
920         ierr = PetscSectionGetDof(mesh->supportSection, q, &qdof);CHKERRQ(ierr);
921         ierr = PetscSectionGetOffset(mesh->supportSection, q, &qoff);CHKERRQ(ierr);
922         ierr = PetscSectionGetOffset(newSupportSection, q, &newqOff);CHKERRQ(ierr);
923         for (i = 0; i < qdof; i++) {
924           PetscInt numCones, j;
925           const PetscInt *cone;
926           PetscInt r = mesh->supports[qoff + i];
927 
928           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
929           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
930           for (j = 0; j < numCones; j++) {
931             if (cone[j] == q) break;
932           }
933           if (j < numCones) newSupports[newOff+offsets[p]++] = r;
934         }
935         for (i = 0; i < dof; i++) {
936           PetscInt numCones, j;
937           const PetscInt *cone;
938           PetscInt r = mesh->supports[off + i];
939 
940           ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr);
941           ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr);
942           for (j = 0; j < numCones; j++) {
943             if (cone[j] == p) break;
944           }
945           if (j < numCones) newSupports[newqOff+offsets[q]++] = r;
946         }
947         ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr);
948       }
949     }
950   }
951   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
952   mesh->supportSection = newSupportSection;
953   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
954   mesh->supports = newSupports;
955   ierr = PetscFree(offsets);CHKERRQ(ierr);
956   ierr = PetscFree(numTrueSupp);CHKERRQ(ierr);
957 
958   PetscFunctionReturn(0);
959 }
960 
961 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM,PetscSection,PetscSection,Mat);
962 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM,PetscSection,PetscSection,Mat);
963 
964 #undef __FUNCT__
965 #define __FUNCT__ "DMPlexSetTree_Internal"
966 static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
967 {
968   DM_Plex       *mesh = (DM_Plex *)dm->data;
969   DM             refTree;
970   PetscInt       size;
971   PetscErrorCode ierr;
972 
973   PetscFunctionBegin;
974   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
975   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
976   ierr = PetscObjectReference((PetscObject)parentSection);CHKERRQ(ierr);
977   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
978   mesh->parentSection = parentSection;
979   ierr = PetscSectionGetStorageSize(parentSection,&size);CHKERRQ(ierr);
980   if (parents != mesh->parents) {
981     ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
982     ierr = PetscMalloc1(size,&mesh->parents);CHKERRQ(ierr);
983     ierr = PetscMemcpy(mesh->parents, parents, size * sizeof(*parents));CHKERRQ(ierr);
984   }
985   if (childIDs != mesh->childIDs) {
986     ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
987     ierr = PetscMalloc1(size,&mesh->childIDs);CHKERRQ(ierr);
988     ierr = PetscMemcpy(mesh->childIDs, childIDs, size * sizeof(*childIDs));CHKERRQ(ierr);
989   }
990   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
991   if (refTree) {
992     DMLabel canonLabel;
993 
994     ierr = DMGetLabel(refTree,"canonical",&canonLabel);CHKERRQ(ierr);
995     if (canonLabel) {
996       PetscInt i;
997 
998       for (i = 0; i < size; i++) {
999         PetscInt canon;
1000         ierr = DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon);CHKERRQ(ierr);
1001         if (canon >= 0) {
1002           mesh->childIDs[i] = canon;
1003         }
1004       }
1005     }
1006     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
1007   }
1008   else {
1009     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
1010   }
1011   ierr = DMPlexTreeSymmetrize(dm);CHKERRQ(ierr);
1012   if (computeCanonical) {
1013     PetscInt d, dim;
1014 
1015     /* add the canonical label */
1016     ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
1017     ierr = DMCreateLabel(dm,"canonical");CHKERRQ(ierr);
1018     for (d = 0; d <= dim; d++) {
1019       PetscInt p, dStart, dEnd, canon = -1, cNumChildren;
1020       const PetscInt *cChildren;
1021 
1022       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
1023       for (p = dStart; p < dEnd; p++) {
1024         ierr = DMPlexGetTreeChildren(dm,p,&cNumChildren,&cChildren);CHKERRQ(ierr);
1025         if (cNumChildren) {
1026           canon = p;
1027           break;
1028         }
1029       }
1030       if (canon == -1) continue;
1031       for (p = dStart; p < dEnd; p++) {
1032         PetscInt numChildren, i;
1033         const PetscInt *children;
1034 
1035         ierr = DMPlexGetTreeChildren(dm,p,&numChildren,&children);CHKERRQ(ierr);
1036         if (numChildren) {
1037           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);
1038           ierr = DMSetLabelValue(dm,"canonical",p,canon);CHKERRQ(ierr);
1039           for (i = 0; i < numChildren; i++) {
1040             ierr = DMSetLabelValue(dm,"canonical",children[i],cChildren[i]);CHKERRQ(ierr);
1041           }
1042         }
1043       }
1044     }
1045   }
1046   if (exchangeSupports) {
1047     ierr = DMPlexTreeExchangeSupports(dm);CHKERRQ(ierr);
1048   }
1049   mesh->createanchors = DMPlexCreateAnchors_Tree;
1050   /* reset anchors */
1051   ierr = DMPlexSetAnchors(dm,NULL,NULL);CHKERRQ(ierr);
1052   PetscFunctionReturn(0);
1053 }
1054 
1055 #undef __FUNCT__
1056 #define __FUNCT__ "DMPlexSetTree"
1057 /*@
1058   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
1059   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
1060   tree root.
1061 
1062   Collective on dm
1063 
1064   Input Parameters:
1065 + dm - the DMPlex object
1066 . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1067                   offset indexes the parent and childID list; the reference count of parentSection is incremented
1068 . parents - a list of the point parents; copied, can be destroyed
1069 - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1070              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
1071 
1072   Level: intermediate
1073 
1074 .seealso: DMPlexGetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
1075 @*/
1076 PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
1077 {
1078   PetscErrorCode ierr;
1079 
1080   PetscFunctionBegin;
1081   ierr = DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
1082   PetscFunctionReturn(0);
1083 }
1084 
1085 #undef __FUNCT__
1086 #define __FUNCT__ "DMPlexGetTree"
1087 /*@
1088   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1089   Collective on dm
1090 
1091   Input Parameters:
1092 . dm - the DMPlex object
1093 
1094   Output Parameters:
1095 + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1096                   offset indexes the parent and childID list
1097 . parents - a list of the point parents
1098 . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1099              the child corresponds to the point in the reference tree with index childID
1100 . childSection - the inverse of the parent section
1101 - children - a list of the point children
1102 
1103   Level: intermediate
1104 
1105 .seealso: DMPlexSetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
1106 @*/
1107 PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1108 {
1109   DM_Plex        *mesh = (DM_Plex *)dm->data;
1110 
1111   PetscFunctionBegin;
1112   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1113   if (parentSection) *parentSection = mesh->parentSection;
1114   if (parents)       *parents       = mesh->parents;
1115   if (childIDs)      *childIDs      = mesh->childIDs;
1116   if (childSection)  *childSection  = mesh->childSection;
1117   if (children)      *children      = mesh->children;
1118   PetscFunctionReturn(0);
1119 }
1120 
1121 #undef __FUNCT__
1122 #define __FUNCT__ "DMPlexGetTreeParent"
1123 /*@
1124   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the Sieve DAG)
1125 
1126   Input Parameters:
1127 + dm - the DMPlex object
1128 - point - the query point
1129 
1130   Output Parameters:
1131 + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1132 - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point
1133             does not have a parent
1134 
1135   Level: intermediate
1136 
1137 .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeChildren()
1138 @*/
1139 PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1140 {
1141   DM_Plex       *mesh = (DM_Plex *)dm->data;
1142   PetscSection   pSec;
1143   PetscErrorCode ierr;
1144 
1145   PetscFunctionBegin;
1146   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1147   pSec = mesh->parentSection;
1148   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1149     PetscInt dof;
1150 
1151     ierr = PetscSectionGetDof (pSec, point, &dof);CHKERRQ(ierr);
1152     if (dof) {
1153       PetscInt off;
1154 
1155       ierr = PetscSectionGetOffset (pSec, point, &off);CHKERRQ(ierr);
1156       if (parent)  *parent = mesh->parents[off];
1157       if (childID) *childID = mesh->childIDs[off];
1158       PetscFunctionReturn(0);
1159     }
1160   }
1161   if (parent) {
1162     *parent = point;
1163   }
1164   if (childID) {
1165     *childID = 0;
1166   }
1167   PetscFunctionReturn(0);
1168 }
1169 
1170 #undef __FUNCT__
1171 #define __FUNCT__ "DMPlexGetTreeChildren"
1172 /*@C
1173   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the Sieve DAG)
1174 
1175   Input Parameters:
1176 + dm - the DMPlex object
1177 - point - the query point
1178 
1179   Output Parameters:
1180 + numChildren - if not NULL, set to the number of children
1181 - children - if not NULL, set to a list children, or set to NULL if the point has no children
1182 
1183   Level: intermediate
1184 
1185   Fortran Notes:
1186   Since it returns an array, this routine is only available in Fortran 90, and you must
1187   include petsc.h90 in your code.
1188 
1189 .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeParent()
1190 @*/
1191 PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1192 {
1193   DM_Plex       *mesh = (DM_Plex *)dm->data;
1194   PetscSection   childSec;
1195   PetscInt       dof = 0;
1196   PetscErrorCode ierr;
1197 
1198   PetscFunctionBegin;
1199   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1200   childSec = mesh->childSection;
1201   if (childSec && point >= childSec->pStart && point < childSec->pEnd) {
1202     ierr = PetscSectionGetDof (childSec, point, &dof);CHKERRQ(ierr);
1203   }
1204   if (numChildren) *numChildren = dof;
1205   if (children) {
1206     if (dof) {
1207       PetscInt off;
1208 
1209       ierr = PetscSectionGetOffset (childSec, point, &off);CHKERRQ(ierr);
1210       *children = &mesh->children[off];
1211     }
1212     else {
1213       *children = NULL;
1214     }
1215   }
1216   PetscFunctionReturn(0);
1217 }
1218 
1219 #undef __FUNCT__
1220 #define __FUNCT__ "DMPlexComputeAnchorMatrix_Tree_Direct"
1221 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
1222 {
1223   PetscDS        ds;
1224   PetscInt       spdim;
1225   PetscInt       numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
1226   const PetscInt *anchors;
1227   PetscSection   aSec;
1228   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
1229   IS             aIS;
1230   PetscErrorCode ierr;
1231 
1232   PetscFunctionBegin;
1233   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
1234   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
1235   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1236   ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
1237   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
1238   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
1239   ierr = PetscSectionGetChart(cSec,&conStart,&conEnd);CHKERRQ(ierr);
1240   ierr = DMGetDimension(dm,&spdim);CHKERRQ(ierr);
1241   ierr = PetscMalloc6(spdim,&v0,spdim,&v0parent,spdim,&vtmp,spdim*spdim,&J,spdim*spdim,&Jparent,spdim*spdim,&invJparent);CHKERRQ(ierr);
1242 
1243   for (f = 0; f < numFields; f++) {
1244     PetscObject disc;
1245     PetscFE fe = NULL;
1246     PetscFV fv = NULL;
1247     PetscClassId id;
1248     PetscDualSpace space;
1249     PetscInt i, j, k, nPoints, offset;
1250     PetscInt fSize, fComp;
1251     PetscReal *B = NULL;
1252     PetscReal *weights, *pointsRef, *pointsReal;
1253     Mat Amat, Bmat, Xmat;
1254 
1255     ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
1256     ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
1257     if (id == PETSCFE_CLASSID) {
1258       fe = (PetscFE) disc;
1259       ierr = PetscFEGetDualSpace(fe,&space);CHKERRQ(ierr);
1260       ierr = PetscDualSpaceGetDimension(space,&fSize);CHKERRQ(ierr);
1261       ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr);
1262     }
1263     else if (id == PETSCFV_CLASSID) {
1264       fv = (PetscFV) disc;
1265       ierr = PetscFVGetDualSpace(fv,&space);CHKERRQ(ierr);
1266       ierr = PetscDualSpaceGetDimension(space,&fSize);CHKERRQ(ierr);
1267       ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr);
1268     }
1269     else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
1270 
1271     ierr = MatCreate(PETSC_COMM_SELF,&Amat);CHKERRQ(ierr);
1272     ierr = MatSetSizes(Amat,fSize,fSize,fSize,fSize);CHKERRQ(ierr);
1273     ierr = MatSetType(Amat,MATSEQDENSE);CHKERRQ(ierr);
1274     ierr = MatSetUp(Amat);CHKERRQ(ierr);
1275     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Bmat);CHKERRQ(ierr);
1276     ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Xmat);CHKERRQ(ierr);
1277     nPoints = 0;
1278     for (i = 0; i < fSize; i++) {
1279       PetscInt        qPoints;
1280       PetscQuadrature quad;
1281 
1282       ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr);
1283       ierr = PetscQuadratureGetData(quad,NULL,&qPoints,NULL,NULL);CHKERRQ(ierr);
1284       nPoints += qPoints;
1285     }
1286     ierr = PetscMalloc3(nPoints,&weights,spdim*nPoints,&pointsRef,spdim*nPoints,&pointsReal);CHKERRQ(ierr);
1287     offset = 0;
1288     for (i = 0; i < fSize; i++) {
1289       PetscInt        qPoints;
1290       const PetscReal    *p, *w;
1291       PetscQuadrature quad;
1292 
1293       ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr);
1294       ierr = PetscQuadratureGetData(quad,NULL,&qPoints,&p,&w);CHKERRQ(ierr);
1295       ierr = PetscMemcpy(weights+offset,w,qPoints*sizeof(*w));CHKERRQ(ierr);
1296       ierr = PetscMemcpy(pointsRef+spdim*offset,p,spdim*qPoints*sizeof(*p));CHKERRQ(ierr);
1297       offset += qPoints;
1298     }
1299     if (id == PETSCFE_CLASSID) {
1300       ierr = PetscFEGetTabulation(fe,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr);
1301     }
1302     else {
1303       ierr = PetscFVGetTabulation(fv,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr);
1304     }
1305     offset = 0;
1306     for (i = 0; i < fSize; i++) {
1307       PetscInt        qPoints;
1308       PetscQuadrature quad;
1309 
1310       ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr);
1311       ierr = PetscQuadratureGetData(quad,NULL,&qPoints,NULL,NULL);CHKERRQ(ierr);
1312       for (j = 0; j < fSize; j++) {
1313         PetscScalar val = 0.;
1314 
1315         for (k = 0; k < qPoints; k++) {
1316           val += B[((offset + k) * fSize + j) * fComp] * weights[k];
1317         }
1318         ierr = MatSetValue(Amat,i,j,val,INSERT_VALUES);CHKERRQ(ierr);
1319       }
1320       offset += qPoints;
1321     }
1322     if (id == PETSCFE_CLASSID) {
1323       ierr = PetscFERestoreTabulation(fe,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr);
1324     }
1325     else {
1326       ierr = PetscFVRestoreTabulation(fv,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr);
1327     }
1328     ierr = MatAssemblyBegin(Amat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1329     ierr = MatAssemblyEnd(Amat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1330     ierr = MatLUFactor(Amat,NULL,NULL,NULL);CHKERRQ(ierr);
1331     for (c = cStart; c < cEnd; c++) {
1332       PetscInt parent;
1333       PetscInt closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
1334       PetscInt *childOffsets, *parentOffsets;
1335 
1336       ierr = DMPlexGetTreeParent(dm,c,&parent,NULL);CHKERRQ(ierr);
1337       if (parent == c) continue;
1338       ierr = DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1339       for (i = 0; i < closureSize; i++) {
1340         PetscInt p = closure[2*i];
1341         PetscInt conDof;
1342 
1343         if (p < conStart || p >= conEnd) continue;
1344         if (numFields > 1) {
1345           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
1346         }
1347         else {
1348           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
1349         }
1350         if (conDof) break;
1351       }
1352       if (i == closureSize) {
1353         ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1354         continue;
1355       }
1356 
1357       ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
1358       ierr = DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent);CHKERRQ(ierr);
1359       for (i = 0; i < nPoints; i++) {
1360         CoordinatesRefToReal(spdim, spdim, v0, J, &pointsRef[i*spdim],vtmp);CHKERRQ(ierr);
1361         CoordinatesRealToRef(spdim, spdim, v0parent, invJparent, vtmp, &pointsReal[i*spdim]);CHKERRQ(ierr);
1362       }
1363       if (id == PETSCFE_CLASSID) {
1364         ierr = PetscFEGetTabulation(fe,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr);
1365       }
1366       else {
1367         ierr = PetscFVGetTabulation(fv,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr);
1368       }
1369       offset = 0;
1370       for (i = 0; i < fSize; i++) {
1371         PetscInt        qPoints;
1372         PetscQuadrature quad;
1373 
1374         ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr);
1375         ierr = PetscQuadratureGetData(quad,NULL,&qPoints,NULL,NULL);CHKERRQ(ierr);
1376         for (j = 0; j < fSize; j++) {
1377           PetscScalar val = 0.;
1378 
1379           for (k = 0; k < qPoints; k++) {
1380             val += B[((offset + k) * fSize + j) * fComp] * weights[k];
1381           }
1382           MatSetValue(Bmat,i,j,val,INSERT_VALUES);CHKERRQ(ierr);
1383         }
1384         offset += qPoints;
1385       }
1386       if (id == PETSCFE_CLASSID) {
1387         ierr = PetscFERestoreTabulation(fe,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr);
1388       }
1389       else {
1390         ierr = PetscFVRestoreTabulation(fv,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr);
1391       }
1392       ierr = MatAssemblyBegin(Bmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1393       ierr = MatAssemblyEnd(Bmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1394       ierr = MatMatSolve(Amat,Bmat,Xmat);CHKERRQ(ierr);
1395       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
1396       ierr = PetscMalloc2(closureSize+1,&childOffsets,closureSizeP+1,&parentOffsets);CHKERRQ(ierr);
1397       childOffsets[0] = 0;
1398       for (i = 0; i < closureSize; i++) {
1399         PetscInt p = closure[2*i];
1400         PetscInt dof;
1401 
1402         if (numFields > 1) {
1403           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
1404         }
1405         else {
1406           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
1407         }
1408         childOffsets[i+1]=childOffsets[i]+dof / fComp;
1409       }
1410       parentOffsets[0] = 0;
1411       for (i = 0; i < closureSizeP; i++) {
1412         PetscInt p = closureP[2*i];
1413         PetscInt dof;
1414 
1415         if (numFields > 1) {
1416           ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
1417         }
1418         else {
1419           ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
1420         }
1421         parentOffsets[i+1]=parentOffsets[i]+dof / fComp;
1422       }
1423       for (i = 0; i < closureSize; i++) {
1424         PetscInt conDof, conOff, aDof, aOff;
1425         PetscInt p = closure[2*i];
1426         PetscInt o = closure[2*i+1];
1427 
1428         if (p < conStart || p >= conEnd) continue;
1429         if (numFields > 1) {
1430           ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr);
1431           ierr = PetscSectionGetFieldOffset(cSec,p,f,&conOff);CHKERRQ(ierr);
1432         }
1433         else {
1434           ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr);
1435           ierr = PetscSectionGetOffset(cSec,p,&conOff);CHKERRQ(ierr);
1436         }
1437         if (!conDof) continue;
1438         ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
1439         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
1440         for (k = 0; k < aDof; k++) {
1441           PetscInt a = anchors[aOff + k];
1442           PetscInt aSecDof, aSecOff;
1443 
1444           if (numFields > 1) {
1445             ierr = PetscSectionGetFieldDof(section,a,f,&aSecDof);CHKERRQ(ierr);
1446             ierr = PetscSectionGetFieldOffset(section,a,f,&aSecOff);CHKERRQ(ierr);
1447           }
1448           else {
1449             ierr = PetscSectionGetDof(section,a,&aSecDof);CHKERRQ(ierr);
1450             ierr = PetscSectionGetOffset(section,a,&aSecOff);CHKERRQ(ierr);
1451           }
1452           if (!aSecDof) continue;
1453 
1454           for (j = 0; j < closureSizeP; j++) {
1455             PetscInt q = closureP[2*j];
1456             PetscInt oq = closureP[2*j+1];
1457 
1458             if (q == a) {
1459               PetscInt r, s, t;
1460 
1461               for (r = childOffsets[i]; r < childOffsets[i+1]; r++) {
1462                 for (s = parentOffsets[j]; s < parentOffsets[j+1]; s++) {
1463                   PetscScalar val;
1464                   PetscInt insertCol, insertRow;
1465 
1466                   ierr = MatGetValue(Xmat,r,s,&val);CHKERRQ(ierr);
1467                   if (o >= 0) {
1468                     insertRow = conOff + fComp * (r - childOffsets[i]);
1469                   }
1470                   else {
1471                     insertRow = conOff + fComp * (childOffsets[i + 1] - 1 - r);
1472                   }
1473                   if (oq >= 0) {
1474                     insertCol = aSecOff + fComp * (s - parentOffsets[j]);
1475                   }
1476                   else {
1477                     insertCol = aSecOff + fComp * (parentOffsets[j + 1] - 1 - s);
1478                   }
1479                   for (t = 0; t < fComp; t++) {
1480                     ierr = MatSetValue(cMat,insertRow + t,insertCol + t,val,INSERT_VALUES);CHKERRQ(ierr);
1481                   }
1482                 }
1483               }
1484             }
1485           }
1486         }
1487       }
1488       ierr = PetscFree2(childOffsets,parentOffsets);CHKERRQ(ierr);
1489       ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1490       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr);
1491     }
1492     ierr = MatDestroy(&Amat);CHKERRQ(ierr);
1493     ierr = MatDestroy(&Bmat);CHKERRQ(ierr);
1494     ierr = MatDestroy(&Xmat);CHKERRQ(ierr);
1495     ierr = PetscFree3(weights,pointsRef,pointsReal);CHKERRQ(ierr);
1496   }
1497   ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1498   ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1499   ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJparent);CHKERRQ(ierr);
1500   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
1501 
1502   PetscFunctionReturn(0);
1503 }
1504 
1505 #undef __FUNCT__
1506 #define __FUNCT__ "DMPlexReferenceTreeGetChildrenMatrices"
1507 static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1508 {
1509   Mat            refCmat;
1510   PetscDS        ds;
1511   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
1512   PetscScalar    ***refPointFieldMats;
1513   PetscSection   refConSec, refAnSec, refSection;
1514   IS             refAnIS;
1515   const PetscInt *refAnchors;
1516   PetscErrorCode ierr;
1517 
1518   PetscFunctionBegin;
1519   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
1520   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1521   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
1522   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
1523   ierr = ISGetIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
1524   ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr);
1525   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
1526   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr);
1527   ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldN);CHKERRQ(ierr);
1528   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
1529   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
1530   ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr);
1531   ierr = PetscMalloc1(maxDof*maxAnDof,&cols);CHKERRQ(ierr);
1532   for (p = pRefStart; p < pRefEnd; p++) {
1533     PetscInt parent, closureSize, *closure = NULL, pDof;
1534 
1535     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
1536     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
1537     if (!pDof || parent == p) continue;
1538 
1539     ierr = PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr);
1540     ierr = PetscCalloc1(numFields,&refPointFieldN[p-pRefStart]);CHKERRQ(ierr);
1541     ierr = DMPlexGetTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1542     for (f = 0; f < numFields; f++) {
1543       PetscInt cDof, cOff, numCols, r, i, fComp;
1544       PetscObject disc;
1545       PetscClassId id;
1546       PetscFE fe = NULL;
1547       PetscFV fv = NULL;
1548 
1549       ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
1550       ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
1551       if (id == PETSCFE_CLASSID) {
1552         fe = (PetscFE) disc;
1553         ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr);
1554       }
1555       else if (id == PETSCFV_CLASSID) {
1556         fv = (PetscFV) disc;
1557         ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr);
1558       }
1559       else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
1560 
1561       if (numFields > 1) {
1562         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
1563         ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr);
1564       }
1565       else {
1566         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
1567         ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr);
1568       }
1569 
1570       if (!cDof) continue;
1571       for (r = 0; r < cDof; r++) {
1572         rows[r] = cOff + r;
1573       }
1574       numCols = 0;
1575       for (i = 0; i < closureSize; i++) {
1576         PetscInt q = closure[2*i];
1577         PetscInt o = closure[2*i+1];
1578         PetscInt aDof, aOff, j;
1579 
1580         if (numFields > 1) {
1581           ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr);
1582           ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr);
1583         }
1584         else {
1585           ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr);
1586           ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr);
1587         }
1588 
1589         for (j = 0; j < aDof; j++) {
1590           PetscInt node = (o >= 0) ? (j / fComp) : ((aDof - 1 - j) / fComp);
1591           PetscInt comp = (j % fComp);
1592 
1593           cols[numCols++] = aOff + node * fComp + comp;
1594         }
1595       }
1596       refPointFieldN[p-pRefStart][f] = numCols;
1597       ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
1598       ierr = MatGetValues(refCmat,cDof,rows,numCols,cols,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr);
1599     }
1600     ierr = DMPlexRestoreTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1601   }
1602   *childrenMats = refPointFieldMats;
1603   *childrenN = refPointFieldN;
1604   ierr = ISRestoreIndices(refAnIS,&refAnchors);CHKERRQ(ierr);
1605   ierr = PetscFree(rows);CHKERRQ(ierr);
1606   ierr = PetscFree(cols);CHKERRQ(ierr);
1607   PetscFunctionReturn(0);
1608 }
1609 
1610 #undef __FUNCT__
1611 #define __FUNCT__ "DMPlexReferenceTreeRestoreChildrenMatrices"
1612 static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1613 {
1614   PetscDS        ds;
1615   PetscInt       **refPointFieldN;
1616   PetscScalar    ***refPointFieldMats;
1617   PetscInt       numFields, pRefStart, pRefEnd, p, f;
1618   PetscSection   refConSec;
1619   PetscErrorCode ierr;
1620 
1621   PetscFunctionBegin;
1622   refPointFieldN = *childrenN;
1623   *childrenN = NULL;
1624   refPointFieldMats = *childrenMats;
1625   *childrenMats = NULL;
1626   ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr);
1627   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1628   ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
1629   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
1630   for (p = pRefStart; p < pRefEnd; p++) {
1631     PetscInt parent, pDof;
1632 
1633     ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr);
1634     ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr);
1635     if (!pDof || parent == p) continue;
1636 
1637     for (f = 0; f < numFields; f++) {
1638       PetscInt cDof;
1639 
1640       if (numFields > 1) {
1641         ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr);
1642       }
1643       else {
1644         ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr);
1645       }
1646 
1647       if (!cDof) continue;
1648       ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr);
1649     }
1650     ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr);
1651     ierr = PetscFree(refPointFieldN[p - pRefStart]);CHKERRQ(ierr);
1652   }
1653   ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr);
1654   ierr = PetscFree(refPointFieldN);CHKERRQ(ierr);
1655   PetscFunctionReturn(0);
1656 }
1657 
1658 #undef __FUNCT__
1659 #define __FUNCT__ "DMPlexComputeAnchorMatrix_Tree_FromReference"
1660 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
1661 {
1662   DM             refTree;
1663   PetscDS        ds;
1664   Mat            refCmat;
1665   PetscInt       numFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
1666   PetscScalar ***refPointFieldMats, *pointWork;
1667   PetscSection   refConSec, refAnSec, anSec;
1668   IS             refAnIS, anIS;
1669   const PetscInt *anchors;
1670   PetscErrorCode ierr;
1671 
1672   PetscFunctionBegin;
1673   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1674   ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
1675   ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr);
1676   ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr);
1677   ierr = DMSetDS(refTree,ds);CHKERRQ(ierr);
1678   ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr);
1679   ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr);
1680   ierr = DMPlexGetAnchors(dm,&anSec,&anIS);CHKERRQ(ierr);
1681   ierr = ISGetIndices(anIS,&anchors);CHKERRQ(ierr);
1682   ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
1683   ierr = PetscSectionGetChart(conSec,&conStart,&conEnd);CHKERRQ(ierr);
1684   ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr);
1685   ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr);
1686   ierr = PetscMalloc1(maxDof*maxDof*maxAnDof,&pointWork);CHKERRQ(ierr);
1687 
1688   /* step 1: get submats for every constrained point in the reference tree */
1689   ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
1690 
1691   /* step 2: compute the preorder */
1692   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
1693   ierr = PetscMalloc2(pEnd-pStart,&perm,pEnd-pStart,&iperm);CHKERRQ(ierr);
1694   for (p = pStart; p < pEnd; p++) {
1695     perm[p - pStart] = p;
1696     iperm[p - pStart] = p-pStart;
1697   }
1698   for (p = 0; p < pEnd - pStart;) {
1699     PetscInt point = perm[p];
1700     PetscInt parent;
1701 
1702     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
1703     if (parent == point) {
1704       p++;
1705     }
1706     else {
1707       PetscInt size, closureSize, *closure = NULL, i;
1708 
1709       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1710       for (i = 0; i < closureSize; i++) {
1711         PetscInt q = closure[2*i];
1712         if (iperm[q-pStart] > iperm[point-pStart]) {
1713           /* swap */
1714           perm[p]               = q;
1715           perm[iperm[q-pStart]] = point;
1716           iperm[point-pStart]   = iperm[q-pStart];
1717           iperm[q-pStart]       = p;
1718           break;
1719         }
1720       }
1721       size = closureSize;
1722       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1723       if (i == size) {
1724         p++;
1725       }
1726     }
1727   }
1728 
1729   /* step 3: fill the constraint matrix */
1730   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
1731    * allow progressive fill without assembly, so we are going to set up the
1732    * values outside of the Mat first.
1733    */
1734   {
1735     PetscInt nRows, row, nnz;
1736     PetscBool done;
1737     const PetscInt *ia, *ja;
1738     PetscScalar *vals;
1739 
1740     ierr = MatGetRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
1741     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not get RowIJ of constraint matrix");
1742     nnz  = ia[nRows];
1743     /* malloc and then zero rows right before we fill them: this way valgrind
1744      * can tell if we are doing progressive fill in the wrong order */
1745     ierr = PetscMalloc1(nnz,&vals);CHKERRQ(ierr);
1746     for (p = 0; p < pEnd - pStart; p++) {
1747       PetscInt parent, childid, closureSize, *closure = NULL;
1748       PetscInt point = perm[p], pointDof;
1749 
1750       ierr = DMPlexGetTreeParent(dm,point,&parent,&childid);CHKERRQ(ierr);
1751       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
1752       ierr = PetscSectionGetDof(conSec,point,&pointDof);CHKERRQ(ierr);
1753       if (!pointDof) continue;
1754       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1755       for (f = 0; f < numFields; f++) {
1756         PetscInt cDof, cOff, numCols, numFillCols, i, r, fComp = -1, matOffset, offset;
1757         PetscScalar *pointMat;
1758         PetscObject disc;
1759         PetscClassId id;
1760         PetscFE fe = NULL;
1761         PetscFV fv = NULL;
1762 
1763         ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr);
1764         ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr);
1765         if (id == PETSCFE_CLASSID) {
1766           fe = (PetscFE) disc;
1767           ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr);
1768         }
1769         else if (id == PETSCFV_CLASSID) {
1770           fv = (PetscFV) disc;
1771           ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr);
1772         }
1773         else {
1774           SETERRQ(PetscObjectComm((PetscObject)disc),PETSC_ERR_SUP,"Unsupported discretization");
1775         }
1776 
1777         if (numFields > 1) {
1778           ierr = PetscSectionGetFieldDof(conSec,point,f,&cDof);CHKERRQ(ierr);
1779           ierr = PetscSectionGetFieldOffset(conSec,point,f,&cOff);CHKERRQ(ierr);
1780         }
1781         else {
1782           ierr = PetscSectionGetDof(conSec,point,&cDof);CHKERRQ(ierr);
1783           ierr = PetscSectionGetOffset(conSec,point,&cOff);CHKERRQ(ierr);
1784         }
1785         if (!cDof) continue;
1786 
1787         /* make sure that every row for this point is the same size */
1788 #if defined(PETSC_USE_DEBUG)
1789         for (r = 0; r < cDof; r++) {
1790           if (cDof > 1 && r) {
1791             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]));
1792           }
1793         }
1794 #endif
1795         /* zero rows */
1796         for (i = ia[cOff] ; i< ia[cOff+cDof];i++) {
1797           vals[i] = 0.;
1798         }
1799         matOffset = ia[cOff];
1800         numFillCols = ia[cOff+1] - matOffset;
1801         pointMat = refPointFieldMats[childid-pRefStart][f];
1802         numCols = refPointFieldN[childid-pRefStart][f];
1803         offset = 0;
1804         for (i = 0; i < closureSize; i++) {
1805           PetscInt q = closure[2*i];
1806           PetscInt o = closure[2*i+1];
1807           PetscInt aDof, aOff, j, k, qConDof, qConOff;
1808 
1809           qConDof = qConOff = 0;
1810           if (numFields > 1) {
1811             ierr = PetscSectionGetFieldDof(section,q,f,&aDof);CHKERRQ(ierr);
1812             ierr = PetscSectionGetFieldOffset(section,q,f,&aOff);CHKERRQ(ierr);
1813             if (q >= conStart && q < conEnd) {
1814               ierr = PetscSectionGetFieldDof(conSec,q,f,&qConDof);CHKERRQ(ierr);
1815               ierr = PetscSectionGetFieldOffset(conSec,q,f,&qConOff);CHKERRQ(ierr);
1816             }
1817           }
1818           else {
1819             ierr = PetscSectionGetDof(section,q,&aDof);CHKERRQ(ierr);
1820             ierr = PetscSectionGetOffset(section,q,&aOff);CHKERRQ(ierr);
1821             if (q >= conStart && q < conEnd) {
1822               ierr = PetscSectionGetDof(conSec,q,&qConDof);CHKERRQ(ierr);
1823               ierr = PetscSectionGetOffset(conSec,q,&qConOff);CHKERRQ(ierr);
1824             }
1825           }
1826           if (!aDof) continue;
1827           if (qConDof) {
1828             /* this point has anchors: its rows of the matrix should already
1829              * be filled, thanks to preordering */
1830             /* first multiply into pointWork, then set in matrix */
1831             PetscInt aMatOffset = ia[qConOff];
1832             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
1833             for (r = 0; r < cDof; r++) {
1834               for (j = 0; j < aNumFillCols; j++) {
1835                 PetscScalar inVal = 0;
1836                 for (k = 0; k < aDof; k++) {
1837                   PetscInt node = (o >= 0) ? (k / fComp) : ((aDof - 1 - k) / fComp);
1838                   PetscInt comp = (k % fComp);
1839                   PetscInt col  = node * fComp + comp;
1840 
1841                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j];
1842                 }
1843                 pointWork[r * aNumFillCols + j] = inVal;
1844               }
1845             }
1846             /* assume that the columns are sorted, spend less time searching */
1847             for (j = 0, k = 0; j < aNumFillCols; j++) {
1848               PetscInt col = ja[aMatOffset + j];
1849               for (;k < numFillCols; k++) {
1850                 if (ja[matOffset + k] == col) {
1851                   break;
1852                 }
1853               }
1854               if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, col);
1855               for (r = 0; r < cDof; r++) {
1856                 vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
1857               }
1858             }
1859           }
1860           else {
1861             /* find where to put this portion of pointMat into the matrix */
1862             for (k = 0; k < numFillCols; k++) {
1863               if (ja[matOffset + k] == aOff) {
1864                 break;
1865               }
1866             }
1867             if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, aOff);
1868             for (j = 0; j < aDof; j++) {
1869               PetscInt node = (o >= 0) ? (j / fComp) : ((aDof - 1 - j) / fComp);
1870               PetscInt comp = (j % fComp);
1871               PetscInt col  = node * fComp + comp;
1872               for (r = 0; r < cDof; r++) {
1873                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + col];
1874               }
1875             }
1876           }
1877           offset += aDof;
1878         }
1879       }
1880       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1881     }
1882     for (row = 0; row < nRows; row++) {
1883       ierr = MatSetValues(cMat,1,&row,ia[row+1]-ia[row],&ja[ia[row]],&vals[ia[row]],INSERT_VALUES);CHKERRQ(ierr);
1884     }
1885     ierr = MatRestoreRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr);
1886     if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not restore RowIJ of constraint matrix");
1887     ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1888     ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1889     ierr = PetscFree(vals);CHKERRQ(ierr);
1890   }
1891 
1892   /* clean up */
1893   ierr = ISRestoreIndices(anIS,&anchors);CHKERRQ(ierr);
1894   ierr = PetscFree2(perm,iperm);CHKERRQ(ierr);
1895   ierr = PetscFree(pointWork);CHKERRQ(ierr);
1896   ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
1897   PetscFunctionReturn(0);
1898 }
1899 
1900 #undef __FUNCT__
1901 #define __FUNCT__ "DMPlexTreeRefineCell"
1902 /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
1903  * a non-conforming mesh.  Local refinement comes later */
1904 PetscErrorCode DMPlexTreeRefineCell (DM dm, PetscInt cell, DM *ncdm)
1905 {
1906   DM K;
1907   PetscMPIInt rank;
1908   PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
1909   PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations;
1910   PetscInt *Kembedding;
1911   PetscInt *cellClosure=NULL, nc;
1912   PetscScalar *newVertexCoords;
1913   PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
1914   PetscSection parentSection;
1915   PetscErrorCode ierr;
1916 
1917   PetscFunctionBegin;
1918   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRQ(ierr);
1919   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
1920   ierr = DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm);CHKERRQ(ierr);
1921   ierr = DMSetDimension(*ncdm,dim);CHKERRQ(ierr);
1922 
1923   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1924   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&parentSection);CHKERRQ(ierr);
1925   ierr = DMPlexGetReferenceTree(dm,&K);CHKERRQ(ierr);
1926   if (!rank) {
1927     /* compute the new charts */
1928     ierr = PetscMalloc5(dim+1,&pNewCount,dim+1,&pNewStart,dim+1,&pNewEnd,dim+1,&pOldStart,dim+1,&pOldEnd);CHKERRQ(ierr);
1929     offset = 0;
1930     for (d = 0; d <= dim; d++) {
1931       PetscInt pOldCount, kStart, kEnd, k;
1932 
1933       pNewStart[d] = offset;
1934       ierr = DMPlexGetHeightStratum(dm,d,&pOldStart[d],&pOldEnd[d]);CHKERRQ(ierr);
1935       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
1936       pOldCount = pOldEnd[d] - pOldStart[d];
1937       /* adding the new points */
1938       pNewCount[d] = pOldCount + kEnd - kStart;
1939       if (!d) {
1940         /* removing the cell */
1941         pNewCount[d]--;
1942       }
1943       for (k = kStart; k < kEnd; k++) {
1944         PetscInt parent;
1945         ierr = DMPlexGetTreeParent(K,k,&parent,NULL);CHKERRQ(ierr);
1946         if (parent == k) {
1947           /* avoid double counting points that won't actually be new */
1948           pNewCount[d]--;
1949         }
1950       }
1951       pNewEnd[d] = pNewStart[d] + pNewCount[d];
1952       offset = pNewEnd[d];
1953 
1954     }
1955     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]);
1956     /* get the current closure of the cell that we are removing */
1957     ierr = DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
1958 
1959     ierr = PetscMalloc1(pNewEnd[dim],&newConeSizes);CHKERRQ(ierr);
1960     {
1961       PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
1962 
1963       ierr = DMPlexGetChart(K,&kStart,&kEnd);CHKERRQ(ierr);
1964       ierr = PetscMalloc4(kEnd-kStart,&Kembedding,kEnd-kStart,&perm,kEnd-kStart,&iperm,kEnd-kStart,&preOrient);CHKERRQ(ierr);
1965 
1966       for (k = kStart; k < kEnd; k++) {
1967         perm[k - kStart] = k;
1968         iperm [k - kStart] = k - kStart;
1969         preOrient[k - kStart] = 0;
1970       }
1971 
1972       ierr = DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
1973       for (j = 1; j < closureSizeK; j++) {
1974         PetscInt parentOrientA = closureK[2*j+1];
1975         PetscInt parentOrientB = cellClosure[2*j+1];
1976         PetscInt p, q;
1977 
1978         p = closureK[2*j];
1979         q = cellClosure[2*j];
1980         for (d = 0; d <= dim; d++) {
1981           if (q >= pOldStart[d] && q < pOldEnd[d]) {
1982             Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
1983           }
1984         }
1985         if (parentOrientA != parentOrientB) {
1986           PetscInt numChildren, i;
1987           const PetscInt *children;
1988 
1989           ierr = DMPlexGetTreeChildren(K,p,&numChildren,&children);CHKERRQ(ierr);
1990           for (i = 0; i < numChildren; i++) {
1991             PetscInt kPerm, oPerm;
1992 
1993             k    = children[i];
1994             ierr = DMPlexReferenceTreeGetChildSymmetry(K,p,parentOrientA,0,k,parentOrientB,&oPerm,&kPerm);CHKERRQ(ierr);
1995             /* perm = what refTree position I'm in */
1996             perm[kPerm-kStart]      = k;
1997             /* iperm = who is at this position */
1998             iperm[k-kStart]         = kPerm-kStart;
1999             preOrient[kPerm-kStart] = oPerm;
2000           }
2001         }
2002       }
2003       ierr = DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr);
2004     }
2005     ierr = PetscSectionSetChart(parentSection,0,pNewEnd[dim]);CHKERRQ(ierr);
2006     offset = 0;
2007     numNewCones = 0;
2008     for (d = 0; d <= dim; d++) {
2009       PetscInt kStart, kEnd, k;
2010       PetscInt p;
2011       PetscInt size;
2012 
2013       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
2014         /* skip cell 0 */
2015         if (p == cell) continue;
2016         /* old cones to new cones */
2017         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
2018         newConeSizes[offset++] = size;
2019         numNewCones += size;
2020       }
2021 
2022       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
2023       for (k = kStart; k < kEnd; k++) {
2024         PetscInt kParent;
2025 
2026         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
2027         if (kParent != k) {
2028           Kembedding[k] = offset;
2029           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
2030           newConeSizes[offset++] = size;
2031           numNewCones += size;
2032           if (kParent != 0) {
2033             ierr = PetscSectionSetDof(parentSection,Kembedding[k],1);CHKERRQ(ierr);
2034           }
2035         }
2036       }
2037     }
2038 
2039     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
2040     ierr = PetscSectionGetStorageSize(parentSection,&numPointsWithParents);CHKERRQ(ierr);
2041     ierr = PetscMalloc2(numNewCones,&newCones,numNewCones,&newOrientations);CHKERRQ(ierr);
2042     ierr = PetscMalloc2(numPointsWithParents,&parents,numPointsWithParents,&childIDs);CHKERRQ(ierr);
2043 
2044     /* fill new cones */
2045     offset = 0;
2046     for (d = 0; d <= dim; d++) {
2047       PetscInt kStart, kEnd, k, l;
2048       PetscInt p;
2049       PetscInt size;
2050       const PetscInt *cone, *orientation;
2051 
2052       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
2053         /* skip cell 0 */
2054         if (p == cell) continue;
2055         /* old cones to new cones */
2056         ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr);
2057         ierr = DMPlexGetCone(dm,p,&cone);CHKERRQ(ierr);
2058         ierr = DMPlexGetConeOrientation(dm,p,&orientation);CHKERRQ(ierr);
2059         for (l = 0; l < size; l++) {
2060           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
2061           newOrientations[offset++] = orientation[l];
2062         }
2063       }
2064 
2065       ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr);
2066       for (k = kStart; k < kEnd; k++) {
2067         PetscInt kPerm = perm[k], kParent;
2068         PetscInt preO  = preOrient[k];
2069 
2070         ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr);
2071         if (kParent != k) {
2072           /* embed new cones */
2073           ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr);
2074           ierr = DMPlexGetCone(K,kPerm,&cone);CHKERRQ(ierr);
2075           ierr = DMPlexGetConeOrientation(K,kPerm,&orientation);CHKERRQ(ierr);
2076           for (l = 0; l < size; l++) {
2077             PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size -(preO + 1) - l) % size);
2078             PetscInt newO, lSize, oTrue;
2079 
2080             q                         = iperm[cone[m]];
2081             newCones[offset]          = Kembedding[q];
2082             ierr                      = DMPlexGetConeSize(K,q,&lSize);CHKERRQ(ierr);
2083             oTrue                     = orientation[m];
2084             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
2085             newO                      = DihedralCompose(lSize,oTrue,preOrient[q]);
2086             newOrientations[offset++] = newO;
2087           }
2088           if (kParent != 0) {
2089             PetscInt newPoint = Kembedding[kParent];
2090             ierr              = PetscSectionGetOffset(parentSection,Kembedding[k],&pOffset);CHKERRQ(ierr);
2091             parents[pOffset]  = newPoint;
2092             childIDs[pOffset] = k;
2093           }
2094         }
2095       }
2096     }
2097 
2098     ierr = PetscMalloc1(dim*(pNewEnd[dim]-pNewStart[dim]),&newVertexCoords);CHKERRQ(ierr);
2099 
2100     /* fill coordinates */
2101     offset = 0;
2102     {
2103       PetscInt kStart, kEnd, l;
2104       PetscSection vSection;
2105       PetscInt v;
2106       Vec coords;
2107       PetscScalar *coordvals;
2108       PetscInt dof, off;
2109       PetscReal v0[3], J[9], detJ;
2110 
2111 #if defined(PETSC_USE_DEBUG)
2112       {
2113         PetscInt k;
2114         ierr = DMPlexGetHeightStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
2115         for (k = kStart; k < kEnd; k++) {
2116           ierr = DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
2117           if (detJ <= 0.) SETERRQ1 (PETSC_COMM_SELF,PETSC_ERR_PLIB,"reference tree cell %d has bad determinant",k);
2118         }
2119       }
2120 #endif
2121       ierr = DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr);
2122       ierr = DMGetCoordinateSection(dm,&vSection);CHKERRQ(ierr);
2123       ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr);
2124       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
2125       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
2126 
2127         ierr = PetscSectionGetDof(vSection,v,&dof);CHKERRQ(ierr);
2128         ierr = PetscSectionGetOffset(vSection,v,&off);CHKERRQ(ierr);
2129         for (l = 0; l < dof; l++) {
2130           newVertexCoords[offset++] = coordvals[off + l];
2131         }
2132       }
2133       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
2134 
2135       ierr = DMGetCoordinateSection(K,&vSection);CHKERRQ(ierr);
2136       ierr = DMGetCoordinatesLocal(K,&coords);CHKERRQ(ierr);
2137       ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr);
2138       ierr = DMPlexGetDepthStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr);
2139       for (v = kStart; v < kEnd; v++) {
2140         PetscReal coord[3], newCoord[3];
2141         PetscInt  vPerm = perm[v];
2142         PetscInt  kParent;
2143 
2144         ierr = DMPlexGetTreeParent(K,v,&kParent,NULL);CHKERRQ(ierr);
2145         if (kParent != v) {
2146           /* this is a new vertex */
2147           ierr = PetscSectionGetOffset(vSection,vPerm,&off);CHKERRQ(ierr);
2148           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off+l]);
2149           CoordinatesRefToReal(dim, dim, v0, J, coord, newCoord);CHKERRQ(ierr);
2150           for (l = 0; l < dim; ++l) newVertexCoords[offset+l] = newCoord[l];
2151           offset += dim;
2152         }
2153       }
2154       ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr);
2155     }
2156 
2157     /* need to reverse the order of pNewCount: vertices first, cells last */
2158     for (d = 0; d < (dim + 1) / 2; d++) {
2159       PetscInt tmp;
2160 
2161       tmp = pNewCount[d];
2162       pNewCount[d] = pNewCount[dim - d];
2163       pNewCount[dim - d] = tmp;
2164     }
2165 
2166     ierr = DMPlexCreateFromDAG(*ncdm,dim,pNewCount,newConeSizes,newCones,newOrientations,newVertexCoords);CHKERRQ(ierr);
2167     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
2168     ierr = DMPlexSetTree(*ncdm,parentSection,parents,childIDs);CHKERRQ(ierr);
2169 
2170     /* clean up */
2171     ierr = DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr);
2172     ierr = PetscFree5(pNewCount,pNewStart,pNewEnd,pOldStart,pOldEnd);CHKERRQ(ierr);
2173     ierr = PetscFree(newConeSizes);CHKERRQ(ierr);
2174     ierr = PetscFree2(newCones,newOrientations);CHKERRQ(ierr);
2175     ierr = PetscFree(newVertexCoords);CHKERRQ(ierr);
2176     ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr);
2177     ierr = PetscFree4(Kembedding,perm,iperm,preOrient);CHKERRQ(ierr);
2178   }
2179   else {
2180     PetscInt    p, counts[4];
2181     PetscInt    *coneSizes, *cones, *orientations;
2182     Vec         coordVec;
2183     PetscScalar *coords;
2184 
2185     for (d = 0; d <= dim; d++) {
2186       PetscInt dStart, dEnd;
2187 
2188       ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr);
2189       counts[d] = dEnd - dStart;
2190     }
2191     ierr = PetscMalloc1(pEnd-pStart,&coneSizes);CHKERRQ(ierr);
2192     for (p = pStart; p < pEnd; p++) {
2193       ierr = DMPlexGetConeSize(dm,p,&coneSizes[p-pStart]);CHKERRQ(ierr);
2194     }
2195     ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2196     ierr = DMPlexGetConeOrientations(dm, &orientations);CHKERRQ(ierr);
2197     ierr = DMGetCoordinatesLocal(dm,&coordVec);CHKERRQ(ierr);
2198     ierr = VecGetArray(coordVec,&coords);CHKERRQ(ierr);
2199 
2200     ierr = PetscSectionSetChart(parentSection,pStart,pEnd);CHKERRQ(ierr);
2201     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
2202     ierr = DMPlexCreateFromDAG(*ncdm,dim,counts,coneSizes,cones,orientations,NULL);CHKERRQ(ierr);
2203     ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr);
2204     ierr = DMPlexSetTree(*ncdm,parentSection,NULL,NULL);CHKERRQ(ierr);
2205     ierr = VecRestoreArray(coordVec,&coords);CHKERRQ(ierr);
2206   }
2207   ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
2208 
2209   PetscFunctionReturn(0);
2210 }
2211 
2212 PETSC_EXTERN PetscErrorCode indicesPointFields_private(PetscSection,PetscInt,PetscInt,PetscInt[],PetscBool,PetscInt,PetscInt[]);
2213 PETSC_EXTERN PetscErrorCode indicesPoint_private(PetscSection,PetscInt,PetscInt,PetscInt *,PetscBool,PetscInt,PetscInt[]);
2214 
2215 #undef __FUNCT__
2216 #define __FUNCT__ "DMPlexComputeInterpolatorTree"
2217 PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
2218 {
2219   PetscSF        coarseToFineEmbedded;
2220   PetscSection   globalCoarse, globalFine;
2221   PetscSection   localCoarse, localFine;
2222   PetscSection   aSec, cSec;
2223   PetscSection   rootIndicesSec, rootMatricesSec;
2224   PetscSection   leafIndicesSec, leafMatricesSec;
2225   PetscInt       *rootIndices, *leafIndices;
2226   PetscScalar    *rootMatrices, *leafMatrices;
2227   IS             aIS;
2228   const PetscInt *anchors;
2229   Mat            cMat;
2230   PetscInt       numFields;
2231   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
2232   PetscInt       aStart, aEnd, cStart, cEnd;
2233   PetscInt       *maxChildIds;
2234   PetscInt       *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
2235   PetscErrorCode ierr;
2236 
2237   PetscFunctionBegin;
2238   ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr);
2239   ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr);
2240   ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr);
2241   { /* winnow fine points that don't have global dofs out of the sf */
2242     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
2243 
2244     for (p = pStartF, numPointsWithDofs = 0; p < pEndF; p++) {
2245       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
2246       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
2247       if ((dof - cdof) > 0) {
2248         numPointsWithDofs++;
2249       }
2250     }
2251     ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr);
2252     for (p = pStartF, offset = 0; p < pEndF; p++) {
2253       ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr);
2254       ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr);
2255       if ((dof - cdof) > 0) {
2256         pointsWithDofs[offset++] = p - pStartF;
2257       }
2258     }
2259     ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr);
2260   }
2261   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
2262   ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr);
2263   for (p = pStartC; p < pEndC; p++) {
2264     maxChildIds[p - pStartC] = -1;
2265   }
2266   ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
2267   ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr);
2268 
2269   ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr);
2270   ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr);
2271 
2272   ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr);
2273   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
2274   ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
2275 
2276   ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr);
2277   ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr);
2278 
2279   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
2280   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr);
2281   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootMatricesSec);CHKERRQ(ierr);
2282   ierr = PetscSectionSetChart(rootIndicesSec,pStartC,pEndC);CHKERRQ(ierr);
2283   ierr = PetscSectionSetChart(rootMatricesSec,pStartC,pEndC);CHKERRQ(ierr);
2284   ierr = PetscSectionGetNumFields(globalCoarse,&numFields);CHKERRQ(ierr);
2285   {
2286     PetscInt maxFields = PetscMax(1,numFields) + 1;
2287     ierr = PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO);CHKERRQ(ierr);
2288   }
2289 
2290   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
2291     PetscInt dof, matSize;
2292     PetscInt aDof           = 0;
2293     PetscInt cDof           = 0;
2294     PetscInt maxChildId     = maxChildIds[p - pStartC];
2295     PetscInt numRowIndices  = 0;
2296     PetscInt numColIndices  = 0;
2297 
2298     ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
2299     if (dof < 0) {
2300       dof = -(dof + 1);
2301     }
2302     if (p >= aStart && p < aEnd) {
2303       ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
2304     }
2305     if (p >= cStart && p < cEnd) {
2306       ierr = PetscSectionGetDof(cSec,p,&cDof);CHKERRQ(ierr);
2307     }
2308     offsets[0]    = 0;
2309     newOffsets[0] = 0;
2310     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2311       PetscInt *closure = NULL, closureSize, cl, f;
2312 
2313       ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
2314       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
2315         PetscInt c = closure[2 * cl], clDof;
2316 
2317         ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr);
2318         numRowIndices += clDof;
2319         for (f = 0; f < numFields; f++) {
2320           ierr = PetscSectionGetFieldDof(localCoarse,c,f,&clDof);CHKERRQ(ierr);
2321           offsets[f + 1] += clDof;
2322         }
2323       }
2324       for (f = 0; f < numFields; f++) {
2325         offsets[f + 1]   += offsets[f];
2326         newOffsets[f + 1] = offsets[f + 1];
2327       }
2328       /* get the number of indices needed and their field offsets */
2329       ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,NULL,NULL,&numColIndices,NULL,NULL,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
2330       ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
2331       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
2332         numColIndices = numRowIndices;
2333         matSize = 0;
2334       }
2335       else if (numFields) { /* we send one submat for each field: sum their sizes */
2336         matSize = 0;
2337         for (f = 0; f < numFields; f++) {
2338           PetscInt numRow, numCol;
2339 
2340           numRow = offsets[f + 1] - offsets[f];
2341           numCol = newOffsets[f + 1] - newOffsets[f + 1];
2342           matSize += numRow * numCol;
2343         }
2344       }
2345       else {
2346         matSize = numRowIndices * numColIndices;
2347       }
2348     }
2349     else if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2350       PetscInt aOff, a, f;
2351 
2352       ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
2353       for (f = 0; f < numFields; f++) {
2354         PetscInt fDof;
2355 
2356         ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
2357         offsets[f+1] = fDof;
2358       }
2359       for (a = 0; a < aDof; a++) {
2360         PetscInt anchor = anchors[a + aOff], aLocalDof;
2361 
2362         ierr = PetscSectionGetDof(localCoarse,anchor,&aLocalDof);CHKERRQ(ierr);
2363         numColIndices += aLocalDof;
2364         for (f = 0; f < numFields; f++) {
2365           PetscInt fDof;
2366 
2367           ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
2368           newOffsets[f+1] += fDof;
2369         }
2370       }
2371       if (numFields) {
2372         matSize = 0;
2373         for (f = 0; f < numFields; f++) {
2374           matSize += offsets[f+1] * newOffsets[f+1];
2375         }
2376       }
2377       else {
2378         matSize = numColIndices * dof;
2379       }
2380     }
2381     else { /* no children, and no constraints on dofs: just get the global indices */
2382       numColIndices = dof;
2383       matSize       = 0;
2384     }
2385     /* we will pack the column indices with the field offsets */
2386     ierr = PetscSectionSetDof(rootIndicesSec,p,numColIndices ? numColIndices+2*numFields : 0);CHKERRQ(ierr);
2387     ierr = PetscSectionSetDof(rootMatricesSec,p,matSize);CHKERRQ(ierr);
2388   }
2389   ierr = PetscSectionSetUp(rootIndicesSec);CHKERRQ(ierr);
2390   ierr = PetscSectionSetUp(rootMatricesSec);CHKERRQ(ierr);
2391   {
2392     PetscInt    numRootIndices, numRootMatrices;
2393 
2394     ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr);
2395     ierr = PetscSectionGetStorageSize(rootMatricesSec,&numRootMatrices);CHKERRQ(ierr);
2396     ierr = PetscMalloc2(numRootIndices,&rootIndices,numRootMatrices,&rootMatrices);CHKERRQ(ierr);
2397     for (p = pStartC; p < pEndC; p++) {
2398       PetscInt    numRowIndices, numColIndices, matSize, dof;
2399       PetscInt    pIndOff, pMatOff;
2400       PetscInt    *pInd;
2401       PetscInt    maxChildId = maxChildIds[p - pStartC];
2402       PetscScalar *pMat = NULL;
2403 
2404       ierr = PetscSectionGetDof(rootIndicesSec,p,&numColIndices);CHKERRQ(ierr);
2405       if (!numColIndices) {
2406         continue;
2407       }
2408       offsets[0]        = 0;
2409       newOffsets[0]     = 0;
2410       offsetsCopy[0]    = 0;
2411       newOffsetsCopy[0] = 0;
2412       numColIndices -= 2 * numFields;
2413       ierr = PetscSectionGetOffset(rootIndicesSec,p,&pIndOff);CHKERRQ(ierr);
2414       pInd = &(rootIndices[pIndOff]);
2415       ierr = PetscSectionGetDof(rootMatricesSec,p,&matSize);CHKERRQ(ierr);
2416       if (matSize) {
2417         ierr = PetscSectionGetOffset(rootMatricesSec,p,&pMatOff);CHKERRQ(ierr);
2418         pMat = &rootMatrices[pMatOff];
2419       }
2420       ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr);
2421       if (dof < 0) {
2422         dof = -(dof + 1);
2423       }
2424       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
2425         PetscInt i, j;
2426         PetscInt numRowIndices = matSize / numColIndices;
2427 
2428         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
2429           PetscInt numIndices, *indices;
2430           ierr = DMPlexGetClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
2431           if (numIndices != numColIndices) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"mismatching constraint indices calculations");
2432           for (i = 0; i < numColIndices; i++) {
2433             pInd[i] = indices[i];
2434           }
2435           for (i = 0; i < numFields; i++) {
2436             pInd[numColIndices + i]             = offsets[i+1];
2437             pInd[numColIndices + numFields + i] = offsets[i+1];
2438           }
2439           ierr = DMPlexRestoreClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr);
2440         }
2441         else {
2442           PetscInt closureSize, *closure = NULL, cl;
2443           PetscScalar *pMatIn, *pMatModified;
2444           PetscInt numPoints,*points;
2445 
2446           ierr = DMGetWorkArray(coarse,numRowIndices * numRowIndices,PETSC_SCALAR,&pMatIn);CHKERRQ(ierr);
2447           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
2448             for (j = 0; j < numRowIndices; j++) {
2449               pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
2450             }
2451           }
2452           ierr = DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2453           if (numFields) {
2454             PetscInt f;
2455 
2456             for (cl = 0; cl < closureSize; cl++) {
2457               PetscInt c = closure[2 * cl];
2458 
2459               for (f = 0; f < numFields; f++) {
2460                 PetscInt fDof;
2461 
2462                 ierr = PetscSectionGetFieldDof(localCoarse,c,f,&fDof);CHKERRQ(ierr);
2463                 offsets[f + 1] += fDof;
2464               }
2465             }
2466             for (f = 0; f < numFields; f++) {
2467               offsets[f + 1]   += offsets[f];
2468               newOffsets[f + 1] = offsets[f + 1];
2469             }
2470           }
2471           /* apply hanging node constraints on the right, get the new points and the new offsets */
2472           ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,pMatIn,&numPoints,NULL,&points,&pMatModified,newOffsets,PETSC_FALSE);CHKERRQ(ierr);
2473           if (!numFields) {
2474             for (i = 0; i < numRowIndices * numColIndices; i++) {
2475               pMat[i] = pMatModified[i];
2476             }
2477           }
2478           else {
2479             PetscInt f, i, j, count;
2480             for (f = 0, count = 0; f < numFields; f++) {
2481               for (i = offsets[f]; i < offsets[f+1]; i++) {
2482                 for (j = newOffsets[f]; j < newOffsets[f+1]; j++, count++) {
2483                   pMat[count] = pMatModified[i * numColIndices + j];
2484                 }
2485               }
2486             }
2487           }
2488           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,PETSC_SCALAR,&pMatModified);CHKERRQ(ierr);
2489           ierr = DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2490           ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,PETSC_SCALAR,&pMatIn);CHKERRQ(ierr);
2491           if (numFields) {
2492             PetscInt f;
2493             for (f = 0; f < numFields; f++) {
2494               pInd[numColIndices + f]             = offsets[f+1];
2495               pInd[numColIndices + numFields + f] = newOffsets[f+1];
2496             }
2497             for (cl = 0; cl < numPoints*2; cl += 2) {
2498               PetscInt o = points[cl+1], globalOff, c = points[cl];
2499               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
2500               indicesPointFields_private(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, o, pInd);
2501             }
2502           } else {
2503             for (cl = 0; cl < numPoints*2; cl += 2) {
2504               PetscInt o = points[cl+1], c = points[cl], globalOff;
2505               ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr);
2506               indicesPoint_private(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, o, pInd);
2507             }
2508           }
2509         }
2510       }
2511       else if (matSize) {
2512         PetscInt cOff;
2513         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
2514 
2515         numRowIndices = matSize / numColIndices;
2516         if (numRowIndices != dof) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Miscounted dofs");
2517         ierr = DMGetWorkArray(coarse,numRowIndices,PETSC_INT,&rowIndices);CHKERRQ(ierr);
2518         ierr = DMGetWorkArray(coarse,numColIndices,PETSC_INT,&colIndices);CHKERRQ(ierr);
2519         ierr = PetscSectionGetOffset(cSec,p,&cOff);CHKERRQ(ierr);
2520         ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr);
2521         ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr);
2522         if (numFields) {
2523           PetscInt f;
2524 
2525           for (f = 0; f < numFields; f++) {
2526             PetscInt fDof;
2527             ierr = PetscSectionGetFieldDof(cSec,p,f,&fDof);CHKERRQ(ierr);
2528             offsets[f + 1] = fDof;
2529             for (a = 0; a < aDof; a++) {
2530               PetscInt anchor = anchors[a + aOff];
2531               ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr);
2532               newOffsets[f + 1] += fDof;
2533             }
2534           }
2535           for (f = 0; f < numFields; f++) {
2536             offsets[f + 1]       += offsets[f];
2537             offsetsCopy[f + 1]    = offsets[f + 1];
2538             newOffsets[f + 1]    += newOffsets[f];
2539             newOffsetsCopy[f + 1] = newOffsets[f + 1];
2540           }
2541           indicesPointFields_private(cSec,p,cOff,offsetsCopy,PETSC_TRUE,0,rowIndices);CHKERRQ(ierr);
2542           for (a = 0; a < aDof; a++) {
2543             PetscInt anchor = anchors[a + aOff], lOff;
2544             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
2545             indicesPointFields_private(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,0,colIndices);CHKERRQ(ierr);
2546           }
2547         }
2548         else {
2549           indicesPoint_private(cSec,p,cOff,offsetsCopy,PETSC_TRUE,0,rowIndices);CHKERRQ(ierr);
2550           for (a = 0; a < aDof; a++) {
2551             PetscInt anchor = anchors[a + aOff], lOff;
2552             ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr);
2553             indicesPoint_private(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,0,colIndices);CHKERRQ(ierr);
2554           }
2555         }
2556         if (numFields) {
2557           PetscInt count, f, a;
2558           for (f = 0, count = 0; f < numFields; f++) {
2559             PetscInt iSize = offsets[f + 1] - offsets[f];
2560             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
2561             ierr = MatGetValues(cMat,iSize,&rowIndices[offsets[f]],jSize,&colIndices[newOffsets[f]],&pMat[count]);CHKERRQ(ierr);
2562             count += iSize * jSize;
2563             pInd[numColIndices + f]             = offsets[f+1];
2564             pInd[numColIndices + numFields + f] = newOffsets[f+1];
2565           }
2566           for (a = 0; a < aDof; a++) {
2567             PetscInt anchor = anchors[a + aOff];
2568             PetscInt gOff;
2569             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
2570             indicesPointFields_private(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr);
2571           }
2572         }
2573         else {
2574           PetscInt a;
2575           ierr = MatGetValues(cMat,numRowIndices,rowIndices,numColIndices,colIndices,pMat);CHKERRQ(ierr);
2576           for (a = 0; a < aDof; a++) {
2577             PetscInt anchor = anchors[a + aOff];
2578             PetscInt gOff;
2579             ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr);
2580             indicesPoint_private(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr);
2581           }
2582         }
2583         ierr = DMRestoreWorkArray(coarse,numColIndices,PETSC_INT,&colIndices);CHKERRQ(ierr);
2584         ierr = DMRestoreWorkArray(coarse,numRowIndices,PETSC_INT,&rowIndices);CHKERRQ(ierr);
2585       }
2586       else {
2587         PetscInt gOff;
2588 
2589         ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr);
2590         if (numFields) {
2591           PetscInt f;
2592 
2593           for (f = 0; f < numFields; f++) {
2594             PetscInt fDof;
2595             ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr);
2596             offsets[f + 1] = fDof + offsets[f];
2597           }
2598           for (f = 0; f < numFields; f++) {
2599             pInd[numColIndices + f]             = offsets[f+1];
2600             pInd[numColIndices + numFields + f] = offsets[f+1];
2601           }
2602           indicesPointFields_private(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr);
2603         }
2604         else {
2605           indicesPoint_private(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr);
2606         }
2607       }
2608     }
2609     ierr = PetscFree(maxChildIds);CHKERRQ(ierr);
2610   }
2611   {
2612     PetscSF  indicesSF, matricesSF;
2613     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
2614 
2615     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr);
2616     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafMatricesSec);CHKERRQ(ierr);
2617     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootIndicesSec,&remoteOffsetsIndices,leafIndicesSec);CHKERRQ(ierr);
2618     ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootMatricesSec,&remoteOffsetsMatrices,leafMatricesSec);CHKERRQ(ierr);
2619     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootIndicesSec,remoteOffsetsIndices,leafIndicesSec,&indicesSF);CHKERRQ(ierr);
2620     ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootMatricesSec,remoteOffsetsMatrices,leafMatricesSec,&matricesSF);CHKERRQ(ierr);
2621     ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr);
2622     ierr = PetscFree(remoteOffsetsIndices);CHKERRQ(ierr);
2623     ierr = PetscFree(remoteOffsetsMatrices);CHKERRQ(ierr);
2624     ierr = PetscSectionGetStorageSize(leafIndicesSec,&numLeafIndices);CHKERRQ(ierr);
2625     ierr = PetscSectionGetStorageSize(leafMatricesSec,&numLeafMatrices);CHKERRQ(ierr);
2626     ierr = PetscMalloc2(numLeafIndices,&leafIndices,numLeafMatrices,&leafMatrices);CHKERRQ(ierr);
2627     ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2628     ierr = PetscSFBcastBegin(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
2629     ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr);
2630     ierr = PetscSFBcastEnd(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr);
2631     ierr = PetscSFDestroy(&matricesSF);CHKERRQ(ierr);
2632     ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr);
2633     ierr = PetscFree2(rootIndices,rootMatrices);CHKERRQ(ierr);
2634     ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr);
2635     ierr = PetscSectionDestroy(&rootMatricesSec);CHKERRQ(ierr);
2636   }
2637   /* count to preallocate */
2638   ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr);
2639   {
2640     PetscInt    nGlobal;
2641     PetscInt    *dnnz, *onnz;
2642     PetscLayout rowMap, colMap;
2643     PetscInt    rowStart, rowEnd, colStart, colEnd;
2644     PetscInt    maxDof;
2645     PetscInt    *rowIndices;
2646     DM           refTree;
2647     PetscInt     **refPointFieldN;
2648     PetscScalar  ***refPointFieldMats;
2649     PetscSection refConSec, refAnSec;
2650     PetscInt     pRefStart,pRefEnd,maxConDof,maxColumns;
2651     PetscScalar  *pointWork;
2652 
2653     ierr = PetscSectionGetConstrainedStorageSize(globalFine,&nGlobal);CHKERRQ(ierr);
2654     ierr = PetscCalloc2(nGlobal,&dnnz,nGlobal,&onnz);CHKERRQ(ierr);
2655     ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr);
2656     ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr);
2657     ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr);
2658     ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr);
2659     ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr);
2660     ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr);
2661     ierr = DMGetWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
2662     for (p = pStartF; p < pEndF; p++) {
2663       PetscInt    gDof, gcDof, gOff;
2664       PetscInt    numColIndices, pIndOff, *pInd;
2665       PetscInt    matSize;
2666       PetscInt    i;
2667 
2668       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
2669       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
2670       if ((gDof - gcDof) <= 0) {
2671         continue;
2672       }
2673       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
2674       if (gOff < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"I though having global dofs meant a non-negative offset");
2675       if ((gOff < rowStart) || ((gOff + gDof - gcDof) > rowEnd)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"I thought the row map would constrain the global dofs");
2676       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
2677       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
2678       numColIndices -= 2 * numFields;
2679       if (numColIndices <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"global fine dof with no dofs to interpolate from");
2680       pInd = &leafIndices[pIndOff];
2681       offsets[0]        = 0;
2682       offsetsCopy[0]    = 0;
2683       newOffsets[0]     = 0;
2684       newOffsetsCopy[0] = 0;
2685       if (numFields) {
2686         PetscInt f;
2687         for (f = 0; f < numFields; f++) {
2688           PetscInt rowDof;
2689 
2690           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
2691           offsets[f + 1]        = offsets[f] + rowDof;
2692           offsetsCopy[f + 1]    = offsets[f + 1];
2693           newOffsets[f + 1]     = pInd[numColIndices + numFields + f];
2694           numD[f] = 0;
2695           numO[f] = 0;
2696         }
2697         ierr = indicesPointFields_private(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr);
2698         for (f = 0; f < numFields; f++) {
2699           PetscInt colOffset    = newOffsets[f];
2700           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
2701 
2702           for (i = 0; i < numFieldCols; i++) {
2703             PetscInt gInd = pInd[i + colOffset];
2704 
2705             if (gInd >= colStart && gInd < colEnd) {
2706               numD[f]++;
2707             }
2708             else if (gInd >= 0) { /* negative means non-entry */
2709               numO[f]++;
2710             }
2711           }
2712         }
2713       }
2714       else {
2715         ierr = indicesPoint_private(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr);
2716         numD[0] = 0;
2717         numO[0] = 0;
2718         for (i = 0; i < numColIndices; i++) {
2719           PetscInt gInd = pInd[i];
2720 
2721           if (gInd >= colStart && gInd < colEnd) {
2722             numD[0]++;
2723           }
2724           else if (gInd >= 0) { /* negative means non-entry */
2725             numO[0]++;
2726           }
2727         }
2728       }
2729       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
2730       if (!matSize) { /* incoming matrix is identity */
2731         PetscInt childId;
2732 
2733         childId = childIds[p-pStartF];
2734         if (childId < 0) { /* no child interpolation: one nnz per */
2735           if (numFields) {
2736             PetscInt f;
2737             for (f = 0; f < numFields; f++) {
2738               PetscInt numRows = offsets[f+1] - offsets[f], row;
2739               for (row = 0; row < numRows; row++) {
2740                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
2741                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
2742                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2743                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2744                   dnnz[gIndFine - rowStart] = 1;
2745                 }
2746                 else if (gIndCoarse >= 0) { /* remote */
2747                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2748                   onnz[gIndFine - rowStart] = 1;
2749                 }
2750                 else { /* constrained */
2751                   if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2752                 }
2753               }
2754             }
2755           }
2756           else {
2757             PetscInt i;
2758             for (i = 0; i < gDof; i++) {
2759               PetscInt gIndCoarse = pInd[i];
2760               PetscInt gIndFine   = rowIndices[i];
2761               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2762                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2763                 dnnz[gIndFine - rowStart] = 1;
2764               }
2765               else if (gIndCoarse >= 0) { /* remote */
2766                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2767                 onnz[gIndFine - rowStart] = 1;
2768               }
2769               else { /* constrained */
2770                 if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2771               }
2772             }
2773           }
2774         }
2775         else { /* interpolate from all */
2776           if (numFields) {
2777             PetscInt f;
2778             for (f = 0; f < numFields; f++) {
2779               PetscInt numRows = offsets[f+1] - offsets[f], row;
2780               for (row = 0; row < numRows; row++) {
2781                 PetscInt gIndFine = rowIndices[offsets[f] + row];
2782                 if (gIndFine >= 0) {
2783                   if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2784                   dnnz[gIndFine - rowStart] = numD[f];
2785                   onnz[gIndFine - rowStart] = numO[f];
2786                 }
2787               }
2788             }
2789           }
2790           else {
2791             PetscInt i;
2792             for (i = 0; i < gDof; i++) {
2793               PetscInt gIndFine = rowIndices[i];
2794               if (gIndFine >= 0) {
2795                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2796                 dnnz[gIndFine - rowStart] = numD[0];
2797                 onnz[gIndFine - rowStart] = numO[0];
2798               }
2799             }
2800           }
2801         }
2802       }
2803       else { /* interpolate from all */
2804         if (numFields) {
2805           PetscInt f;
2806           for (f = 0; f < numFields; f++) {
2807             PetscInt numRows = offsets[f+1] - offsets[f], row;
2808             for (row = 0; row < numRows; row++) {
2809               PetscInt gIndFine = rowIndices[offsets[f] + row];
2810               if (gIndFine >= 0) {
2811                 if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2812                 dnnz[gIndFine - rowStart] = numD[f];
2813                 onnz[gIndFine - rowStart] = numO[f];
2814               }
2815             }
2816           }
2817         }
2818         else { /* every dof get a full row */
2819           PetscInt i;
2820           for (i = 0; i < gDof; i++) {
2821             PetscInt gIndFine = rowIndices[i];
2822             if (gIndFine >= 0) {
2823               if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2824               dnnz[gIndFine - rowStart] = numD[0];
2825               onnz[gIndFine - rowStart] = numO[0];
2826             }
2827           }
2828         }
2829       }
2830     }
2831     ierr = MatXAIJSetPreallocation(mat,1,dnnz,onnz,NULL,NULL);CHKERRQ(ierr);
2832     ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
2833 
2834     ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr);
2835     ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
2836     ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr);
2837     ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr);
2838     ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr);
2839     ierr = PetscSectionGetMaxDof(refConSec,&maxConDof);CHKERRQ(ierr);
2840     ierr = PetscSectionGetMaxDof(leafIndicesSec,&maxColumns);CHKERRQ(ierr);
2841     ierr = PetscMalloc1(maxConDof*maxColumns,&pointWork);CHKERRQ(ierr);
2842     for (p = pStartF; p < pEndF; p++) {
2843       PetscInt    gDof, gcDof, gOff;
2844       PetscInt    numColIndices, pIndOff, *pInd;
2845       PetscInt    matSize;
2846       PetscInt    childId;
2847 
2848 
2849       ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr);
2850       ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr);
2851       if ((gDof - gcDof) <= 0) {
2852         continue;
2853       }
2854       childId = childIds[p-pStartF];
2855       ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr);
2856       ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr);
2857       ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr);
2858       numColIndices -= 2 * numFields;
2859       pInd = &leafIndices[pIndOff];
2860       offsets[0]        = 0;
2861       offsetsCopy[0]    = 0;
2862       newOffsets[0]     = 0;
2863       newOffsetsCopy[0] = 0;
2864       rowOffsets[0]     = 0;
2865       if (numFields) {
2866         PetscInt f;
2867         for (f = 0; f < numFields; f++) {
2868           PetscInt rowDof;
2869 
2870           ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr);
2871           offsets[f + 1]     = offsets[f] + rowDof;
2872           offsetsCopy[f + 1] = offsets[f + 1];
2873           rowOffsets[f + 1]  = pInd[numColIndices + f];
2874           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2875         }
2876         ierr = indicesPointFields_private(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr);
2877       }
2878       else {
2879         ierr = indicesPoint_private(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr);
2880       }
2881       ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr);
2882       if (!matSize) { /* incoming matrix is identity */
2883         if (childId < 0) { /* no child interpolation: scatter */
2884           if (numFields) {
2885             PetscInt f;
2886             for (f = 0; f < numFields; f++) {
2887               PetscInt numRows = offsets[f+1] - offsets[f], row;
2888               for (row = 0; row < numRows; row++) {
2889                 ierr = MatSetValue(mat,rowIndices[offsets[f]+row],pInd[newOffsets[f]+row],1.,INSERT_VALUES);CHKERRQ(ierr);
2890               }
2891             }
2892           }
2893           else {
2894             PetscInt numRows = gDof, row;
2895             for (row = 0; row < numRows; row++) {
2896               ierr = MatSetValue(mat,rowIndices[row],pInd[row],1.,INSERT_VALUES);CHKERRQ(ierr);
2897             }
2898           }
2899         }
2900         else { /* interpolate from all */
2901           if (numFields) {
2902             PetscInt f;
2903             for (f = 0; f < numFields; f++) {
2904               PetscInt numRows = offsets[f+1] - offsets[f];
2905               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
2906               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],refPointFieldMats[childId - pRefStart][f],INSERT_VALUES);CHKERRQ(ierr);
2907             }
2908           }
2909           else {
2910             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,refPointFieldMats[childId - pRefStart][0],INSERT_VALUES);CHKERRQ(ierr);
2911           }
2912         }
2913       }
2914       else { /* interpolate from all */
2915         PetscInt    pMatOff;
2916         PetscScalar *pMat;
2917 
2918         ierr = PetscSectionGetOffset(leafMatricesSec,p,&pMatOff);CHKERRQ(ierr);
2919         pMat = &leafMatrices[pMatOff];
2920         if (childId < 0) { /* copy the incoming matrix */
2921           if (numFields) {
2922             PetscInt f, count;
2923             for (f = 0, count = 0; f < numFields; f++) {
2924               PetscInt numRows = offsets[f+1]-offsets[f];
2925               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2926               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2927               PetscScalar *inMat = &pMat[count];
2928 
2929               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],inMat,INSERT_VALUES);CHKERRQ(ierr);
2930               count += numCols * numInRows;
2931             }
2932           }
2933           else {
2934             ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,pMat,INSERT_VALUES);CHKERRQ(ierr);
2935           }
2936         }
2937         else { /* multiply the incoming matrix by the child interpolation */
2938           if (numFields) {
2939             PetscInt f, count;
2940             for (f = 0, count = 0; f < numFields; f++) {
2941               PetscInt numRows = offsets[f+1]-offsets[f];
2942               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2943               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2944               PetscScalar *inMat = &pMat[count];
2945               PetscInt i, j, k;
2946               if (refPointFieldN[childId - pRefStart][f] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2947               for (i = 0; i < numRows; i++) {
2948                 for (j = 0; j < numCols; j++) {
2949                   PetscScalar val = 0.;
2950                   for (k = 0; k < numInRows; k++) {
2951                     val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2952                   }
2953                   pointWork[i * numCols + j] = val;
2954                 }
2955               }
2956               ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],pointWork,INSERT_VALUES);CHKERRQ(ierr);
2957               count += numCols * numInRows;
2958             }
2959           }
2960           else { /* every dof gets a full row */
2961             PetscInt numRows   = gDof;
2962             PetscInt numCols   = numColIndices;
2963             PetscInt numInRows = matSize / numColIndices;
2964             PetscInt i, j, k;
2965             if (refPointFieldN[childId - pRefStart][0] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2966             for (i = 0; i < numRows; i++) {
2967               for (j = 0; j < numCols; j++) {
2968                 PetscScalar val = 0.;
2969                 for (k = 0; k < numInRows; k++) {
2970                   val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2971                 }
2972                 pointWork[i * numCols + j] = val;
2973               }
2974             }
2975             ierr = MatSetValues(mat,numRows,rowIndices,numCols,pInd,pointWork,INSERT_VALUES);CHKERRQ(ierr);
2976           }
2977         }
2978       }
2979     }
2980     ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr);
2981     ierr = DMRestoreWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr);
2982     ierr = PetscFree(pointWork);CHKERRQ(ierr);
2983   }
2984   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2985   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2986   ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr);
2987   ierr = PetscSectionDestroy(&leafMatricesSec);CHKERRQ(ierr);
2988   ierr = PetscFree2(leafIndices,leafMatrices);CHKERRQ(ierr);
2989   ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr);
2990   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
2991   PetscFunctionReturn(0);
2992 }
2993