xref: /petsc/src/dm/impls/plex/plextree.c (revision 28b400f66ebc7ae0049166a2294dfcd3df27e64b)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2af0996ceSBarry Smith #include <petsc/private/isimpl.h>
3af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
4d6a7ad0dSToby Isaac #include <petscsf.h>
50c37af3bSToby Isaac #include <petscds.h>
6d6a7ad0dSToby Isaac 
70e3d61c9SBarry Smith /* hierarchy routines */
8d6a7ad0dSToby Isaac 
9d6a7ad0dSToby Isaac /*@
10d6a7ad0dSToby Isaac   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.
11d6a7ad0dSToby Isaac 
12d6a7ad0dSToby Isaac   Not collective
13d6a7ad0dSToby Isaac 
14d6a7ad0dSToby Isaac   Input Parameters:
15d6a7ad0dSToby Isaac + dm - The DMPlex object
16d6a7ad0dSToby Isaac - ref - The reference tree DMPlex object
17d6a7ad0dSToby Isaac 
180b7167a0SToby Isaac   Level: intermediate
19d6a7ad0dSToby Isaac 
20da43764aSToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexCreateDefaultReferenceTree()
21d6a7ad0dSToby Isaac @*/
22d6a7ad0dSToby Isaac PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
23d6a7ad0dSToby Isaac {
24d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
25d6a7ad0dSToby Isaac 
26d6a7ad0dSToby Isaac   PetscFunctionBegin;
27d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2847a1df27SMatthew G. Knepley   if (ref) {PetscValidHeaderSpecific(ref, DM_CLASSID, 2);}
295f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectReference((PetscObject)ref));
305f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&mesh->referenceTree));
31d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
32d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
33d6a7ad0dSToby Isaac }
34d6a7ad0dSToby Isaac 
35d6a7ad0dSToby Isaac /*@
36d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
37d6a7ad0dSToby Isaac 
38d6a7ad0dSToby Isaac   Not collective
39d6a7ad0dSToby Isaac 
40d6a7ad0dSToby Isaac   Input Parameters:
41d6a7ad0dSToby Isaac . dm - The DMPlex object
42d6a7ad0dSToby Isaac 
437a7aea1fSJed Brown   Output Parameters:
44d6a7ad0dSToby Isaac . ref - The reference tree DMPlex object
45d6a7ad0dSToby Isaac 
460b7167a0SToby Isaac   Level: intermediate
47d6a7ad0dSToby Isaac 
48da43764aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexCreateDefaultReferenceTree()
49d6a7ad0dSToby Isaac @*/
50d6a7ad0dSToby Isaac PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
51d6a7ad0dSToby Isaac {
52d6a7ad0dSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
53d6a7ad0dSToby Isaac 
54d6a7ad0dSToby Isaac   PetscFunctionBegin;
55d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
56d6a7ad0dSToby Isaac   PetscValidPointer(ref,2);
57d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
58d6a7ad0dSToby Isaac   PetscFunctionReturn(0);
59d6a7ad0dSToby Isaac }
60d6a7ad0dSToby Isaac 
61dcbd3bf7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
62dcbd3bf7SToby Isaac {
63dcbd3bf7SToby Isaac   PetscInt       coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
64dcbd3bf7SToby Isaac 
65dcbd3bf7SToby Isaac   PetscFunctionBegin;
66dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
67dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
68dcbd3bf7SToby Isaac     if (childB) *childB = childA;
69dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
70dcbd3bf7SToby Isaac   }
71dcbd3bf7SToby Isaac   for (dim = 0; dim < 3; dim++) {
725f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd));
73dcbd3bf7SToby Isaac     if (parent >= dStart && parent <= dEnd) {
74dcbd3bf7SToby Isaac       break;
75dcbd3bf7SToby Isaac     }
76dcbd3bf7SToby Isaac   }
772c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dim > 2,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim);
78*28b400f6SJacob Faibussowitsch   PetscCheck(dim,PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
79dcbd3bf7SToby Isaac   if (childA < dStart || childA >= dEnd) {
80dcbd3bf7SToby Isaac     /* this is a lower-dimensional child: bootstrap */
81dcbd3bf7SToby Isaac     PetscInt size, i, sA = -1, sB, sOrientB, sConeSize;
82dcbd3bf7SToby Isaac     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
83dcbd3bf7SToby Isaac 
845f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetSupportSize(dm,childA,&size));
855f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetSupport(dm,childA,&supp));
86dcbd3bf7SToby Isaac 
87dcbd3bf7SToby Isaac     /* find a point sA in supp(childA) that has the same parent */
88dcbd3bf7SToby Isaac     for (i = 0; i < size; i++) {
89dcbd3bf7SToby Isaac       PetscInt sParent;
90dcbd3bf7SToby Isaac 
91dcbd3bf7SToby Isaac       sA   = supp[i];
92dcbd3bf7SToby Isaac       if (sA == parent) continue;
935f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTreeParent(dm,sA,&sParent,NULL));
94dcbd3bf7SToby Isaac       if (sParent == parent) {
95dcbd3bf7SToby Isaac         break;
96dcbd3bf7SToby Isaac       }
97dcbd3bf7SToby Isaac     }
982c71b3e2SJacob Faibussowitsch     PetscCheckFalse(i == size,PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
99dcbd3bf7SToby Isaac     /* find out which point sB is in an equivalent position to sA under
100dcbd3bf7SToby Isaac      * parentOrientB */
1015f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexReferenceTreeGetChildSymmetry_Default(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB));
1025f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeSize(dm,sA,&sConeSize));
1035f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCone(dm,sA,&coneA));
1045f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCone(dm,sB,&coneB));
1055f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeOrientation(dm,sA,&oA));
1065f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeOrientation(dm,sB,&oB));
107dcbd3bf7SToby Isaac     /* step through the cone of sA in natural order */
108dcbd3bf7SToby Isaac     for (i = 0; i < sConeSize; i++) {
109dcbd3bf7SToby Isaac       if (coneA[i] == childA) {
110dcbd3bf7SToby Isaac         /* if childA is at position i in coneA,
111dcbd3bf7SToby Isaac          * then we want the point that is at sOrientB*i in coneB */
112dcbd3bf7SToby Isaac         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
113dcbd3bf7SToby Isaac         if (childB) *childB = coneB[j];
114dcbd3bf7SToby Isaac         if (childOrientB) {
115b5a892a1SMatthew G. Knepley           DMPolytopeType ct;
116dcbd3bf7SToby Isaac           PetscInt       oBtrue;
117dcbd3bf7SToby Isaac 
1185f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetConeSize(dm,childA,&coneSize));
119dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
1202c71b3e2SJacob Faibussowitsch           PetscCheckFalse(coneSize != 0 && coneSize != 2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
121b5a892a1SMatthew G. Knepley           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
122dcbd3bf7SToby Isaac           /* we may have to flip an edge */
123b5a892a1SMatthew G. Knepley           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientation(ct, -1, oB[j]);
124b5a892a1SMatthew G. Knepley           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
125b5a892a1SMatthew G. Knepley           ABswap        = DihedralSwap(coneSize,DMPolytopeConvertNewOrientation_Internal(ct, oA[i]),oBtrue);
126dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
127dcbd3bf7SToby Isaac         }
128dcbd3bf7SToby Isaac         break;
129dcbd3bf7SToby Isaac       }
130dcbd3bf7SToby Isaac     }
1312c71b3e2SJacob Faibussowitsch     PetscCheckFalse(i == sConeSize,PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
132dcbd3bf7SToby Isaac     PetscFunctionReturn(0);
133dcbd3bf7SToby Isaac   }
134dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
1355f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetConeSize(dm,parent,&coneSize));
136dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
137dcbd3bf7SToby Isaac   if (dim == 2) {
138dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
139dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
140dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
141dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
142dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
143dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
144947b95d8SBarry Smith   } else {
145dcbd3bf7SToby Isaac     ABswapVert = ABswap;
146dcbd3bf7SToby Isaac   }
147dcbd3bf7SToby Isaac   if (childB) {
148dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
149dcbd3bf7SToby Isaac     PetscInt p, posA = -1, numChildren, i;
150dcbd3bf7SToby Isaac     const PetscInt *children;
151dcbd3bf7SToby Isaac 
152dcbd3bf7SToby Isaac     /* count which position the child is in */
1535f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeChildren(dm,parent,&numChildren,&children));
154dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
155dcbd3bf7SToby Isaac       p = children[i];
156dcbd3bf7SToby Isaac       if (p == childA) {
157dcbd3bf7SToby Isaac         posA = i;
158dcbd3bf7SToby Isaac         break;
159dcbd3bf7SToby Isaac       }
160dcbd3bf7SToby Isaac     }
161dcbd3bf7SToby Isaac     if (posA >= coneSize) {
162dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
163dcbd3bf7SToby Isaac        * is invariant */
1642c71b3e2SJacob Faibussowitsch       PetscCheckFalse(dim != 2 || posA != 3,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Expected a middle triangle, got something else");
165dcbd3bf7SToby Isaac       *childB = childA;
166dcbd3bf7SToby Isaac     }
167dcbd3bf7SToby Isaac     else {
168dcbd3bf7SToby Isaac       /* figure out position B by applying ABswapVert */
169dcbd3bf7SToby Isaac       PetscInt posB;
170dcbd3bf7SToby Isaac 
171dcbd3bf7SToby Isaac       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
172dcbd3bf7SToby Isaac       if (childB) *childB = children[posB];
173dcbd3bf7SToby Isaac     }
174dcbd3bf7SToby Isaac   }
175dcbd3bf7SToby Isaac   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
176dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
177dcbd3bf7SToby Isaac }
178dcbd3bf7SToby Isaac 
179dcbd3bf7SToby Isaac /*@
180dcbd3bf7SToby Isaac   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another
181dcbd3bf7SToby Isaac 
182dcbd3bf7SToby Isaac   Input Parameters:
183dcbd3bf7SToby Isaac + dm - the reference tree DMPlex object
184dcbd3bf7SToby Isaac . parent - the parent point
185dcbd3bf7SToby Isaac . parentOrientA - the reference orientation for describing the parent
186dcbd3bf7SToby Isaac . childOrientA - the reference orientation for describing the child
187dcbd3bf7SToby Isaac . childA - the reference childID for describing the child
188dcbd3bf7SToby Isaac - parentOrientB - the new orientation for describing the parent
189dcbd3bf7SToby Isaac 
190dcbd3bf7SToby Isaac   Output Parameters:
191dcbd3bf7SToby Isaac + childOrientB - if not NULL, set to the new oreintation for describing the child
192ff1f73f7SToby Isaac - childB - if not NULL, the new childID for describing the child
193dcbd3bf7SToby Isaac 
194dcbd3bf7SToby Isaac   Level: developer
195dcbd3bf7SToby Isaac 
196dcbd3bf7SToby Isaac .seealso: DMPlexGetReferenceTree(), DMPlexSetReferenceTree(), DMPlexSetTree()
197dcbd3bf7SToby Isaac @*/
198dcbd3bf7SToby Isaac PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
199dcbd3bf7SToby Isaac {
200dcbd3bf7SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
201dcbd3bf7SToby Isaac 
202dcbd3bf7SToby Isaac   PetscFunctionBegin;
203dcbd3bf7SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
204*28b400f6SJacob Faibussowitsch   PetscCheck(mesh->getchildsymmetry,PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlexReferenceTreeGetChildSymmetry not implemented");
2055f80ce2aSJacob Faibussowitsch   CHKERRQ(mesh->getchildsymmetry(dm,parent,parentOrientA,childOrientA,childA,parentOrientB,childOrientB,childB));
206dcbd3bf7SToby Isaac   PetscFunctionReturn(0);
207dcbd3bf7SToby Isaac }
208dcbd3bf7SToby Isaac 
209776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM,PetscSection,PetscInt*,PetscInt*,PetscBool,PetscBool);
210f9f063d4SToby Isaac 
211f2c1aa1dSLisandro Dalcin PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
212f2c1aa1dSLisandro Dalcin {
213f2c1aa1dSLisandro Dalcin   PetscFunctionBegin;
2145f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_TRUE,PETSC_FALSE));
215f2c1aa1dSLisandro Dalcin   PetscFunctionReturn(0);
216f2c1aa1dSLisandro Dalcin }
217f2c1aa1dSLisandro Dalcin 
2180e2cc29aSToby Isaac PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
219da43764aSToby Isaac {
2200e2cc29aSToby Isaac   MPI_Comm       comm;
2210e2cc29aSToby Isaac   PetscInt       dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
222da43764aSToby Isaac   PetscInt      *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
223da43764aSToby Isaac   DMLabel        identity, identityRef;
22410f7e118SToby Isaac   PetscSection   unionSection, unionConeSection, parentSection;
225da43764aSToby Isaac   PetscScalar   *unionCoords;
226da43764aSToby Isaac   IS             perm;
227da43764aSToby Isaac 
228da43764aSToby Isaac   PetscFunctionBegin;
2290e2cc29aSToby Isaac   comm = PetscObjectComm((PetscObject)K);
2305f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(K, &dim));
2315f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(K, &pStart, &pEnd));
2325f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLabel(K, labelName, &identity));
2335f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLabel(Kref, labelName, &identityRef));
2345f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(Kref, &pRefStart, &pRefEnd));
2355f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(comm, &unionSection));
2365f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart)));
237da43764aSToby Isaac   /* count points that will go in the union */
238da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
2395f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetDof(unionSection, p - pStart, 1));
240da43764aSToby Isaac   }
241da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
242da43764aSToby Isaac     PetscInt q, qSize;
2435f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetValue(identityRef, p, &q));
2445f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetStratumSize(identityRef, q, &qSize));
245da43764aSToby Isaac     if (qSize > 1) {
2465f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1));
247da43764aSToby Isaac     }
248da43764aSToby Isaac   }
2495f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart,&permvals));
250da43764aSToby Isaac   offset = 0;
251da43764aSToby Isaac   /* stratify points in the union by topological dimension */
252da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
253da43764aSToby Isaac     PetscInt cStart, cEnd, c;
254da43764aSToby Isaac 
2555f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(K, d, &cStart, &cEnd));
256da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
257da43764aSToby Isaac       permvals[offset++] = c;
258da43764aSToby Isaac     }
259da43764aSToby Isaac 
2605f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd));
261da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
262da43764aSToby Isaac       permvals[offset++] = c + (pEnd - pStart);
263da43764aSToby Isaac     }
264da43764aSToby Isaac   }
2655f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm));
2665f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetPermutation(unionSection,perm));
2675f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(unionSection));
2685f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(unionSection,&numUnionPoints));
2695f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(numUnionPoints,&coneSizes,dim+1,&numDimPoints));
270da43764aSToby Isaac   /* count dimension points */
271da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
272da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
2735f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(K,d,&cStart,NULL));
2745f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(unionSection,cStart-pStart,&cOff));
275da43764aSToby Isaac     if (d < dim) {
2765f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetHeightStratum(K,d+1,&cStart,NULL));
2775f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(unionSection,cStart-pStart,&cOff2));
278da43764aSToby Isaac     }
279da43764aSToby Isaac     else {
280da43764aSToby Isaac       cOff2 = numUnionPoints;
281da43764aSToby Isaac     }
282da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
283da43764aSToby Isaac   }
2845f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(comm, &unionConeSection));
2855f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(unionConeSection, 0, numUnionPoints));
286da43764aSToby Isaac   /* count the cones in the union */
287da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
288da43764aSToby Isaac     PetscInt dof, uOff;
289da43764aSToby Isaac 
2905f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeSize(K, p, &dof));
2915f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(unionSection, p - pStart,&uOff));
2925f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetDof(unionConeSection, uOff, dof));
293da43764aSToby Isaac     coneSizes[uOff] = dof;
294da43764aSToby Isaac   }
295da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
296da43764aSToby Isaac     PetscInt dof, uDof, uOff;
297da43764aSToby Isaac 
2985f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeSize(Kref, p, &dof));
2995f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
3005f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
301da43764aSToby Isaac     if (uDof) {
3025f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetDof(unionConeSection, uOff, dof));
303da43764aSToby Isaac       coneSizes[uOff] = dof;
304da43764aSToby Isaac     }
305da43764aSToby Isaac   }
3065f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(unionConeSection));
3075f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(unionConeSection,&numCones));
3085f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(numCones,&unionCones,numCones,&unionOrientations));
309da43764aSToby Isaac   /* write the cones in the union */
310da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
311da43764aSToby Isaac     PetscInt dof, uOff, c, cOff;
312da43764aSToby Isaac     const PetscInt *cone, *orientation;
313da43764aSToby Isaac 
3145f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeSize(K, p, &dof));
3155f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCone(K, p, &cone));
3165f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeOrientation(K, p, &orientation));
3175f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(unionSection, p - pStart,&uOff));
3185f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(unionConeSection,uOff,&cOff));
319da43764aSToby Isaac     for (c = 0; c < dof; c++) {
320da43764aSToby Isaac       PetscInt e, eOff;
321da43764aSToby Isaac       e                           = cone[c];
3225f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
323da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
324da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
325da43764aSToby Isaac     }
326da43764aSToby Isaac   }
327da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
328da43764aSToby Isaac     PetscInt dof, uDof, uOff, c, cOff;
329da43764aSToby Isaac     const PetscInt *cone, *orientation;
330da43764aSToby Isaac 
3315f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeSize(Kref, p, &dof));
3325f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCone(Kref, p, &cone));
3335f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeOrientation(Kref, p, &orientation));
3345f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
3355f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
336da43764aSToby Isaac     if (uDof) {
3375f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(unionConeSection,uOff,&cOff));
338da43764aSToby Isaac       for (c = 0; c < dof; c++) {
339da43764aSToby Isaac         PetscInt e, eOff, eDof;
340da43764aSToby Isaac 
341da43764aSToby Isaac         e    = cone[c];
3425f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart),&eDof));
343da43764aSToby Isaac         if (eDof) {
3445f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff));
345da43764aSToby Isaac         }
346da43764aSToby Isaac         else {
3475f80ce2aSJacob Faibussowitsch           CHKERRQ(DMLabelGetValue(identityRef, e, &e));
3485f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
349da43764aSToby Isaac         }
350da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
351da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
352da43764aSToby Isaac       }
353da43764aSToby Isaac     }
354da43764aSToby Isaac   }
355da43764aSToby Isaac   /* get the coordinates */
356da43764aSToby Isaac   {
357da43764aSToby Isaac     PetscInt     vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
358da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
359da43764aSToby Isaac     Vec          KcoordsVec, KrefCoordsVec;
360da43764aSToby Isaac     PetscScalar *Kcoords;
361da43764aSToby Isaac 
3625f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinateSection(K, &KcoordsSec));
3635f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinatesLocal(K, &KcoordsVec));
3645f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinateSection(Kref, &KrefCoordsSec));
3655f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinatesLocal(Kref, &KrefCoordsVec));
366da43764aSToby Isaac 
367da43764aSToby Isaac     numVerts = numDimPoints[0];
3685f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numVerts * dim,&unionCoords));
3695f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetDepthStratum(K,0,&vStart,&vEnd));
370da43764aSToby Isaac 
371da43764aSToby Isaac     offset = 0;
372da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
3735f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(unionSection,v - pStart,&vOff));
3745f80ce2aSJacob Faibussowitsch       CHKERRQ(VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords));
375da43764aSToby Isaac       for (d = 0; d < dim; d++) {
376da43764aSToby Isaac         unionCoords[offset * dim + d] = Kcoords[d];
377da43764aSToby Isaac       }
378da43764aSToby Isaac       offset++;
379da43764aSToby Isaac     }
3805f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetDepthStratum(Kref,0,&vRefStart,&vRefEnd));
381da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
3825f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(unionSection,v - pRefStart + (pEnd - pStart),&vDof));
3835f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(unionSection,v - pRefStart + (pEnd - pStart),&vOff));
3845f80ce2aSJacob Faibussowitsch       CHKERRQ(VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords));
385da43764aSToby Isaac       if (vDof) {
386da43764aSToby Isaac         for (d = 0; d < dim; d++) {
387da43764aSToby Isaac           unionCoords[offset * dim + d] = Kcoords[d];
388da43764aSToby Isaac         }
389da43764aSToby Isaac         offset++;
390da43764aSToby Isaac       }
391da43764aSToby Isaac     }
392da43764aSToby Isaac   }
3935f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreate(comm,ref));
3945f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetType(*ref,DMPLEX));
3955f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetDimension(*ref,dim));
3965f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreateFromDAG(*ref,dim,numDimPoints,coneSizes,unionCones,unionOrientations,unionCoords));
39710f7e118SToby Isaac   /* set the tree */
3985f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(comm,&parentSection));
3995f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(parentSection,0,numUnionPoints));
40010f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
40110f7e118SToby Isaac     PetscInt uDof, uOff;
40210f7e118SToby Isaac 
4035f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
4045f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
40510f7e118SToby Isaac     if (uDof) {
4065f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetDof(parentSection,uOff,1));
40710f7e118SToby Isaac     }
40810f7e118SToby Isaac   }
4095f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(parentSection));
4105f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(parentSection,&parentSize));
4115f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(parentSize,&parents,parentSize,&childIDs));
41210f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
41310f7e118SToby Isaac     PetscInt uDof, uOff;
41410f7e118SToby Isaac 
4155f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
4165f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
41710f7e118SToby Isaac     if (uDof) {
41810f7e118SToby Isaac       PetscInt pOff, parent, parentU;
4195f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(parentSection,uOff,&pOff));
4205f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelGetValue(identityRef,p,&parent));
4215f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(unionSection, parent - pStart,&parentU));
42210f7e118SToby Isaac       parents[pOff] = parentU;
42310f7e118SToby Isaac       childIDs[pOff] = uOff;
42410f7e118SToby Isaac     }
42510f7e118SToby Isaac   }
4265f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreateReferenceTree_SetTree(*ref,parentSection,parents,childIDs));
4275f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&parentSection));
4285f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(parents,childIDs));
42910f7e118SToby Isaac 
430da43764aSToby Isaac   /* clean up */
4315f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&unionSection));
4325f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&unionConeSection));
4335f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&perm));
4345f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(unionCoords));
4355f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(unionCones,unionOrientations));
4365f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(coneSizes,numDimPoints));
4370e2cc29aSToby Isaac   PetscFunctionReturn(0);
4380e2cc29aSToby Isaac }
4390e2cc29aSToby Isaac 
4400e2cc29aSToby Isaac /*@
4410e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4420e2cc29aSToby Isaac 
443d083f849SBarry Smith   Collective
4440e2cc29aSToby Isaac 
4450e2cc29aSToby Isaac   Input Parameters:
4460e2cc29aSToby Isaac + comm    - the MPI communicator
4470e2cc29aSToby Isaac . dim     - the spatial dimension
4480e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4490e2cc29aSToby Isaac 
4500e2cc29aSToby Isaac   Output Parameters:
4510e2cc29aSToby Isaac . ref     - the reference tree DMPlex object
4520e2cc29aSToby Isaac 
4530e2cc29aSToby Isaac   Level: intermediate
4540e2cc29aSToby Isaac 
4550e2cc29aSToby Isaac .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree()
4560e2cc29aSToby Isaac @*/
4570e2cc29aSToby Isaac PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
4580e2cc29aSToby Isaac {
4590e2cc29aSToby Isaac   DM_Plex       *mesh;
4600e2cc29aSToby Isaac   DM             K, Kref;
4610e2cc29aSToby Isaac   PetscInt       p, pStart, pEnd;
4620e2cc29aSToby Isaac   DMLabel        identity;
4630e2cc29aSToby Isaac 
4640e2cc29aSToby Isaac   PetscFunctionBegin;
4650e2cc29aSToby Isaac #if 1
4660e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4670e2cc29aSToby Isaac #endif
4680e2cc29aSToby Isaac   /* create a reference element */
4695f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K));
4705f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateLabel(K, "identity"));
4715f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLabel(K, "identity", &identity));
4725f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(K, &pStart, &pEnd));
4730e2cc29aSToby Isaac   for (p = pStart; p < pEnd; p++) {
4745f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelSetValue(identity, p, p));
4750e2cc29aSToby Isaac   }
4760e2cc29aSToby Isaac   /* refine it */
4775f80ce2aSJacob Faibussowitsch   CHKERRQ(DMRefine(K,comm,&Kref));
4780e2cc29aSToby Isaac 
4790e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4800e2cc29aSToby Isaac    * points that appear in both */
4815f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref));
4820e2cc29aSToby Isaac   mesh = (DM_Plex *) (*ref)->data;
4830e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
4845f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&K));
4855f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&Kref));
486da43764aSToby Isaac   PetscFunctionReturn(0);
487da43764aSToby Isaac }
488da43764aSToby Isaac 
489878b19aaSToby Isaac static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
490878b19aaSToby Isaac {
491878b19aaSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
492878b19aaSToby Isaac   PetscSection   childSec, pSec;
493878b19aaSToby Isaac   PetscInt       p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
494878b19aaSToby Isaac   PetscInt       *offsets, *children, pStart, pEnd;
495878b19aaSToby Isaac 
496878b19aaSToby Isaac   PetscFunctionBegin;
497878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4985f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&mesh->childSection));
4995f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(mesh->children));
500878b19aaSToby Isaac   pSec = mesh->parentSection;
501878b19aaSToby Isaac   if (!pSec) PetscFunctionReturn(0);
5025f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(pSec,&pSize));
503878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
504878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
505878b19aaSToby Isaac 
506878b19aaSToby Isaac     parMax = PetscMax(parMax,par+1);
507878b19aaSToby Isaac     parMin = PetscMin(parMin,par);
508878b19aaSToby Isaac   }
509878b19aaSToby Isaac   if (parMin > parMax) {
510878b19aaSToby Isaac     parMin = -1;
511878b19aaSToby Isaac     parMax = -1;
512878b19aaSToby Isaac   }
5135f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)pSec),&childSec));
5145f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(childSec,parMin,parMax));
515878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
516878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
517878b19aaSToby Isaac 
5185f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionAddDof(childSec,par,1));
519878b19aaSToby Isaac   }
5205f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(childSec));
5215f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(childSec,&cSize));
5225f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(cSize,&children));
5235f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc1(parMax-parMin,&offsets));
5245f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(pSec,&pStart,&pEnd));
525878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
526878b19aaSToby Isaac     PetscInt dof, off, i;
527878b19aaSToby Isaac 
5285f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(pSec,p,&dof));
5295f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(pSec,p,&off));
530878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
531878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
532878b19aaSToby Isaac 
5335f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(childSec,par,&cOff));
534878b19aaSToby Isaac       children[cOff + offsets[par-parMin]++] = p;
535878b19aaSToby Isaac     }
536878b19aaSToby Isaac   }
537878b19aaSToby Isaac   mesh->childSection = childSec;
538878b19aaSToby Isaac   mesh->children = children;
5395f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(offsets));
540878b19aaSToby Isaac   PetscFunctionReturn(0);
541878b19aaSToby Isaac }
542878b19aaSToby Isaac 
5436dd5a8c8SToby Isaac static PetscErrorCode AnchorsFlatten (PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
5446dd5a8c8SToby Isaac {
5456dd5a8c8SToby Isaac   PetscInt       pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5466dd5a8c8SToby Isaac   const PetscInt *vals;
5476dd5a8c8SToby Isaac   PetscSection   secNew;
5486dd5a8c8SToby Isaac   PetscBool      anyNew, globalAnyNew;
5496dd5a8c8SToby Isaac   PetscBool      compress;
5506dd5a8c8SToby Isaac 
5516dd5a8c8SToby Isaac   PetscFunctionBegin;
5525f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(section,&pStart,&pEnd));
5535f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetLocalSize(is,&size));
5545f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(is,&vals));
5555f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)section),&secNew));
5565f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(secNew,pStart,pEnd));
5576dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5586dd5a8c8SToby Isaac     PetscInt dof;
5596dd5a8c8SToby Isaac 
5606dd5a8c8SToby Isaac     p = vals[i];
5616dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5625f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(section, p, &dof));
5636dd5a8c8SToby Isaac     if (dof) break;
5646dd5a8c8SToby Isaac   }
5656dd5a8c8SToby Isaac   if (i == size) {
5665f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetUp(secNew));
5676dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5686dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5696dd5a8c8SToby Isaac     sizeNew  = 0;
5706dd5a8c8SToby Isaac   }
5716dd5a8c8SToby Isaac   else {
5726dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5736dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5746dd5a8c8SToby Isaac       PetscInt dof, off;
5756dd5a8c8SToby Isaac 
5765f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(section, p, &dof));
5775f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(section, p, &off));
5786dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5796dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5806dd5a8c8SToby Isaac 
5816dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5825f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(section, q, &qDof));
5836dd5a8c8SToby Isaac         }
5846dd5a8c8SToby Isaac         if (qDof) {
5855f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionAddDof(secNew, p, qDof));
5866dd5a8c8SToby Isaac         }
5876dd5a8c8SToby Isaac         else {
5885f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionAddDof(secNew, p, 1));
5896dd5a8c8SToby Isaac         }
5906dd5a8c8SToby Isaac       }
5916dd5a8c8SToby Isaac     }
5925f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetUp(secNew));
5935f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(secNew,&sizeNew));
5945f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(sizeNew,&valsNew));
5956dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5966dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5976dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
5986dd5a8c8SToby Isaac 
5995f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(section, p, &dof));
6005f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(section, p, &off));
6015f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(secNew, p, &dofNew));
6025f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(secNew, p, &offNew));
6036dd5a8c8SToby Isaac       count = 0;
6046dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
6056dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
6066dd5a8c8SToby Isaac 
6076dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
6085f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(section, q, &qDof));
6095f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetOffset(section, q, &qOff));
6106dd5a8c8SToby Isaac         }
6116dd5a8c8SToby Isaac         if (qDof) {
6126dd5a8c8SToby Isaac           PetscInt oldCount = count;
6136dd5a8c8SToby Isaac 
6146dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
6156dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
6166dd5a8c8SToby Isaac 
6176dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
6186dd5a8c8SToby Isaac               if (valsNew[offNew + k] == r) {
6196dd5a8c8SToby Isaac                 break;
6206dd5a8c8SToby Isaac               }
6216dd5a8c8SToby Isaac             }
6226dd5a8c8SToby Isaac             if (k == oldCount) {
6236dd5a8c8SToby Isaac               valsNew[offNew + count++] = r;
6246dd5a8c8SToby Isaac             }
6256dd5a8c8SToby Isaac           }
6266dd5a8c8SToby Isaac         }
6276dd5a8c8SToby Isaac         else {
6286dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
6296dd5a8c8SToby Isaac 
6306dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
6316dd5a8c8SToby Isaac             if (valsNew[offNew + k] == q) {
6326dd5a8c8SToby Isaac               break;
6336dd5a8c8SToby Isaac             }
6346dd5a8c8SToby Isaac           }
6356dd5a8c8SToby Isaac           if (k == oldCount) {
6366dd5a8c8SToby Isaac             valsNew[offNew + count++] = q;
6376dd5a8c8SToby Isaac           }
6386dd5a8c8SToby Isaac         }
6396dd5a8c8SToby Isaac       }
6406dd5a8c8SToby Isaac       if (count < dofNew) {
6415f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionSetDof(secNew, p, count));
6426dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6436dd5a8c8SToby Isaac       }
6446dd5a8c8SToby Isaac     }
6456dd5a8c8SToby Isaac   }
6465f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(is,&vals));
6475f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPIU_Allreduce(&anyNew,&globalAnyNew,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew)));
6486dd5a8c8SToby Isaac   if (!globalAnyNew) {
6495f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&secNew));
6506dd5a8c8SToby Isaac     *sectionNew = NULL;
6516dd5a8c8SToby Isaac     *isNew = NULL;
6526dd5a8c8SToby Isaac   }
6536dd5a8c8SToby Isaac   else {
6546dd5a8c8SToby Isaac     PetscBool globalCompress;
6556dd5a8c8SToby Isaac 
6565f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPIU_Allreduce(&compress,&globalCompress,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew)));
6576dd5a8c8SToby Isaac     if (compress) {
6586dd5a8c8SToby Isaac       PetscSection secComp;
6596dd5a8c8SToby Isaac       PetscInt *valsComp = NULL;
6606dd5a8c8SToby Isaac 
6615f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)section),&secComp));
6625f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetChart(secComp,pStart,pEnd));
6636dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6646dd5a8c8SToby Isaac         PetscInt dof;
6656dd5a8c8SToby Isaac 
6665f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(secNew, p, &dof));
6675f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionSetDof(secComp, p, dof));
6686dd5a8c8SToby Isaac       }
6695f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetUp(secComp));
6705f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetStorageSize(secComp,&sizeNew));
6715f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(sizeNew,&valsComp));
6726dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6736dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6746dd5a8c8SToby Isaac 
6755f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(secNew, p, &dof));
6765f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(secNew, p, &off));
6775f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(secComp, p, &offNew));
6786dd5a8c8SToby Isaac         for (j = 0; j < dof; j++) {
6796dd5a8c8SToby Isaac           valsComp[offNew + j] = valsNew[off + j];
6806dd5a8c8SToby Isaac         }
6816dd5a8c8SToby Isaac       }
6825f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionDestroy(&secNew));
6836dd5a8c8SToby Isaac       secNew  = secComp;
6845f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(valsNew));
6856dd5a8c8SToby Isaac       valsNew = valsComp;
6866dd5a8c8SToby Isaac     }
6875f80ce2aSJacob Faibussowitsch     CHKERRQ(ISCreateGeneral(PetscObjectComm((PetscObject)is),sizeNew,valsNew,PETSC_OWN_POINTER,isNew));
6886dd5a8c8SToby Isaac   }
6896dd5a8c8SToby Isaac   PetscFunctionReturn(0);
6906dd5a8c8SToby Isaac }
6916dd5a8c8SToby Isaac 
692f7c74593SToby Isaac static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
69366af876cSToby Isaac {
69466af876cSToby Isaac   PetscInt       p, pStart, pEnd, *anchors, size;
69566af876cSToby Isaac   PetscInt       aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
69666af876cSToby Isaac   PetscSection   aSec;
697f9f063d4SToby Isaac   DMLabel        canonLabel;
69866af876cSToby Isaac   IS             aIS;
69966af876cSToby Isaac 
70066af876cSToby Isaac   PetscFunctionBegin;
70166af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7025f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(dm,&pStart,&pEnd));
7035f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLabel(dm,"canonical",&canonLabel));
70466af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
70566af876cSToby Isaac     PetscInt parent;
70666af876cSToby Isaac 
707f9f063d4SToby Isaac     if (canonLabel) {
708f9f063d4SToby Isaac       PetscInt canon;
709f9f063d4SToby Isaac 
7105f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelGetValue(canonLabel,p,&canon));
711f9f063d4SToby Isaac       if (p != canon) continue;
712f9f063d4SToby Isaac     }
7135f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeParent(dm,p,&parent,NULL));
71466af876cSToby Isaac     if (parent != p) {
71566af876cSToby Isaac       aMin = PetscMin(aMin,p);
71666af876cSToby Isaac       aMax = PetscMax(aMax,p+1);
71766af876cSToby Isaac     }
71866af876cSToby Isaac   }
71966af876cSToby Isaac   if (aMin > aMax) {
72066af876cSToby Isaac     aMin = -1;
72166af876cSToby Isaac     aMax = -1;
72266af876cSToby Isaac   }
7235f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PETSC_COMM_SELF,&aSec));
7245f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(aSec,aMin,aMax));
72566af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
72666af876cSToby Isaac     PetscInt parent, ancestor = p;
72766af876cSToby Isaac 
728f9f063d4SToby Isaac     if (canonLabel) {
729f9f063d4SToby Isaac       PetscInt canon;
730f9f063d4SToby Isaac 
7315f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelGetValue(canonLabel,p,&canon));
732f9f063d4SToby Isaac       if (p != canon) continue;
733f9f063d4SToby Isaac     }
7345f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeParent(dm,p,&parent,NULL));
73566af876cSToby Isaac     while (parent != ancestor) {
73666af876cSToby Isaac       ancestor = parent;
7375f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTreeParent(dm,ancestor,&parent,NULL));
73866af876cSToby Isaac     }
73966af876cSToby Isaac     if (ancestor != p) {
74066af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
74166af876cSToby Isaac 
7425f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
7435f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetDof(aSec,p,closureSize));
7445f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
74566af876cSToby Isaac     }
74666af876cSToby Isaac   }
7475f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(aSec));
7485f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(aSec,&size));
7495f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(size,&anchors));
75066af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
75166af876cSToby Isaac     PetscInt parent, ancestor = p;
75266af876cSToby Isaac 
753f9f063d4SToby Isaac     if (canonLabel) {
754f9f063d4SToby Isaac       PetscInt canon;
755f9f063d4SToby Isaac 
7565f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelGetValue(canonLabel,p,&canon));
757f9f063d4SToby Isaac       if (p != canon) continue;
758f9f063d4SToby Isaac     }
7595f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeParent(dm,p,&parent,NULL));
76066af876cSToby Isaac     while (parent != ancestor) {
76166af876cSToby Isaac       ancestor = parent;
7625f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTreeParent(dm,ancestor,&parent,NULL));
76366af876cSToby Isaac     }
76466af876cSToby Isaac     if (ancestor != p) {
76566af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
76666af876cSToby Isaac 
7675f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(aSec,p,&aOff));
76866af876cSToby Isaac 
7695f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
77066af876cSToby Isaac       for (j = 0; j < closureSize; j++) {
77166af876cSToby Isaac         anchors[aOff + j] = closure[2*j];
77266af876cSToby Isaac       }
7735f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
77466af876cSToby Isaac     }
77566af876cSToby Isaac   }
7765f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(PETSC_COMM_SELF,size,anchors,PETSC_OWN_POINTER,&aIS));
7776dd5a8c8SToby Isaac   {
7786dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7796dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7806dd5a8c8SToby Isaac 
7815f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)aSec));
7825f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)aIS));
7836dd5a8c8SToby Isaac     while (aSecNew) {
7845f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionDestroy(&aSec));
7855f80ce2aSJacob Faibussowitsch       CHKERRQ(ISDestroy(&aIS));
7866dd5a8c8SToby Isaac       aSec    = aSecNew;
7876dd5a8c8SToby Isaac       aIS     = aISNew;
7886dd5a8c8SToby Isaac       aSecNew = NULL;
7896dd5a8c8SToby Isaac       aISNew  = NULL;
7905f80ce2aSJacob Faibussowitsch       CHKERRQ(AnchorsFlatten(aSec,aIS,&aSecNew,&aISNew));
7916dd5a8c8SToby Isaac     }
7926dd5a8c8SToby Isaac   }
7935f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexSetAnchors(dm,aSec,aIS));
7945f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&aSec));
7955f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&aIS));
79666af876cSToby Isaac   PetscFunctionReturn(0);
79766af876cSToby Isaac }
79866af876cSToby Isaac 
7996461c1adSToby Isaac static PetscErrorCode DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt *dof,PetscInt *numTrueSupp)
8006461c1adSToby Isaac {
8016461c1adSToby Isaac   PetscFunctionBegin;
8026461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
8036461c1adSToby Isaac     PetscInt i, alldof;
8046461c1adSToby Isaac     const PetscInt *supp;
8056461c1adSToby Isaac     PetscInt count = 0;
8066461c1adSToby Isaac 
8075f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetSupportSize(dm,p,&alldof));
8085f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetSupport(dm,p,&supp));
8096461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
8106461c1adSToby Isaac       PetscInt q = supp[i], numCones, j;
8116461c1adSToby Isaac       const PetscInt *cone;
8126461c1adSToby Isaac 
8135f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetConeSize(dm,q,&numCones));
8145f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetCone(dm,q,&cone));
8156461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
8166461c1adSToby Isaac         if (cone[j] == p) break;
8176461c1adSToby Isaac       }
8186461c1adSToby Isaac       if (j < numCones) count++;
8196461c1adSToby Isaac     }
8206461c1adSToby Isaac     numTrueSupp[p] = count;
8216461c1adSToby Isaac   }
8226461c1adSToby Isaac   *dof = numTrueSupp[p];
8236461c1adSToby Isaac   PetscFunctionReturn(0);
8246461c1adSToby Isaac }
8256461c1adSToby Isaac 
826776742edSToby Isaac static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
827776742edSToby Isaac {
828776742edSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
829776742edSToby Isaac   PetscSection   newSupportSection;
830776742edSToby Isaac   PetscInt       newSize, *newSupports, pStart, pEnd, p, d, depth;
8316461c1adSToby Isaac   PetscInt       *numTrueSupp;
832776742edSToby Isaac   PetscInt       *offsets;
833776742edSToby Isaac 
834776742edSToby Isaac   PetscFunctionBegin;
835776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
836776742edSToby Isaac   /* symmetrize the hierarchy */
8375f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepth(dm,&depth));
8385f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)),&newSupportSection));
8395f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(dm,&pStart,&pEnd));
8405f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(newSupportSection,pStart,pEnd));
8415f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc1(pEnd,&offsets));
8425f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd,&numTrueSupp));
8436461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8446461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
845776742edSToby Isaac    * parent(q) */
846776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8475f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(dm,d,&pStart,&pEnd));
848776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
849776742edSToby Isaac       PetscInt dof, q, qdof, parent;
850776742edSToby Isaac 
8515f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTrueSupportSize(dm,p,&dof,numTrueSupp));
8525f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionAddDof(newSupportSection, p, dof));
853776742edSToby Isaac       q    = p;
8545f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTreeParent(dm,q,&parent,NULL));
855776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
856776742edSToby Isaac         q = parent;
857776742edSToby Isaac 
8585f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTrueSupportSize(dm,q,&qdof,numTrueSupp));
8595f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionAddDof(newSupportSection,p,qdof));
8605f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionAddDof(newSupportSection,q,dof));
8615f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeParent(dm,q,&parent,NULL));
862776742edSToby Isaac       }
863776742edSToby Isaac     }
864776742edSToby Isaac   }
8655f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(newSupportSection));
8665f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(newSupportSection,&newSize));
8675f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(newSize,&newSupports));
868776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8695f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(dm,d,&pStart,&pEnd));
870776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
871776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
872776742edSToby Isaac 
8735f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(mesh->supportSection, p, &dof));
8745f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(mesh->supportSection, p, &off));
8755f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(newSupportSection, p, &newDof));
8765f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(newSupportSection, p, &newOff));
877776742edSToby Isaac       for (i = 0; i < dof; i++) {
8786461c1adSToby Isaac         PetscInt numCones, j;
8796461c1adSToby Isaac         const PetscInt *cone;
8806461c1adSToby Isaac         PetscInt q = mesh->supports[off + i];
8816461c1adSToby Isaac 
8825f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetConeSize(dm,q,&numCones));
8835f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetCone(dm,q,&cone));
8846461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8856461c1adSToby Isaac           if (cone[j] == p) break;
8866461c1adSToby Isaac         }
8876461c1adSToby Isaac         if (j < numCones) newSupports[newOff+offsets[p]++] = q;
888776742edSToby Isaac       }
889776742edSToby Isaac       mesh->maxSupportSize = PetscMax(mesh->maxSupportSize,newDof);
890776742edSToby Isaac 
891776742edSToby Isaac       q    = p;
8925f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTreeParent(dm,q,&parent,NULL));
893776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
894776742edSToby Isaac         q = parent;
8955f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(mesh->supportSection, q, &qdof));
8965f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(mesh->supportSection, q, &qoff));
8975f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(newSupportSection, q, &newqOff));
898776742edSToby Isaac         for (i = 0; i < qdof; i++) {
8996461c1adSToby Isaac           PetscInt numCones, j;
9006461c1adSToby Isaac           const PetscInt *cone;
9016461c1adSToby Isaac           PetscInt r = mesh->supports[qoff + i];
9026461c1adSToby Isaac 
9035f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetConeSize(dm,r,&numCones));
9045f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetCone(dm,r,&cone));
9056461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9066461c1adSToby Isaac             if (cone[j] == q) break;
9076461c1adSToby Isaac           }
9086461c1adSToby Isaac           if (j < numCones) newSupports[newOff+offsets[p]++] = r;
909776742edSToby Isaac         }
910776742edSToby Isaac         for (i = 0; i < dof; i++) {
9116461c1adSToby Isaac           PetscInt numCones, j;
9126461c1adSToby Isaac           const PetscInt *cone;
9136461c1adSToby Isaac           PetscInt r = mesh->supports[off + i];
9146461c1adSToby Isaac 
9155f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetConeSize(dm,r,&numCones));
9165f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetCone(dm,r,&cone));
9176461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9186461c1adSToby Isaac             if (cone[j] == p) break;
9196461c1adSToby Isaac           }
9206461c1adSToby Isaac           if (j < numCones) newSupports[newqOff+offsets[q]++] = r;
921776742edSToby Isaac         }
9225f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeParent(dm,q,&parent,NULL));
923776742edSToby Isaac       }
924776742edSToby Isaac     }
925776742edSToby Isaac   }
9265f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&mesh->supportSection));
927776742edSToby Isaac   mesh->supportSection = newSupportSection;
9285f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(mesh->supports));
929776742edSToby Isaac   mesh->supports = newSupports;
9305f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(offsets));
9315f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(numTrueSupp));
932776742edSToby Isaac 
933776742edSToby Isaac   PetscFunctionReturn(0);
934776742edSToby Isaac }
935776742edSToby Isaac 
936f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM,PetscSection,PetscSection,Mat);
937f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM,PetscSection,PetscSection,Mat);
938f7c74593SToby Isaac 
939776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
940f9f063d4SToby Isaac {
941f9f063d4SToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
942f9f063d4SToby Isaac   DM             refTree;
943f9f063d4SToby Isaac   PetscInt       size;
944f9f063d4SToby Isaac 
945f9f063d4SToby Isaac   PetscFunctionBegin;
946f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
947f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
9485f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectReference((PetscObject)parentSection));
9495f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&mesh->parentSection));
950f9f063d4SToby Isaac   mesh->parentSection = parentSection;
9515f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(parentSection,&size));
952f9f063d4SToby Isaac   if (parents != mesh->parents) {
9535f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(mesh->parents));
9545f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(size,&mesh->parents));
9555f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscArraycpy(mesh->parents, parents, size));
956f9f063d4SToby Isaac   }
957f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
9585f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(mesh->childIDs));
9595f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(size,&mesh->childIDs));
9605f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscArraycpy(mesh->childIDs, childIDs, size));
961f9f063d4SToby Isaac   }
9625f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetReferenceTree(dm,&refTree));
963f9f063d4SToby Isaac   if (refTree) {
964f9f063d4SToby Isaac     DMLabel canonLabel;
965f9f063d4SToby Isaac 
9665f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetLabel(refTree,"canonical",&canonLabel));
967f9f063d4SToby Isaac     if (canonLabel) {
968f9f063d4SToby Isaac       PetscInt i;
969f9f063d4SToby Isaac 
970f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
971f9f063d4SToby Isaac         PetscInt canon;
9725f80ce2aSJacob Faibussowitsch         CHKERRQ(DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon));
973f9f063d4SToby Isaac         if (canon >= 0) {
974f9f063d4SToby Isaac           mesh->childIDs[i] = canon;
975f9f063d4SToby Isaac         }
976f9f063d4SToby Isaac       }
977f9f063d4SToby Isaac     }
978f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
9796e0288c8SStefano Zampini   } else {
980f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
981f9f063d4SToby Isaac   }
9825f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexTreeSymmetrize(dm));
983f9f063d4SToby Isaac   if (computeCanonical) {
984f9f063d4SToby Isaac     PetscInt d, dim;
985f9f063d4SToby Isaac 
986f9f063d4SToby Isaac     /* add the canonical label */
9875f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetDimension(dm,&dim));
9885f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCreateLabel(dm,"canonical"));
989f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
990f9f063d4SToby Isaac       PetscInt p, dStart, dEnd, canon = -1, cNumChildren;
991f9f063d4SToby Isaac       const PetscInt *cChildren;
992f9f063d4SToby Isaac 
9935f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetDepthStratum(dm,d,&dStart,&dEnd));
994f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
9955f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeChildren(dm,p,&cNumChildren,&cChildren));
996f9f063d4SToby Isaac         if (cNumChildren) {
997f9f063d4SToby Isaac           canon = p;
998f9f063d4SToby Isaac           break;
999f9f063d4SToby Isaac         }
1000f9f063d4SToby Isaac       }
1001f9f063d4SToby Isaac       if (canon == -1) continue;
1002f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
1003f9f063d4SToby Isaac         PetscInt numChildren, i;
1004f9f063d4SToby Isaac         const PetscInt *children;
1005f9f063d4SToby Isaac 
10065f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeChildren(dm,p,&numChildren,&children));
1007f9f063d4SToby Isaac         if (numChildren) {
10082c71b3e2SJacob Faibussowitsch           PetscCheckFalse(numChildren != cNumChildren,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"All parent points in a stratum should have the same number of children: %d != %d", numChildren, cNumChildren);
10095f80ce2aSJacob Faibussowitsch           CHKERRQ(DMSetLabelValue(dm,"canonical",p,canon));
1010f9f063d4SToby Isaac           for (i = 0; i < numChildren; i++) {
10115f80ce2aSJacob Faibussowitsch             CHKERRQ(DMSetLabelValue(dm,"canonical",children[i],cChildren[i]));
1012f9f063d4SToby Isaac           }
1013f9f063d4SToby Isaac         }
1014f9f063d4SToby Isaac       }
1015f9f063d4SToby Isaac     }
1016f9f063d4SToby Isaac   }
1017776742edSToby Isaac   if (exchangeSupports) {
10185f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexTreeExchangeSupports(dm));
1019776742edSToby Isaac   }
1020f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
1021f7c74593SToby Isaac   /* reset anchors */
10225f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexSetAnchors(dm,NULL,NULL));
1023f9f063d4SToby Isaac   PetscFunctionReturn(0);
1024f9f063d4SToby Isaac }
1025f9f063d4SToby Isaac 
10260b7167a0SToby Isaac /*@
10270b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
10280b7167a0SToby Isaac   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
10290b7167a0SToby Isaac   tree root.
10300b7167a0SToby Isaac 
10310b7167a0SToby Isaac   Collective on dm
10320b7167a0SToby Isaac 
10330b7167a0SToby Isaac   Input Parameters:
10340b7167a0SToby Isaac + dm - the DMPlex object
10350b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
10360b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
10370b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
10380b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
10390b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
10400b7167a0SToby Isaac 
10410b7167a0SToby Isaac   Level: intermediate
10420b7167a0SToby Isaac 
1043a17985deSToby Isaac .seealso: DMPlexGetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
10440b7167a0SToby Isaac @*/
1045b2f41788SToby Isaac PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
10460b7167a0SToby Isaac {
10470b7167a0SToby Isaac   PetscFunctionBegin;
10485f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_FALSE,PETSC_TRUE));
10490b7167a0SToby Isaac   PetscFunctionReturn(0);
10500b7167a0SToby Isaac }
10510b7167a0SToby Isaac 
1052b2f41788SToby Isaac /*@
1053b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1054b2f41788SToby Isaac   Collective on dm
1055b2f41788SToby Isaac 
1056f899ff85SJose E. Roman   Input Parameter:
1057b2f41788SToby Isaac . dm - the DMPlex object
1058b2f41788SToby Isaac 
1059b2f41788SToby Isaac   Output Parameters:
1060b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1061b2f41788SToby Isaac                   offset indexes the parent and childID list
1062b2f41788SToby Isaac . parents - a list of the point parents
1063b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1064b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1065b2f41788SToby Isaac . childSection - the inverse of the parent section
1066b2f41788SToby Isaac - children - a list of the point children
1067b2f41788SToby Isaac 
1068b2f41788SToby Isaac   Level: intermediate
1069b2f41788SToby Isaac 
1070a17985deSToby Isaac .seealso: DMPlexSetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren()
1071b2f41788SToby Isaac @*/
1072b2f41788SToby Isaac PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1073b2f41788SToby Isaac {
1074b2f41788SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
1075b2f41788SToby Isaac 
1076b2f41788SToby Isaac   PetscFunctionBegin;
1077b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1078b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1079b2f41788SToby Isaac   if (parents)       *parents       = mesh->parents;
1080b2f41788SToby Isaac   if (childIDs)      *childIDs      = mesh->childIDs;
1081b2f41788SToby Isaac   if (childSection)  *childSection  = mesh->childSection;
1082b2f41788SToby Isaac   if (children)      *children      = mesh->children;
1083b2f41788SToby Isaac   PetscFunctionReturn(0);
1084b2f41788SToby Isaac }
1085b2f41788SToby Isaac 
1086d961a43aSToby Isaac /*@
1087eaf898f9SPatrick Sanan   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)
1088d961a43aSToby Isaac 
1089d961a43aSToby Isaac   Input Parameters:
1090d961a43aSToby Isaac + dm - the DMPlex object
1091d961a43aSToby Isaac - point - the query point
1092d961a43aSToby Isaac 
1093d961a43aSToby Isaac   Output Parameters:
1094d961a43aSToby Isaac + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1095d961a43aSToby Isaac - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point
1096d961a43aSToby Isaac             does not have a parent
1097d961a43aSToby Isaac 
1098d961a43aSToby Isaac   Level: intermediate
1099d961a43aSToby Isaac 
1100d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeChildren()
1101d961a43aSToby Isaac @*/
1102d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1103d961a43aSToby Isaac {
1104d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1105d961a43aSToby Isaac   PetscSection   pSec;
1106d961a43aSToby Isaac 
1107d961a43aSToby Isaac   PetscFunctionBegin;
1108d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1109d961a43aSToby Isaac   pSec = mesh->parentSection;
1110d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1111d961a43aSToby Isaac     PetscInt dof;
1112d961a43aSToby Isaac 
11135f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof (pSec, point, &dof));
1114d961a43aSToby Isaac     if (dof) {
1115d961a43aSToby Isaac       PetscInt off;
1116d961a43aSToby Isaac 
11175f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset (pSec, point, &off));
1118d961a43aSToby Isaac       if (parent)  *parent = mesh->parents[off];
1119d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
1120d961a43aSToby Isaac       PetscFunctionReturn(0);
1121d961a43aSToby Isaac     }
1122d961a43aSToby Isaac   }
1123d961a43aSToby Isaac   if (parent) {
1124d961a43aSToby Isaac     *parent = point;
1125d961a43aSToby Isaac   }
1126d961a43aSToby Isaac   if (childID) {
1127d961a43aSToby Isaac     *childID = 0;
1128d961a43aSToby Isaac   }
1129d961a43aSToby Isaac   PetscFunctionReturn(0);
1130d961a43aSToby Isaac }
1131d961a43aSToby Isaac 
1132d961a43aSToby Isaac /*@C
1133eaf898f9SPatrick Sanan   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)
1134d961a43aSToby Isaac 
1135d961a43aSToby Isaac   Input Parameters:
1136d961a43aSToby Isaac + dm - the DMPlex object
1137d961a43aSToby Isaac - point - the query point
1138d961a43aSToby Isaac 
1139d961a43aSToby Isaac   Output Parameters:
1140d961a43aSToby Isaac + numChildren - if not NULL, set to the number of children
1141d961a43aSToby Isaac - children - if not NULL, set to a list children, or set to NULL if the point has no children
1142d961a43aSToby Isaac 
1143d961a43aSToby Isaac   Level: intermediate
1144d961a43aSToby Isaac 
1145d961a43aSToby Isaac   Fortran Notes:
1146d961a43aSToby Isaac   Since it returns an array, this routine is only available in Fortran 90, and you must
1147d961a43aSToby Isaac   include petsc.h90 in your code.
1148d961a43aSToby Isaac 
1149d961a43aSToby Isaac .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeParent()
1150d961a43aSToby Isaac @*/
1151d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1152d961a43aSToby Isaac {
1153d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1154d961a43aSToby Isaac   PetscSection   childSec;
1155d961a43aSToby Isaac   PetscInt       dof = 0;
1156d961a43aSToby Isaac 
1157d961a43aSToby Isaac   PetscFunctionBegin;
1158d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1159d961a43aSToby Isaac   childSec = mesh->childSection;
1160d961a43aSToby Isaac   if (childSec && point >= childSec->pStart && point < childSec->pEnd) {
11615f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof (childSec, point, &dof));
1162d961a43aSToby Isaac   }
1163d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1164d961a43aSToby Isaac   if (children) {
1165d961a43aSToby Isaac     if (dof) {
1166d961a43aSToby Isaac       PetscInt off;
1167d961a43aSToby Isaac 
11685f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset (childSec, point, &off));
1169d961a43aSToby Isaac       *children = &mesh->children[off];
1170d961a43aSToby Isaac     }
1171d961a43aSToby Isaac     else {
1172d961a43aSToby Isaac       *children = NULL;
1173d961a43aSToby Isaac     }
1174d961a43aSToby Isaac   }
1175d961a43aSToby Isaac   PetscFunctionReturn(0);
1176d961a43aSToby Isaac }
11770c37af3bSToby Isaac 
117852a3aeb4SToby Isaac static PetscErrorCode EvaluateBasis(PetscSpace space, PetscInt nBasis, PetscInt nFunctionals, PetscInt nComps, PetscInt nPoints, const PetscInt *pointsPerFn, const PetscReal *points, const PetscReal *weights, PetscReal *work, Mat basisAtPoints)
1179b3a4bf2aSToby Isaac {
118052a3aeb4SToby Isaac   PetscInt       f, b, p, c, offset, qPoints;
1181b3a4bf2aSToby Isaac 
1182b3a4bf2aSToby Isaac   PetscFunctionBegin;
11835f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSpaceEvaluate(space,nPoints,points,work,NULL,NULL));
118452a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
118552a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
118652a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1187b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1188b3a4bf2aSToby Isaac 
118952a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
119052a3aeb4SToby Isaac         for (c = 0; c < nComps; c++) {
119152a3aeb4SToby Isaac           val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
1192b3a4bf2aSToby Isaac         }
119352a3aeb4SToby Isaac       }
11945f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetValue(basisAtPoints,b,f,val,INSERT_VALUES));
1195b3a4bf2aSToby Isaac     }
1196b3a4bf2aSToby Isaac     offset += qPoints;
1197b3a4bf2aSToby Isaac   }
11985f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(basisAtPoints,MAT_FINAL_ASSEMBLY));
11995f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(basisAtPoints,MAT_FINAL_ASSEMBLY));
1200b3a4bf2aSToby Isaac   PetscFunctionReturn(0);
1201b3a4bf2aSToby Isaac }
1202b3a4bf2aSToby Isaac 
1203f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
12040c37af3bSToby Isaac {
12050c37af3bSToby Isaac   PetscDS        ds;
12060c37af3bSToby Isaac   PetscInt       spdim;
12070c37af3bSToby Isaac   PetscInt       numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
12080c37af3bSToby Isaac   const PetscInt *anchors;
1209f7c74593SToby Isaac   PetscSection   aSec;
12100c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
12110c37af3bSToby Isaac   IS             aIS;
12120c37af3bSToby Isaac 
12130c37af3bSToby Isaac   PetscFunctionBegin;
12145f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(dm,&pStart,&pEnd));
12155f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(dm,&ds));
12165f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSGetNumFields(ds,&numFields));
12175f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetHeightStratum(dm,0,&cStart,&cEnd));
12185f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetAnchors(dm,&aSec,&aIS));
12195f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(aIS,&anchors));
12205f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(cSec,&conStart,&conEnd));
12215f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(dm,&spdim));
12225f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc6(spdim,&v0,spdim,&v0parent,spdim,&vtmp,spdim*spdim,&J,spdim*spdim,&Jparent,spdim*spdim,&invJparent));
12230c37af3bSToby Isaac 
12240c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
12250dd1b1feSToby Isaac     PetscObject       disc;
12260dd1b1feSToby Isaac     PetscClassId      id;
1227b3a4bf2aSToby Isaac     PetscSpace        bspace;
1228b3a4bf2aSToby Isaac     PetscDualSpace    dspace;
12299c3cf19fSMatthew G. Knepley     PetscInt          i, j, k, nPoints, Nc, offset;
123052a3aeb4SToby Isaac     PetscInt          fSize, maxDof;
1231b3a4bf2aSToby Isaac     PetscReal         *weights, *pointsRef, *pointsReal, *work;
12321683a169SBarry Smith     PetscScalar       *scwork;
12331683a169SBarry Smith     const PetscScalar *X;
12342c44ad04SToby Isaac     PetscInt          *sizes, *workIndRow, *workIndCol;
12350c37af3bSToby Isaac     Mat               Amat, Bmat, Xmat;
12362c44ad04SToby Isaac     const PetscInt    *numDof  = NULL;
1237085f0adfSToby Isaac     const PetscInt    ***perms = NULL;
1238085f0adfSToby Isaac     const PetscScalar ***flips = NULL;
12390c37af3bSToby Isaac 
12405f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDSGetDiscretization(ds,f,&disc));
12415f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectGetClassId(disc,&id));
12420dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1243b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE) disc;
1244b3a4bf2aSToby Isaac 
12455f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFEGetBasisSpace(fe,&bspace));
12465f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFEGetDualSpace(fe,&dspace));
12475f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDualSpaceGetDimension(dspace,&fSize));
12485f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFEGetNumComponents(fe,&Nc));
12490dd1b1feSToby Isaac     }
12500dd1b1feSToby Isaac     else if (id == PETSCFV_CLASSID) {
1251b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV) disc;
1252b3a4bf2aSToby Isaac 
12535f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFVGetNumComponents(fv,&Nc));
12545f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSpaceCreate(PetscObjectComm((PetscObject)fv),&bspace));
12555f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSpaceSetType(bspace,PETSCSPACEPOLYNOMIAL));
12565f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSpaceSetDegree(bspace,0,PETSC_DETERMINE));
12575f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSpaceSetNumComponents(bspace,Nc));
12585f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSpaceSetNumVariables(bspace,spdim));
12595f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSpaceSetUp(bspace));
12605f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFVGetDualSpace(fv,&dspace));
12615f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDualSpaceGetDimension(dspace,&fSize));
12620dd1b1feSToby Isaac     }
126398921bdaSJacob Faibussowitsch     else SETERRQ(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
12645f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDualSpaceGetNumDof(dspace,&numDof));
12652c44ad04SToby Isaac     for (i = 0, maxDof = 0; i <= spdim; i++) {maxDof = PetscMax(maxDof,numDof[i]);}
12665f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDualSpaceGetSymmetries(dspace,&perms,&flips));
12670dd1b1feSToby Isaac 
12685f80ce2aSJacob Faibussowitsch     CHKERRQ(MatCreate(PETSC_COMM_SELF,&Amat));
12695f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetSizes(Amat,fSize,fSize,fSize,fSize));
12705f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetType(Amat,MATSEQDENSE));
12715f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetUp(Amat));
12725f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Bmat));
12735f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Xmat));
12740c37af3bSToby Isaac     nPoints = 0;
12750c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
127652a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
12770c37af3bSToby Isaac       PetscQuadrature quad;
12780c37af3bSToby Isaac 
12795f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDualSpaceGetFunctional(dspace,i,&quad));
12805f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscQuadratureGetData(quad,NULL,&thisNc,&qPoints,NULL,NULL));
12812c71b3e2SJacob Faibussowitsch       PetscCheckFalse(thisNc != Nc,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %D does not much basis dim %D",thisNc,Nc);
12820c37af3bSToby Isaac       nPoints += qPoints;
12830c37af3bSToby Isaac     }
12845f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc7(fSize,&sizes,nPoints*Nc,&weights,spdim*nPoints,&pointsRef,spdim*nPoints,&pointsReal,nPoints*fSize*Nc,&work,maxDof,&workIndRow,maxDof,&workIndCol));
12855f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(maxDof * maxDof,&scwork));
12860c37af3bSToby Isaac     offset = 0;
12870c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12880c37af3bSToby Isaac       PetscInt        qPoints;
12890c37af3bSToby Isaac       const PetscReal    *p, *w;
12900c37af3bSToby Isaac       PetscQuadrature quad;
12910c37af3bSToby Isaac 
12925f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDualSpaceGetFunctional(dspace,i,&quad));
12935f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscQuadratureGetData(quad,NULL,NULL,&qPoints,&p,&w));
12945f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscArraycpy(weights+Nc*offset,w,Nc*qPoints));
12955f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscArraycpy(pointsRef+spdim*offset,p,spdim*qPoints));
1296b3a4bf2aSToby Isaac       sizes[i] = qPoints;
12970c37af3bSToby Isaac       offset  += qPoints;
12980c37af3bSToby Isaac     }
12995f80ce2aSJacob Faibussowitsch     CHKERRQ(EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsRef,weights,work,Amat));
13005f80ce2aSJacob Faibussowitsch     CHKERRQ(MatLUFactor(Amat,NULL,NULL,NULL));
13010c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
13020c37af3bSToby Isaac       PetscInt        parent;
13030c37af3bSToby Isaac       PetscInt        closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
13040c37af3bSToby Isaac       PetscInt        *childOffsets, *parentOffsets;
13050c37af3bSToby Isaac 
13065f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTreeParent(dm,c,&parent,NULL));
13070c37af3bSToby Isaac       if (parent == c) continue;
13085f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure));
13090c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13100c37af3bSToby Isaac         PetscInt p = closure[2*i];
13110c37af3bSToby Isaac         PetscInt conDof;
13120c37af3bSToby Isaac 
13130c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1314085f0adfSToby Isaac         if (numFields) {
13155f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(cSec,p,f,&conDof));
13160c37af3bSToby Isaac         }
13170c37af3bSToby Isaac         else {
13185f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(cSec,p,&conDof));
13190c37af3bSToby Isaac         }
13200c37af3bSToby Isaac         if (conDof) break;
13210c37af3bSToby Isaac       }
13220c37af3bSToby Isaac       if (i == closureSize) {
13235f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure));
13240c37af3bSToby Isaac         continue;
13250c37af3bSToby Isaac       }
13260c37af3bSToby Isaac 
13275f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ));
13285f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent));
13290c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1330c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
1331c330f8ffSToby Isaac 
1332c330f8ffSToby Isaac         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i*spdim],vtmp);
1333c330f8ffSToby Isaac         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i*spdim]);
13340c37af3bSToby Isaac       }
13355f80ce2aSJacob Faibussowitsch       CHKERRQ(EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsReal,weights,work,Bmat));
13365f80ce2aSJacob Faibussowitsch       CHKERRQ(MatMatSolve(Amat,Bmat,Xmat));
13375f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDenseGetArrayRead(Xmat,&X));
13385f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP));
13395f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc2(closureSize+1,&childOffsets,closureSizeP+1,&parentOffsets));
13400c37af3bSToby Isaac       childOffsets[0] = 0;
13410c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13420c37af3bSToby Isaac         PetscInt p = closure[2*i];
13430c37af3bSToby Isaac         PetscInt dof;
13440c37af3bSToby Isaac 
1345085f0adfSToby Isaac         if (numFields) {
13465f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(section,p,f,&dof));
13470c37af3bSToby Isaac         }
13480c37af3bSToby Isaac         else {
13495f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(section,p,&dof));
13500c37af3bSToby Isaac         }
135152a3aeb4SToby Isaac         childOffsets[i+1]=childOffsets[i]+dof;
13520c37af3bSToby Isaac       }
13530c37af3bSToby Isaac       parentOffsets[0] = 0;
13540c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
13550c37af3bSToby Isaac         PetscInt p = closureP[2*i];
13560c37af3bSToby Isaac         PetscInt dof;
13570c37af3bSToby Isaac 
1358085f0adfSToby Isaac         if (numFields) {
13595f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(section,p,f,&dof));
13600c37af3bSToby Isaac         }
13610c37af3bSToby Isaac         else {
13625f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(section,p,&dof));
13630c37af3bSToby Isaac         }
136452a3aeb4SToby Isaac         parentOffsets[i+1]=parentOffsets[i]+dof;
13650c37af3bSToby Isaac       }
13660c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13672c44ad04SToby Isaac         PetscInt conDof, conOff, aDof, aOff, nWork;
13680c37af3bSToby Isaac         PetscInt p = closure[2*i];
13690c37af3bSToby Isaac         PetscInt o = closure[2*i+1];
1370085f0adfSToby Isaac         const PetscInt    *perm;
1371085f0adfSToby Isaac         const PetscScalar *flip;
13720c37af3bSToby Isaac 
13730c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1374085f0adfSToby Isaac         if (numFields) {
13755f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(cSec,p,f,&conDof));
13765f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldOffset(cSec,p,f,&conOff));
13770c37af3bSToby Isaac         }
13780c37af3bSToby Isaac         else {
13795f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(cSec,p,&conDof));
13805f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetOffset(cSec,p,&conOff));
13810c37af3bSToby Isaac         }
13820c37af3bSToby Isaac         if (!conDof) continue;
1383085f0adfSToby Isaac         perm  = (perms && perms[i]) ? perms[i][o] : NULL;
1384085f0adfSToby Isaac         flip  = (flips && flips[i]) ? flips[i][o] : NULL;
13855f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(aSec,p,&aDof));
13865f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(aSec,p,&aOff));
13872c44ad04SToby Isaac         nWork = childOffsets[i+1]-childOffsets[i];
13880c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
13890c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
13900c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
13910c37af3bSToby Isaac 
1392085f0adfSToby Isaac           if (numFields) {
13935f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldDof(section,a,f,&aSecDof));
13945f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldOffset(section,a,f,&aSecOff));
13950c37af3bSToby Isaac           }
13960c37af3bSToby Isaac           else {
13975f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetDof(section,a,&aSecDof));
13985f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetOffset(section,a,&aSecOff));
13990c37af3bSToby Isaac           }
14000c37af3bSToby Isaac           if (!aSecDof) continue;
14010c37af3bSToby Isaac 
14020c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
14030c37af3bSToby Isaac             PetscInt q = closureP[2*j];
14040c37af3bSToby Isaac             PetscInt oq = closureP[2*j+1];
14052c44ad04SToby Isaac 
14062c44ad04SToby Isaac             if (q == a) {
140752a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1408085f0adfSToby Isaac               const PetscInt    *permP;
1409085f0adfSToby Isaac               const PetscScalar *flipP;
1410085f0adfSToby Isaac 
1411085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1412085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
14132c44ad04SToby Isaac               nWorkP = parentOffsets[j+1]-parentOffsets[j];
14142c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
14151683a169SBarry Smith                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
14162c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
14172c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
14182c44ad04SToby Isaac                 for (s = 0; s < nWorkP; s++) {
14192c44ad04SToby Isaac                   scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
14202c44ad04SToby Isaac                 }
14212c44ad04SToby Isaac               }
142252a3aeb4SToby Isaac               for (r = 0; r < nWork; r++)  {workIndRow[perm  ? perm[r]  : r] = conOff  + r;}
142352a3aeb4SToby Isaac               for (s = 0; s < nWorkP; s++) {workIndCol[permP ? permP[s] : s] = aSecOff + s;}
14242c44ad04SToby Isaac               if (flip) {
14252c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14262c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14272c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flip[r];
14282c44ad04SToby Isaac                   }
14292c44ad04SToby Isaac                 }
14302c44ad04SToby Isaac               }
14312c44ad04SToby Isaac               if (flipP) {
14322c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14332c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14342c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flipP[s];
14352c44ad04SToby Isaac                   }
14362c44ad04SToby Isaac                 }
14372c44ad04SToby Isaac               }
14385f80ce2aSJacob Faibussowitsch               CHKERRQ(MatSetValues(cMat,nWork,workIndRow,nWorkP,workIndCol,scwork,INSERT_VALUES));
14392c44ad04SToby Isaac               break;
14400c37af3bSToby Isaac             }
14410c37af3bSToby Isaac           }
14420c37af3bSToby Isaac         }
14430c37af3bSToby Isaac       }
14445f80ce2aSJacob Faibussowitsch       CHKERRQ(MatDenseRestoreArrayRead(Xmat,&X));
14455f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree2(childOffsets,parentOffsets));
14465f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure));
14475f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP));
14480c37af3bSToby Isaac     }
14495f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&Amat));
14505f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&Bmat));
14515f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&Xmat));
14525f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(scwork));
14535f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree7(sizes,weights,pointsRef,pointsReal,work,workIndRow,workIndCol));
1454b3a4bf2aSToby Isaac     if (id == PETSCFV_CLASSID) {
14555f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSpaceDestroy(&bspace));
1456b3a4bf2aSToby Isaac     }
14570c37af3bSToby Isaac   }
14585f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY));
14595f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY));
14605f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree6(v0,v0parent,vtmp,J,Jparent,invJparent));
14615f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(aIS,&anchors));
14620c37af3bSToby Isaac 
14630c37af3bSToby Isaac   PetscFunctionReturn(0);
14640c37af3bSToby Isaac }
146595a0b26dSToby Isaac 
146621968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
146795a0b26dSToby Isaac {
1468f7c74593SToby Isaac   Mat               refCmat;
146921968bf8SToby Isaac   PetscDS           ds;
1470085f0adfSToby Isaac   PetscInt          numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
147121968bf8SToby Isaac   PetscScalar       ***refPointFieldMats;
147221968bf8SToby Isaac   PetscSection      refConSec, refAnSec, refSection;
147321968bf8SToby Isaac   IS                refAnIS;
147421968bf8SToby Isaac   const PetscInt    *refAnchors;
1475085f0adfSToby Isaac   const PetscInt    **perms;
1476085f0adfSToby Isaac   const PetscScalar **flips;
147795a0b26dSToby Isaac 
147895a0b26dSToby Isaac   PetscFunctionBegin;
14795f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(refTree,&ds));
14805f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSGetNumFields(ds,&numFields));
1481085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
14825f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(refTree,&refConSec,&refCmat,NULL));
14835f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetAnchors(refTree,&refAnSec,&refAnIS));
14845f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(refAnIS,&refAnchors));
14855f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(refTree,&refSection));
14865f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
14875f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats));
14885f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pRefEnd-pRefStart,&refPointFieldN));
14895f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetMaxDof(refConSec,&maxDof));
14905f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetMaxDof(refAnSec,&maxAnDof));
14915f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(maxDof,&rows));
14925f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(maxDof*maxAnDof,&cols));
149395a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
149495a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
149595a0b26dSToby Isaac 
14965f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeParent(refTree,p,&parent,NULL));
14975f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(refConSec,p,&pDof));
149895a0b26dSToby Isaac     if (!pDof || parent == p) continue;
149995a0b26dSToby Isaac 
15005f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(maxFields,&refPointFieldMats[p-pRefStart]));
15015f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc1(maxFields,&refPointFieldN[p-pRefStart]));
15025f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure));
1503085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1504085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
150595a0b26dSToby Isaac 
1506085f0adfSToby Isaac       if (f < numFields) {
15075f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
15085f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldOffset(refConSec,p,f,&cOff));
15095f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips));
1510085f0adfSToby Isaac       } else {
15115f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(refConSec,p,&cDof));
15125f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(refConSec,p,&cOff));
15135f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetPointSyms(refSection,closureSize,closure,&perms,&flips));
151495a0b26dSToby Isaac       }
151595a0b26dSToby Isaac 
151695a0b26dSToby Isaac       for (r = 0; r < cDof; r++) {
151795a0b26dSToby Isaac         rows[r] = cOff + r;
151895a0b26dSToby Isaac       }
151995a0b26dSToby Isaac       numCols = 0;
152095a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
152195a0b26dSToby Isaac         PetscInt          q = closure[2*i];
152295a0b26dSToby Isaac         PetscInt          aDof, aOff, j;
1523085f0adfSToby Isaac         const PetscInt    *perm = perms ? perms[i] : NULL;
152495a0b26dSToby Isaac 
1525085f0adfSToby Isaac         if (numFields) {
15265f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(refSection,q,f,&aDof));
15275f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldOffset(refSection,q,f,&aOff));
152895a0b26dSToby Isaac         }
152995a0b26dSToby Isaac         else {
15305f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(refSection,q,&aDof));
15315f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetOffset(refSection,q,&aOff));
153295a0b26dSToby Isaac         }
153395a0b26dSToby Isaac 
153495a0b26dSToby Isaac         for (j = 0; j < aDof; j++) {
1535085f0adfSToby Isaac           cols[numCols++] = aOff + (perm ? perm[j] : j);
153695a0b26dSToby Isaac         }
153795a0b26dSToby Isaac       }
153895a0b26dSToby Isaac       refPointFieldN[p-pRefStart][f] = numCols;
15395f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]));
15405f80ce2aSJacob Faibussowitsch       CHKERRQ(MatGetValues(refCmat,cDof,rows,numCols,cols,refPointFieldMats[p-pRefStart][f]));
1541085f0adfSToby Isaac       if (flips) {
1542085f0adfSToby Isaac         PetscInt colOff = 0;
1543085f0adfSToby Isaac 
1544085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1545085f0adfSToby Isaac           PetscInt          q = closure[2*i];
1546085f0adfSToby Isaac           PetscInt          aDof, aOff, j;
1547085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1548085f0adfSToby Isaac 
1549085f0adfSToby Isaac           if (numFields) {
15505f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldDof(refSection,q,f,&aDof));
15515f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldOffset(refSection,q,f,&aOff));
1552085f0adfSToby Isaac           }
1553085f0adfSToby Isaac           else {
15545f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetDof(refSection,q,&aDof));
15555f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetOffset(refSection,q,&aOff));
1556085f0adfSToby Isaac           }
1557085f0adfSToby Isaac           if (flip) {
1558085f0adfSToby Isaac             PetscInt k;
1559085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1560085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1561085f0adfSToby Isaac                 refPointFieldMats[p-pRefStart][f][k * numCols + colOff + j] *= flip[j];
1562085f0adfSToby Isaac               }
1563085f0adfSToby Isaac             }
1564085f0adfSToby Isaac           }
1565085f0adfSToby Isaac           colOff += aDof;
1566085f0adfSToby Isaac         }
1567085f0adfSToby Isaac       }
1568085f0adfSToby Isaac       if (numFields) {
15695f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionRestoreFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips));
1570085f0adfSToby Isaac       } else {
15715f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionRestorePointSyms(refSection,closureSize,closure,&perms,&flips));
1572085f0adfSToby Isaac       }
157395a0b26dSToby Isaac     }
15745f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexRestoreTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure));
157595a0b26dSToby Isaac   }
157621968bf8SToby Isaac   *childrenMats = refPointFieldMats;
157721968bf8SToby Isaac   *childrenN = refPointFieldN;
15785f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(refAnIS,&refAnchors));
15795f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(rows));
15805f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(cols));
158121968bf8SToby Isaac   PetscFunctionReturn(0);
158221968bf8SToby Isaac }
158321968bf8SToby Isaac 
158421968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
158521968bf8SToby Isaac {
158621968bf8SToby Isaac   PetscDS        ds;
158721968bf8SToby Isaac   PetscInt       **refPointFieldN;
158821968bf8SToby Isaac   PetscScalar    ***refPointFieldMats;
1589085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
159021968bf8SToby Isaac   PetscSection   refConSec;
159121968bf8SToby Isaac 
159221968bf8SToby Isaac   PetscFunctionBegin;
159321968bf8SToby Isaac   refPointFieldN = *childrenN;
159421968bf8SToby Isaac   *childrenN = NULL;
159521968bf8SToby Isaac   refPointFieldMats = *childrenMats;
159621968bf8SToby Isaac   *childrenMats = NULL;
15975f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(refTree,&ds));
15985f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSGetNumFields(ds,&numFields));
1599367003a6SStefano Zampini   maxFields = PetscMax(1,numFields);
16005f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
16015f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
160221968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
160321968bf8SToby Isaac     PetscInt parent, pDof;
160421968bf8SToby Isaac 
16055f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeParent(refTree,p,&parent,NULL));
16065f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(refConSec,p,&pDof));
160721968bf8SToby Isaac     if (!pDof || parent == p) continue;
160821968bf8SToby Isaac 
1609085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
161021968bf8SToby Isaac       PetscInt cDof;
161121968bf8SToby Isaac 
1612085f0adfSToby Isaac       if (numFields) {
16135f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
161421968bf8SToby Isaac       }
161521968bf8SToby Isaac       else {
16165f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(refConSec,p,&cDof));
161721968bf8SToby Isaac       }
161821968bf8SToby Isaac 
16195f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(refPointFieldMats[p - pRefStart][f]));
162021968bf8SToby Isaac     }
16215f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(refPointFieldMats[p - pRefStart]));
16225f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(refPointFieldN[p - pRefStart]));
162321968bf8SToby Isaac   }
16245f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(refPointFieldMats));
16255f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(refPointFieldN));
162621968bf8SToby Isaac   PetscFunctionReturn(0);
162721968bf8SToby Isaac }
162821968bf8SToby Isaac 
162921968bf8SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
163021968bf8SToby Isaac {
163121968bf8SToby Isaac   DM             refTree;
163221968bf8SToby Isaac   PetscDS        ds;
163321968bf8SToby Isaac   Mat            refCmat;
1634085f0adfSToby Isaac   PetscInt       numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
163521968bf8SToby Isaac   PetscScalar ***refPointFieldMats, *pointWork;
163621968bf8SToby Isaac   PetscSection   refConSec, refAnSec, anSec;
163721968bf8SToby Isaac   IS             refAnIS, anIS;
163821968bf8SToby Isaac   const PetscInt *anchors;
163921968bf8SToby Isaac 
164021968bf8SToby Isaac   PetscFunctionBegin;
164121968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
16425f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(dm,&ds));
16435f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSGetNumFields(ds,&numFields));
1644085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
16455f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetReferenceTree(dm,&refTree));
16465f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCopyDisc(dm,refTree));
16475f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(refTree,&refConSec,&refCmat,NULL));
16485f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetAnchors(refTree,&refAnSec,&refAnIS));
16495f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetAnchors(dm,&anSec,&anIS));
16505f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(anIS,&anchors));
16515f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
16525f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(conSec,&conStart,&conEnd));
16535f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetMaxDof(refConSec,&maxDof));
16545f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetMaxDof(refAnSec,&maxAnDof));
16555f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(maxDof*maxDof*maxAnDof,&pointWork));
165621968bf8SToby Isaac 
165721968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
16585f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
165995a0b26dSToby Isaac 
166095a0b26dSToby Isaac   /* step 2: compute the preorder */
16615f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(dm,&pStart,&pEnd));
16625f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(pEnd-pStart,&perm,pEnd-pStart,&iperm));
166395a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
166495a0b26dSToby Isaac     perm[p - pStart] = p;
166595a0b26dSToby Isaac     iperm[p - pStart] = p-pStart;
166695a0b26dSToby Isaac   }
166795a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
166895a0b26dSToby Isaac     PetscInt point = perm[p];
166995a0b26dSToby Isaac     PetscInt parent;
167095a0b26dSToby Isaac 
16715f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeParent(dm,point,&parent,NULL));
167295a0b26dSToby Isaac     if (parent == point) {
167395a0b26dSToby Isaac       p++;
167495a0b26dSToby Isaac     }
167595a0b26dSToby Isaac     else {
167695a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
167795a0b26dSToby Isaac 
16785f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
167995a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
168095a0b26dSToby Isaac         PetscInt q = closure[2*i];
168195a0b26dSToby Isaac         if (iperm[q-pStart] > iperm[point-pStart]) {
168295a0b26dSToby Isaac           /* swap */
168395a0b26dSToby Isaac           perm[p]               = q;
168495a0b26dSToby Isaac           perm[iperm[q-pStart]] = point;
168595a0b26dSToby Isaac           iperm[point-pStart]   = iperm[q-pStart];
168695a0b26dSToby Isaac           iperm[q-pStart]       = p;
168795a0b26dSToby Isaac           break;
168895a0b26dSToby Isaac         }
168995a0b26dSToby Isaac       }
169095a0b26dSToby Isaac       size = closureSize;
16915f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
169295a0b26dSToby Isaac       if (i == size) {
169395a0b26dSToby Isaac         p++;
169495a0b26dSToby Isaac       }
169595a0b26dSToby Isaac     }
169695a0b26dSToby Isaac   }
169795a0b26dSToby Isaac 
169895a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
169995a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
170095a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
170195a0b26dSToby Isaac    * values outside of the Mat first.
170295a0b26dSToby Isaac    */
170395a0b26dSToby Isaac   {
170495a0b26dSToby Isaac     PetscInt nRows, row, nnz;
170595a0b26dSToby Isaac     PetscBool done;
170695a0b26dSToby Isaac     const PetscInt *ia, *ja;
170795a0b26dSToby Isaac     PetscScalar *vals;
170895a0b26dSToby Isaac 
17095f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done));
1710*28b400f6SJacob Faibussowitsch     PetscCheck(done,PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not get RowIJ of constraint matrix");
171195a0b26dSToby Isaac     nnz  = ia[nRows];
171295a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
171395a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
17145f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(nnz,&vals));
171595a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
171695a0b26dSToby Isaac       PetscInt        parent, childid, closureSize, *closure = NULL;
171795a0b26dSToby Isaac       PetscInt        point = perm[p], pointDof;
171895a0b26dSToby Isaac 
17195f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTreeParent(dm,point,&parent,&childid));
172095a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
17215f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(conSec,point,&pointDof));
172295a0b26dSToby Isaac       if (!pointDof) continue;
17235f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
1724085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1725085f0adfSToby Isaac         PetscInt cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
172695a0b26dSToby Isaac         PetscScalar *pointMat;
1727085f0adfSToby Isaac         const PetscInt    **perms;
1728085f0adfSToby Isaac         const PetscScalar **flips;
172995a0b26dSToby Isaac 
1730085f0adfSToby Isaac         if (numFields) {
17315f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(conSec,point,f,&cDof));
17325f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldOffset(conSec,point,f,&cOff));
173395a0b26dSToby Isaac         }
173495a0b26dSToby Isaac         else {
17355f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(conSec,point,&cDof));
17365f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetOffset(conSec,point,&cOff));
173795a0b26dSToby Isaac         }
173895a0b26dSToby Isaac         if (!cDof) continue;
17395f80ce2aSJacob Faibussowitsch         if (numFields) CHKERRQ(PetscSectionGetFieldPointSyms(section,f,closureSize,closure,&perms,&flips));
17405f80ce2aSJacob Faibussowitsch         else           CHKERRQ(PetscSectionGetPointSyms(section,closureSize,closure,&perms,&flips));
174195a0b26dSToby Isaac 
174295a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
174376bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
174495a0b26dSToby Isaac           for (r = 0; r < cDof; r++) {
174595a0b26dSToby Isaac             if (cDof > 1 && r) {
17462c71b3e2SJacob Faibussowitsch               PetscCheckFalse((ia[cOff+r+1]-ia[cOff+r]) != (ia[cOff+r]-ia[cOff+r-1]),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Two point rows have different nnz: %D vs. %D", (ia[cOff+r+1]-ia[cOff+r]), (ia[cOff+r]-ia[cOff+r-1]));
174795a0b26dSToby Isaac             }
174895a0b26dSToby Isaac           }
174976bd3646SJed Brown         }
175095a0b26dSToby Isaac         /* zero rows */
175195a0b26dSToby Isaac         for (i = ia[cOff] ; i< ia[cOff+cDof];i++) {
175295a0b26dSToby Isaac           vals[i] = 0.;
175395a0b26dSToby Isaac         }
175495a0b26dSToby Isaac         matOffset = ia[cOff];
175595a0b26dSToby Isaac         numFillCols = ia[cOff+1] - matOffset;
175695a0b26dSToby Isaac         pointMat = refPointFieldMats[childid-pRefStart][f];
175795a0b26dSToby Isaac         numCols = refPointFieldN[childid-pRefStart][f];
175895a0b26dSToby Isaac         offset = 0;
175995a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
176095a0b26dSToby Isaac           PetscInt q = closure[2*i];
176195a0b26dSToby Isaac           PetscInt aDof, aOff, j, k, qConDof, qConOff;
1762085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1763085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
176495a0b26dSToby Isaac 
176595a0b26dSToby Isaac           qConDof = qConOff = 0;
1766085f0adfSToby Isaac           if (numFields) {
17675f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldDof(section,q,f,&aDof));
17685f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldOffset(section,q,f,&aOff));
176995a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
17705f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscSectionGetFieldDof(conSec,q,f,&qConDof));
17715f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscSectionGetFieldOffset(conSec,q,f,&qConOff));
177295a0b26dSToby Isaac             }
177395a0b26dSToby Isaac           }
177495a0b26dSToby Isaac           else {
17755f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetDof(section,q,&aDof));
17765f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetOffset(section,q,&aOff));
177795a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
17785f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscSectionGetDof(conSec,q,&qConDof));
17795f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscSectionGetOffset(conSec,q,&qConOff));
178095a0b26dSToby Isaac             }
178195a0b26dSToby Isaac           }
178295a0b26dSToby Isaac           if (!aDof) continue;
178395a0b26dSToby Isaac           if (qConDof) {
178495a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
178595a0b26dSToby Isaac              * be filled, thanks to preordering */
178695a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
178795a0b26dSToby Isaac             PetscInt aMatOffset = ia[qConOff];
178895a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
178995a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
179095a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
179195a0b26dSToby Isaac                 PetscScalar inVal = 0;
179295a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1793085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
179495a0b26dSToby Isaac 
1795085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
179695a0b26dSToby Isaac                 }
179795a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
179895a0b26dSToby Isaac               }
179995a0b26dSToby Isaac             }
180095a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
180195a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
180295a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
180395a0b26dSToby Isaac               for (;k < numFillCols; k++) {
180495a0b26dSToby Isaac                 if (ja[matOffset + k] == col) {
180595a0b26dSToby Isaac                   break;
180695a0b26dSToby Isaac                 }
180795a0b26dSToby Isaac               }
18082c71b3e2SJacob Faibussowitsch               PetscCheckFalse(k == numFillCols,PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, col);
180995a0b26dSToby Isaac               for (r = 0; r < cDof; r++) {
181095a0b26dSToby Isaac                 vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
181195a0b26dSToby Isaac               }
181295a0b26dSToby Isaac             }
181395a0b26dSToby Isaac           }
181495a0b26dSToby Isaac           else {
181595a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
181695a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
181795a0b26dSToby Isaac               if (ja[matOffset + k] == aOff) {
181895a0b26dSToby Isaac                 break;
181995a0b26dSToby Isaac               }
182095a0b26dSToby Isaac             }
18212c71b3e2SJacob Faibussowitsch             PetscCheckFalse(k == numFillCols,PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, aOff);
182295a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1823085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1824085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1825085f0adfSToby Isaac 
1826085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
182795a0b26dSToby Isaac               }
182895a0b26dSToby Isaac             }
182995a0b26dSToby Isaac           }
183095a0b26dSToby Isaac           offset += aDof;
183195a0b26dSToby Isaac         }
1832085f0adfSToby Isaac         if (numFields) {
18335f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionRestoreFieldPointSyms(section,f,closureSize,closure,&perms,&flips));
1834085f0adfSToby Isaac         } else {
18355f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionRestorePointSyms(section,closureSize,closure,&perms,&flips));
1836085f0adfSToby Isaac         }
183795a0b26dSToby Isaac       }
18385f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
183995a0b26dSToby Isaac     }
184095a0b26dSToby Isaac     for (row = 0; row < nRows; row++) {
18415f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetValues(cMat,1,&row,ia[row+1]-ia[row],&ja[ia[row]],&vals[ia[row]],INSERT_VALUES));
184295a0b26dSToby Isaac     }
18435f80ce2aSJacob Faibussowitsch     CHKERRQ(MatRestoreRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done));
1844*28b400f6SJacob Faibussowitsch     PetscCheck(done,PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not restore RowIJ of constraint matrix");
18455f80ce2aSJacob Faibussowitsch     CHKERRQ(MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY));
18465f80ce2aSJacob Faibussowitsch     CHKERRQ(MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY));
18475f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(vals));
184895a0b26dSToby Isaac   }
184995a0b26dSToby Isaac 
185095a0b26dSToby Isaac   /* clean up */
18515f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(anIS,&anchors));
18525f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(perm,iperm));
18535f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(pointWork));
18545f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
185595a0b26dSToby Isaac   PetscFunctionReturn(0);
185695a0b26dSToby Isaac }
185795a0b26dSToby Isaac 
18586f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
18596f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
18606f5f1567SToby Isaac PetscErrorCode DMPlexTreeRefineCell (DM dm, PetscInt cell, DM *ncdm)
18616f5f1567SToby Isaac {
18626f5f1567SToby Isaac   DM K;
1863420f55faSMatthew G. Knepley   PetscMPIInt rank;
18646f5f1567SToby Isaac   PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
18656f5f1567SToby Isaac   PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations;
18666f5f1567SToby Isaac   PetscInt *Kembedding;
18676f5f1567SToby Isaac   PetscInt *cellClosure=NULL, nc;
18686f5f1567SToby Isaac   PetscScalar *newVertexCoords;
18696f5f1567SToby Isaac   PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
18706f5f1567SToby Isaac   PetscSection parentSection;
18716f5f1567SToby Isaac 
18726f5f1567SToby Isaac   PetscFunctionBegin;
18735f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
18745f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(dm,&dim));
18755f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
18765f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetDimension(*ncdm,dim));
18776f5f1567SToby Isaac 
18785f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
18795f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)dm),&parentSection));
18805f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetReferenceTree(dm,&K));
1881dd400576SPatrick Sanan   if (rank == 0) {
18826f5f1567SToby Isaac     /* compute the new charts */
18835f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc5(dim+1,&pNewCount,dim+1,&pNewStart,dim+1,&pNewEnd,dim+1,&pOldStart,dim+1,&pOldEnd));
18846f5f1567SToby Isaac     offset = 0;
18856f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18866f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
18876f5f1567SToby Isaac 
18886f5f1567SToby Isaac       pNewStart[d] = offset;
18895f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetHeightStratum(dm,d,&pOldStart[d],&pOldEnd[d]));
18905f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetHeightStratum(K,d,&kStart,&kEnd));
18916f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
18926f5f1567SToby Isaac       /* adding the new points */
18936f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
18946f5f1567SToby Isaac       if (!d) {
18956f5f1567SToby Isaac         /* removing the cell */
18966f5f1567SToby Isaac         pNewCount[d]--;
18976f5f1567SToby Isaac       }
18986f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18996f5f1567SToby Isaac         PetscInt parent;
19005f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeParent(K,k,&parent,NULL));
19016f5f1567SToby Isaac         if (parent == k) {
19026f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
19036f5f1567SToby Isaac           pNewCount[d]--;
19046f5f1567SToby Isaac         }
19056f5f1567SToby Isaac       }
19066f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
19076f5f1567SToby Isaac       offset = pNewEnd[d];
19086f5f1567SToby Isaac 
19096f5f1567SToby Isaac     }
19102c71b3e2SJacob Faibussowitsch     PetscCheckFalse(cell < pOldStart[0] || cell >= pOldEnd[0],PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"%d not in cell range [%d, %d)", cell, pOldStart[0], pOldEnd[0]);
19116f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
19125f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure));
19136f5f1567SToby Isaac 
19145f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(pNewEnd[dim],&newConeSizes));
19156f5f1567SToby Isaac     {
1916b5a892a1SMatthew G. Knepley       DMPolytopeType pct, qct;
19176f5f1567SToby Isaac       PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
19186f5f1567SToby Isaac 
19195f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetChart(K,&kStart,&kEnd));
19205f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc4(kEnd-kStart,&Kembedding,kEnd-kStart,&perm,kEnd-kStart,&iperm,kEnd-kStart,&preOrient));
19216f5f1567SToby Isaac 
19226f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19236f5f1567SToby Isaac         perm[k - kStart] = k;
19246f5f1567SToby Isaac         iperm [k - kStart] = k - kStart;
19256f5f1567SToby Isaac         preOrient[k - kStart] = 0;
19266f5f1567SToby Isaac       }
19276f5f1567SToby Isaac 
19285f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK));
19296f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
19306f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2*j+1];
19316f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2*j+1];
19326f5f1567SToby Isaac         PetscInt p, q;
19336f5f1567SToby Isaac 
19346f5f1567SToby Isaac         p = closureK[2*j];
19356f5f1567SToby Isaac         q = cellClosure[2*j];
19365f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetCellType(K, p, &pct));
19375f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetCellType(dm, q, &qct));
19386f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
19396f5f1567SToby Isaac           if (q >= pOldStart[d] && q < pOldEnd[d]) {
19406f5f1567SToby Isaac             Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
19416f5f1567SToby Isaac           }
19426f5f1567SToby Isaac         }
1943b5a892a1SMatthew G. Knepley         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1944b5a892a1SMatthew G. Knepley         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
19456f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
19466f5f1567SToby Isaac           PetscInt numChildren, i;
19476f5f1567SToby Isaac           const PetscInt *children;
19486f5f1567SToby Isaac 
19495f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetTreeChildren(K,p,&numChildren,&children));
19506f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
19516f5f1567SToby Isaac             PetscInt kPerm, oPerm;
19526f5f1567SToby Isaac 
19536f5f1567SToby Isaac             k    = children[i];
19545f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexReferenceTreeGetChildSymmetry(K,p,parentOrientA,0,k,parentOrientB,&oPerm,&kPerm));
19556f5f1567SToby Isaac             /* perm = what refTree position I'm in */
19566f5f1567SToby Isaac             perm[kPerm-kStart]      = k;
19576f5f1567SToby Isaac             /* iperm = who is at this position */
19586f5f1567SToby Isaac             iperm[k-kStart]         = kPerm-kStart;
19596f5f1567SToby Isaac             preOrient[kPerm-kStart] = oPerm;
19606f5f1567SToby Isaac           }
19616f5f1567SToby Isaac         }
19626f5f1567SToby Isaac       }
19635f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK));
19646f5f1567SToby Isaac     }
19655f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetChart(parentSection,0,pNewEnd[dim]));
19666f5f1567SToby Isaac     offset = 0;
19676f5f1567SToby Isaac     numNewCones = 0;
19686f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19696f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
19706f5f1567SToby Isaac       PetscInt p;
19716f5f1567SToby Isaac       PetscInt size;
19726f5f1567SToby Isaac 
19736f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19746f5f1567SToby Isaac         /* skip cell 0 */
19756f5f1567SToby Isaac         if (p == cell) continue;
19766f5f1567SToby Isaac         /* old cones to new cones */
19775f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetConeSize(dm,p,&size));
19786f5f1567SToby Isaac         newConeSizes[offset++] = size;
19796f5f1567SToby Isaac         numNewCones += size;
19806f5f1567SToby Isaac       }
19816f5f1567SToby Isaac 
19825f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetHeightStratum(K,d,&kStart,&kEnd));
19836f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19846f5f1567SToby Isaac         PetscInt kParent;
19856f5f1567SToby Isaac 
19865f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeParent(K,k,&kParent,NULL));
19876f5f1567SToby Isaac         if (kParent != k) {
19886f5f1567SToby Isaac           Kembedding[k] = offset;
19895f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetConeSize(K,k,&size));
19906f5f1567SToby Isaac           newConeSizes[offset++] = size;
19916f5f1567SToby Isaac           numNewCones += size;
19926f5f1567SToby Isaac           if (kParent != 0) {
19935f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionSetDof(parentSection,Kembedding[k],1));
19946f5f1567SToby Isaac           }
19956f5f1567SToby Isaac         }
19966f5f1567SToby Isaac       }
19976f5f1567SToby Isaac     }
19986f5f1567SToby Isaac 
19995f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetUp(parentSection));
20005f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(parentSection,&numPointsWithParents));
20015f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc2(numNewCones,&newCones,numNewCones,&newOrientations));
20025f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc2(numPointsWithParents,&parents,numPointsWithParents,&childIDs));
20036f5f1567SToby Isaac 
20046f5f1567SToby Isaac     /* fill new cones */
20056f5f1567SToby Isaac     offset = 0;
20066f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20076f5f1567SToby Isaac       PetscInt kStart, kEnd, k, l;
20086f5f1567SToby Isaac       PetscInt p;
20096f5f1567SToby Isaac       PetscInt size;
20106f5f1567SToby Isaac       const PetscInt *cone, *orientation;
20116f5f1567SToby Isaac 
20126f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
20136f5f1567SToby Isaac         /* skip cell 0 */
20146f5f1567SToby Isaac         if (p == cell) continue;
20156f5f1567SToby Isaac         /* old cones to new cones */
20165f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetConeSize(dm,p,&size));
20175f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetCone(dm,p,&cone));
20185f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetConeOrientation(dm,p,&orientation));
20196f5f1567SToby Isaac         for (l = 0; l < size; l++) {
20206f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
20216f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
20226f5f1567SToby Isaac         }
20236f5f1567SToby Isaac       }
20246f5f1567SToby Isaac 
20255f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetHeightStratum(K,d,&kStart,&kEnd));
20266f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20276f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
20286f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
20296f5f1567SToby Isaac 
20305f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeParent(K,k,&kParent,NULL));
20316f5f1567SToby Isaac         if (kParent != k) {
20326f5f1567SToby Isaac           /* embed new cones */
20335f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetConeSize(K,k,&size));
20345f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetCone(K,kPerm,&cone));
20355f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetConeOrientation(K,kPerm,&orientation));
20366f5f1567SToby Isaac           for (l = 0; l < size; l++) {
20376f5f1567SToby Isaac             PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size -(preO + 1) - l) % size);
20386f5f1567SToby Isaac             PetscInt newO, lSize, oTrue;
2039b5a892a1SMatthew G. Knepley             DMPolytopeType ct = DM_NUM_POLYTOPES;
20406f5f1567SToby Isaac 
20416f5f1567SToby Isaac             q                         = iperm[cone[m]];
20426f5f1567SToby Isaac             newCones[offset]          = Kembedding[q];
20435f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexGetConeSize(K,q,&lSize));
2044b5a892a1SMatthew G. Knepley             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
2045b5a892a1SMatthew G. Knepley             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
2046b5a892a1SMatthew G. Knepley             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
20476f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
20486f5f1567SToby Isaac             newO                      = DihedralCompose(lSize,oTrue,preOrient[q]);
2049b5a892a1SMatthew G. Knepley             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
20506f5f1567SToby Isaac           }
20516f5f1567SToby Isaac           if (kParent != 0) {
20526f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
20535f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetOffset(parentSection,Kembedding[k],&pOffset));
20546f5f1567SToby Isaac             parents[pOffset]  = newPoint;
20556f5f1567SToby Isaac             childIDs[pOffset] = k;
20566f5f1567SToby Isaac           }
20576f5f1567SToby Isaac         }
20586f5f1567SToby Isaac       }
20596f5f1567SToby Isaac     }
20606f5f1567SToby Isaac 
20615f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(dim*(pNewEnd[dim]-pNewStart[dim]),&newVertexCoords));
20626f5f1567SToby Isaac 
20636f5f1567SToby Isaac     /* fill coordinates */
20646f5f1567SToby Isaac     offset = 0;
20656f5f1567SToby Isaac     {
2066d90620a3SMatthew G. Knepley       PetscInt kStart, kEnd, l;
20676f5f1567SToby Isaac       PetscSection vSection;
20686f5f1567SToby Isaac       PetscInt v;
20696f5f1567SToby Isaac       Vec coords;
20706f5f1567SToby Isaac       PetscScalar *coordvals;
20716f5f1567SToby Isaac       PetscInt dof, off;
2072c111c6b7SMatthew G. Knepley       PetscReal v0[3], J[9], detJ;
20736f5f1567SToby Isaac 
207476bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
2075d90620a3SMatthew G. Knepley         PetscInt k;
20765f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetHeightStratum(K,0,&kStart,&kEnd));
20776f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
20785f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
20792c71b3e2SJacob Faibussowitsch           PetscCheckFalse(detJ <= 0.,PETSC_COMM_SELF,PETSC_ERR_PLIB,"reference tree cell %d has bad determinant",k);
20806f5f1567SToby Isaac         }
2081d90620a3SMatthew G. Knepley       }
20825f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
20835f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoordinateSection(dm,&vSection));
20845f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoordinatesLocal(dm,&coords));
20855f80ce2aSJacob Faibussowitsch       CHKERRQ(VecGetArray(coords,&coordvals));
20866f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
20876f5f1567SToby Isaac 
20885f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(vSection,v,&dof));
20895f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(vSection,v,&off));
20906f5f1567SToby Isaac         for (l = 0; l < dof; l++) {
20916f5f1567SToby Isaac           newVertexCoords[offset++] = coordvals[off + l];
20926f5f1567SToby Isaac         }
20936f5f1567SToby Isaac       }
20945f80ce2aSJacob Faibussowitsch       CHKERRQ(VecRestoreArray(coords,&coordvals));
20956f5f1567SToby Isaac 
20965f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoordinateSection(K,&vSection));
20975f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoordinatesLocal(K,&coords));
20985f80ce2aSJacob Faibussowitsch       CHKERRQ(VecGetArray(coords,&coordvals));
20995f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetDepthStratum(K,0,&kStart,&kEnd));
21006f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
21019bc368c7SMatthew G. Knepley         PetscReal coord[3], newCoord[3];
21026f5f1567SToby Isaac         PetscInt  vPerm = perm[v];
21036f5f1567SToby Isaac         PetscInt  kParent;
2104c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
21056f5f1567SToby Isaac 
21065f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeParent(K,v,&kParent,NULL));
21076f5f1567SToby Isaac         if (kParent != v) {
21086f5f1567SToby Isaac           /* this is a new vertex */
21095f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetOffset(vSection,vPerm,&off));
21109bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off+l]);
2111367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
21129bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset+l] = newCoord[l];
21136f5f1567SToby Isaac           offset += dim;
21146f5f1567SToby Isaac         }
21156f5f1567SToby Isaac       }
21165f80ce2aSJacob Faibussowitsch       CHKERRQ(VecRestoreArray(coords,&coordvals));
21176f5f1567SToby Isaac     }
21186f5f1567SToby Isaac 
21196f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
21206f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
21216f5f1567SToby Isaac       PetscInt tmp;
21226f5f1567SToby Isaac 
21236f5f1567SToby Isaac       tmp = pNewCount[d];
21246f5f1567SToby Isaac       pNewCount[d] = pNewCount[dim - d];
21256f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
21266f5f1567SToby Isaac     }
21276f5f1567SToby Isaac 
21285f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexCreateFromDAG(*ncdm,dim,pNewCount,newConeSizes,newCones,newOrientations,newVertexCoords));
21295f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetReferenceTree(*ncdm,K));
21305f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetTree(*ncdm,parentSection,parents,childIDs));
21316f5f1567SToby Isaac 
21326f5f1567SToby Isaac     /* clean up */
21335f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure));
21345f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree5(pNewCount,pNewStart,pNewEnd,pOldStart,pOldEnd));
21355f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(newConeSizes));
21365f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree2(newCones,newOrientations));
21375f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(newVertexCoords));
21385f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree2(parents,childIDs));
21395f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree4(Kembedding,perm,iperm,preOrient));
21406f5f1567SToby Isaac   }
21416f5f1567SToby Isaac   else {
21426f5f1567SToby Isaac     PetscInt    p, counts[4];
21436f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
21446f5f1567SToby Isaac     Vec         coordVec;
21456f5f1567SToby Isaac     PetscScalar *coords;
21466f5f1567SToby Isaac 
21476f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
21486f5f1567SToby Isaac       PetscInt dStart, dEnd;
21496f5f1567SToby Isaac 
21505f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetDepthStratum(dm,d,&dStart,&dEnd));
21516f5f1567SToby Isaac       counts[d] = dEnd - dStart;
21526f5f1567SToby Isaac     }
21535f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(pEnd-pStart,&coneSizes));
21546f5f1567SToby Isaac     for (p = pStart; p < pEnd; p++) {
21555f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetConeSize(dm,p,&coneSizes[p-pStart]));
21566f5f1567SToby Isaac     }
21575f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCones(dm, &cones));
21585f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeOrientations(dm, &orientations));
21595f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinatesLocal(dm,&coordVec));
21605f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArray(coordVec,&coords));
21616f5f1567SToby Isaac 
21625f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetChart(parentSection,pStart,pEnd));
21635f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetUp(parentSection));
21645f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexCreateFromDAG(*ncdm,dim,counts,coneSizes,cones,orientations,NULL));
21655f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetReferenceTree(*ncdm,K));
21665f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetTree(*ncdm,parentSection,NULL,NULL));
21675f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArray(coordVec,&coords));
21686f5f1567SToby Isaac   }
21695f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&parentSection));
21706f5f1567SToby Isaac 
21716f5f1567SToby Isaac   PetscFunctionReturn(0);
21726f5f1567SToby Isaac }
21736ecaa68aSToby Isaac 
21746ecaa68aSToby Isaac PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
21756ecaa68aSToby Isaac {
21766ecaa68aSToby Isaac   PetscSF           coarseToFineEmbedded;
21776ecaa68aSToby Isaac   PetscSection      globalCoarse, globalFine;
21786ecaa68aSToby Isaac   PetscSection      localCoarse, localFine;
21796ecaa68aSToby Isaac   PetscSection      aSec, cSec;
21806ecaa68aSToby Isaac   PetscSection      rootIndicesSec, rootMatricesSec;
218146bdb399SToby Isaac   PetscSection      leafIndicesSec, leafMatricesSec;
218246bdb399SToby Isaac   PetscInt          *rootIndices, *leafIndices;
218346bdb399SToby Isaac   PetscScalar       *rootMatrices, *leafMatrices;
21846ecaa68aSToby Isaac   IS                aIS;
21856ecaa68aSToby Isaac   const PetscInt    *anchors;
21866ecaa68aSToby Isaac   Mat               cMat;
21874acb8e1eSToby Isaac   PetscInt          numFields, maxFields;
21886ecaa68aSToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p;
21896ecaa68aSToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
21901c58ffc4SToby Isaac   PetscInt          *maxChildIds;
2191e44e4e7fSToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
21924acb8e1eSToby Isaac   const PetscInt    ***perms;
21934acb8e1eSToby Isaac   const PetscScalar ***flips;
21946ecaa68aSToby Isaac 
21956ecaa68aSToby Isaac   PetscFunctionBegin;
21965f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(coarse,&pStartC,&pEndC));
21975f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(fine,&pStartF,&pEndF));
21985f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(fine,&globalFine));
21996ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
220089698031SToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
220189698031SToby Isaac     const PetscInt *leaves;
22026ecaa68aSToby Isaac 
22035f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL));
220489698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
220589698031SToby Isaac       p = leaves ? leaves[l] : l;
22065f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalFine,p,&dof));
22075f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetConstraintDof(globalFine,p,&cdof));
22086ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
22096ecaa68aSToby Isaac         numPointsWithDofs++;
22106ecaa68aSToby Isaac       }
22116ecaa68aSToby Isaac     }
22125f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
22137cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
221489698031SToby Isaac       p = leaves ? leaves[l] : l;
22155f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalFine,p,&dof));
22165f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetConstraintDof(globalFine,p,&cdof));
22176ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
221889698031SToby Isaac         pointsWithDofs[offset++] = l;
22196ecaa68aSToby Isaac       }
22206ecaa68aSToby Isaac     }
22215f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
22225f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(pointsWithDofs));
22236ecaa68aSToby Isaac   }
22246ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
22255f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEndC-pStartC,&maxChildIds));
22266ecaa68aSToby Isaac   for (p = pStartC; p < pEndC; p++) {
22278d2f55e7SToby Isaac     maxChildIds[p - pStartC] = -2;
22286ecaa68aSToby Isaac   }
22295f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX));
22305f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX));
223146bdb399SToby Isaac 
22325f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(coarse,&localCoarse));
22335f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(coarse,&globalCoarse));
223446bdb399SToby Isaac 
22355f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetAnchors(coarse,&aSec,&aIS));
22365f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(aIS,&anchors));
22375f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(aSec,&aStart,&aEnd));
223846bdb399SToby Isaac 
22395f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(coarse,&cSec,&cMat,NULL));
22405f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(cSec,&cStart,&cEnd));
224146bdb399SToby Isaac 
224246bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
22435f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec));
22445f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootMatricesSec));
22455f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(rootIndicesSec,pStartC,pEndC));
22465f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(rootMatricesSec,pStartC,pEndC));
22475f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetNumFields(localCoarse,&numFields));
2248713c1c5dSToby Isaac   maxFields = PetscMax(1,numFields);
22495f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc7(maxFields+1,&offsets,maxFields+1,&offsetsCopy,maxFields+1,&newOffsets,maxFields+1,&newOffsetsCopy,maxFields+1,&rowOffsets,maxFields+1,&numD,maxFields+1,&numO));
22505f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(maxFields+1,(PetscInt****)&perms,maxFields+1,(PetscScalar****)&flips));
22515f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMemzero((void *) perms, (maxFields+1) * sizeof(const PetscInt **)));
22525f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMemzero((void *) flips, (maxFields+1) * sizeof(const PetscScalar **)));
225346bdb399SToby Isaac 
225446bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
22558d2f55e7SToby Isaac     PetscInt dof, matSize   = 0;
22566ecaa68aSToby Isaac     PetscInt aDof           = 0;
22576ecaa68aSToby Isaac     PetscInt cDof           = 0;
22586ecaa68aSToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
22596ecaa68aSToby Isaac     PetscInt numRowIndices  = 0;
22606ecaa68aSToby Isaac     PetscInt numColIndices  = 0;
2261f13f9184SToby Isaac     PetscInt f;
22626ecaa68aSToby Isaac 
22635f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(globalCoarse,p,&dof));
22641cfc5b76SToby Isaac     if (dof < 0) {
22651cfc5b76SToby Isaac       dof = -(dof + 1);
22661cfc5b76SToby Isaac     }
22676ecaa68aSToby Isaac     if (p >= aStart && p < aEnd) {
22685f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(aSec,p,&aDof));
22696ecaa68aSToby Isaac     }
22706ecaa68aSToby Isaac     if (p >= cStart && p < cEnd) {
22715f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(cSec,p,&cDof));
22726ecaa68aSToby Isaac     }
2273f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2274f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
22756ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2276f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
22776ecaa68aSToby Isaac 
22785f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
227946bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
22806ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
22816ecaa68aSToby Isaac 
22825f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(localCoarse,c,&clDof));
22836ecaa68aSToby Isaac         numRowIndices += clDof;
22846ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
22855f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(localCoarse,c,f,&clDof));
22866ecaa68aSToby Isaac           offsets[f + 1] += clDof;
22876ecaa68aSToby Isaac         }
22886ecaa68aSToby Isaac       }
22896ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
22906ecaa68aSToby Isaac         offsets[f + 1]   += offsets[f];
22916ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
22926ecaa68aSToby Isaac       }
229346bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
22945f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,NULL,NULL,NULL,&numColIndices,NULL,NULL,newOffsets,PETSC_FALSE));
22955f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
22966ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
22976ecaa68aSToby Isaac         numColIndices = numRowIndices;
22986ecaa68aSToby Isaac         matSize = 0;
22996ecaa68aSToby Isaac       }
230046bdb399SToby Isaac       else if (numFields) { /* we send one submat for each field: sum their sizes */
23016ecaa68aSToby Isaac         matSize = 0;
23026ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23036ecaa68aSToby Isaac           PetscInt numRow, numCol;
23046ecaa68aSToby Isaac 
23056ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2306f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
23076ecaa68aSToby Isaac           matSize += numRow * numCol;
23086ecaa68aSToby Isaac         }
23096ecaa68aSToby Isaac       }
23106ecaa68aSToby Isaac       else {
23116ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
23126ecaa68aSToby Isaac       }
2313f13f9184SToby Isaac     } else if (maxChildId == -1) {
23148d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2315f13f9184SToby Isaac         PetscInt aOff, a;
23166ecaa68aSToby Isaac 
23175f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(aSec,p,&aOff));
23186ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23196ecaa68aSToby Isaac           PetscInt fDof;
23206ecaa68aSToby Isaac 
23215f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
232221968bf8SToby Isaac           offsets[f+1] = fDof;
23236ecaa68aSToby Isaac         }
23246ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
23256ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
23266ecaa68aSToby Isaac 
23275f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(localCoarse,anchor,&aLocalDof));
23286ecaa68aSToby Isaac           numColIndices += aLocalDof;
23296ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23306ecaa68aSToby Isaac             PetscInt fDof;
23316ecaa68aSToby Isaac 
23325f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof));
233321968bf8SToby Isaac             newOffsets[f+1] += fDof;
23346ecaa68aSToby Isaac           }
23356ecaa68aSToby Isaac         }
23366ecaa68aSToby Isaac         if (numFields) {
23376ecaa68aSToby Isaac           matSize = 0;
23386ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
233921968bf8SToby Isaac             matSize += offsets[f+1] * newOffsets[f+1];
23406ecaa68aSToby Isaac           }
23416ecaa68aSToby Isaac         }
23426ecaa68aSToby Isaac         else {
23436ecaa68aSToby Isaac           matSize = numColIndices * dof;
23446ecaa68aSToby Isaac         }
23456ecaa68aSToby Isaac       }
23466ecaa68aSToby Isaac       else { /* no children, and no constraints on dofs: just get the global indices */
23476ecaa68aSToby Isaac         numColIndices = dof;
23486ecaa68aSToby Isaac         matSize       = 0;
23496ecaa68aSToby Isaac       }
23508d2f55e7SToby Isaac     }
235146bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
23525f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetDof(rootIndicesSec,p,numColIndices ? numColIndices+2*numFields : 0));
23535f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetDof(rootMatricesSec,p,matSize));
23546ecaa68aSToby Isaac   }
23555f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(rootIndicesSec));
23565f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(rootMatricesSec));
23576ecaa68aSToby Isaac   {
23586ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
23596ecaa68aSToby Isaac 
23605f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices));
23615f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(rootMatricesSec,&numRootMatrices));
23625f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc2(numRootIndices,&rootIndices,numRootMatrices,&rootMatrices));
23636ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
23646ecaa68aSToby Isaac       PetscInt    numRowIndices, numColIndices, matSize, dof;
2365f13f9184SToby Isaac       PetscInt    pIndOff, pMatOff, f;
23666ecaa68aSToby Isaac       PetscInt    *pInd;
23676ecaa68aSToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
23686ecaa68aSToby Isaac       PetscScalar *pMat = NULL;
23696ecaa68aSToby Isaac 
23705f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(rootIndicesSec,p,&numColIndices));
23716ecaa68aSToby Isaac       if (!numColIndices) {
23726ecaa68aSToby Isaac         continue;
23736ecaa68aSToby Isaac       }
2374f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2375f13f9184SToby Isaac         offsets[f]        = 0;
2376f13f9184SToby Isaac         newOffsets[f]     = 0;
2377f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2378f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2379f13f9184SToby Isaac       }
23806ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
23815f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(rootIndicesSec,p,&pIndOff));
23826ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
23835f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(rootMatricesSec,p,&matSize));
23846ecaa68aSToby Isaac       if (matSize) {
23855f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(rootMatricesSec,p,&pMatOff));
23866ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
23876ecaa68aSToby Isaac       }
23885f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalCoarse,p,&dof));
23891cfc5b76SToby Isaac       if (dof < 0) {
23901cfc5b76SToby Isaac         dof = -(dof + 1);
23911cfc5b76SToby Isaac       }
23926ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
23936ecaa68aSToby Isaac         PetscInt i, j;
23946ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
23956ecaa68aSToby Isaac 
23966ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
23976ecaa68aSToby Isaac           PetscInt numIndices, *indices;
23985f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetClosureIndices(coarse,localCoarse,globalCoarse,p,PETSC_TRUE,&numIndices,&indices,offsets,NULL));
23992c71b3e2SJacob Faibussowitsch           PetscCheckFalse(numIndices != numColIndices,PETSC_COMM_SELF,PETSC_ERR_PLIB,"mismatching constraint indices calculations");
24006ecaa68aSToby Isaac           for (i = 0; i < numColIndices; i++) {
24016ecaa68aSToby Isaac             pInd[i] = indices[i];
24026ecaa68aSToby Isaac           }
24036ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
240446bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i+1];
240546bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i+1];
24066ecaa68aSToby Isaac           }
24075f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexRestoreClosureIndices(coarse,localCoarse,globalCoarse,p,PETSC_TRUE,&numIndices,&indices,offsets,NULL));
24086ecaa68aSToby Isaac         }
24096ecaa68aSToby Isaac         else {
24106ecaa68aSToby Isaac           PetscInt closureSize, *closure = NULL, cl;
24116ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
24126ecaa68aSToby Isaac           PetscInt numPoints,*points;
24136ecaa68aSToby Isaac 
24145f80ce2aSJacob Faibussowitsch           CHKERRQ(DMGetWorkArray(coarse,numRowIndices * numRowIndices,MPIU_SCALAR,&pMatIn));
24156ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
24166ecaa68aSToby Isaac             for (j = 0; j < numRowIndices; j++) {
24176ecaa68aSToby Isaac               pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
24186ecaa68aSToby Isaac             }
24196ecaa68aSToby Isaac           }
24205f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
24214acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24225f80ce2aSJacob Faibussowitsch             if (numFields) CHKERRQ(PetscSectionGetFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]));
24235f80ce2aSJacob Faibussowitsch             else           CHKERRQ(PetscSectionGetPointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]));
24244acb8e1eSToby Isaac           }
24256ecaa68aSToby Isaac           if (numFields) {
24266ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
24276ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
24286ecaa68aSToby Isaac 
24296ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
24306ecaa68aSToby Isaac                 PetscInt fDof;
24316ecaa68aSToby Isaac 
24325f80ce2aSJacob Faibussowitsch                 CHKERRQ(PetscSectionGetFieldDof(localCoarse,c,f,&fDof));
24336ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
24346ecaa68aSToby Isaac               }
24356ecaa68aSToby Isaac             }
24366ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
24376ecaa68aSToby Isaac               offsets[f + 1]   += offsets[f];
24386ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
24396ecaa68aSToby Isaac             }
24406ecaa68aSToby Isaac           }
24414acb8e1eSToby Isaac           /* TODO : flips here ? */
24426ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
24435f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,perms,pMatIn,&numPoints,NULL,&points,&pMatModified,newOffsets,PETSC_FALSE));
24444acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24455f80ce2aSJacob Faibussowitsch             if (numFields) CHKERRQ(PetscSectionRestoreFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]));
24465f80ce2aSJacob Faibussowitsch             else           CHKERRQ(PetscSectionRestorePointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]));
24474acb8e1eSToby Isaac           }
24484acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24495f80ce2aSJacob Faibussowitsch             if (numFields) CHKERRQ(PetscSectionGetFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]));
24505f80ce2aSJacob Faibussowitsch             else           CHKERRQ(PetscSectionGetPointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]));
24514acb8e1eSToby Isaac           }
24526ecaa68aSToby Isaac           if (!numFields) {
24536ecaa68aSToby Isaac             for (i = 0; i < numRowIndices * numColIndices; i++) {
24546ecaa68aSToby Isaac               pMat[i] = pMatModified[i];
24556ecaa68aSToby Isaac             }
24566ecaa68aSToby Isaac           }
24576ecaa68aSToby Isaac           else {
2458f13f9184SToby Isaac             PetscInt i, j, count;
24596ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
24606ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f+1]; i++) {
24616ecaa68aSToby Isaac                 for (j = newOffsets[f]; j < newOffsets[f+1]; j++, count++) {
24626ecaa68aSToby Isaac                   pMat[count] = pMatModified[i * numColIndices + j];
24636ecaa68aSToby Isaac                 }
24646ecaa68aSToby Isaac               }
24656ecaa68aSToby Isaac             }
24666ecaa68aSToby Isaac           }
24675f80ce2aSJacob Faibussowitsch           CHKERRQ(DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatModified));
24685f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
24695f80ce2aSJacob Faibussowitsch           CHKERRQ(DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatIn));
24706ecaa68aSToby Isaac           if (numFields) {
247146bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
247246bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f+1];
247346bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f+1];
24746ecaa68aSToby Isaac             }
24754acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
24764acb8e1eSToby Isaac               PetscInt globalOff, c = points[2*cl];
24775f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscSectionGetOffset(globalCoarse, c, &globalOff));
24785f80ce2aSJacob Faibussowitsch               CHKERRQ(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
24796ecaa68aSToby Isaac             }
24806ecaa68aSToby Isaac           } else {
24814acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
24824acb8e1eSToby Isaac               PetscInt c = points[2*cl], globalOff;
24834acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
24844acb8e1eSToby Isaac 
24855f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscSectionGetOffset(globalCoarse, c, &globalOff));
24865f80ce2aSJacob Faibussowitsch               CHKERRQ(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
24876ecaa68aSToby Isaac             }
24886ecaa68aSToby Isaac           }
24894acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24905f80ce2aSJacob Faibussowitsch             if (numFields) CHKERRQ(PetscSectionRestoreFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]));
24915f80ce2aSJacob Faibussowitsch             else           CHKERRQ(PetscSectionRestorePointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]));
24924acb8e1eSToby Isaac           }
24935f80ce2aSJacob Faibussowitsch           CHKERRQ(DMRestoreWorkArray(coarse,numPoints,MPIU_SCALAR,&points));
24946ecaa68aSToby Isaac         }
24956ecaa68aSToby Isaac       }
24966ecaa68aSToby Isaac       else if (matSize) {
24976ecaa68aSToby Isaac         PetscInt cOff;
24986ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
24996ecaa68aSToby Isaac 
25006ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
25012c71b3e2SJacob Faibussowitsch         PetscCheckFalse(numRowIndices != dof,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Miscounted dofs");
25025f80ce2aSJacob Faibussowitsch         CHKERRQ(DMGetWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices));
25035f80ce2aSJacob Faibussowitsch         CHKERRQ(DMGetWorkArray(coarse,numColIndices,MPIU_INT,&colIndices));
25045f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(cSec,p,&cOff));
25055f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(aSec,p,&aDof));
25065f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(aSec,p,&aOff));
25076ecaa68aSToby Isaac         if (numFields) {
25086ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25096ecaa68aSToby Isaac             PetscInt fDof;
2510f13f9184SToby Isaac 
25115f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldDof(cSec,p,f,&fDof));
25126ecaa68aSToby Isaac             offsets[f + 1] = fDof;
25136ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
25146ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
25155f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof));
25166ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
25176ecaa68aSToby Isaac             }
25186ecaa68aSToby Isaac           }
25196ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25206ecaa68aSToby Isaac             offsets[f + 1]       += offsets[f];
25216ecaa68aSToby Isaac             offsetsCopy[f + 1]    = offsets[f + 1];
25226ecaa68aSToby Isaac             newOffsets[f + 1]    += newOffsets[f];
25236ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
25246ecaa68aSToby Isaac           }
25255f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetIndicesPointFields_Internal(cSec,PETSC_TRUE,p,cOff,offsetsCopy,PETSC_TRUE,NULL,-1, NULL,rowIndices));
25266ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25276ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25285f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetOffset(localCoarse,anchor,&lOff));
25295f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_TRUE,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL,-1, NULL,colIndices));
25306ecaa68aSToby Isaac           }
25316ecaa68aSToby Isaac         }
25326ecaa68aSToby Isaac         else {
25335f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetIndicesPoint_Internal(cSec,PETSC_TRUE,p,cOff,offsetsCopy,PETSC_TRUE,NULL, NULL,rowIndices));
25346ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25356ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25365f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetOffset(localCoarse,anchor,&lOff));
25375f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_TRUE,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL, NULL,colIndices));
25386ecaa68aSToby Isaac           }
25396ecaa68aSToby Isaac         }
25406ecaa68aSToby Isaac         if (numFields) {
2541f13f9184SToby Isaac           PetscInt count, a;
2542f13f9184SToby Isaac 
25436ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
25446ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
25456ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
25465f80ce2aSJacob Faibussowitsch             CHKERRQ(MatGetValues(cMat,iSize,&rowIndices[offsets[f]],jSize,&colIndices[newOffsets[f]],&pMat[count]));
25476ecaa68aSToby Isaac             count += iSize * jSize;
254846bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
254946bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f+1];
25506ecaa68aSToby Isaac           }
25516ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25526ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25536ecaa68aSToby Isaac             PetscInt gOff;
25545f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetOffset(globalCoarse,anchor,&gOff));
25555f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL,-1, NULL,pInd));
25566ecaa68aSToby Isaac           }
25576ecaa68aSToby Isaac         }
25586ecaa68aSToby Isaac         else {
25596ecaa68aSToby Isaac           PetscInt a;
25605f80ce2aSJacob Faibussowitsch           CHKERRQ(MatGetValues(cMat,numRowIndices,rowIndices,numColIndices,colIndices,pMat));
25616ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25626ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25636ecaa68aSToby Isaac             PetscInt gOff;
25645f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetOffset(globalCoarse,anchor,&gOff));
25655f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL, NULL,pInd));
25666ecaa68aSToby Isaac           }
25676ecaa68aSToby Isaac         }
25685f80ce2aSJacob Faibussowitsch         CHKERRQ(DMRestoreWorkArray(coarse,numColIndices,MPIU_INT,&colIndices));
25695f80ce2aSJacob Faibussowitsch         CHKERRQ(DMRestoreWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices));
25706ecaa68aSToby Isaac       }
25716ecaa68aSToby Isaac       else {
25726ecaa68aSToby Isaac         PetscInt gOff;
25736ecaa68aSToby Isaac 
25745f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(globalCoarse,p,&gOff));
25756ecaa68aSToby Isaac         if (numFields) {
25766ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25776ecaa68aSToby Isaac             PetscInt fDof;
25785f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
25796ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
25806ecaa68aSToby Isaac           }
25816ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
258246bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
258346bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f+1];
25846ecaa68aSToby Isaac           }
25855f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1, NULL,pInd));
2586367003a6SStefano Zampini         } else {
25875f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL, NULL,pInd));
25886ecaa68aSToby Isaac         }
25896ecaa68aSToby Isaac       }
25906ecaa68aSToby Isaac     }
25915f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(maxChildIds));
25926ecaa68aSToby Isaac   }
259346bdb399SToby Isaac   {
259446bdb399SToby Isaac     PetscSF  indicesSF, matricesSF;
259546bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
259646bdb399SToby Isaac 
25975f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec));
25985f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafMatricesSec));
25995f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDistributeSection(coarseToFineEmbedded,rootIndicesSec,&remoteOffsetsIndices,leafIndicesSec));
26005f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDistributeSection(coarseToFineEmbedded,rootMatricesSec,&remoteOffsetsMatrices,leafMatricesSec));
26015f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreateSectionSF(coarseToFineEmbedded,rootIndicesSec,remoteOffsetsIndices,leafIndicesSec,&indicesSF));
26025f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreateSectionSF(coarseToFineEmbedded,rootMatricesSec,remoteOffsetsMatrices,leafMatricesSec,&matricesSF));
26035f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&coarseToFineEmbedded));
26045f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(remoteOffsetsIndices));
26055f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(remoteOffsetsMatrices));
26065f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(leafIndicesSec,&numLeafIndices));
26075f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(leafMatricesSec,&numLeafMatrices));
26085f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc2(numLeafIndices,&leafIndices,numLeafMatrices,&leafMatrices));
26095f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastBegin(indicesSF,MPIU_INT,rootIndices,leafIndices,MPI_REPLACE));
26105f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastBegin(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices,MPI_REPLACE));
26115f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastEnd(indicesSF,MPIU_INT,rootIndices,leafIndices,MPI_REPLACE));
26125f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastEnd(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices,MPI_REPLACE));
26135f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&matricesSF));
26145f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&indicesSF));
26155f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree2(rootIndices,rootMatrices));
26165f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&rootIndicesSec));
26175f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&rootMatricesSec));
261846bdb399SToby Isaac   }
261946bdb399SToby Isaac   /* count to preallocate */
26205f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(fine,&localFine));
262146bdb399SToby Isaac   {
262246bdb399SToby Isaac     PetscInt    nGlobal;
262346bdb399SToby Isaac     PetscInt    *dnnz, *onnz;
2624b9a5774bSToby Isaac     PetscLayout rowMap, colMap;
2625b9a5774bSToby Isaac     PetscInt    rowStart, rowEnd, colStart, colEnd;
26261c58ffc4SToby Isaac     PetscInt    maxDof;
26271c58ffc4SToby Isaac     PetscInt    *rowIndices;
26281c58ffc4SToby Isaac     DM           refTree;
26291c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
26301c58ffc4SToby Isaac     PetscScalar  ***refPointFieldMats;
26311c58ffc4SToby Isaac     PetscSection refConSec, refAnSec;
26320eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,maxConDof,maxColumns,leafStart,leafEnd;
26331c58ffc4SToby Isaac     PetscScalar  *pointWork;
263446bdb399SToby Isaac 
26355f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetConstrainedStorageSize(globalFine,&nGlobal));
26365f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc2(nGlobal,&dnnz,nGlobal,&onnz));
26375f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetLayouts(mat,&rowMap,&colMap));
26385f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLayoutSetUp(rowMap));
26395f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLayoutSetUp(colMap));
26405f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLayoutGetRange(rowMap,&rowStart,&rowEnd));
26415f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLayoutGetRange(colMap,&colStart,&colEnd));
26425f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetMaxDof(localFine,&maxDof));
26435f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetChart(leafIndicesSec,&leafStart,&leafEnd));
26445f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
26450eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
264646bdb399SToby Isaac       PetscInt    gDof, gcDof, gOff;
264746bdb399SToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
264846bdb399SToby Isaac       PetscInt    matSize;
264921968bf8SToby Isaac       PetscInt    i;
265046bdb399SToby Isaac 
26515f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalFine,p,&gDof));
26525f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetConstraintDof(globalFine,p,&gcDof));
265346bdb399SToby Isaac       if ((gDof - gcDof) <= 0) {
265446bdb399SToby Isaac         continue;
265546bdb399SToby Isaac       }
26565f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(globalFine,p,&gOff));
26572c71b3e2SJacob Faibussowitsch       PetscCheckFalse(gOff < 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"I though having global dofs meant a non-negative offset");
26582c71b3e2SJacob Faibussowitsch       PetscCheckFalse((gOff < rowStart) || ((gOff + gDof - gcDof) > rowEnd),PETSC_COMM_SELF,PETSC_ERR_PLIB,"I thought the row map would constrain the global dofs");
26595f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(leafIndicesSec,p,&numColIndices));
26605f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(leafIndicesSec,p,&pIndOff));
266146bdb399SToby Isaac       numColIndices -= 2 * numFields;
26622c71b3e2SJacob Faibussowitsch       PetscCheckFalse(numColIndices <= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"global fine dof with no dofs to interpolate from");
266346bdb399SToby Isaac       pInd = &leafIndices[pIndOff];
266421968bf8SToby Isaac       offsets[0]        = 0;
266521968bf8SToby Isaac       offsetsCopy[0]    = 0;
266621968bf8SToby Isaac       newOffsets[0]     = 0;
266721968bf8SToby Isaac       newOffsetsCopy[0] = 0;
266846bdb399SToby Isaac       if (numFields) {
266921968bf8SToby Isaac         PetscInt f;
267046bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
267146bdb399SToby Isaac           PetscInt rowDof;
267246bdb399SToby Isaac 
26735f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(localFine,p,f,&rowDof));
267421968bf8SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
267521968bf8SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
267621968bf8SToby Isaac           newOffsets[f + 1]     = pInd[numColIndices + numFields + f];
267721968bf8SToby Isaac           numD[f] = 0;
267821968bf8SToby Isaac           numO[f] = 0;
267946bdb399SToby Isaac         }
26805f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,rowIndices));
268146bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
268221968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
268321968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
268446bdb399SToby Isaac 
268546bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
268646bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
268746bdb399SToby Isaac 
268846bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
268921968bf8SToby Isaac               numD[f]++;
269046bdb399SToby Isaac             }
269146bdb399SToby Isaac             else if (gInd >= 0) { /* negative means non-entry */
269221968bf8SToby Isaac               numO[f]++;
269346bdb399SToby Isaac             }
269446bdb399SToby Isaac           }
269546bdb399SToby Isaac         }
269646bdb399SToby Isaac       }
269746bdb399SToby Isaac       else {
26985f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,rowIndices));
269921968bf8SToby Isaac         numD[0] = 0;
270021968bf8SToby Isaac         numO[0] = 0;
270146bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
270246bdb399SToby Isaac           PetscInt gInd = pInd[i];
270346bdb399SToby Isaac 
270446bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
270521968bf8SToby Isaac             numD[0]++;
270646bdb399SToby Isaac           }
270746bdb399SToby Isaac           else if (gInd >= 0) { /* negative means non-entry */
270821968bf8SToby Isaac             numO[0]++;
270946bdb399SToby Isaac           }
271046bdb399SToby Isaac         }
271146bdb399SToby Isaac       }
27125f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(leafMatricesSec,p,&matSize));
271346bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
271446bdb399SToby Isaac         PetscInt childId;
271546bdb399SToby Isaac 
271646bdb399SToby Isaac         childId = childIds[p-pStartF];
271721968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
271846bdb399SToby Isaac           if (numFields) {
2719b9a5774bSToby Isaac             PetscInt f;
2720b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
272121968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
272246bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
272321968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
272421968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
272546bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
27262c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2727b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
272846bdb399SToby Isaac                 }
272946bdb399SToby Isaac                 else if (gIndCoarse >= 0) { /* remote */
27302c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2731b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
273246bdb399SToby Isaac                 }
273346bdb399SToby Isaac                 else { /* constrained */
27342c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(gIndFine >= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
273546bdb399SToby Isaac                 }
273646bdb399SToby Isaac               }
273746bdb399SToby Isaac             }
273846bdb399SToby Isaac           }
273946bdb399SToby Isaac           else {
2740b9a5774bSToby Isaac             PetscInt i;
2741b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
274246bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
274346bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
274446bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
27452c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2746b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
274746bdb399SToby Isaac               }
274846bdb399SToby Isaac               else if (gIndCoarse >= 0) { /* remote */
27492c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2750b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
275146bdb399SToby Isaac               }
275246bdb399SToby Isaac               else { /* constrained */
27532c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine >= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
275446bdb399SToby Isaac               }
275546bdb399SToby Isaac             }
275646bdb399SToby Isaac           }
275746bdb399SToby Isaac         }
275846bdb399SToby Isaac         else { /* interpolate from all */
275946bdb399SToby Isaac           if (numFields) {
2760b9a5774bSToby Isaac             PetscInt f;
2761b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
276221968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
276346bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
276421968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
276546bdb399SToby Isaac                 if (gIndFine >= 0) {
27662c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2767b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2768b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
276946bdb399SToby Isaac                 }
277046bdb399SToby Isaac               }
277146bdb399SToby Isaac             }
277246bdb399SToby Isaac           }
277346bdb399SToby Isaac           else {
2774b9a5774bSToby Isaac             PetscInt i;
2775b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
277646bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
277746bdb399SToby Isaac               if (gIndFine >= 0) {
27782c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2779b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2780b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
278146bdb399SToby Isaac               }
278246bdb399SToby Isaac             }
278346bdb399SToby Isaac           }
278446bdb399SToby Isaac         }
278546bdb399SToby Isaac       }
278646bdb399SToby Isaac       else { /* interpolate from all */
278746bdb399SToby Isaac         if (numFields) {
2788b9a5774bSToby Isaac           PetscInt f;
2789b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
279021968bf8SToby Isaac             PetscInt numRows = offsets[f+1] - offsets[f], row;
279146bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
279221968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
279346bdb399SToby Isaac               if (gIndFine >= 0) {
27942c71b3e2SJacob Faibussowitsch                 PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2795b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2796b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
279746bdb399SToby Isaac               }
279846bdb399SToby Isaac             }
279946bdb399SToby Isaac           }
280046bdb399SToby Isaac         }
280146bdb399SToby Isaac         else { /* every dof get a full row */
2802b9a5774bSToby Isaac           PetscInt i;
2803b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
280446bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
280546bdb399SToby Isaac             if (gIndFine >= 0) {
28062c71b3e2SJacob Faibussowitsch               PetscCheckFalse(gIndFine < rowStart || gIndFine >= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2807b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2808b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
280946bdb399SToby Isaac             }
281046bdb399SToby Isaac           }
281146bdb399SToby Isaac         }
281246bdb399SToby Isaac       }
281346bdb399SToby Isaac     }
28145f80ce2aSJacob Faibussowitsch     CHKERRQ(MatXAIJSetPreallocation(mat,1,dnnz,onnz,NULL,NULL));
28155f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree2(dnnz,onnz));
281621968bf8SToby Isaac 
28175f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetReferenceTree(fine,&refTree));
28185f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
28195f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
28205f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetAnchors(refTree,&refAnSec,NULL));
28215f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
28225f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetMaxDof(refConSec,&maxConDof));
28235f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetMaxDof(leafIndicesSec,&maxColumns));
28245f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(maxConDof*maxColumns,&pointWork));
28250eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2826e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2827e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2828e44e4e7fSToby Isaac       PetscInt matSize;
2829e44e4e7fSToby Isaac       PetscInt childId;
2830e44e4e7fSToby Isaac 
28315f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalFine,p,&gDof));
28325f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetConstraintDof(globalFine,p,&gcDof));
2833e44e4e7fSToby Isaac       if ((gDof - gcDof) <= 0) {
2834e44e4e7fSToby Isaac         continue;
2835e44e4e7fSToby Isaac       }
2836e44e4e7fSToby Isaac       childId = childIds[p-pStartF];
28375f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(globalFine,p,&gOff));
28385f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(leafIndicesSec,p,&numColIndices));
28395f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(leafIndicesSec,p,&pIndOff));
2840e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2841e44e4e7fSToby Isaac       pInd = &leafIndices[pIndOff];
2842e44e4e7fSToby Isaac       offsets[0]        = 0;
2843e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2844e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2845e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2846e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2847e44e4e7fSToby Isaac       if (numFields) {
2848e44e4e7fSToby Isaac         PetscInt f;
2849e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2850e44e4e7fSToby Isaac           PetscInt rowDof;
2851e44e4e7fSToby Isaac 
28525f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(localFine,p,f,&rowDof));
2853e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2854e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2855e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2856e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2857e44e4e7fSToby Isaac         }
28585f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,rowIndices));
2859e44e4e7fSToby Isaac       }
28601c58ffc4SToby Isaac       else {
28615f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,rowIndices));
28621c58ffc4SToby Isaac       }
28635f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(leafMatricesSec,p,&matSize));
2864e44e4e7fSToby Isaac       if (!matSize) { /* incoming matrix is identity */
2865e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2866e44e4e7fSToby Isaac           if (numFields) {
2867e44e4e7fSToby Isaac             PetscInt f;
2868e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2869e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
2870e44e4e7fSToby Isaac               for (row = 0; row < numRows; row++) {
28715f80ce2aSJacob Faibussowitsch                 CHKERRQ(MatSetValue(mat,rowIndices[offsets[f]+row],pInd[newOffsets[f]+row],1.,INSERT_VALUES));
287221968bf8SToby Isaac               }
287321968bf8SToby Isaac             }
2874e44e4e7fSToby Isaac           }
2875e44e4e7fSToby Isaac           else {
2876e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
2877e44e4e7fSToby Isaac             for (row = 0; row < numRows; row++) {
28785f80ce2aSJacob Faibussowitsch               CHKERRQ(MatSetValue(mat,rowIndices[row],pInd[row],1.,INSERT_VALUES));
2879e44e4e7fSToby Isaac             }
2880e44e4e7fSToby Isaac           }
2881e44e4e7fSToby Isaac         }
2882e44e4e7fSToby Isaac         else { /* interpolate from all */
2883e44e4e7fSToby Isaac           if (numFields) {
2884e44e4e7fSToby Isaac             PetscInt f;
2885e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2886e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f];
2887e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
28885f80ce2aSJacob Faibussowitsch               CHKERRQ(MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],refPointFieldMats[childId - pRefStart][f],INSERT_VALUES));
2889e44e4e7fSToby Isaac             }
2890e44e4e7fSToby Isaac           }
2891e44e4e7fSToby Isaac           else {
28925f80ce2aSJacob Faibussowitsch             CHKERRQ(MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,refPointFieldMats[childId - pRefStart][0],INSERT_VALUES));
2893e44e4e7fSToby Isaac           }
2894e44e4e7fSToby Isaac         }
2895e44e4e7fSToby Isaac       }
2896e44e4e7fSToby Isaac       else { /* interpolate from all */
2897e44e4e7fSToby Isaac         PetscInt    pMatOff;
2898e44e4e7fSToby Isaac         PetscScalar *pMat;
2899e44e4e7fSToby Isaac 
29005f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(leafMatricesSec,p,&pMatOff));
2901e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2902e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2903e44e4e7fSToby Isaac           if (numFields) {
2904e44e4e7fSToby Isaac             PetscInt f, count;
2905e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2906e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2907e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2908e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2909e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2910e44e4e7fSToby Isaac 
29115f80ce2aSJacob Faibussowitsch               CHKERRQ(MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],inMat,INSERT_VALUES));
2912e44e4e7fSToby Isaac               count += numCols * numInRows;
2913e44e4e7fSToby Isaac             }
2914e44e4e7fSToby Isaac           }
2915e44e4e7fSToby Isaac           else {
29165f80ce2aSJacob Faibussowitsch             CHKERRQ(MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,pMat,INSERT_VALUES));
2917e44e4e7fSToby Isaac           }
2918e44e4e7fSToby Isaac         }
2919e44e4e7fSToby Isaac         else { /* multiply the incoming matrix by the child interpolation */
2920e44e4e7fSToby Isaac           if (numFields) {
2921e44e4e7fSToby Isaac             PetscInt f, count;
2922e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2923e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2924e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2925e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2926e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2927e44e4e7fSToby Isaac               PetscInt i, j, k;
29282c71b3e2SJacob Faibussowitsch               PetscCheckFalse(refPointFieldN[childId - pRefStart][f] != numInRows,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2929e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2930e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2931e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2932e44e4e7fSToby Isaac                   for (k = 0; k < numInRows; k++) {
2933e44e4e7fSToby Isaac                     val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2934e44e4e7fSToby Isaac                   }
2935e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2936e44e4e7fSToby Isaac                 }
2937e44e4e7fSToby Isaac               }
29385f80ce2aSJacob Faibussowitsch               CHKERRQ(MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],pointWork,INSERT_VALUES));
2939e44e4e7fSToby Isaac               count += numCols * numInRows;
2940e44e4e7fSToby Isaac             }
2941e44e4e7fSToby Isaac           }
2942267d4f3fSToby Isaac           else { /* every dof gets a full row */
2943e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2944e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2945e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2946e44e4e7fSToby Isaac             PetscInt i, j, k;
29472c71b3e2SJacob Faibussowitsch             PetscCheckFalse(refPointFieldN[childId - pRefStart][0] != numInRows,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2948e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2949e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2950e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2951e44e4e7fSToby Isaac                 for (k = 0; k < numInRows; k++) {
2952e44e4e7fSToby Isaac                   val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2953e44e4e7fSToby Isaac                 }
2954e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2955e44e4e7fSToby Isaac               }
2956e44e4e7fSToby Isaac             }
29575f80ce2aSJacob Faibussowitsch             CHKERRQ(MatSetValues(mat,numRows,rowIndices,numCols,pInd,pointWork,INSERT_VALUES));
2958e44e4e7fSToby Isaac           }
2959e44e4e7fSToby Isaac         }
2960e44e4e7fSToby Isaac       }
2961e44e4e7fSToby Isaac     }
29625f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
29635f80ce2aSJacob Faibussowitsch     CHKERRQ(DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
29645f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(pointWork));
2965e44e4e7fSToby Isaac   }
29665f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
29675f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
29685f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&leafIndicesSec));
29695f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&leafMatricesSec));
29705f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(leafIndices,leafMatrices));
29715f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(*(PetscInt****)&perms,*(PetscScalar****)&flips));
29725f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO));
29735f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(aIS,&anchors));
29746ecaa68aSToby Isaac   PetscFunctionReturn(0);
29756ecaa68aSToby Isaac }
2976154bca37SToby Isaac 
29778d2f55e7SToby Isaac /*
29788d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
29798d2f55e7SToby Isaac  *
29808d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
29818d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
29828d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
29838d2f55e7SToby Isaac  *       a_{i,j} = 0;
29848d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
29858d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
29868d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
29878d2f55e7SToby Isaac  */
29888d2f55e7SToby Isaac PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
29898d2f55e7SToby Isaac {
29908d2f55e7SToby Isaac   PetscDS        ds;
29918d2f55e7SToby Isaac   PetscSection   section, cSection;
29928d2f55e7SToby Isaac   DMLabel        canonical, depth;
29938d2f55e7SToby Isaac   Mat            cMat, mat;
29948d2f55e7SToby Isaac   PetscInt       *nnz;
29958d2f55e7SToby Isaac   PetscInt       f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
29968d2f55e7SToby Isaac   PetscInt       m, n;
29978d2f55e7SToby Isaac   PetscScalar    *pointScalar;
29988d2f55e7SToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
29998d2f55e7SToby Isaac 
30008d2f55e7SToby Isaac   PetscFunctionBegin;
30015f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(refTree,&section));
30025f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(refTree, &dim));
30035f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc6(dim,&v0,dim,&v0parent,dim,&vtmp,dim*dim,&J,dim*dim,&Jparent,dim*dim,&invJ));
30045f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(dim,&pointScalar,dim,&pointRef));
30055f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(refTree,&ds));
30065f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSGetNumFields(ds,&numFields));
30075f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetNumFields(section,&numSecFields));
30085f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLabel(refTree,"canonical",&canonical));
30095f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLabel(refTree,"depth",&depth));
30105f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(refTree,&cSection,&cMat,NULL));
30115f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(refTree, &pStart, &pEnd));
30125f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
30135f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetSize(cMat,&n,&m)); /* the injector has transpose sizes from the constraint matrix */
30148d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
30155f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc1(m,&nnz));
30168d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) { /* a point will have non-zeros if it is canonical, it has dofs, and its children have dofs */
30178d2f55e7SToby Isaac     const PetscInt *children;
30188d2f55e7SToby Isaac     PetscInt numChildren;
30198d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30208d2f55e7SToby Isaac 
30218d2f55e7SToby Isaac     if (canonical) {
30228d2f55e7SToby Isaac       PetscInt pCanonical;
30235f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelGetValue(canonical,p,&pCanonical));
30248d2f55e7SToby Isaac       if (p != pCanonical) continue;
30258d2f55e7SToby Isaac     }
30265f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeChildren(refTree,p,&numChildren,&children));
30278d2f55e7SToby Isaac     if (!numChildren) continue;
30288d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30298d2f55e7SToby Isaac       PetscInt child = children[i];
30308d2f55e7SToby Isaac       PetscInt dof;
30318d2f55e7SToby Isaac 
30325f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(section,child,&dof));
30338d2f55e7SToby Isaac       numChildDof += dof;
30348d2f55e7SToby Isaac     }
30355f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(section,p,&numSelfDof));
30368d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30378d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
30388d2f55e7SToby Isaac       PetscInt selfOff;
30398d2f55e7SToby Isaac 
30408d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
30418d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
30428d2f55e7SToby Isaac           PetscInt child = children[i];
30438d2f55e7SToby Isaac           PetscInt dof;
30448d2f55e7SToby Isaac 
30455f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(section,child,f,&dof));
30468d2f55e7SToby Isaac           numChildDof += dof;
30478d2f55e7SToby Isaac         }
30485f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldDof(section,p,f,&numSelfDof));
30495f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldOffset(section,p,f,&selfOff));
30508d2f55e7SToby Isaac       }
30518d2f55e7SToby Isaac       else {
30525f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(section,p,&selfOff));
30538d2f55e7SToby Isaac       }
30548d2f55e7SToby Isaac       for (i = 0; i < numSelfDof; i++) {
30558d2f55e7SToby Isaac         nnz[selfOff + i] = numChildDof;
30568d2f55e7SToby Isaac       }
30578d2f55e7SToby Isaac     }
30588d2f55e7SToby Isaac   }
30595f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateAIJ(PETSC_COMM_SELF,m,n,m,n,-1,nnz,-1,NULL,&mat));
30605f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(nnz));
30618d2f55e7SToby Isaac   /* Setp 2: compute entries */
30628d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
30638d2f55e7SToby Isaac     const PetscInt *children;
30648d2f55e7SToby Isaac     PetscInt numChildren;
30658d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30668d2f55e7SToby Isaac 
30678d2f55e7SToby Isaac     /* same conditions about when entries occur */
30688d2f55e7SToby Isaac     if (canonical) {
30698d2f55e7SToby Isaac       PetscInt pCanonical;
30705f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelGetValue(canonical,p,&pCanonical));
30718d2f55e7SToby Isaac       if (p != pCanonical) continue;
30728d2f55e7SToby Isaac     }
30735f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeChildren(refTree,p,&numChildren,&children));
30748d2f55e7SToby Isaac     if (!numChildren) continue;
30758d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30768d2f55e7SToby Isaac       PetscInt child = children[i];
30778d2f55e7SToby Isaac       PetscInt dof;
30788d2f55e7SToby Isaac 
30795f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(section,child,&dof));
30808d2f55e7SToby Isaac       numChildDof += dof;
30818d2f55e7SToby Isaac     }
30825f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(section,p,&numSelfDof));
30838d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30848d2f55e7SToby Isaac 
30858d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
308659fc6756SToby Isaac       PetscInt       pI = -1, cI = -1;
308752a3aeb4SToby Isaac       PetscInt       selfOff, Nc, parentCell;
30888d2f55e7SToby Isaac       PetscInt       cellShapeOff;
30898d2f55e7SToby Isaac       PetscObject    disc;
30908d2f55e7SToby Isaac       PetscDualSpace dsp;
30918d2f55e7SToby Isaac       PetscClassId   classId;
30928d2f55e7SToby Isaac       PetscScalar    *pointMat;
30933b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
30948d2f55e7SToby Isaac       PetscInt       pO = PETSC_MIN_INT;
30958d2f55e7SToby Isaac       const PetscInt *depthNumDof;
30968d2f55e7SToby Isaac 
30978d2f55e7SToby Isaac       if (numSecFields) {
30988d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
30998d2f55e7SToby Isaac           PetscInt child = children[i];
31008d2f55e7SToby Isaac           PetscInt dof;
31018d2f55e7SToby Isaac 
31025f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(section,child,f,&dof));
31038d2f55e7SToby Isaac           numChildDof += dof;
31048d2f55e7SToby Isaac         }
31055f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldDof(section,p,f,&numSelfDof));
31065f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldOffset(section,p,f,&selfOff));
31078d2f55e7SToby Isaac       }
31088d2f55e7SToby Isaac       else {
31095f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(section,p,&selfOff));
31108d2f55e7SToby Isaac       }
31118d2f55e7SToby Isaac 
31123b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
31138d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
31148d2f55e7SToby Isaac         parentCell = p;
31158d2f55e7SToby Isaac       }
31168d2f55e7SToby Isaac       else {
31178d2f55e7SToby Isaac         PetscInt *star = NULL;
31188d2f55e7SToby Isaac         PetscInt numStar;
31198d2f55e7SToby Isaac 
31208d2f55e7SToby Isaac         parentCell = -1;
31215f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star));
31228d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
31238d2f55e7SToby Isaac           PetscInt c = star[2 * i];
31248d2f55e7SToby Isaac 
31258d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
31268d2f55e7SToby Isaac             parentCell = c;
31278d2f55e7SToby Isaac             break;
31288d2f55e7SToby Isaac           }
31298d2f55e7SToby Isaac         }
31305f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star));
31318d2f55e7SToby Isaac       }
3132a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
31335f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDSGetDiscretization(ds,f,&disc));
31345f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectGetClassId(disc,&classId));
3135c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
31365f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscFEGetDualSpace((PetscFE)disc,&dsp));
3137c5356c36SToby Isaac       }
3138c5356c36SToby Isaac       else if (classId == PETSCFV_CLASSID) {
31395f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscFVGetDualSpace((PetscFV)disc,&dsp));
3140c5356c36SToby Isaac       }
3141c5356c36SToby Isaac       else {
31429b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported discretization object");
3143c5356c36SToby Isaac       }
31445f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDualSpaceGetNumDof(dsp,&depthNumDof));
31455f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscDualSpaceGetNumComponents(dsp,&Nc));
31468d2f55e7SToby Isaac       {
31478d2f55e7SToby Isaac         PetscInt *closure = NULL;
31488d2f55e7SToby Isaac         PetscInt numClosure;
31498d2f55e7SToby Isaac 
31505f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure));
315159fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
31528d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
31538d2f55e7SToby Isaac 
31548d2f55e7SToby Isaac           pO = closure[2 * i + 1];
315559fc6756SToby Isaac           if (point == p) {
315659fc6756SToby Isaac             pI = i;
315759fc6756SToby Isaac             break;
315859fc6756SToby Isaac           }
31595f80ce2aSJacob Faibussowitsch           CHKERRQ(DMLabelGetValue(depth,point,&pointDepth));
31608d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
31618d2f55e7SToby Isaac         }
31625f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure));
31638d2f55e7SToby Isaac       }
31648d2f55e7SToby Isaac 
31655f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat));
31665f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows));
316752a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
316852a3aeb4SToby Isaac       for (i = 0; i < numSelfDof; i++) {
316952a3aeb4SToby Isaac         matRows[i] = selfOff + i;
31703b1c2a6aSToby Isaac       }
317152a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
31723b1c2a6aSToby Isaac       {
31733b1c2a6aSToby Isaac         PetscInt colOff = 0;
31743b1c2a6aSToby Isaac 
31753b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
31763b1c2a6aSToby Isaac           PetscInt child = children[i];
31773b1c2a6aSToby Isaac           PetscInt dof, off, j;
31783b1c2a6aSToby Isaac 
31793b1c2a6aSToby Isaac           if (numSecFields) {
31805f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldDof(cSection,child,f,&dof));
31815f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldOffset(cSection,child,f,&off));
31823b1c2a6aSToby Isaac           }
31833b1c2a6aSToby Isaac           else {
31845f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetDof(cSection,child,&dof));
31855f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetOffset(cSection,child,&off));
31863b1c2a6aSToby Isaac           }
31873b1c2a6aSToby Isaac 
318852a3aeb4SToby Isaac           for (j = 0; j < dof; j++) {
318952a3aeb4SToby Isaac             matCols[colOff++] = off + j;
31903b1c2a6aSToby Isaac           }
31913b1c2a6aSToby Isaac         }
31923b1c2a6aSToby Isaac       }
31938d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
31948d2f55e7SToby Isaac         PetscFE        fe = (PetscFE) disc;
31958d2f55e7SToby Isaac         PetscInt       fSize;
319659fc6756SToby Isaac         const PetscInt ***perms;
319759fc6756SToby Isaac         const PetscScalar ***flips;
319859fc6756SToby Isaac         const PetscInt *pperms;
319959fc6756SToby Isaac 
32005f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscFEGetDualSpace(fe,&dsp));
32015f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscDualSpaceGetDimension(dsp,&fSize));
32025f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
320359fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
320452a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
32058d2f55e7SToby Isaac           PetscQuadrature q;
320652a3aeb4SToby Isaac           PetscInt        dim, thisNc, numPoints, j, k;
32078d2f55e7SToby Isaac           const PetscReal *points;
32088d2f55e7SToby Isaac           const PetscReal *weights;
32098d2f55e7SToby Isaac           PetscInt        *closure = NULL;
32108d2f55e7SToby Isaac           PetscInt        numClosure;
321159fc6756SToby Isaac           PetscInt        iCell = pperms ? pperms[i] : i;
321259fc6756SToby Isaac           PetscInt        parentCellShapeDof = cellShapeOff + iCell;
3213ef0bb6c7SMatthew G. Knepley           PetscTabulation Tparent;
32148d2f55e7SToby Isaac 
32155f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscDualSpaceGetFunctional(dsp,parentCellShapeDof,&q));
32165f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscQuadratureGetData(q,&dim,&thisNc,&numPoints,&points,&weights));
32172c71b3e2SJacob Faibussowitsch           PetscCheckFalse(thisNc != Nc,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %D does not much basis dim %D",thisNc,Nc);
32185f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscFECreateTabulation(fe,1,numPoints,points,0,&Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
32193b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
32208d2f55e7SToby Isaac             PetscInt          childCell = -1;
322152a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3222c330f8ffSToby Isaac             const PetscReal   xi0[3] = {-1.,-1.,-1.};
32238d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
32248d2f55e7SToby Isaac             const PetscScalar *point;
3225ef0bb6c7SMatthew G. Knepley             PetscTabulation Tchild;
32268d2f55e7SToby Isaac             PetscInt          childCellShapeOff, pointMatOff;
32278d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
32288d2f55e7SToby Isaac             PetscInt          d;
32298d2f55e7SToby Isaac 
32308d2f55e7SToby Isaac             for (d = 0; d < dim; d++) {
32318d2f55e7SToby Isaac               pointScalar[d] = points[dim * j + d];
32328d2f55e7SToby Isaac             }
32338d2f55e7SToby Isaac             point = pointScalar;
32348d2f55e7SToby Isaac #else
32358d2f55e7SToby Isaac             point = pointReal;
32368d2f55e7SToby Isaac #endif
32378d2f55e7SToby Isaac 
3238ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
32393b1c2a6aSToby Isaac 
32403b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
32418d2f55e7SToby Isaac               PetscInt child = children[k];
32428d2f55e7SToby Isaac               PetscInt *star = NULL;
32438d2f55e7SToby Isaac               PetscInt numStar, s;
32448d2f55e7SToby Isaac 
32455f80ce2aSJacob Faibussowitsch               CHKERRQ(DMPlexGetTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star));
32468d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
32478d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
32488d2f55e7SToby Isaac 
32498d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
32505f80ce2aSJacob Faibussowitsch                 CHKERRQ(DMPlexLocatePoint_Internal(refTree,dim,point,c,&childCell));
32518d2f55e7SToby Isaac                 if (childCell >= 0) break;
32528d2f55e7SToby Isaac               }
32535f80ce2aSJacob Faibussowitsch               CHKERRQ(DMPlexRestoreTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star));
32548d2f55e7SToby Isaac               if (childCell >= 0) break;
32558d2f55e7SToby Isaac             }
32562c71b3e2SJacob Faibussowitsch             PetscCheckFalse(childCell < 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not locate quadrature point");
32575f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
32585f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3259c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3260c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
32618d2f55e7SToby Isaac 
32625f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscFECreateTabulation(fe,1,1,pointRef,0,&Tchild));
32635f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexGetTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure));
32643b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3265c5356c36SToby Isaac               PetscInt child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
32668d2f55e7SToby Isaac               PetscInt l;
326759fc6756SToby Isaac               const PetscInt *cperms;
32688d2f55e7SToby Isaac 
32695f80ce2aSJacob Faibussowitsch               CHKERRQ(DMLabelGetValue(depth,child,&childDepth));
32708d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
327159fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
32728d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
32738d2f55e7SToby Isaac                 PetscInt pointDepth;
32748d2f55e7SToby Isaac 
32758d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
327659fc6756SToby Isaac                 if (point == child) {
327759fc6756SToby Isaac                   cI = l;
327859fc6756SToby Isaac                   break;
327959fc6756SToby Isaac                 }
32805f80ce2aSJacob Faibussowitsch                 CHKERRQ(DMLabelGetValue(depth,point,&pointDepth));
32818d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
32828d2f55e7SToby Isaac               }
32838d2f55e7SToby Isaac               if (l == numClosure) {
32848d2f55e7SToby Isaac                 pointMatOff += childDof;
32858d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
32868d2f55e7SToby Isaac               }
328759fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
32888d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
328959fc6756SToby Isaac                 PetscInt    lCell = cperms ? cperms[l] : l;
329059fc6756SToby Isaac                 PetscInt    childCellDof = childCellShapeOff + lCell;
329152a3aeb4SToby Isaac                 PetscReal   *childValAtPoint;
329252a3aeb4SToby Isaac                 PetscReal   val = 0.;
32938d2f55e7SToby Isaac 
3294ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
329552a3aeb4SToby Isaac                 for (m = 0; m < Nc; m++) {
329652a3aeb4SToby Isaac                   val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
329752a3aeb4SToby Isaac                 }
329852a3aeb4SToby Isaac 
329952a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
33008d2f55e7SToby Isaac               }
33018d2f55e7SToby Isaac               pointMatOff += childDof;
33028d2f55e7SToby Isaac             }
33035f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexRestoreTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure));
33045f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscTabulationDestroy(&Tchild));
33058d2f55e7SToby Isaac           }
33065f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscTabulationDestroy(&Tparent));
33078d2f55e7SToby Isaac         }
33088d2f55e7SToby Isaac       }
3309c5356c36SToby Isaac       else { /* just the volume-weighted averages of the children */
33103b1c2a6aSToby Isaac         PetscReal parentVol;
3311bfaa5bdcSToby Isaac         PetscInt  childCell;
33123b1c2a6aSToby Isaac 
33135f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3314bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
331552a3aeb4SToby Isaac           PetscInt  child = children[i], j;
33163b1c2a6aSToby Isaac           PetscReal childVol;
33173b1c2a6aSToby Isaac 
33183b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
33195f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
332052a3aeb4SToby Isaac           for (j = 0; j < Nc; j++) {
3321bfaa5bdcSToby Isaac             pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
332252a3aeb4SToby Isaac           }
3323bfaa5bdcSToby Isaac           childCell++;
33243b1c2a6aSToby Isaac         }
33258d2f55e7SToby Isaac       }
33263b1c2a6aSToby Isaac       /* Insert pointMat into mat */
33275f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetValues(mat,numSelfDof,matRows,numChildDof,matCols,pointMat,INSERT_VALUES));
33285f80ce2aSJacob Faibussowitsch       CHKERRQ(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows));
33295f80ce2aSJacob Faibussowitsch       CHKERRQ(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat));
33308d2f55e7SToby Isaac     }
33318d2f55e7SToby Isaac   }
33325f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree6(v0,v0parent,vtmp,J,Jparent,invJ));
33335f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(pointScalar,pointRef));
33345f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
33355f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
33368d2f55e7SToby Isaac   *inj = mat;
33378d2f55e7SToby Isaac   PetscFunctionReturn(0);
33388d2f55e7SToby Isaac }
33398d2f55e7SToby Isaac 
3340f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3341f30e825dSToby Isaac {
3342f30e825dSToby Isaac   PetscDS        ds;
3343f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3344f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3345f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3346f30e825dSToby Isaac 
3347f30e825dSToby Isaac   PetscFunctionBegin;
33485f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(refTree,&ds));
33495f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSGetNumFields(ds,&numFields));
33505f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
33515f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(refTree,&refSection));
33525f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
33535f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats));
33545f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetMaxDof(refConSec,&maxDof));
33555f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(maxDof,&rows));
33565f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(maxDof*maxDof,&cols));
3357f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3358f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3359f30e825dSToby Isaac 
33605f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeParent(refTree,p,&parent,NULL));
33615f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(refConSec,p,&pDof));
33625f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(refSection,parent,&parentDof));
3363f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3364f30e825dSToby Isaac 
33655f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]));
3366f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
336752a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3368f30e825dSToby Isaac 
3369f30e825dSToby Isaac       if (numFields > 1) {
33705f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
33715f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldOffset(refConSec,p,f,&cOff));
3372f30e825dSToby Isaac       }
3373f30e825dSToby Isaac       else {
33745f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(refConSec,p,&cDof));
33755f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(refConSec,p,&cOff));
3376f30e825dSToby Isaac       }
3377f30e825dSToby Isaac 
3378f30e825dSToby Isaac       for (r = 0; r < cDof; r++) {
3379f30e825dSToby Isaac         rows[r] = cOff + r;
3380f30e825dSToby Isaac       }
3381f30e825dSToby Isaac       numCols = 0;
3382f30e825dSToby Isaac       {
3383f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3384f30e825dSToby Isaac 
3385f30e825dSToby Isaac         if (numFields > 1) {
33865f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(refSection,parent,f,&aDof));
33875f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldOffset(refSection,parent,f,&aOff));
3388f30e825dSToby Isaac         }
3389f30e825dSToby Isaac         else {
33905f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(refSection,parent,&aDof));
33915f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetOffset(refSection,parent,&aOff));
3392f30e825dSToby Isaac         }
3393f30e825dSToby Isaac 
3394f30e825dSToby Isaac         for (j = 0; j < aDof; j++) {
3395f30e825dSToby Isaac           cols[numCols++] = aOff + j;
3396f30e825dSToby Isaac         }
3397f30e825dSToby Isaac       }
33985f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]));
3399f30e825dSToby Isaac       /* transpose of constraint matrix */
34005f80ce2aSJacob Faibussowitsch       CHKERRQ(MatGetValues(inj,numCols,cols,cDof,rows,refPointFieldMats[p-pRefStart][f]));
3401f30e825dSToby Isaac     }
3402f30e825dSToby Isaac   }
3403f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
34045f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(rows));
34055f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(cols));
3406f30e825dSToby Isaac   PetscFunctionReturn(0);
3407f30e825dSToby Isaac }
3408f30e825dSToby Isaac 
3409f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3410f30e825dSToby Isaac {
3411f30e825dSToby Isaac   PetscDS        ds;
3412f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3413f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3414c6154584SToby Isaac   PetscSection   refConSec, refSection;
3415f30e825dSToby Isaac 
3416f30e825dSToby Isaac   PetscFunctionBegin;
3417f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3418f30e825dSToby Isaac   *childrenMats = NULL;
34195f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(refTree,&ds));
34205f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(refTree,&refSection));
34215f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSGetNumFields(ds,&numFields));
34225f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
34235f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
3424f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3425f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3426f30e825dSToby Isaac 
34275f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeParent(refTree,p,&parent,NULL));
34285f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(refConSec,p,&pDof));
34295f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(refSection,parent,&parentDof));
3430f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3431f30e825dSToby Isaac 
3432f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3433f30e825dSToby Isaac       PetscInt cDof;
3434f30e825dSToby Isaac 
3435f30e825dSToby Isaac       if (numFields > 1) {
34365f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
3437f30e825dSToby Isaac       }
3438f30e825dSToby Isaac       else {
34395f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(refConSec,p,&cDof));
3440f30e825dSToby Isaac       }
3441f30e825dSToby Isaac 
34425f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(refPointFieldMats[p - pRefStart][f]));
3443f30e825dSToby Isaac     }
34445f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(refPointFieldMats[p - pRefStart]));
3445f30e825dSToby Isaac   }
34465f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(refPointFieldMats));
3447f30e825dSToby Isaac   PetscFunctionReturn(0);
3448f30e825dSToby Isaac }
3449f30e825dSToby Isaac 
3450ebf164c7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree,Mat *injRef)
3451154bca37SToby Isaac {
3452ebf164c7SToby Isaac   Mat            cMatRef;
34536148253fSToby Isaac   PetscObject    injRefObj;
34548d2f55e7SToby Isaac 
3455154bca37SToby Isaac   PetscFunctionBegin;
34565f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(refTree,NULL,&cMatRef,NULL));
34575f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectQuery((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",&injRefObj));
3458ebf164c7SToby Isaac   *injRef = (Mat) injRefObj;
3459ebf164c7SToby Isaac   if (!*injRef) {
34605f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexComputeInjectorReferenceTree(refTree,injRef));
34615f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectCompose((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",(PetscObject)*injRef));
3462ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
34635f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectDereference((PetscObject)*injRef));
3464ebf164c7SToby Isaac   }
3465ebf164c7SToby Isaac   PetscFunctionReturn(0);
34666148253fSToby Isaac }
3467f30e825dSToby Isaac 
3468c921d74cSToby Isaac static PetscErrorCode DMPlexTransferInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, const PetscInt *childIds, Vec fineVec, PetscInt numFields, PetscInt *offsets, PetscSection *rootMultiSec, PetscSection *multiLeafSec, PetscInt **gatheredIndices, PetscScalar **gatheredValues)
3469ebf164c7SToby Isaac {
3470c921d74cSToby Isaac   PetscInt       pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3471ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3472ebf164c7SToby Isaac   PetscSection   localCoarse, localFine, leafIndicesSec;
3473c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3474c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3475c921d74cSToby Isaac   const PetscInt *rootDegrees;
3476c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3477ebf164c7SToby Isaac   PetscSF        coarseToFineEmbedded;
3478ebf164c7SToby Isaac 
3479ebf164c7SToby Isaac   PetscFunctionBegin;
34805f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(coarse,&pStartC,&pEndC));
34815f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(fine,&pStartF,&pEndF));
34825f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(fine,&localFine));
34835f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(fine,&globalFine));
34845f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec));
34855f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(leafIndicesSec,pStartF, pEndF));
34865f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetMaxDof(localFine,&maxDof));
34878d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
34887e96bdafSToby Isaac     PetscInt l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
34897e96bdafSToby Isaac     const PetscInt *leaves;
34908d2f55e7SToby Isaac 
34915f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL));
34927e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
34937e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
34945f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalFine,p,&dof));
34955f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetConstraintDof(globalFine,p,&cdof));
34968d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
34978d2f55e7SToby Isaac         numPointsWithDofs++;
3498f30e825dSToby Isaac 
34995f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(localFine,p,&dof));
35005f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionSetDof(leafIndicesSec,p,dof + 1));
35018d2f55e7SToby Isaac       }
35028d2f55e7SToby Isaac     }
35035f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
35045f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetUp(leafIndicesSec));
35055f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(leafIndicesSec,&numIndices));
35065f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1),&leafInds));
35075f80ce2aSJacob Faibussowitsch     if (gatheredValues)  CHKERRQ(PetscMalloc1(numIndices,&leafVals));
35087e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
35097e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35105f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalFine,p,&dof));
35115f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetConstraintDof(globalFine,p,&cdof));
35128d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3513f30e825dSToby Isaac         PetscInt    off, gOff;
3514f30e825dSToby Isaac         PetscInt    *pInd;
3515c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3516f30e825dSToby Isaac 
35177e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3518f30e825dSToby Isaac 
35195f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(leafIndicesSec,p,&off));
3520f30e825dSToby Isaac 
3521c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3522c921d74cSToby Isaac         if (gatheredValues) {
3523c921d74cSToby Isaac           PetscInt i;
3524c921d74cSToby Isaac 
3525c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3526c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3527c921d74cSToby Isaac         }
35285f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(globalFine,p,&gOff));
3529f30e825dSToby Isaac 
3530f30e825dSToby Isaac         offsets[0] = 0;
3531f30e825dSToby Isaac         if (numFields) {
3532f30e825dSToby Isaac           PetscInt f;
3533f30e825dSToby Isaac 
3534f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3535f30e825dSToby Isaac             PetscInt fDof;
35365f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldDof(localFine,p,f,&fDof));
3537f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3538f30e825dSToby Isaac           }
35395f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1, NULL,pInd));
3540367003a6SStefano Zampini         } else {
35415f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL, NULL,pInd));
3542f30e825dSToby Isaac         }
35435f80ce2aSJacob Faibussowitsch         if (gatheredValues) CHKERRQ(VecGetValues(fineVec,dof,pInd,pVal));
35448d2f55e7SToby Isaac       }
35458d2f55e7SToby Isaac     }
35465f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
35475f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(pointsWithDofs));
35488d2f55e7SToby Isaac   }
3549f30e825dSToby Isaac 
35505f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(coarse,&pStartC,&pEndC));
35515f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(coarse,&localCoarse));
35525f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(coarse,&globalCoarse));
3553f30e825dSToby Isaac 
35546148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
35556148253fSToby Isaac     MPI_Datatype threeInt;
35566148253fSToby Isaac     PetscMPIInt  rank;
35576148253fSToby Isaac     PetscInt     (*parentNodeAndIdCoarse)[3];
35586148253fSToby Isaac     PetscInt     (*parentNodeAndIdFine)[3];
35596148253fSToby Isaac     PetscInt     p, nleaves, nleavesToParents;
35606148253fSToby Isaac     PetscSF      pointSF, sfToParents;
35616148253fSToby Isaac     const PetscInt *ilocal;
35626148253fSToby Isaac     const PetscSFNode *iremote;
35636148253fSToby Isaac     PetscSFNode  *iremoteToParents;
35646148253fSToby Isaac     PetscInt     *ilocalToParents;
35656148253fSToby Isaac 
35665f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse),&rank));
35675f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Type_contiguous(3,MPIU_INT,&threeInt));
35685f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Type_commit(&threeInt));
35695f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc2(pEndC-pStartC,&parentNodeAndIdCoarse,pEndF-pStartF,&parentNodeAndIdFine));
35705f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetPointSF(coarse,&pointSF));
35715f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFGetGraph(pointSF,NULL,&nleaves,&ilocal,&iremote));
35726148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
35736148253fSToby Isaac       PetscInt parent, childId;
35745f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTreeParent(coarse,p,&parent,&childId));
35756148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
35766148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
35776148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
35786148253fSToby Isaac       if (nleaves > 0) {
35796148253fSToby Isaac         PetscInt leaf = -1;
35806148253fSToby Isaac 
35816148253fSToby Isaac         if (ilocal) {
35825f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscFindInt(parent,nleaves,ilocal,&leaf));
35836148253fSToby Isaac         }
35846148253fSToby Isaac         else {
35856148253fSToby Isaac           leaf = p - pStartC;
35866148253fSToby Isaac         }
35876148253fSToby Isaac         if (leaf >= 0) {
35886148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
35896148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
35906148253fSToby Isaac         }
35916148253fSToby Isaac       }
35926148253fSToby Isaac     }
35936148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
35946148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
35956148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
35966148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
35976148253fSToby Isaac     }
35985f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastBegin(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine,MPI_REPLACE));
35995f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastEnd(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine,MPI_REPLACE));
36006148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3601f30e825dSToby Isaac       PetscInt dof;
3602f30e825dSToby Isaac 
36035f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(leafIndicesSec,p,&dof));
3604f30e825dSToby Isaac       if (dof) {
3605f30e825dSToby Isaac         PetscInt off;
3606f30e825dSToby Isaac 
36075f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(leafIndicesSec,p,&off));
3608c921d74cSToby Isaac         if (gatheredIndices) {
3609c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3610c921d74cSToby Isaac         } else if (gatheredValues) {
3611c921d74cSToby Isaac           leafVals[off] = (PetscScalar) PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3612c921d74cSToby Isaac         }
3613f30e825dSToby Isaac       }
36146148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36156148253fSToby Isaac         nleavesToParents++;
36166148253fSToby Isaac       }
36176148253fSToby Isaac     }
36185f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(nleavesToParents,&ilocalToParents));
36195f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(nleavesToParents,&iremoteToParents));
36206148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
36216148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36226148253fSToby Isaac         ilocalToParents[nleavesToParents] = p - pStartF;
36236148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p-pStartF][0];
36246148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p-pStartF][1];
36256148253fSToby Isaac         nleavesToParents++;
36266148253fSToby Isaac       }
36276148253fSToby Isaac     }
36285f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreate(PetscObjectComm((PetscObject)coarse),&sfToParents));
36295f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFSetGraph(sfToParents,pEndC-pStartC,nleavesToParents,ilocalToParents,PETSC_OWN_POINTER,iremoteToParents,PETSC_OWN_POINTER));
36305f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&coarseToFineEmbedded));
36316148253fSToby Isaac 
36326148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
36336148253fSToby Isaac 
36345f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree2(parentNodeAndIdCoarse,parentNodeAndIdFine));
36355f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Type_free(&threeInt));
36366148253fSToby Isaac   }
3637f30e825dSToby Isaac 
36386148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
36396148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
36406148253fSToby Isaac     PetscSF  sfDofsOnly;
36416148253fSToby Isaac 
36426148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
36435f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalCoarse,p,&dof));
36445f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
36456148253fSToby Isaac       if ((dof - cdof) > 0) {
36466148253fSToby Isaac         numPointsWithDofs++;
36476148253fSToby Isaac       }
36486148253fSToby Isaac     }
36495f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
36506148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
36515f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalCoarse,p,&dof));
36525f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
36536148253fSToby Isaac       if ((dof - cdof) > 0) {
3654e03d9830SToby Isaac         pointsWithDofs[offset++] = p - pStartC;
36556148253fSToby Isaac       }
36566148253fSToby Isaac     }
36575f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
36585f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&coarseToFineEmbedded));
36595f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(pointsWithDofs));
36606148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
36616148253fSToby Isaac   }
3662f30e825dSToby Isaac 
36636148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
36645f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFComputeDegreeBegin(coarseToFineEmbedded,&rootDegrees));
36655f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFComputeDegreeEnd(coarseToFineEmbedded,&rootDegrees));
36665f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&multiRootSec));
36675f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(multiRootSec,pStartC,pEndC));
36688d2f55e7SToby Isaac   for (p = pStartC; p < pEndC; p++) {
36695f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetDof(multiRootSec,p,rootDegrees[p-pStartC]));
36708d2f55e7SToby Isaac   }
36715f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(multiRootSec));
36725f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(multiRootSec,&numMulti));
36735f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec));
3674f30e825dSToby Isaac   { /* distribute the leaf section */
3675f30e825dSToby Isaac     PetscSF multi, multiInv, indicesSF;
3676f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
36778d2f55e7SToby Isaac 
36785f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFGetMultiSF(coarseToFineEmbedded,&multi));
36795f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreateInverseSF(multi,&multiInv));
36805f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDistributeSection(multiInv,leafIndicesSec,&remoteOffsets,rootIndicesSec));
36815f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreateSectionSF(multiInv,leafIndicesSec,remoteOffsets,rootIndicesSec,&indicesSF));
36825f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(remoteOffsets));
36835f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&multiInv));
36845f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices));
3685c921d74cSToby Isaac     if (gatheredIndices) {
36865f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(numRootIndices,&rootInds));
36875f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastBegin(indicesSF,MPIU_INT,leafInds,rootInds,MPI_REPLACE));
36885f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastEnd(indicesSF,MPIU_INT,leafInds,rootInds,MPI_REPLACE));
3689c921d74cSToby Isaac     }
3690c921d74cSToby Isaac     if (gatheredValues) {
36915f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(numRootIndices,&rootVals));
36925f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastBegin(indicesSF,MPIU_SCALAR,leafVals,rootVals,MPI_REPLACE));
36935f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastEnd(indicesSF,MPIU_SCALAR,leafVals,rootVals,MPI_REPLACE));
3694c921d74cSToby Isaac     }
36955f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&indicesSF));
36968d2f55e7SToby Isaac   }
36975f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&leafIndicesSec));
36985f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(leafInds));
36995f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(leafVals));
37005f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFDestroy(&coarseToFineEmbedded));
3701c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3702c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3703c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3704c921d74cSToby Isaac   if (gatheredValues)  *gatheredValues  = rootVals;
3705ebf164c7SToby Isaac   PetscFunctionReturn(0);
3706ebf164c7SToby Isaac }
3707ebf164c7SToby Isaac 
3708ebf164c7SToby Isaac PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3709ebf164c7SToby Isaac {
3710ebf164c7SToby Isaac   DM             refTree;
3711c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3712ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3713ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3714ebf164c7SToby Isaac   PetscSection   cSecRef;
3715277f51e8SBarry Smith   PetscInt       *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3716ebf164c7SToby Isaac   Mat            injRef;
3717c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3718ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3719ebf164c7SToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
3720ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3721ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3722ebf164c7SToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3723ebf164c7SToby Isaac 
3724ebf164c7SToby Isaac   PetscFunctionBegin;
3725ebf164c7SToby Isaac 
3726ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
37275f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetReferenceTree(coarse,&refTree));
37285f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(refTree,&cSecRef,NULL,NULL));
37295f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd));
37305f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexReferenceTreeGetInjector(refTree,&injRef));
3731ebf164c7SToby Isaac 
37325f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(fine,&pStartF,&pEndF));
37335f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(fine,&localFine));
37345f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(fine,&globalFine));
37355f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetNumFields(localFine,&numFields));
37365f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(coarse,&pStartC,&pEndC));
37375f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(coarse,&localCoarse));
37385f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(coarse,&globalCoarse));
37395f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetMaxDof(localCoarse,&maxDof));
3740ebf164c7SToby Isaac   {
3741ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
37425f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets));
3743ebf164c7SToby Isaac   }
3744ebf164c7SToby Isaac 
37455f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexTransferInjectorTree(coarse,fine,coarseToFine,childIds,NULL,numFields,offsets,&multiRootSec,&rootIndicesSec,&rootIndices,NULL));
37468d2f55e7SToby Isaac 
37475f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(maxDof,&parentIndices));
3748f30e825dSToby Isaac 
3749f30e825dSToby Isaac   /* count indices */
37505f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetLayouts(mat,&rowMap,&colMap));
37515f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutSetUp(rowMap));
37525f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutSetUp(colMap));
37535f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutGetRange(rowMap,&rowStart,&rowEnd));
37545f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutGetRange(colMap,&colStart,&colEnd));
37555f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc2(rowEnd-rowStart,&nnzD,rowEnd-rowStart,&nnzO));
3756f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3757f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
37588d2f55e7SToby Isaac 
37595f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(globalCoarse,p,&dof));
37605f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
3761f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
37625f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(globalCoarse,p,&gOff));
37638d2f55e7SToby Isaac 
37648d2f55e7SToby Isaac     rowOffsets[0] = 0;
3765f30e825dSToby Isaac     offsetsCopy[0] = 0;
37668d2f55e7SToby Isaac     if (numFields) {
37678d2f55e7SToby Isaac       PetscInt f;
37688d2f55e7SToby Isaac 
3769f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3770f30e825dSToby Isaac         PetscInt fDof;
37715f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
3772f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
37738d2f55e7SToby Isaac       }
37745f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,parentIndices));
3775367003a6SStefano Zampini     } else {
37765f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,parentIndices));
3777f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
37788d2f55e7SToby Isaac     }
3779f30e825dSToby Isaac 
37805f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(multiRootSec,p,&numLeaves));
37815f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(multiRootSec,p,&leafStart));
3782f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3783f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3784f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3785f30e825dSToby Isaac       const PetscInt *childIndices;
3786f30e825dSToby Isaac 
37875f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(rootIndicesSec,l,&numIndices));
37885f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(rootIndicesSec,l,&offset));
3789f30e825dSToby Isaac       childId = rootIndices[offset++];
3790f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3791f30e825dSToby Isaac       numIndices--;
3792f30e825dSToby Isaac 
3793f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3794f30e825dSToby Isaac         PetscInt i;
3795f30e825dSToby Isaac 
3796f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3797f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3798f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3799f30e825dSToby Isaac           if (rowIndex < 0) continue;
38002c71b3e2SJacob Faibussowitsch           PetscCheckFalse(colIndex < 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unconstrained fine and constrained coarse");
3801a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3802f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
3803f30e825dSToby Isaac           }
3804f30e825dSToby Isaac           else {
3805f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3806f30e825dSToby Isaac           }
3807f30e825dSToby Isaac         }
3808f30e825dSToby Isaac       }
3809f30e825dSToby Isaac       else {
3810f30e825dSToby Isaac         PetscInt parentId, f, lim;
3811f30e825dSToby Isaac 
38125f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeParent(refTree,childId,&parentId,NULL));
3813f30e825dSToby Isaac 
3814f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3815f30e825dSToby Isaac         offsets[0] = 0;
38168d2f55e7SToby Isaac         if (numFields) {
38178d2f55e7SToby Isaac           PetscInt f;
3818f30e825dSToby Isaac 
38198d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3820f30e825dSToby Isaac             PetscInt fDof;
38215f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldDof(cSecRef,childId,f,&fDof));
3822f30e825dSToby Isaac 
3823f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
38248d2f55e7SToby Isaac           }
38258d2f55e7SToby Isaac         }
38268d2f55e7SToby Isaac         else {
3827f30e825dSToby Isaac           PetscInt cDof;
3828f30e825dSToby Isaac 
38295f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(cSecRef,childId,&cDof));
3830f30e825dSToby Isaac           offsets[1] = cDof;
3831f30e825dSToby Isaac         }
3832f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3833f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3834f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3835f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3836f30e825dSToby Isaac 
3837f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3838f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3839f30e825dSToby Isaac 
3840f30e825dSToby Isaac             if (colIndex < 0) continue;
3841f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3842f30e825dSToby Isaac               numD++;
3843f30e825dSToby Isaac             }
3844f30e825dSToby Isaac             else {
3845f30e825dSToby Isaac               numO++;
3846f30e825dSToby Isaac             }
3847f30e825dSToby Isaac           }
3848f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3849f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3850f30e825dSToby Isaac 
3851f30e825dSToby Isaac             if (rowIndex < 0) continue;
3852f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3853f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
38548d2f55e7SToby Isaac           }
38558d2f55e7SToby Isaac         }
38568d2f55e7SToby Isaac       }
3857f30e825dSToby Isaac     }
3858f30e825dSToby Isaac   }
3859f30e825dSToby Isaac   /* preallocate */
38605f80ce2aSJacob Faibussowitsch   CHKERRQ(MatXAIJSetPreallocation(mat,1,nnzD,nnzO,NULL,NULL));
38615f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(nnzD,nnzO));
3862f30e825dSToby Isaac   /* insert values */
38635f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats));
3864f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3865f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3866f30e825dSToby Isaac 
38675f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(globalCoarse,p,&dof));
38685f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
3869f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
38705f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(globalCoarse,p,&gOff));
3871f30e825dSToby Isaac 
3872f30e825dSToby Isaac     rowOffsets[0] = 0;
3873f30e825dSToby Isaac     offsetsCopy[0] = 0;
38748d2f55e7SToby Isaac     if (numFields) {
38758d2f55e7SToby Isaac       PetscInt f;
3876f30e825dSToby Isaac 
38778d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3878f30e825dSToby Isaac         PetscInt fDof;
38795f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
3880f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3881f30e825dSToby Isaac       }
38825f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,parentIndices));
3883367003a6SStefano Zampini     } else {
38845f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,parentIndices));
3885f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3886f30e825dSToby Isaac     }
3887f30e825dSToby Isaac 
38885f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(multiRootSec,p,&numLeaves));
38895f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(multiRootSec,p,&leafStart));
3890f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3891f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3892f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3893f30e825dSToby Isaac       const PetscInt *childIndices;
3894f30e825dSToby Isaac 
38955f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(rootIndicesSec,l,&numIndices));
38965f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(rootIndicesSec,l,&offset));
3897f30e825dSToby Isaac       childId = rootIndices[offset++];
3898f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3899f30e825dSToby Isaac       numIndices--;
3900f30e825dSToby Isaac 
3901f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3902f30e825dSToby Isaac         PetscInt i;
3903f30e825dSToby Isaac 
3904f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
39055f80ce2aSJacob Faibussowitsch           CHKERRQ(MatSetValue(mat,parentIndices[i],childIndices[i],1.,INSERT_VALUES));
39068d2f55e7SToby Isaac         }
39078d2f55e7SToby Isaac       }
39088d2f55e7SToby Isaac       else {
3909f30e825dSToby Isaac         PetscInt parentId, f, lim;
39108d2f55e7SToby Isaac 
39115f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeParent(refTree,childId,&parentId,NULL));
3912f30e825dSToby Isaac 
3913f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3914f30e825dSToby Isaac         offsets[0] = 0;
39158d2f55e7SToby Isaac         if (numFields) {
3916f30e825dSToby Isaac           PetscInt f;
39178d2f55e7SToby Isaac 
3918f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3919f30e825dSToby Isaac             PetscInt fDof;
39205f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldDof(cSecRef,childId,f,&fDof));
3921f30e825dSToby Isaac 
3922f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
39238d2f55e7SToby Isaac           }
39248d2f55e7SToby Isaac         }
39258d2f55e7SToby Isaac         else {
3926f30e825dSToby Isaac           PetscInt cDof;
3927f30e825dSToby Isaac 
39285f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(cSecRef,childId,&cDof));
3929f30e825dSToby Isaac           offsets[1] = cDof;
39308d2f55e7SToby Isaac         }
3931f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3932f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3933f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3934f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3935f30e825dSToby Isaac 
39365f80ce2aSJacob Faibussowitsch           CHKERRQ(MatSetValues(mat,rowOffsets[f+1]-rowOffsets[f],rowIndices,offsets[f+1]-offsets[f],colIndices,childMat,INSERT_VALUES));
39378d2f55e7SToby Isaac         }
39388d2f55e7SToby Isaac       }
39398d2f55e7SToby Isaac     }
39408d2f55e7SToby Isaac   }
39415f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&multiRootSec));
39425f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&rootIndicesSec));
39435f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(parentIndices));
39445f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats));
39455f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(rootIndices));
39465f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree3(offsets,offsetsCopy,rowOffsets));
3947f30e825dSToby Isaac 
39485f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
39495f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
3950154bca37SToby Isaac   PetscFunctionReturn(0);
3951154bca37SToby Isaac }
395238fc2455SToby Isaac 
39530eb7e1eaSToby Isaac static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3954ebf164c7SToby Isaac {
395562095d54SToby Isaac   PetscSF           coarseToFineEmbedded;
395662095d54SToby Isaac   PetscSection      globalCoarse, globalFine;
395762095d54SToby Isaac   PetscSection      localCoarse, localFine;
395862095d54SToby Isaac   PetscSection      aSec, cSec;
395962095d54SToby Isaac   PetscSection      rootValuesSec;
396062095d54SToby Isaac   PetscSection      leafValuesSec;
396162095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
396262095d54SToby Isaac   IS                aIS;
396362095d54SToby Isaac   const PetscInt    *anchors;
396462095d54SToby Isaac   Mat               cMat;
396562095d54SToby Isaac   PetscInt          numFields;
3966412e9a14SMatthew G. Knepley   PetscInt          pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
396762095d54SToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
396862095d54SToby Isaac   PetscInt          *maxChildIds;
396962095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
39700eb7e1eaSToby Isaac   PetscFV           fv = NULL;
39710eb7e1eaSToby Isaac   PetscInt          dim, numFVcomps = -1, fvField = -1;
39720eb7e1eaSToby Isaac   DM                cellDM = NULL, gradDM = NULL;
39730eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
39740eb7e1eaSToby Isaac   const PetscScalar *gradArray = NULL;
397562095d54SToby Isaac 
3976ebf164c7SToby Isaac   PetscFunctionBegin;
39775f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE));
39785f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(coarse,&pStartC,&pEndC));
39795f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSimplexOrBoxCells(coarse,0,&cellStart,&cellEnd));
39805f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(fine,&pStartF,&pEndF));
39815f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(fine,&globalFine));
39825f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinateDim(coarse,&dim));
398362095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3984e4a60869SToby Isaac     PetscInt       nleaves, l;
3985e4a60869SToby Isaac     const PetscInt *leaves;
398662095d54SToby Isaac     PetscInt       dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
398762095d54SToby Isaac 
39885f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL));
3989e4a60869SToby Isaac 
3990e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3991e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3992e4a60869SToby Isaac 
39935f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalFine,p,&dof));
39945f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetConstraintDof(globalFine,p,&cdof));
399562095d54SToby Isaac       if ((dof - cdof) > 0) {
399662095d54SToby Isaac         numPointsWithDofs++;
399762095d54SToby Isaac       }
399862095d54SToby Isaac     }
39995f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
40004833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
4001e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
4002e4a60869SToby Isaac 
40035f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalFine,p,&dof));
40045f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetConstraintDof(globalFine,p,&cdof));
400562095d54SToby Isaac       if ((dof - cdof) > 0) {
4006e4a60869SToby Isaac         pointsWithDofs[offset++] = l;
400762095d54SToby Isaac       }
400862095d54SToby Isaac     }
40095f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
40105f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(pointsWithDofs));
401162095d54SToby Isaac   }
401262095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
40135f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEndC-pStartC,&maxChildIds));
401462095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) {
401562095d54SToby Isaac     maxChildIds[p - pStartC] = -2;
401662095d54SToby Isaac   }
40175f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX));
40185f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX));
401962095d54SToby Isaac 
40205f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(coarse,&localCoarse));
40215f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(coarse,&globalCoarse));
402262095d54SToby Isaac 
40235f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetAnchors(coarse,&aSec,&aIS));
40245f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(aIS,&anchors));
40255f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(aSec,&aStart,&aEnd));
402662095d54SToby Isaac 
40275f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(coarse,&cSec,&cMat,NULL));
40285f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(cSec,&cStart,&cEnd));
402962095d54SToby Isaac 
403062095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
40315f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootValuesSec));
40325f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(rootValuesSec,pStartC,pEndC));
40335f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetNumFields(localCoarse,&numFields));
403462095d54SToby Isaac   {
403562095d54SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
40365f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO));
403762095d54SToby Isaac   }
40380eb7e1eaSToby Isaac   if (grad) {
40390eb7e1eaSToby Isaac     PetscInt i;
40400eb7e1eaSToby Isaac 
40415f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetDM(cellGeom,&cellDM));
40425f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArrayRead(cellGeom,&cellGeomArray));
40435f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetDM(grad,&gradDM));
40445f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArrayRead(grad,&gradArray));
40450eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1,numFields); i++) {
40460eb7e1eaSToby Isaac       PetscObject  obj;
40470eb7e1eaSToby Isaac       PetscClassId id;
40480eb7e1eaSToby Isaac 
40495f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetField(coarse, i, NULL, &obj));
40505f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectGetClassId(obj,&id));
40510eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
40520eb7e1eaSToby Isaac         fv      = (PetscFV) obj;
40535f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscFVGetNumComponents(fv,&numFVcomps));
40540eb7e1eaSToby Isaac         fvField = i;
40550eb7e1eaSToby Isaac         break;
40560eb7e1eaSToby Isaac       }
40570eb7e1eaSToby Isaac     }
40580eb7e1eaSToby Isaac   }
405962095d54SToby Isaac 
406062095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
406162095d54SToby Isaac     PetscInt dof;
406262095d54SToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
406362095d54SToby Isaac     PetscInt numValues      = 0;
406462095d54SToby Isaac 
40655f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(globalCoarse,p,&dof));
406662095d54SToby Isaac     if (dof < 0) {
406762095d54SToby Isaac       dof = -(dof + 1);
406862095d54SToby Isaac     }
406962095d54SToby Isaac     offsets[0]    = 0;
407062095d54SToby Isaac     newOffsets[0] = 0;
407162095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
407262095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
407362095d54SToby Isaac 
40745f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
407562095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
407662095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
407762095d54SToby Isaac 
40785f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(localCoarse,c,&clDof));
407962095d54SToby Isaac         numValues += clDof;
408062095d54SToby Isaac       }
40815f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
408262095d54SToby Isaac     }
408362095d54SToby Isaac     else if (maxChildId == -1) {
40845f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(localCoarse,p,&numValues));
408562095d54SToby Isaac     }
408662095d54SToby Isaac     /* we will pack the column indices with the field offsets */
408778b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
40880eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
40890eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
40900eb7e1eaSToby Isaac     }
40915f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetDof(rootValuesSec,p,numValues));
409262095d54SToby Isaac   }
40935f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(rootValuesSec));
409462095d54SToby Isaac   {
409562095d54SToby Isaac     PetscInt          numRootValues;
409662095d54SToby Isaac     const PetscScalar *coarseArray;
409762095d54SToby Isaac 
40985f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(rootValuesSec,&numRootValues));
40995f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numRootValues,&rootValues));
41005f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArrayRead(vecCoarseLocal,&coarseArray));
410162095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
410262095d54SToby Isaac       PetscInt    numValues;
410362095d54SToby Isaac       PetscInt    pValOff;
410462095d54SToby Isaac       PetscScalar *pVal;
410562095d54SToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
410662095d54SToby Isaac 
41075f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(rootValuesSec,p,&numValues));
410862095d54SToby Isaac       if (!numValues) {
410962095d54SToby Isaac         continue;
411062095d54SToby Isaac       }
41115f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(rootValuesSec,p,&pValOff));
411262095d54SToby Isaac       pVal = &(rootValues[pValOff]);
411362095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
41140eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
41155f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexVecGetClosure(coarse,NULL,vecCoarseLocal,p,&closureSize,&pVal));
41160eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
4117193eb951SToby Isaac           PetscFVCellGeom *cg;
41186dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
41190eb7e1eaSToby Isaac           PetscInt        i;
41200eb7e1eaSToby Isaac 
41210eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
41220eb7e1eaSToby Isaac 
41235f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexPointLocalRead(cellDM,p,cellGeomArray,(void *) &cg));
41240eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
41250eb7e1eaSToby Isaac           pVal += dim;
41265f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexPointGlobalRead(gradDM,p,gradArray,(void *) &gradVals));
41270eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
41280eb7e1eaSToby Isaac         }
412962095d54SToby Isaac       }
413078b7adb5SToby Isaac       else if (maxChildId == -1) {
413178b7adb5SToby Isaac         PetscInt lDof, lOff, i;
413278b7adb5SToby Isaac 
41335f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(localCoarse,p,&lDof));
41345f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(localCoarse,p,&lOff));
413578b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
413678b7adb5SToby Isaac       }
413778b7adb5SToby Isaac     }
41385f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArrayRead(vecCoarseLocal,&coarseArray));
41395f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(maxChildIds));
414062095d54SToby Isaac   }
414162095d54SToby Isaac   {
414262095d54SToby Isaac     PetscSF  valuesSF;
414362095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
414462095d54SToby Isaac 
41455f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafValuesSec));
41465f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDistributeSection(coarseToFineEmbedded,rootValuesSec,&remoteOffsetsValues,leafValuesSec));
41475f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreateSectionSF(coarseToFineEmbedded,rootValuesSec,remoteOffsetsValues,leafValuesSec,&valuesSF));
41485f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&coarseToFineEmbedded));
41495f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(remoteOffsetsValues));
41505f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(leafValuesSec,&numLeafValues));
41515f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numLeafValues,&leafValues));
41525f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastBegin(valuesSF,MPIU_SCALAR,rootValues,leafValues,MPI_REPLACE));
41535f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastEnd(valuesSF,MPIU_SCALAR,rootValues,leafValues,MPI_REPLACE));
41545f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&valuesSF));
41555f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(rootValues));
41565f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&rootValuesSec));
415762095d54SToby Isaac   }
41585f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(fine,&localFine));
415962095d54SToby Isaac   {
416062095d54SToby Isaac     PetscInt    maxDof;
416162095d54SToby Isaac     PetscInt    *rowIndices;
416262095d54SToby Isaac     DM           refTree;
416362095d54SToby Isaac     PetscInt     **refPointFieldN;
416462095d54SToby Isaac     PetscScalar  ***refPointFieldMats;
416562095d54SToby Isaac     PetscSection refConSec, refAnSec;
41660eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,leafStart,leafEnd;
416762095d54SToby Isaac     PetscScalar  *pointWork;
416862095d54SToby Isaac 
41695f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetMaxDof(localFine,&maxDof));
41705f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
41715f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork));
41725f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetReferenceTree(fine,&refTree));
41735f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCopyDisc(fine,refTree));
41745f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
41755f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
41765f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetAnchors(refTree,&refAnSec,NULL));
41775f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
41785f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetChart(leafValuesSec,&leafStart,&leafEnd));
41795f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetSimplexOrBoxCells(fine,0,&cellStart,&cellEnd));
41800eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
418162095d54SToby Isaac       PetscInt          gDof, gcDof, gOff, lDof;
418262095d54SToby Isaac       PetscInt          numValues, pValOff;
418362095d54SToby Isaac       PetscInt          childId;
418462095d54SToby Isaac       const PetscScalar *pVal;
41850eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
418662095d54SToby Isaac 
41875f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(globalFine,p,&gDof));
41885f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(localFine,p,&lDof));
41895f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetConstraintDof(globalFine,p,&gcDof));
419062095d54SToby Isaac       if ((gDof - gcDof) <= 0) {
419162095d54SToby Isaac         continue;
419262095d54SToby Isaac       }
41935f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(globalFine,p,&gOff));
41945f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(leafValuesSec,p,&numValues));
419562095d54SToby Isaac       if (!numValues) continue;
41965f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(leafValuesSec,p,&pValOff));
419762095d54SToby Isaac       pVal = &leafValues[pValOff];
419862095d54SToby Isaac       offsets[0]        = 0;
419962095d54SToby Isaac       offsetsCopy[0]    = 0;
420062095d54SToby Isaac       newOffsets[0]     = 0;
420162095d54SToby Isaac       newOffsetsCopy[0] = 0;
42024833aeb0SToby Isaac       childId           = cids[p - pStartF];
420362095d54SToby Isaac       if (numFields) {
420462095d54SToby Isaac         PetscInt f;
420562095d54SToby Isaac         for (f = 0; f < numFields; f++) {
420662095d54SToby Isaac           PetscInt rowDof;
420762095d54SToby Isaac 
42085f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetFieldDof(localFine,p,f,&rowDof));
420962095d54SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
421062095d54SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
421162095d54SToby Isaac           /* TODO: closure indices */
42129f4e70e1SToby Isaac           newOffsets[f + 1]     = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
421362095d54SToby Isaac         }
42145f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,NULL,rowIndices));
421562095d54SToby Isaac       }
421662095d54SToby Isaac       else {
42174833aeb0SToby Isaac         offsets[0]    = 0;
42184833aeb0SToby Isaac         offsets[1]    = lDof;
42194833aeb0SToby Isaac         newOffsets[0] = 0;
42204833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
42215f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,NULL,rowIndices));
422262095d54SToby Isaac       }
422362095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
42245f80ce2aSJacob Faibussowitsch         CHKERRQ(VecSetValues(vecFine,numValues,rowIndices,pVal,INSERT_VALUES));
422562095d54SToby Isaac       } else {
422662095d54SToby Isaac         PetscInt f;
422762095d54SToby Isaac 
422878b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
422978b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
423078b7adb5SToby Isaac           fvGradData = &pVal[numValues];
423178b7adb5SToby Isaac         }
423262095d54SToby Isaac         for (f = 0; f < PetscMax(1,numFields); f++) {
423362095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
423462095d54SToby Isaac           PetscInt numRows = offsets[f+1] - offsets[f];
423562095d54SToby Isaac           PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
423662095d54SToby Isaac           const PetscScalar *cVal = &pVal[newOffsets[f]];
423762095d54SToby Isaac           PetscScalar *rVal = &pointWork[offsets[f]];
423862095d54SToby Isaac           PetscInt i, j;
423962095d54SToby Isaac 
4240708c7f19SToby Isaac #if 0
42415f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscInfo(coarse,"childId %D, numRows %D, numCols %D, refPointFieldN %D maxDof %D\n",childId,numRows,numCols,refPointFieldN[childId - pRefStart][f], maxDof));
4242708c7f19SToby Isaac #endif
424362095d54SToby Isaac           for (i = 0; i < numRows; i++) {
424462095d54SToby Isaac             PetscScalar val = 0.;
424562095d54SToby Isaac             for (j = 0; j < numCols; j++) {
424662095d54SToby Isaac               val += childMat[i * numCols + j] * cVal[j];
424762095d54SToby Isaac             }
424862095d54SToby Isaac             rVal[i] = val;
424962095d54SToby Isaac           }
42500eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
42510eb7e1eaSToby Isaac             PetscReal   centroid[3];
42520eb7e1eaSToby Isaac             PetscScalar diff[3];
42530eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
42540eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
42550eb7e1eaSToby Isaac 
42565f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexComputeCellGeometryFVM(fine,p,NULL,centroid,NULL));
42570eb7e1eaSToby Isaac             for (i = 0; i < dim; i++) {
42580eb7e1eaSToby Isaac               diff[i] = centroid[i] - parentCentroid[i];
42590eb7e1eaSToby Isaac             }
42600eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
42610eb7e1eaSToby Isaac               PetscScalar val = 0.;
42620eb7e1eaSToby Isaac 
426389698031SToby Isaac               for (j = 0; j < dim; j++) {
42640eb7e1eaSToby Isaac                 val += gradient[dim * i + j] * diff[j];
42650eb7e1eaSToby Isaac               }
42660eb7e1eaSToby Isaac               rVal[i] += val;
42670eb7e1eaSToby Isaac             }
42680eb7e1eaSToby Isaac           }
42695f80ce2aSJacob Faibussowitsch           CHKERRQ(VecSetValues(vecFine,numRows,&rowIndices[offsets[f]],rVal,INSERT_VALUES));
427062095d54SToby Isaac         }
427162095d54SToby Isaac       }
427262095d54SToby Isaac     }
42735f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
42745f80ce2aSJacob Faibussowitsch     CHKERRQ(DMRestoreWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork));
42755f80ce2aSJacob Faibussowitsch     CHKERRQ(DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
427662095d54SToby Isaac   }
42775f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(leafValues));
42785f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&leafValuesSec));
42795f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO));
42805f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(aIS,&anchors));
4281ebf164c7SToby Isaac   PetscFunctionReturn(0);
4282ebf164c7SToby Isaac }
4283ebf164c7SToby Isaac 
4284ebf164c7SToby Isaac static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4285ebf164c7SToby Isaac {
4286c921d74cSToby Isaac   DM             refTree;
4287c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4288c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4289c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4290c921d74cSToby Isaac   PetscSection   cSecRef;
4291c921d74cSToby Isaac   PetscInt       *parentIndices, pRefStart, pRefEnd;
4292d3bc4906SToby Isaac   PetscScalar    *rootValues, *parentValues;
4293c921d74cSToby Isaac   Mat            injRef;
4294c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4295c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4296c921d74cSToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
4297c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4298c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4299c921d74cSToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4300c921d74cSToby Isaac 
4301ebf164c7SToby Isaac   PetscFunctionBegin;
4302c921d74cSToby Isaac 
4303c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
43045f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE));
43055f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetOption(vecCoarse,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE));
43065f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetReferenceTree(coarse,&refTree));
43075f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCopyDisc(coarse,refTree));
43085f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(refTree,&cSecRef,NULL,NULL));
43095f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd));
43105f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexReferenceTreeGetInjector(refTree,&injRef));
4311c921d74cSToby Isaac 
43125f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(fine,&pStartF,&pEndF));
43135f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(fine,&localFine));
43145f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(fine,&globalFine));
43155f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetNumFields(localFine,&numFields));
43165f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(coarse,&pStartC,&pEndC));
43175f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(coarse,&localCoarse));
43185f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(coarse,&globalCoarse));
43195f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetMaxDof(localCoarse,&maxDof));
4320c921d74cSToby Isaac   {
4321c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
43225f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets));
4323c921d74cSToby Isaac   }
4324c921d74cSToby Isaac 
43255f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexTransferInjectorTree(coarse,fine,coarseToFine,cids,vecFine,numFields,offsets,&multiRootSec,&rootIndicesSec,NULL,&rootValues));
4326c921d74cSToby Isaac 
43275f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(maxDof,&parentIndices,maxDof,&parentValues));
4328c921d74cSToby Isaac 
4329c921d74cSToby Isaac   /* count indices */
43305f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetLayout(vecFine,&colMap));
43315f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetLayout(vecCoarse,&rowMap));
43325f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutSetUp(rowMap));
43335f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutSetUp(colMap));
43345f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutGetRange(rowMap,&rowStart,&rowEnd));
43355f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutGetRange(colMap,&colStart,&colEnd));
4336c921d74cSToby Isaac   /* insert values */
43375f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats));
4338c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4339c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
434078b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4341c921d74cSToby Isaac 
43425f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(globalCoarse,p,&dof));
43435f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
4344c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
43455f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(localCoarse,p,&dof));
43465f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(globalCoarse,p,&gOff));
4347c921d74cSToby Isaac 
4348c921d74cSToby Isaac     rowOffsets[0] = 0;
4349c921d74cSToby Isaac     offsetsCopy[0] = 0;
4350c921d74cSToby Isaac     if (numFields) {
4351c921d74cSToby Isaac       PetscInt f;
4352c921d74cSToby Isaac 
4353c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4354c921d74cSToby Isaac         PetscInt fDof;
43555f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
4356c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4357c921d74cSToby Isaac       }
43585f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,NULL,parentIndices));
4359367003a6SStefano Zampini     } else {
43605f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,NULL,parentIndices));
4361c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4362c921d74cSToby Isaac     }
4363c921d74cSToby Isaac 
43645f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(multiRootSec,p,&numLeaves));
43655f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(multiRootSec,p,&leafStart));
4366c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
43672f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4368c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4369c921d74cSToby Isaac       PetscInt numIndices, childId, offset;
4370c921d74cSToby Isaac       const PetscScalar *childValues;
4371c921d74cSToby Isaac 
43725f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(rootIndicesSec,l,&numIndices));
43735f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(rootIndicesSec,l,&offset));
4374c921d74cSToby Isaac       childId = (PetscInt) PetscRealPart(rootValues[offset++]);
4375c921d74cSToby Isaac       childValues = &rootValues[offset];
4376c921d74cSToby Isaac       numIndices--;
4377c921d74cSToby Isaac 
4378c921d74cSToby Isaac       if (childId == -2) { /* skip */
4379c921d74cSToby Isaac         continue;
4380c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
43812f65e181SToby Isaac         PetscInt m;
43822f65e181SToby Isaac 
438378b7adb5SToby Isaac         contribute = PETSC_TRUE;
43842f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4385beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4386d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4387d3bc4906SToby Isaac 
438878b7adb5SToby Isaac         contribute = PETSC_TRUE;
43895f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeParent(refTree,childId,&parentId,NULL));
4390d3bc4906SToby Isaac 
4391d3bc4906SToby Isaac         lim = PetscMax(1,numFields);
4392d3bc4906SToby Isaac         offsets[0] = 0;
4393d3bc4906SToby Isaac         if (numFields) {
4394d3bc4906SToby Isaac           PetscInt f;
4395d3bc4906SToby Isaac 
4396d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4397d3bc4906SToby Isaac             PetscInt fDof;
43985f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetFieldDof(cSecRef,childId,f,&fDof));
4399d3bc4906SToby Isaac 
4400d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4401d3bc4906SToby Isaac           }
4402d3bc4906SToby Isaac         }
4403d3bc4906SToby Isaac         else {
4404d3bc4906SToby Isaac           PetscInt cDof;
4405d3bc4906SToby Isaac 
44065f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(cSecRef,childId,&cDof));
4407d3bc4906SToby Isaac           offsets[1] = cDof;
4408d3bc4906SToby Isaac         }
4409d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4410d3bc4906SToby Isaac           PetscScalar       *childMat   = &childrenMats[childId - pRefStart][f][0];
4411d3bc4906SToby Isaac           PetscInt          n           = offsets[f+1]-offsets[f];
4412e328ff09SToby Isaac           PetscInt          m           = rowOffsets[f+1]-rowOffsets[f];
4413d3bc4906SToby Isaac           PetscInt          i, j;
4414d3bc4906SToby Isaac           const PetscScalar *colValues  = &childValues[offsets[f]];
4415d3bc4906SToby Isaac 
4416e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4417d3bc4906SToby Isaac             PetscScalar val = 0.;
4418d3bc4906SToby Isaac             for (j = 0; j < n; j++) {
4419d3bc4906SToby Isaac               val += childMat[n * i + j] * colValues[j];
4420d3bc4906SToby Isaac             }
4421e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4422d3bc4906SToby Isaac           }
4423d3bc4906SToby Isaac         }
4424c921d74cSToby Isaac       }
4425c921d74cSToby Isaac     }
44265f80ce2aSJacob Faibussowitsch     if (contribute) CHKERRQ(VecSetValues(vecCoarse,dof,parentIndices,parentValues,INSERT_VALUES));
4427c921d74cSToby Isaac   }
44285f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&multiRootSec));
44295f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&rootIndicesSec));
44305f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(parentIndices,parentValues));
44315f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats));
44325f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(rootValues));
44335f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree3(offsets,offsetsCopy,rowOffsets));
4434ebf164c7SToby Isaac   PetscFunctionReturn(0);
4435ebf164c7SToby Isaac }
4436ebf164c7SToby Isaac 
4437ff1f73f7SToby Isaac /*@
4438ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4439ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4440ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4441ff1f73f7SToby Isaac 
4442ff1f73f7SToby Isaac   collective
4443ff1f73f7SToby Isaac 
4444ff1f73f7SToby Isaac   Input Parameters:
4445ff1f73f7SToby Isaac + dmIn        - The DMPlex mesh for the input vector
4446ff1f73f7SToby Isaac . vecIn       - The input vector
4447ff1f73f7SToby Isaac . sfRefine    - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4448ff1f73f7SToby Isaac                 the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4449ff1f73f7SToby Isaac . sfCoarsen   - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4450ff1f73f7SToby Isaac                 the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4451ff1f73f7SToby Isaac . cidsRefine  - The childIds of the points in dmOut.  These childIds relate back to the reference tree: childid[j] = k implies
4452ff1f73f7SToby Isaac                 that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4453ff1f73f7SToby Isaac                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in dmOut is exactly
4454ff1f73f7SToby Isaac                 equivalent to its root in dmIn, so no interpolation is necessary.  childid[j] = -2 indicates that this
4455ff1f73f7SToby Isaac                 point j in dmOut is not a leaf of sfRefine.
4456ff1f73f7SToby Isaac . cidsCoarsen - The childIds of the points in dmIn.  These childIds relate back to the reference tree: childid[j] = k implies
4457ff1f73f7SToby Isaac                 that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4458ff1f73f7SToby Isaac                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4459ff1f73f7SToby Isaac . useBCs      - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4460ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4461ff1f73f7SToby Isaac 
4462ff1f73f7SToby Isaac   Output Parameters:
44638966356dSPierre Jolivet . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transferred
4464ff1f73f7SToby Isaac                 projection of vecIn from dmIn to dmOut.  Note that any field discretized with a PetscFV finite volume
4465ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4466ff1f73f7SToby Isaac                 coarse points to fine points.
4467ff1f73f7SToby Isaac 
4468ff1f73f7SToby Isaac   Level: developer
4469ff1f73f7SToby Isaac 
4470fd292e60Sprj- .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree(), PetscFVGetComputeGradients()
4471ff1f73f7SToby Isaac @*/
4472ff1f73f7SToby Isaac PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
447338fc2455SToby Isaac {
447438fc2455SToby Isaac   PetscFunctionBegin;
44755f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSet(vecOut,0.0));
4476ff1f73f7SToby Isaac   if (sfRefine) {
4477fbfa57b9SToby Isaac     Vec vecInLocal;
44780eb7e1eaSToby Isaac     DM  dmGrad = NULL;
44790eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4480fbfa57b9SToby Isaac 
44815f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetLocalVector(dmIn,&vecInLocal));
44825f80ce2aSJacob Faibussowitsch     CHKERRQ(VecSet(vecInLocal,0.0));
44830eb7e1eaSToby Isaac     {
44840eb7e1eaSToby Isaac       PetscInt  numFields, i;
44850eb7e1eaSToby Isaac 
44865f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetNumFields(dmIn, &numFields));
44870eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
44880eb7e1eaSToby Isaac         PetscObject  obj;
44890eb7e1eaSToby Isaac         PetscClassId classid;
44900eb7e1eaSToby Isaac 
44915f80ce2aSJacob Faibussowitsch         CHKERRQ(DMGetField(dmIn, i, NULL, &obj));
44925f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscObjectGetClassId(obj, &classid));
44930eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
44945f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetDataFVM(dmIn,(PetscFV)obj,&cellGeom,&faceGeom,&dmGrad));
44950eb7e1eaSToby Isaac           break;
44960eb7e1eaSToby Isaac         }
44970eb7e1eaSToby Isaac       }
44980eb7e1eaSToby Isaac     }
44990eb7e1eaSToby Isaac     if (useBCs) {
45005f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexInsertBoundaryValues(dmIn,PETSC_TRUE,vecInLocal,time,faceGeom,cellGeom,NULL));
45010eb7e1eaSToby Isaac     }
45025f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGlobalToLocalBegin(dmIn,vecIn,INSERT_VALUES,vecInLocal));
45035f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGlobalToLocalEnd(dmIn,vecIn,INSERT_VALUES,vecInLocal));
45040eb7e1eaSToby Isaac     if (dmGrad) {
45055f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetGlobalVector(dmGrad,&grad));
45065f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexReconstructGradientsFVM(dmIn,vecInLocal,grad));
45070eb7e1eaSToby Isaac     }
45085f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexTransferVecTree_Interpolate(dmIn,vecInLocal,dmOut,vecOut,sfRefine,cidsRefine,grad,cellGeom));
45095f80ce2aSJacob Faibussowitsch     CHKERRQ(DMRestoreLocalVector(dmIn,&vecInLocal));
45100eb7e1eaSToby Isaac     if (dmGrad) {
45115f80ce2aSJacob Faibussowitsch       CHKERRQ(DMRestoreGlobalVector(dmGrad,&grad));
45120eb7e1eaSToby Isaac     }
4513ebf164c7SToby Isaac   }
4514ff1f73f7SToby Isaac   if (sfCoarsen) {
45155f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexTransferVecTree_Inject(dmIn,vecIn,dmOut,vecOut,sfCoarsen,cidsCoarsen));
4516ebf164c7SToby Isaac   }
45175f80ce2aSJacob Faibussowitsch   CHKERRQ(VecAssemblyBegin(vecOut));
45185f80ce2aSJacob Faibussowitsch   CHKERRQ(VecAssemblyEnd(vecOut));
451938fc2455SToby Isaac   PetscFunctionReturn(0);
452038fc2455SToby Isaac }
4521